aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cschnei...@apache.org
Subject [1/2] aries-rsa git commit: [ARIES-1573] Configuration from properties
Date Tue, 21 Jun 2016 18:07:10 GMT
Repository: aries-rsa
Updated Branches:
  refs/heads/master 7909d39cf -> 7c73a3710


[ARIES-1573] Configuration from properties


Project: http://git-wip-us.apache.org/repos/asf/aries-rsa/repo
Commit: http://git-wip-us.apache.org/repos/asf/aries-rsa/commit/a2b6e974
Tree: http://git-wip-us.apache.org/repos/asf/aries-rsa/tree/a2b6e974
Diff: http://git-wip-us.apache.org/repos/asf/aries-rsa/diff/a2b6e974

Branch: refs/heads/master
Commit: a2b6e974c3c8b5c0f29d78562a1cc5df80de0301
Parents: 7909d39
Author: Dmytro Pishchukhin <dmytro.pishchukhin@gmail.com>
Authored: Tue Jun 21 15:55:28 2016 +0200
Committer: Christian Schneider <chris@die-schneider.net>
Committed: Tue Jun 21 19:59:07 2016 +0200

----------------------------------------------------------------------
 discovery/config/Readme.md                      |  19 ++
 discovery/config/bnd.bnd                        |   2 +
 discovery/config/pom.xml                        |  60 +++++++
 .../aries/rsa/discovery/config/Activator.java   |  82 +++++++++
 .../rsa/discovery/config/ConfigDiscovery.java   | 176 +++++++++++++++++++
 .../rsa/discovery/config/PropertyValidator.java | 104 +++++++++++
 .../discovery/config/PropertyValidatorTest.java | 106 +++++++++++
 discovery/pom.xml                               |   1 +
 features/src/main/resources/features.xml        |   5 +
 9 files changed, 555 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/Readme.md
----------------------------------------------------------------------
diff --git a/discovery/config/Readme.md b/discovery/config/Readme.md
new file mode 100644
index 0000000..d0aaa2f
--- /dev/null
+++ b/discovery/config/Readme.md
@@ -0,0 +1,19 @@
+# Config Discovery
+
+Reads endpoint descriptions from ConfigAdmin configurations factory pid **org.apache.aries.rsa.discovery.config**.
+
+The config discovery module will notify all interested EndpointListeners of each described
endpoint.
+This will cause the TopologyManager to let the RemoteServiceAdmin create local proxy services
for
+the remote endpoints.
+
+## Example
+
+Configuration properties in org.apache.aries.rsa.discovery.config-test.cfg file
+
+```
+service.imported = true
+service.imported.configs = org.apache.cxf.rs
+objectClass = org.acme.foo.rest.api.FooService
+org.apache.cxf.rs.address = http://localhost:9100/
+org.apache.cxf.rs.provider = org.acme.foo.rest.json.CustomJSONProvider
+```

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/bnd.bnd
----------------------------------------------------------------------
diff --git a/discovery/config/bnd.bnd b/discovery/config/bnd.bnd
new file mode 100644
index 0000000..6c6d30f
--- /dev/null
+++ b/discovery/config/bnd.bnd
@@ -0,0 +1,2 @@
+Bundle-Activator: org.apache.aries.rsa.discovery.config.Activator
+Private-Package: org.apache.aries.rsa.discovery.config

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/pom.xml
----------------------------------------------------------------------
diff --git a/discovery/config/pom.xml b/discovery/config/pom.xml
new file mode 100644
index 0000000..a3db8c3
--- /dev/null
+++ b/discovery/config/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements. See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership. The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License. You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied. See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.aries.rsa</groupId>
+        <artifactId>org.apache.aries.rsa.discovery</artifactId>
+        <version>1.9-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.aries.rsa.discovery</groupId>
+    <artifactId>org.apache.aries.rsa.discovery.config</artifactId>
+    <packaging>bundle</packaging>
+    <name>Aries Remote Service Admin Discovery Config</name>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.rsa</groupId>
+            <artifactId>org.apache.aries.rsa.spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <configuration>
+                    <excludePackageNames>org.osgi.*</excludePackageNames>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/Activator.java
----------------------------------------------------------------------
diff --git a/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/Activator.java
b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/Activator.java
new file mode 100644
index 0000000..9b0cf09
--- /dev/null
+++ b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/Activator.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.rsa.discovery.config;
+
+import org.osgi.framework.*;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+
+import java.util.Hashtable;
+
+public class Activator implements BundleActivator {
+    private static final String FACTORY_PID = "org.apache.aries.rsa.discovery.config";
+
+    private ServiceTracker<EndpointListener, EndpointListener> listenerTracker;
+    private ServiceRegistration<ManagedServiceFactory> registration;
+
+    public void start(BundleContext context) {
+        ConfigDiscovery configDiscovery = new ConfigDiscovery();
+        listenerTracker = new EPListenerTracker(context, configDiscovery);
+        listenerTracker.open();
+        Hashtable<String, Object> props = new Hashtable<>();
+        props.put(Constants.SERVICE_PID, FACTORY_PID);
+        registration = context.registerService(ManagedServiceFactory.class, configDiscovery,
props);
+    }
+
+    public void stop(BundleContext context) {
+        registration.unregister();
+        listenerTracker.close();
+    }
+
+    private final class EPListenerTracker extends ServiceTracker<EndpointListener, EndpointListener>
{
+        private final ConfigDiscovery configDiscovery;
+
+        private EPListenerTracker(BundleContext context, ConfigDiscovery configDiscovery)
{
+            super(context, EndpointListener.class, null);
+            this.configDiscovery = configDiscovery;
+        }
+
+        @Override
+        public EndpointListener addingService(ServiceReference<EndpointListener> reference)
{
+            EndpointListener service = super.addingService(reference);
+            configDiscovery.addListener(reference, service);
+            return service;
+        }
+
+        @Override
+        public void modifiedService(ServiceReference<EndpointListener> reference, EndpointListener
service) {
+            super.modifiedService(reference, service);
+            configDiscovery.removeListener(service);
+
+            // This may cause duplicate registrations of remote services,
+            // but that's fine and should be filtered out on another level.
+            // See Remote Service Admin spec section 122.6.3
+            configDiscovery.addListener(reference, service);
+        }
+
+        @Override
+        public void removedService(ServiceReference<EndpointListener> reference, EndpointListener
service) {
+            super.removedService(reference, service);
+            configDiscovery.removeListener(service);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/ConfigDiscovery.java
----------------------------------------------------------------------
diff --git a/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/ConfigDiscovery.java
b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/ConfigDiscovery.java
new file mode 100644
index 0000000..8112de9
--- /dev/null
+++ b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/ConfigDiscovery.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.rsa.discovery.config;
+
+import org.apache.aries.rsa.util.StringPlus;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+class ConfigDiscovery implements ManagedServiceFactory {
+    private final Map<EndpointDescription, String> endpointDescriptions = new ConcurrentHashMap<>();
+    private final Map<EndpointListener, Collection<String>> listenerToFilters
= new HashMap<>();
+    private final Map<String, Collection<EndpointListener>> filterToListeners
= new HashMap<>();
+
+    @Override
+    public String getName() {
+        return "Aries RSA Config Discovery";
+    }
+
+    @Override
+    public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException
{
+        addDeclaredRemoteService(pid, properties);
+    }
+
+    @Override
+    public void deleted(String pid) {
+        removeServiceDeclaredInConfig(pid);
+    }
+
+    void addListener(ServiceReference<EndpointListener> endpointListenerRef, EndpointListener
endpointListener) {
+        List<String> filters = StringPlus.normalize(endpointListenerRef.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE));
+        if (filters.isEmpty()) {
+            return;
+        }
+
+        synchronized (listenerToFilters) {
+            listenerToFilters.put(endpointListener, filters);
+            for (String filter : filters) {
+                Collection<EndpointListener> listeners = filterToListeners.get(filter);
+                if (listeners == null) {
+                    listeners = new ArrayList<>();
+                    filterToListeners.put(filter, listeners);
+                }
+                listeners.add(endpointListener);
+            }
+        }
+
+        triggerCallbacks(filters, endpointListener);
+    }
+
+    void removeListener(EndpointListener endpointListener) {
+        synchronized (listenerToFilters) {
+            Collection<String> filters = listenerToFilters.remove(endpointListener);
+            if (filters == null) {
+                return;
+            }
+
+            for (String filter : filters) {
+                Collection<EndpointListener> listeners = filterToListeners.get(filter);
+                if (listeners != null) {
+                    listeners.remove(endpointListener);
+                    if (listeners.isEmpty()) {
+                        filterToListeners.remove(filter);
+                    }
+                }
+            }
+        }
+    }
+
+    private Map<String, Collection<EndpointListener>> getMatchingListeners(EndpointDescription
endpoint) {
+        // return a copy of matched filters/listeners so that caller doesn't need to hold
locks while triggering events
+        Map<String, Collection<EndpointListener>> matched = new HashMap<>();
+        synchronized (listenerToFilters) {
+            for (Map.Entry<String, Collection<EndpointListener>> entry : filterToListeners.entrySet())
{
+                String filter = entry.getKey();
+                if (matchFilter(filter, endpoint)) {
+                    matched.put(filter, new ArrayList<>(entry.getValue()));
+                }
+            }
+        }
+        return matched;
+    }
+
+    private void addDeclaredRemoteService(String pid, Dictionary config) {
+        EndpointDescription endpoint = new EndpointDescription(PropertyValidator.validate(config));
+        endpointDescriptions.put(endpoint, pid);
+        addedEndpointDescription(endpoint);
+    }
+
+    private void removeServiceDeclaredInConfig(String pid) {
+        for (Iterator<Map.Entry<EndpointDescription, String>> i = endpointDescriptions.entrySet().iterator();
+             i.hasNext(); ) {
+            Map.Entry<EndpointDescription, String> entry = i.next();
+            if (pid.equals(entry.getValue())) {
+                removedEndpointDescription(entry.getKey());
+                i.remove();
+            }
+        }
+    }
+
+    private void addedEndpointDescription(EndpointDescription endpoint) {
+        triggerCallbacks(endpoint, true);
+    }
+
+    private void removedEndpointDescription(EndpointDescription endpoint) {
+        triggerCallbacks(endpoint, false);
+    }
+
+    private void triggerCallbacks(EndpointDescription endpoint, boolean added) {
+        for (Map.Entry<String, Collection<EndpointListener>> entry : getMatchingListeners(endpoint).entrySet())
{
+            String filter = entry.getKey();
+            for (EndpointListener listener : entry.getValue()) {
+                triggerCallbacks(listener, filter, endpoint, added);
+            }
+        }
+    }
+
+    private void triggerCallbacks(EndpointListener endpointListener, String filter,
+                                  EndpointDescription endpoint, boolean added) {
+        if (!matchFilter(filter, endpoint)) {
+            return;
+        }
+
+        if (added) {
+            endpointListener.endpointAdded(endpoint, filter);
+        } else {
+            endpointListener.endpointRemoved(endpoint, filter);
+        }
+    }
+
+    private void triggerCallbacks(Collection<String> filters, EndpointListener endpointListener)
{
+        for (String filter : filters) {
+            for (EndpointDescription endpoint : endpointDescriptions.keySet()) {
+                triggerCallbacks(endpointListener, filter, endpoint, true);
+            }
+        }
+    }
+
+    private static boolean matchFilter(String filter, EndpointDescription endpoint) {
+        if (filter == null) {
+            return false;
+        }
+
+        try {
+            Filter f = FrameworkUtil.createFilter(filter);
+            Dictionary<String, Object> dict = new Hashtable<>(endpoint.getProperties());
+            return f.match(dict);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/PropertyValidator.java
----------------------------------------------------------------------
diff --git a/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/PropertyValidator.java
b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/PropertyValidator.java
new file mode 100644
index 0000000..bd421b4
--- /dev/null
+++ b/discovery/config/src/main/java/org/apache/aries/rsa/discovery/config/PropertyValidator.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.rsa.discovery.config;
+
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.util.*;
+
+class PropertyValidator {
+    /**
+     * Validates configuration properties,
+     * filter out ConfigAdmin specific properties,
+     * transforms if needed property types to OSGi CMPN 6. Chapter 122.4
+     *
+     * @param config configuration properties
+     * @return map with validated properties
+     */
+    static Map<String, Object> validate(Dictionary config) {
+        return validatePropertyTypes(filterConfigAdminProperties(toMap(config)));
+    }
+
+    static Map<String, Object> validatePropertyTypes(Map<String, Object> map)
{
+        HashMap<String, Object> result = new HashMap<>();
+        if (map != null) {
+            for (String key : map.keySet()) {
+                if (Constants.OBJECTCLASS.equals(key)) {
+                    result.put(key, convertToStringArray(map.get(key)));
+                } else {
+                    result.put(key, map.get(key));
+                }
+            }
+        }
+        return result;
+    }
+
+    static String[] convertToStringArray(Object o) {
+        String[] result;
+        
+        if (o == null) {
+            result = new String[0];
+        } else if (o instanceof List) {
+            List list = (List) o;
+            result = new String[list.size()];
+            for (int i = 0; i < list.size(); i++) {
+                result[i] = String.valueOf(list.get(i));
+            }
+        } else if (o.getClass().isArray()) {
+            Object[] array = (Object[]) o;
+            result = new String[array.length];
+            for (int i = 0; i < array.length; i++) {
+                result[i] = String.valueOf(array[i]);
+            }
+        } else {
+            result = new String[1];
+            result[0] = String.valueOf(o);
+        }
+        return result;
+    }
+
+    static Map<String, Object> filterConfigAdminProperties(Map<String, ?> map)
{
+        HashMap<String, Object> result = new HashMap<>();
+        if (map != null) {
+            for (String key : map.keySet()) {
+                if (Constants.SERVICE_PID.equals(key)
+                        || ConfigurationAdmin.SERVICE_FACTORYPID.equals(key)
+                        || ConfigurationAdmin.SERVICE_BUNDLELOCATION.equals(key)) {
+                    continue;
+                }
+                result.put(key, map.get(key));
+            }
+        }
+        return result;
+    }
+
+    static Map<String, Object> toMap(Dictionary dic) {
+        HashMap<String, Object> map = new HashMap<>();
+        if (dic != null) {
+            Enumeration keys = dic.keys();
+            while (keys.hasMoreElements()) {
+                String key = (String) keys.nextElement();
+                map.put(key, dic.get(key));
+            }
+        }
+        return map;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/config/src/test/java/org/apache/aries/rsa/discovery/config/PropertyValidatorTest.java
----------------------------------------------------------------------
diff --git a/discovery/config/src/test/java/org/apache/aries/rsa/discovery/config/PropertyValidatorTest.java
b/discovery/config/src/test/java/org/apache/aries/rsa/discovery/config/PropertyValidatorTest.java
new file mode 100644
index 0000000..14cd0d5
--- /dev/null
+++ b/discovery/config/src/test/java/org/apache/aries/rsa/discovery/config/PropertyValidatorTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.rsa.discovery.config;
+
+import org.hamcrest.core.Is;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+import static java.util.Collections.singletonList;
+import static org.apache.aries.rsa.discovery.config.PropertyValidator.*;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author dpishchukhin
+ */
+public class PropertyValidatorTest {
+    @Test
+    public void testToMap() throws Exception {
+        Hashtable dic = new Hashtable() {{
+            put("key", "value");
+        }};
+
+        assertThat(toMap(dic).size(), is(1));
+        assertThat(toMap(dic).keySet().contains("key"), is(true));
+        assertThat(toMap(dic).get("key"), Is.<Object>is("value"));
+
+        assertThat(toMap(null), notNullValue());
+        assertThat(toMap(null).size(), is(0));
+    }
+
+    @Test
+    public void testFilterConfigAdminProperties() throws Exception {
+        Map<String, Object> map = new HashMap<String, Object>() {{
+            put(Constants.SERVICE_PID, "testPid");
+            put(ConfigurationAdmin.SERVICE_FACTORYPID, "factoryPid");
+            put(ConfigurationAdmin.SERVICE_BUNDLELOCATION, "bundleLocation");
+        }};
+
+        assertThat(filterConfigAdminProperties(map).size(), is(0));
+        assertThat(filterConfigAdminProperties(null), notNullValue());
+        assertThat(filterConfigAdminProperties(null).size(), is(0));
+    }
+
+    @Test
+    public void testValidatePropertyTypes_null_param() throws Exception {
+        assertThat(validatePropertyTypes(null), notNullValue());
+        assertThat(validatePropertyTypes(null).size(), is(0));
+    }
+
+    @Test
+    public void testValidatePropertyTypes_objectClass() throws Exception {
+        Map<String, Object> map = new HashMap<String, Object>() {{
+            put(Constants.OBJECTCLASS, "test");
+        }};
+        Map<String, Object> config = validatePropertyTypes(map);
+        assertThat(config.containsKey(Constants.OBJECTCLASS), is(true));
+        assertThat(config.get(Constants.OBJECTCLASS), Is.<Object>is(new String[]{"test"}));
+
+        map = new HashMap<String, Object>() {{
+            put(Constants.OBJECTCLASS, new String[]{"test"});
+        }};
+        config = validatePropertyTypes(map);
+        assertThat(config.get(Constants.OBJECTCLASS), Is.<Object>is(new String[]{"test"}));
+
+        map = new HashMap<String, Object>() {{
+            put(Constants.OBJECTCLASS, singletonList("test"));
+        }};
+        config = validatePropertyTypes(map);
+        assertThat(config.get(Constants.OBJECTCLASS), Is.<Object>is(new String[]{"test"}));
+    }
+
+    @Test
+    public void testConvertToStringArray() throws Exception {
+        assertThat(convertToStringArray(null), Is.<Object>is(new String[0]));
+        assertThat(convertToStringArray("test"), Is.<Object>is(new String[]{"test"}));
+        assertThat(convertToStringArray(new String[]{"test"}), Is.<Object>is(new String[]{"test"}));
+        assertThat(convertToStringArray(singletonList("test")), Is.<Object>is(new String[]{"test"}));
+        assertThat(convertToStringArray(new Vector<>(singletonList("test"))), Is.<Object>is(new
String[]{"test"}));
+        assertThat(convertToStringArray(1), Is.<Object>is(new String[]{"1"}));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/discovery/pom.xml
----------------------------------------------------------------------
diff --git a/discovery/pom.xml b/discovery/pom.xml
index cf9ecab..bd9a940 100644
--- a/discovery/pom.xml
+++ b/discovery/pom.xml
@@ -34,5 +34,6 @@
     <modules>
       <module>local</module>
       <module>zookeeper</module>
+      <module>config</module>
     </modules>
 </project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/a2b6e974/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/features/src/main/resources/features.xml b/features/src/main/resources/features.xml
index be79a3b..a109ce0 100644
--- a/features/src/main/resources/features.xml
+++ b/features/src/main/resources/features.xml
@@ -28,6 +28,11 @@
         <bundle>mvn:org.apache.aries.rsa.discovery/org.apache.aries.rsa.discovery.local/${project.version}</bundle>
     </feature>
 
+    <feature name="aries-rsa-discovery-config" version="${project.version}">
+        <feature>aries-rsa-core</feature>
+        <bundle>mvn:org.apache.aries.rsa.discovery/org.apache.aries.rsa.discovery.config/${project.version}</bundle>
+    </feature>
+
     <feature name="aries-rsa-discovery-zookeeper" version="${project.version}">
         <feature>aries-rsa-core</feature>
         <bundle>mvn:org.apache.zookeeper/zookeeper/${zookeeper.version}</bundle>


Mime
View raw message