DOSGI-202 Make DOSGi independent of jdom
authorChristian Schneider <cschneider@apache.org>
Thu, 15 Aug 2013 20:40:29 +0000 (20:40 +0000)
committerChristian Schneider <cschneider@apache.org>
Thu, 15 Aug 2013 20:40:29 +0000 (20:40 +0000)
git-svn-id: https://svn.apache.org/repos/asf/cxf/dosgi/trunk@1514476 13f79535-47bb-0310-9956-ffa450edef68

31 files changed:
discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
discovery/local/pom.xml
discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscovery.java
discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtils.java [deleted file]
discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/Utils.java
discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java [new file with mode: 0644]
discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java [new file with mode: 0644]
discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java [new file with mode: 0644]
discovery/local/src/main/resources/endpoint-description.xsd [new file with mode: 0644]
discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtilsTest.java [deleted file]
discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java [new file with mode: 0644]
discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java [new file with mode: 0644]
discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java [new file with mode: 0644]
discovery/local/src/test/resources/ed2-generated.xml
distribution/features/src/main/resources/features.xml
distribution/multi-bundle/pom.xml
distribution/multi-bundle/src/main/appended-resources/META-INF/NOTICE
distribution/multi-bundle/src/main/assembly/assembly.xml
distribution/multi-bundle/src/main/resources/META-INF/NOTICE.jdom [deleted file]
distribution/multi-bundle/src/main/resources/distro_bundles.xml
distribution/multi-bundle2/src/main/assembly/assembly.xml
dsw/cxf-dsw/pom.xml
dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java [new file with mode: 0644]
dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRule.java
dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImpl.java
dsw/cxf-dsw/src/main/resources/service-decoration.xsd [new file with mode: 0644]
dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java [new file with mode: 0644]
dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImplTest.java
parent/pom.xml

index 2f506c3..0967626 100644 (file)
@@ -28,22 +28,24 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cxf.dosgi.discovery.local.util.EndpointUtils;
 import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
 import org.apache.zookeeper.ZooDefs.Ids;
 import org.apache.zookeeper.ZooKeeper;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.EndpointListener;
 import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.zookeeper.KeeperException.NoNodeException;
-import static org.apache.zookeeper.KeeperException.NodeExistsException;
-
 /**
  * Listens for local Endpoints and publishes them to ZooKeeper.
  */
@@ -56,10 +58,13 @@ public class PublishingEndpointListener implements EndpointListener {
     private final List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
     private boolean closed;
 
+    private final EndpointDescriptionParser endpointDescriptionParser;
+
     public PublishingEndpointListener(ZooKeeper zk, BundleContext bctx) {
         this.zk = zk;
         discoveryPluginTracker = new ServiceTracker(bctx, DiscoveryPlugin.class.getName(), null);
         discoveryPluginTracker.open();
+        endpointDescriptionParser = new EndpointDescriptionParser();
     }
 
     public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
@@ -104,7 +109,11 @@ public class PublishingEndpointListener implements EndpointListener {
             String fullPath = path + '/' + endpointKey;
             LOG.debug("Creating ZooKeeper node: {}", fullPath);
             ensurePath(path, zk);
-            createEphemeralNode(fullPath, getData(props));
+            List<PropertyType> propsOut = new PropertiesMapper().fromProps(props);
+            EndpointDescriptionType epd = new EndpointDescriptionType();
+            epd.getProperty().addAll(propsOut);
+            byte[] epData = endpointDescriptionParser.getData(epd);
+            createEphemeralNode(fullPath, epData);
         }
     }
 
@@ -176,10 +185,6 @@ public class PublishingEndpointListener implements EndpointListener {
         }
     }
 
-    static byte[] getData(Map<String, Object> props) {
-        return EndpointUtils.getEndpointDescriptionXML(props).getBytes();
-    }
-
     static String getKey(String endpoint) throws URISyntaxException {
         URI uri = new URI(endpoint);
 
index 6a0fcbc..5584c77 100644 (file)
  */
 package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
 
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.cxf.dosgi.discovery.local.util.EndpointUtils;
 import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
 import org.apache.zookeeper.AsyncCallback.StatCallback;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.KeeperException.Code;
@@ -34,6 +36,7 @@ import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.data.Stat;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,11 +64,14 @@ public class InterfaceMonitor implements Watcher, StatCallback {
     // This map reference changes, so don't synchronize on it
     private Map<String, EndpointDescription> nodes = new HashMap<String, EndpointDescription>();
 
+    private EndpointDescriptionParser parser;
+
     public InterfaceMonitor(ZooKeeper zk, String objClass, EndpointListener endpointListener, String scope) {
         this.zk = zk;
         this.znode = Utils.getZooKeeperPath(objClass);
         this.recursive = objClass == null || objClass.isEmpty();
         this.endpointListener = endpointListener;
+        this.parser = new EndpointDescriptionParser();
         LOG.debug("Creating new InterfaceMonitor {} for scope [{}] and objectClass [{}]",
                 new Object[] {recursive ? "(recursive)" : "", scope, objClass});
     }
@@ -230,7 +236,7 @@ public class InterfaceMonitor implements Watcher, StatCallback {
             byte[] data = zk.getData(node, false, null);
             LOG.debug("Got data for node: {}", node);
 
-            EndpointDescription endpoint = EndpointUtils.getFirstEnpointDescription(data);
+            EndpointDescription endpoint = getFirstEnpointDescription(data);
             if (endpoint != null) {
                 return endpoint;
             }
@@ -240,4 +246,13 @@ public class InterfaceMonitor implements Watcher, StatCallback {
         }
         return null;
     }
+
+    public EndpointDescription getFirstEnpointDescription(byte[] data) {
+        List<EndpointDescriptionType> elements = parser.getEndpointDescriptions(new ByteArrayInputStream(data));
+        if (elements.isEmpty()) {
+            return null;
+        }
+        Map<String, Object> props = new PropertiesMapper().toProps(elements.get(0).getProperty());
+        return new EndpointDescription(props);
+    }
 }
index bec2f2d..b1cb54d 100644 (file)
@@ -25,6 +25,8 @@ import java.util.Map;
 
 import junit.framework.TestCase;
 
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.ZooDefs.Ids;
@@ -40,6 +42,8 @@ import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
 
 public class PublishingEndpointListenerTest extends TestCase {
 
@@ -124,9 +128,14 @@ public class PublishingEndpointListenerTest extends TestCase {
 
         final ZooKeeper zk = EasyMock.createNiceMock(ZooKeeper.class);
         String expectedFullPath = "/osgi/service_registry/org/foo/myClass/some.machine#9876##test";
+        
+        List<PropertyType> props2 = new PropertiesMapper().fromProps(expectedProps);
+        EndpointDescriptionType epd = new EndpointDescriptionType();
+        epd.getProperty().addAll(props2);
+        byte[] data = new EndpointDescriptionParser().getData(epd);
         EasyMock.expect(zk.create(
                 EasyMock.eq(expectedFullPath),
-                EasyMock.aryEq(PublishingEndpointListener.getData(expectedProps)),
+                EasyMock.aryEq(data),
                 EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
                 EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("");
         EasyMock.replay(zk);
index bcc30fd..6fb1a0a 100644 (file)
         </dependency>
 
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.jdom</artifactId>
-            <version>${jdom.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
     <build>
         <plugins>
             <plugin>
+                <groupId>org.jvnet.jaxb2.maven2</groupId>
+                <artifactId>maven-jaxb2-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                             org.osgi.service.remoteserviceadmin;version="[${remote.service.admin.interfaces.version},2.0)",
                             *
                         </Import-Package>
-                        <Private-Package>org.apache.cxf.dosgi.discovery.local.internal</Private-Package>
-                        <Export-Package>
-                            org.apache.cxf.dosgi.discovery.local.util
-                        </Export-Package>
                     </instructions>
                 </configuration>
             </plugin>
index 8beb680..962481b 100644 (file)
@@ -27,8 +27,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.cxf.dosgi.discovery.local.util.EndpointUtils;
 import org.apache.cxf.dosgi.discovery.local.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionBundleParser;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -50,9 +50,11 @@ public class LocalDiscovery implements BundleListener {
         new HashMap<String, Collection<EndpointListener>>();
     final BundleContext bundleContext;
 
+    EndpointDescriptionBundleParser bundleParser;
     ServiceTracker listenerTracker;
 
     public LocalDiscovery(BundleContext bc) {
+        this.bundleParser = new EndpointDescriptionBundleParser();
         bundleContext = bc;
 
         listenerTracker = new ServiceTracker(bundleContext, EndpointListener.class.getName(), null) {
@@ -173,7 +175,7 @@ public class LocalDiscovery implements BundleListener {
     }
 
     private void findDeclaredRemoteServices(Bundle bundle) {
-        List<EndpointDescription> endpoints = EndpointUtils.getAllEndpointDescriptions(bundle);
+        List<EndpointDescription> endpoints = bundleParser.getAllEndpointDescriptions(bundle);
         for (EndpointDescription endpoint : endpoints) {
             endpointDescriptions.put(endpoint, bundle);
             addedEndpointDescription(endpoint);
diff --git a/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtils.java b/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtils.java
deleted file mode 100644 (file)
index 3f968ca..0000000
+++ /dev/null
@@ -1,545 +0,0 @@
-/**
- * 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.cxf.dosgi.discovery.local.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.Namespace;
-import org.jdom.input.SAXBuilder;
-import org.jdom.output.Format;
-import org.jdom.output.XMLOutputter;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class EndpointUtils {
-
-    private static final Logger LOG = LoggerFactory.getLogger(EndpointUtils.class);
-
-    private static final String REMOTE_SERVICES_HEADER_NAME = "Remote-Service";
-    private static final String REMOTE_SERVICES_DIRECTORY = "OSGI-INF/remote-service/";
-    // this one was replaced by the RSA one in the spec
-    private static final String REMOTE_SERVICES_NS = "http://www.osgi.org/xmlns/sd/v1.0.0";
-    private static final String REMOTE_SERVICES_ADMIN_NS = "http://www.osgi.org/xmlns/rsa/v1.0.0";
-
-    private static final String SERVICE_DESCRIPTION_ELEMENT = "service-description";
-    private static final String ENDPOINT_DESCRIPTION_ELEMENT = "endpoint-description";
-
-    private static final String PROVIDE_INTERFACE_ELEMENT = "provide";
-    private static final String PROVIDE_INTERFACE_NAME_ATTRIBUTE = "interface";
-
-    private static final String PROPERTY_ELEMENT = "property";
-    private static final String PROPERTY_NAME_ATTRIBUTE = "name";
-    private static final String PROPERTY_VALUE_ATTRIBUTE = "value";
-    private static final String PROPERTY_VALUE_TYPE_ATTRIBUTE = "value-type";
-    private static final String PROPERTY_INTERFACE_ATTRIBUTE = "interface";
-
-    private static final String INTERFACE_SEPARATOR = ":";
-
-    private EndpointUtils() {
-    }
-
-    public static List<EndpointDescription> getAllEndpointDescriptions(Bundle b) {
-        List<Element> elements = getAllDescriptionElements(b);
-
-        List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>(elements.size());
-        for (Element el : elements) {
-            if (ENDPOINT_DESCRIPTION_ELEMENT.equals(el.getName())) {
-                endpoints.add(getEndpointDescription(el));
-            } else if (SERVICE_DESCRIPTION_ELEMENT.equals(el.getName())) {
-                endpoints.add(getLegacyEndpointDescription(el));
-            }
-        }
-        return endpoints;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static EndpointDescription getEndpointDescription(Element endpointDescriptionElement) {
-        Map<String, Object> map = new HashMap<String, Object>();
-
-        List<Element> properties = endpointDescriptionElement.getChildren(PROPERTY_ELEMENT,
-                Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        for (Element prop : properties) {
-            boolean handled = handleArray(prop, map);
-            if (handled) {
-                continue;
-            }
-            handled = handleCollection(prop, map);
-            if (handled) {
-                continue;
-            }
-            handled = handleXML(prop, map);
-            if (handled) {
-                continue;
-            }
-
-            String name = prop.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
-            String value = prop.getAttributeValue(PROPERTY_VALUE_ATTRIBUTE);
-            if (value == null) {
-                value = prop.getText();
-            }
-            String type = getTypeName(prop);
-            map.put(name, instantiate(type, value));
-        }
-        return new EndpointDescription(map);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static EndpointDescription getLegacyEndpointDescription(Element el) {
-        Namespace ns = Namespace.getNamespace(REMOTE_SERVICES_NS);
-
-        List<String> iNames = getProvidedInterfaces(el.getChildren(PROVIDE_INTERFACE_ELEMENT, ns));
-        Map<String, Object> remoteProps = getProperties(el.getChildren(PROPERTY_ELEMENT, ns));
-
-        if (remoteProps.get(Constants.OBJECTCLASS) == null) {
-            remoteProps.put(Constants.OBJECTCLASS, iNames.toArray(new String[] {}));
-        }
-
-        Object uri = remoteProps.get("org.apache.cxf.ws.address");
-        if (uri == null) {
-            uri = remoteProps.get("osgi.remote.configuration.pojo.address");
-        }
-        if (uri == null) {
-            String firstIntf = iNames.get(0);
-            uri = "http://localhost:9000/" + firstIntf.replace('.', '/');
-        }
-        remoteProps.put(RemoteConstants.ENDPOINT_ID, uri.toString());
-
-        Object exportedConfigs = remoteProps.get(RemoteConstants.SERVICE_EXPORTED_CONFIGS);
-        if (exportedConfigs == null) {
-            exportedConfigs = "org.apache.cxf.ws";
-        }
-        remoteProps.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, exportedConfigs);
-
-        for (Iterator<String> it = remoteProps.keySet().iterator(); it.hasNext();) {
-            if (it.next().startsWith("service.exported.")) {
-                it.remove();
-            }
-        }
-
-        return new EndpointDescription(remoteProps);
-    }
-
-    private static String getTypeName(Element prop) {
-        String type = prop.getAttributeValue(PROPERTY_VALUE_TYPE_ATTRIBUTE);
-        return type == null ? "String" : type;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static boolean handleArray(Element prop, Map<String, Object> map) {
-        Element arrayEl = prop.getChild("array", Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        if (arrayEl == null) {
-            return false;
-        }
-
-        List<Element> values = arrayEl.getChildren(PROPERTY_VALUE_ATTRIBUTE,
-                Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        String type = getTypeName(prop);
-        Class<?> cls = null;
-        if ("long".equals(type)) {
-            cls = long.class;
-        } else if ("double".equals(type)) {
-            cls = double.class;
-        } else if ("float".equals(type)) {
-            cls = float.class;
-        } else if ("int".equals(type)) {
-            cls = int.class;
-        } else if ("byte".equals(type)) {
-            cls = byte.class;
-        } else if ("boolean".equals(type)) {
-            cls = boolean.class;
-        } else if ("short".equals(type)) {
-            cls = short.class;
-        }
-
-        try {
-            if (cls == null) {
-                cls = ClassLoader.getSystemClassLoader().loadClass("java.lang." + type);
-            }
-            Object array = Array.newInstance(cls, values.size());
-
-            for (int i = 0; i < values.size(); i++) {
-                Element vEl = values.get(i);
-                Object val = handleValue(vEl, type);
-                Array.set(array, i, val);
-            }
-
-            String name = prop.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
-            map.put(name, array);
-            return true;
-        } catch (Exception e) {
-            LOG.warn("Could not create array for Endpoint Description", e);
-            return false;
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private static boolean handleCollection(Element prop, Map<String, Object> map) {
-        Collection<Object> col = null;
-        Element el = prop.getChild("list",
-                Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        if (el != null) {
-            col = new ArrayList<Object>();
-        } else {
-            el = prop.getChild("set", Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-            if (el != null) {
-                col = new HashSet<Object>();
-            }
-        }
-
-        if (el == null) {
-            return false;
-        }
-
-        String type = getTypeName(prop);
-        List<Element> values = el.getChildren(PROPERTY_VALUE_ATTRIBUTE,
-                Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        for (Element val : values) {
-            Object obj = handleValue(val, type);
-            col.add(obj);
-        }
-
-        String name = prop.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
-        map.put(name, col);
-        return true;
-    }
-
-    private static boolean handleXML(Element prop, Map<String, Object> map) {
-        String sb = readXML(prop);
-        if (sb == null) {
-            return false;
-        }
-
-        String name = prop.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
-        map.put(name, sb);
-        return true;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static String readXML(Element prop) {
-        Element el = prop.getChild("xml", Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS));
-        if (el == null) {
-            return null;
-        }
-
-        String type = getTypeName(prop);
-        if (!"String".equals(type)) {
-            LOG.warn("Embedded XML must be of type String, found: " + type);
-            return null;
-        }
-
-        XMLOutputter outputter = new XMLOutputter(Format.getCompactFormat());
-        StringBuilder sb = new StringBuilder();
-        List<Element> children = el.getChildren();
-        for (Element child : children) {
-            sb.append(outputter.outputString(child));
-        }
-        return sb.toString();
-    }
-
-    private static Object handleValue(Element val, String type) {
-        String xml = readXML(val);
-        return xml != null ? xml : instantiate(type, val.getText());
-    }
-
-    private static Object instantiate(String type, String value) {
-        if ("String".equals(type)) {
-            return value;
-        }
-
-        value = value.trim();
-        String boxedType = null;
-        if ("long".equals(type)) {
-            boxedType = "Long";
-        } else if ("double".equals(type)) {
-            boxedType = "Double";
-        } else if ("float".equals(type)) {
-            boxedType = "Float";
-        } else if ("int".equals(type)) {
-            boxedType = "Integer";
-        } else if ("byte".equals(type)) {
-            boxedType = "Byte";
-        } else if ("char".equals(type)) {
-            boxedType = "Character";
-        } else if ("boolean".equals(type)) {
-            boxedType = "Boolean";
-        } else if ("short".equals(type)) {
-            boxedType = "Short";
-        }
-
-        if (boxedType == null) {
-            boxedType = type;
-        }
-        String javaType = "java.lang." + boxedType;
-
-        try {
-            if ("Character".equals(boxedType)) {
-                return new Character(value.charAt(0));
-            } else {
-                Class<?> cls = ClassLoader.getSystemClassLoader().loadClass(javaType);
-                Constructor<?> ctor = cls.getConstructor(String.class);
-                return ctor.newInstance(value);
-            }
-        } catch (Exception e) {
-            LOG.warn("Could not create Endpoint Property of type " + type + " and value " + value);
-            return null;
-        }
-    }
-
-    static List<Element> getAllDescriptionElements(Bundle b) {
-        Object header = null;
-
-        Dictionary<?, ?> headers = b.getHeaders();
-        if (headers != null) {
-            header = headers.get(REMOTE_SERVICES_HEADER_NAME);
-        }
-
-        if (header == null) {
-            header = REMOTE_SERVICES_DIRECTORY;
-        }
-
-        String dir = header.toString();
-        String filePattern = "*.xml";
-        if (dir.endsWith("/")) {
-            dir = dir.substring(0, dir.length() - 1);
-        } else {
-            int idx = dir.lastIndexOf('/');
-            if (idx >= 0 & dir.length() > idx) {
-                filePattern = dir.substring(idx + 1);
-                dir = dir.substring(0, idx);
-            } else {
-                filePattern = dir;
-                dir = "";
-            }
-        }
-
-        Enumeration<?> urls = b.findEntries(dir, filePattern, false);
-        if (urls == null) {
-            return Collections.emptyList();
-        }
-
-        List<Element> elements = new ArrayList<Element>();
-        while (urls.hasMoreElements()) {
-            URL resourceURL = (URL) urls.nextElement();
-            try {
-                elements.addAll(getElements(resourceURL.openStream()));
-            } catch (Exception ex) {
-                LOG.warn("Problem parsing: " + resourceURL, ex);
-            }
-        }
-        return elements;
-    }
-
-    private static Map<String, Object> getProperties(List<Element> elements) {
-        Map<String, Object> props = new HashMap<String, Object>();
-
-        for (Element p : elements) {
-            String key = p.getAttributeValue(PROPERTY_NAME_ATTRIBUTE);
-            String value = p.getAttributeValue(PROPERTY_VALUE_ATTRIBUTE);
-            if (value == null) {
-                value = p.getTextTrim();
-            }
-
-            String iface = p.getAttributeValue(PROPERTY_INTERFACE_ATTRIBUTE);
-            if (key != null) {
-                props.put(iface == null || iface.isEmpty()
-                          ? key
-                          : key + INTERFACE_SEPARATOR + iface,
-                          value);
-            }
-        }
-
-        return props;
-    }
-
-    private static List<String> getProvidedInterfaces(List<Element> elements) {
-        List<String> names = new ArrayList<String>();
-
-        for (Element p : elements) {
-            String name = p.getAttributeValue(PROVIDE_INTERFACE_NAME_ATTRIBUTE);
-            if (name != null) {
-                names.add(name);
-            }
-        }
-
-        return names;
-    }
-
-    public static String getEndpointDescriptionXML(Map<String, Object> m) {
-        Document d = new Document();
-        Namespace ns = Namespace.getNamespace("http://www.osgi.org/xmlns/rsa/v1.0.0");
-        Element rootEl = new Element("endpoint-descriptions", ns);
-        d.setRootElement(rootEl);
-        Element contentEl = new Element("endpoint-description", ns);
-        rootEl.addContent(contentEl);
-
-        for (Map.Entry<String, Object> entry : m.entrySet()) {
-            String key = entry.getKey();
-            Object val = entry.getValue();
-
-            Element propEl = new Element("property", ns);
-            propEl.setAttribute("name", key);
-            if (val.getClass().isArray()) {
-                Element arrayEl = new Element("array", ns);
-                propEl.addContent(arrayEl);
-                for (Object o : normalizeArray(val)) {
-                    setValueType(propEl, o);
-                    Element valueEl = new Element("value", ns);
-                    arrayEl.addContent(valueEl);
-                    valueEl.addContent(o.toString());
-                }
-            } else if (val instanceof List) {
-                Element listEl = new Element("list", ns);
-                propEl.addContent(listEl);
-                handleCollectionValue(ns, (Collection<?>) val, propEl, listEl);
-            } else if (val instanceof Set) {
-                Element setEl = new Element("set", ns);
-                propEl.addContent(setEl);
-                handleCollectionValue(ns, (Collection<?>) val, propEl, setEl);
-            } else if (val instanceof String
-                    || val instanceof Character
-                    || val instanceof Boolean
-                    || val instanceof Byte) {
-                setValueType(propEl, val);
-                propEl.setAttribute("value", val.toString());
-            } else if (val instanceof Long
-                    || val instanceof Double
-                    || val instanceof Float
-                    || val instanceof Integer
-                    || val instanceof Short) {
-                // various numbers..   maybe "val instanceof Number"?
-                setValueType(propEl, val);
-                propEl.setAttribute("value", val.toString());
-            } else {
-                // Don't add this property as the value type is not supported
-                continue;
-            }
-            contentEl.addContent(propEl);
-        }
-
-        return new XMLOutputter(Format.getPrettyFormat()).outputString(d);
-    }
-
-    private static Object[] normalizeArray(Object val) {
-        List<Object> l = new ArrayList<Object>();
-        if (val instanceof int[]) {
-            int[] ia = (int[]) val;
-            for (int i : ia) {
-                l.add(i);
-            }
-        } else if (val instanceof long[]) {
-            long[] la = (long[]) val;
-            for (long i : la) {
-                l.add(i);
-            }
-        } else if (val instanceof float[]) {
-            float[] fa = (float[]) val;
-            for (float f : fa) {
-                l.add(f);
-            }
-        } else if (val instanceof byte[]) {
-            byte[] ba = (byte[]) val;
-            for (byte b : ba) {
-                l.add(b);
-            }
-        } else if (val instanceof boolean[]) {
-            boolean[] ba = (boolean[]) val;
-            for (boolean b : ba) {
-                l.add(b);
-            }
-        } else if (val instanceof short[]) {
-            short[] sa = (short[]) val;
-            for (short s : sa) {
-                l.add(s);
-            }
-        } else if (val instanceof char[]) {
-            char[] ca = (char[]) val;
-            for (char c : ca) {
-                l.add(c);
-            }
-        } else {
-            return (Object[]) val;
-        }
-        return l.toArray();
-    }
-
-    private static void handleCollectionValue(Namespace ns, Collection<?> val, Element propEl, Element listEl) {
-        for (Object o : val) {
-            setValueType(propEl, o);
-            Element valueEl = new Element("value", ns);
-            listEl.addContent(valueEl);
-            valueEl.addContent(o.toString());
-        }
-    }
-
-    private static void setValueType(Element propEl, Object val) {
-        if (val instanceof String) {
-            return;
-        }
-
-        String dataType = val.getClass().getName();
-        if (dataType.startsWith("java.lang.")) {
-            dataType = dataType.substring("java.lang.".length());
-        }
-        propEl.setAttribute("value-type", dataType);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static List<Element> getElements(InputStream in) throws JDOMException, IOException {
-        List<Element> elements = new ArrayList<Element>();
-
-        Document d = new SAXBuilder().build(in);
-        if (d.getRootElement().getNamespaceURI().equals(REMOTE_SERVICES_ADMIN_NS)) {
-            elements.addAll(d.getRootElement().getChildren(ENDPOINT_DESCRIPTION_ELEMENT,
-                                                           Namespace.getNamespace(REMOTE_SERVICES_ADMIN_NS)));
-        }
-
-        Namespace nsOld = Namespace.getNamespace(REMOTE_SERVICES_NS);
-        elements.addAll(d.getRootElement().getChildren(SERVICE_DESCRIPTION_ELEMENT, nsOld));
-
-        return elements;
-    }
-
-    public static EndpointDescription getFirstEnpointDescription(byte[] data) throws JDOMException, IOException {
-        List<Element> elements = getElements(new ByteArrayInputStream(data));
-        return elements.isEmpty() ? null : getEndpointDescription(elements.get(0));
-    }
-}
index aebd207..fe297c3 100644 (file)
  */
 package org.apache.cxf.dosgi.discovery.local.util;
 
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
 
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
@@ -89,4 +98,28 @@ public final class Utils {
             return false;
         }
     }
+    
+    public static String normXML(String s) {
+        String s2 = stripComment(s);
+        String s3 = stripProlog(s2);
+        try {
+            TransformerFactory transFactory = TransformerFactory.newInstance();
+            Transformer transformer = transFactory.newTransformer();
+            StringWriter buffer = new StringWriter();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.transform(new StreamSource(new StringReader(s3)), new StreamResult(buffer));
+            return buffer.toString();
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    private static String stripComment(String s) {
+        return Pattern.compile("<!--(.*?)-->", Pattern.DOTALL).matcher(s).replaceAll("");
+    }
+
+    private static String stripProlog(String s) {
+        return s.replaceAll("<\\?(.*?)\\?>", "");
+    }
 }
diff --git a/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java b/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java
new file mode 100644 (file)
index 0000000..30a65e0
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class EndpointDescriptionBundleParser {
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointDescriptionBundleParser.class);
+
+    private static final String REMOTE_SERVICES_HEADER_NAME = "Remote-Service";
+    private static final String REMOTE_SERVICES_DIRECTORY = "OSGI-INF/remote-service/";
+
+    private EndpointDescriptionParser parser;
+
+    public EndpointDescriptionBundleParser() {
+        parser = new EndpointDescriptionParser();
+    }
+
+    public List<EndpointDescription> getAllEndpointDescriptions(Bundle b) {
+        List<EndpointDescriptionType> elements = getAllDescriptionElements(b);
+
+        List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>(elements.size());
+        for (EndpointDescriptionType epd : elements) {
+            Map<String, Object> props = new PropertiesMapper().toProps(epd.getProperty());
+            endpoints.add(new EndpointDescription(props));
+        }
+        return endpoints;
+    }
+
+    List<EndpointDescriptionType> getAllDescriptionElements(Bundle b) {
+        Enumeration<URL> urls = getEndpointDescriptionURLs(b);
+        List<EndpointDescriptionType> elements = new ArrayList<EndpointDescriptionType>();
+        while (urls.hasMoreElements()) {
+            URL resourceURL = (URL) urls.nextElement();
+            try {
+                elements.addAll(parser.getEndpointDescriptions(resourceURL.openStream()));
+            } catch (Exception ex) {
+                LOG.warn("Problem parsing: " + resourceURL, ex);
+            }
+        }
+        return elements;
+    }
+    
+    Enumeration<URL> getEndpointDescriptionURLs(Bundle b) {
+        String origDir = getRemoteServicesDir(b);
+        
+        // Split origDir into dir and file pattern
+        String filePattern = "*.xml";
+        String dir;
+        if (origDir.endsWith("/")) {
+            dir = origDir.substring(0, origDir.length() - 1);
+        } else {
+            int idx = origDir.lastIndexOf('/');
+            if (idx >= 0 & origDir.length() > idx) {
+                filePattern = origDir.substring(idx + 1);
+                dir = origDir.substring(0, idx);
+            } else {
+                filePattern = origDir;
+                dir = "";
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        Enumeration<URL> urls = b.findEntries(dir, filePattern, false);
+        return (urls == null) ? Collections.enumeration(new ArrayList<URL>()) : urls;
+    }
+
+    private static String getRemoteServicesDir(Bundle b) {
+        Dictionary<?, ?> headers = b.getHeaders();
+        Object header = null;
+        if (headers != null) {
+            header = headers.get(REMOTE_SERVICES_HEADER_NAME);
+        }
+        return (header == null) ? REMOTE_SERVICES_DIRECTORY : header.toString();
+    }
+
+}
diff --git a/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java b/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java
new file mode 100644 (file)
index 0000000..fb502c8
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionsType;
+
+public class EndpointDescriptionParser {
+    private JAXBContext jaxbContext;
+
+    public EndpointDescriptionParser() {
+        try {
+            jaxbContext = JAXBContext.newInstance(EndpointDescriptionsType.class.getPackage().getName(),
+                                                  this.getClass().getClassLoader());
+        } catch (JAXBException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    public List<EndpointDescriptionType> getEndpointDescriptions(InputStream is) {
+        try {
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            Source source = new StreamSource(is);
+            JAXBElement<EndpointDescriptionsType> jaxb = unmarshaller.unmarshal(source, EndpointDescriptionsType.class);
+            EndpointDescriptionsType decorations = jaxb.getValue();
+            return decorations.getEndpointDescription();
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage(), ex);
+        }
+    }
+
+    public void writeTo(EndpointDescriptionsType endpointDescriptions, OutputStream os) {
+        try {
+            Marshaller marshaller = jaxbContext.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            QName name = new QName("http://www.osgi.org/xmlns/rsa/v1.0.0", "endpoint-descriptions");
+            JAXBElement<EndpointDescriptionsType> el = 
+                new JAXBElement<EndpointDescriptionsType>(name, EndpointDescriptionsType.class, 
+                    endpointDescriptions);
+            marshaller.marshal(el, os);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage(), ex);
+        } finally {
+            try {
+                os.close();
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+    }
+    
+    public byte[] getData(EndpointDescriptionType endpointDescription) {
+        EndpointDescriptionsType endpointDescriptions = new EndpointDescriptionsType();
+        endpointDescriptions.getEndpointDescription().add(endpointDescription);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        writeTo(endpointDescriptions, bos);
+        return bos.toByteArray();
+    }
+}
diff --git a/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java b/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java
new file mode 100644 (file)
index 0000000..a7ed445
--- /dev/null
@@ -0,0 +1,345 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Node;
+import org.osgi.xmlns.rsa.v1_0.ArrayType;
+import org.osgi.xmlns.rsa.v1_0.ObjectFactory;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+import org.osgi.xmlns.rsa.v1_0.ValueType;
+import org.osgi.xmlns.rsa.v1_0.XmlType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PropertiesMapper {
+    private static final Logger LOG = LoggerFactory.getLogger(PropertiesMapper.class);
+
+    public Map<String, Object> toProps(List<PropertyType> properties) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        for (PropertyType prop : properties) {
+            map.put(prop.getName(), getValue(prop));
+        }
+        return map;
+    }
+
+    private Object getValue(PropertyType prop) {
+        Object value = null;
+        String type = getTypeName(prop);
+        Object content = getFirstNonText(prop.getContent());
+        if (content instanceof JAXBElement<?>) {
+            JAXBElement<?> el = (JAXBElement<?>)content;
+            if (el.getDeclaredType() == ArrayType.class) {
+                String elName = el.getName().getLocalPart();
+                ArrayType inValue = (ArrayType)el.getValue();
+                if ("array".equals(elName)) {
+                    value = getArray(inValue, type);
+                } else if ("set".equals(elName)) {
+                    value = handleCollection(inValue, new HashSet<Object>(), type);
+                } else if ("list".equals(elName)) {
+                    value = handleCollection(inValue, new ArrayList<Object>(), type);
+                }
+            } else if (el.getDeclaredType() == XmlType.class) {
+                value = readXML((XmlType)el.getValue(), type);
+            }
+        } else {
+            if (prop.getValue() != null) {
+                value = instantiate(type, prop.getValue());
+            } else {
+                if (prop.getContent().size() > 0) {
+                    value = instantiate(type, prop.getContent().get(0).toString());
+                }
+            }
+        }
+        return value;
+    }
+
+    private Object getFirstNonText(List<Serializable> contentList) {
+        for (Object content : contentList) {
+            if (content instanceof JAXBElement<?>) {
+                return content;
+            }
+        }
+        return null;
+    }
+
+    private static String getTypeName(PropertyType prop) {
+        String type = prop.getValueType();
+        return type == null ? "String" : type;
+    }
+
+    private Object getArray(ArrayType arrayEl, String type) {
+        List<ValueType> values = arrayEl.getValue();
+        Class<?> cls = null;
+        if ("long".equals(type)) {
+            cls = long.class;
+        } else if ("double".equals(type)) {
+            cls = double.class;
+        } else if ("float".equals(type)) {
+            cls = float.class;
+        } else if ("int".equals(type)) {
+            cls = int.class;
+        } else if ("byte".equals(type)) {
+            cls = byte.class;
+        } else if ("boolean".equals(type)) {
+            cls = boolean.class;
+        } else if ("short".equals(type)) {
+            cls = short.class;
+        }
+
+        try {
+            if (cls == null) {
+                cls = ClassLoader.getSystemClassLoader().loadClass("java.lang." + type);
+            }
+            Object array = Array.newInstance(cls, values.size());
+
+            for (int i = 0; i < values.size(); i++) {
+                Object val = getValue(values.get(i), type);
+                Array.set(array, i, val);
+            }
+
+            return array;
+        } catch (Exception e) {
+            LOG.warn("Could not create array for Endpoint Description", e);
+            return null;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private Collection handleCollection(ArrayType el, Collection value, String type) {
+        List<ValueType> values = el.getValue();
+        for (ValueType val : values) {
+            Object obj = getValue(val, type);
+            value.add(obj);
+        }
+        return value;
+    }
+    
+    private Object getValue(ValueType value, String type) {
+        if (value.getContent().size() == 1 && value.getContent().get(0) instanceof String) {
+            return handleValue((String)value.getContent().get(0), type);
+        }
+        JAXBElement<?> valueContent = (JAXBElement<?>)getFirstNonText(value.getContent());
+        if (valueContent.getDeclaredType() == XmlType.class) {
+            return readXML((XmlType)valueContent.getValue(), type);
+        }
+        return "";
+    }
+
+    private String readXML(XmlType el, String type) {
+        if (el == null) {
+            return null;
+        }
+        if (!"String".equals(type)) {
+            LOG.warn("Embedded XML must be of type String, found: " + type);
+            return null;
+        }
+        Node xmlContent = (Node)el.getAny();
+        xmlContent.normalize();
+        try {
+            TransformerFactory transFactory = TransformerFactory.newInstance();
+            Transformer transformer = transFactory.newTransformer();
+            StringWriter buffer = new StringWriter();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.transform(new DOMSource(xmlContent), new StreamResult(buffer));
+            return buffer.toString();
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    private static Object handleValue(String val, String type) {
+        return instantiate(type, val);
+    }
+
+    private static Object instantiate(String type, String value) {
+        if ("String".equals(type)) {
+            return value;
+        }
+
+        value = value.trim();
+        String boxedType = null;
+        if ("long".equals(type)) {
+            boxedType = "Long";
+        } else if ("double".equals(type)) {
+            boxedType = "Double";
+        } else if ("float".equals(type)) {
+            boxedType = "Float";
+        } else if ("int".equals(type)) {
+            boxedType = "Integer";
+        } else if ("byte".equals(type)) {
+            boxedType = "Byte";
+        } else if ("char".equals(type)) {
+            boxedType = "Character";
+        } else if ("boolean".equals(type)) {
+            boxedType = "Boolean";
+        } else if ("short".equals(type)) {
+            boxedType = "Short";
+        }
+
+        if (boxedType == null) {
+            boxedType = type;
+        }
+        String javaType = "java.lang." + boxedType;
+
+        try {
+            if ("Character".equals(boxedType)) {
+                return new Character(value.charAt(0));
+            } else {
+                Class<?> cls = ClassLoader.getSystemClassLoader().loadClass(javaType);
+                Constructor<?> ctor = cls.getConstructor(String.class);
+                return ctor.newInstance(value);
+            }
+        } catch (Exception e) {
+            LOG.warn("Could not create Endpoint Property of type " + type + " and value " + value);
+            return null;
+        }
+    }
+    
+    public List<PropertyType> fromProps(Map<String, Object> m) {
+        List<PropertyType> props = new ArrayList<PropertyType>();
+        for (Map.Entry<String, Object> entry : m.entrySet()) {
+            String key = entry.getKey();
+            Object val = entry.getValue();
+
+            PropertyType propEl = new PropertyType();
+            propEl.setName(key);
+            ObjectFactory factory = new ObjectFactory();
+            if (val.getClass().isArray()) {
+                ArrayType arrayEl = new ArrayType();
+                propEl.getContent().add(factory.createArray(arrayEl));
+                for (Object o : normalizeArray(val)) {
+                    setValueType(propEl, o);
+                    ValueType valueType =  new ValueType();
+                    valueType.getContent().add(o.toString());
+                    arrayEl.getValue().add(valueType);
+                }
+            } else if (val instanceof List) {
+                ArrayType listEl = new ArrayType();
+                propEl.getContent().add(factory.createList(listEl));
+                handleCollectionValue((Collection<?>) val, propEl, listEl);
+            } else if (val instanceof Set) {
+                ArrayType setEl = new ArrayType();
+                propEl.getContent().add(factory.createSet(setEl));
+                handleCollectionValue((Collection<?>) val, propEl, setEl);
+            } else if (val instanceof String
+                    || val instanceof Character
+                    || val instanceof Boolean
+                    || val instanceof Byte) {
+                setValueType(propEl, val);
+                propEl.setValue(val.toString());
+            } else if (val instanceof Long
+                    || val instanceof Double
+                    || val instanceof Float
+                    || val instanceof Integer
+                    || val instanceof Short) {
+                // various numbers..   maybe "val instanceof Number"?
+                setValueType(propEl, val);
+                propEl.setValue(val.toString());
+            } else {
+                // Don't add this property as the value type is not supported
+                continue;
+            }
+            props.add(propEl);
+        }
+        return props;
+    }
+
+    private static Object[] normalizeArray(Object val) {
+        List<Object> l = new ArrayList<Object>();
+        if (val instanceof int[]) {
+            int[] ia = (int[]) val;
+            for (int i : ia) {
+                l.add(i);
+            }
+        } else if (val instanceof long[]) {
+            long[] la = (long[]) val;
+            for (long i : la) {
+                l.add(i);
+            }
+        } else if (val instanceof float[]) {
+            float[] fa = (float[]) val;
+            for (float f : fa) {
+                l.add(f);
+            }
+        } else if (val instanceof byte[]) {
+            byte[] ba = (byte[]) val;
+            for (byte b : ba) {
+                l.add(b);
+            }
+        } else if (val instanceof boolean[]) {
+            boolean[] ba = (boolean[]) val;
+            for (boolean b : ba) {
+                l.add(b);
+            }
+        } else if (val instanceof short[]) {
+            short[] sa = (short[]) val;
+            for (short s : sa) {
+                l.add(s);
+            }
+        } else if (val instanceof char[]) {
+            char[] ca = (char[]) val;
+            for (char c : ca) {
+                l.add(c);
+            }
+        } else {
+            return (Object[]) val;
+        }
+        return l.toArray();
+    }
+
+    private static void handleCollectionValue(Collection<?> val, PropertyType propEl, ArrayType listEl) {
+        for (Object o : val) {
+            setValueType(propEl, o);
+            ValueType valueType = new ValueType();
+            valueType.getContent().add(o.toString());
+            listEl.getValue().add(valueType);
+        }
+    }
+
+    private static void setValueType(PropertyType propEl, Object val) {
+        if (val instanceof String) {
+            return;
+        }
+
+        String dataType = val.getClass().getName();
+        if (dataType.startsWith("java.lang.")) {
+            dataType = dataType.substring("java.lang.".length());
+        }
+        propEl.setValueType(dataType);
+    }
+}
diff --git a/discovery/local/src/main/resources/endpoint-description.xsd b/discovery/local/src/main/resources/endpoint-description.xsd
new file mode 100644 (file)
index 0000000..b3254c1
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.osgi.org/xmlns/rsa/v1.0.0" targetNamespace="http://www.osgi.org/xmlns/rsa/v1.0.0">
+    <element name="endpoint-descriptions"
+        type="tns:EndpointDescriptionsType">
+    </element>
+    
+    <complexType name="EndpointDescriptionsType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:endpoint-description">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="EndpointDescriptionType">
+        <sequence>
+            <element ref="tns:property" maxOccurs="unbounded" minOccurs="0"></element>
+        </sequence>
+    </complexType>
+
+    <complexType name="PropertyType" mixed="true">
+        <choice>
+            <element ref="tns:array"></element>
+            <element ref="tns:list"></element>
+            <element ref="tns:set"></element>
+            <element ref="tns:xml"></element>
+        </choice>
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value-type" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+    </complexType>
+
+    <complexType name="ArrayType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:value">
+            </element>
+        </sequence>
+    </complexType>
+    <element name="endpoint-description"
+        type="tns:EndpointDescriptionType">
+    </element>
+    <element name="property" type="tns:PropertyType"></element>
+    <element name="array" type="tns:ArrayType"></element>
+    <element name="list" type="tns:ArrayType"></element>
+    <element name="set" type="tns:ArrayType"></element>
+
+    <complexType name="XmlType">
+        <sequence>
+            <any></any>
+        </sequence>
+    </complexType>
+    <element name="value" type="tns:ValueType"></element>
+    <element name="xml" type="tns:XmlType"></element>
+
+    <complexType name="ValueType" mixed="true">
+        <sequence>
+            <element ref="tns:xml"></element>
+        </sequence>
+    </complexType>
+</schema>
\ No newline at end of file
diff --git a/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtilsTest.java b/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/util/EndpointUtilsTest.java
deleted file mode 100644 (file)
index 2cb4d02..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/**
- * 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.cxf.dosgi.discovery.local.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import junit.framework.TestCase;
-
-import org.easymock.EasyMock;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-import org.jdom.output.Format;
-import org.jdom.output.XMLOutputter;
-import org.osgi.framework.Bundle;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-
-public class EndpointUtilsTest extends TestCase {
-
-    private static final String LF = "\n";
-
-    public void testNoRemoteServicesXMLFiles() {
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.replay(b);
-
-        List<Element> rsElements = EndpointUtils.getAllDescriptionElements(b);
-        assertEquals(0, rsElements.size());
-    }
-
-    public void testEndpointDescriptionXMLFiles() {
-        URL ed1URL = getClass().getResource("/ed1.xml");
-
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.expect(b.findEntries(
-            EasyMock.eq("OSGI-INF/remote-service"),
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
-                Collections.enumeration(Arrays.asList(ed1URL))).anyTimes();
-        EasyMock.replay(b);
-
-        List<Element> edElements = EndpointUtils.getAllDescriptionElements(b);
-        assertEquals(4, edElements.size());
-    }
-
-    public void testAllEndpoints1() {
-        URL ed1URL = getClass().getResource("/ed1.xml");
-
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.expect(b.findEntries(
-            EasyMock.eq("OSGI-INF/remote-service"),
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
-                Collections.enumeration(Arrays.asList(ed1URL))).anyTimes();
-        EasyMock.replay(b);
-
-        List<EndpointDescription> endpoints = EndpointUtils.getAllEndpointDescriptions(b);
-        assertEquals(4, endpoints.size());
-        EndpointDescription endpoint0 = endpoints.get(0);
-        assertEquals("http://somewhere:12345", endpoint0.getId());
-        assertEquals(Arrays.asList("SomeService"), endpoint0.getInterfaces());
-        assertEquals(Arrays.asList("confidentiality"),
-            endpoint0.getProperties().get("osgi.remote.requires.intents"));
-        assertEquals("testValue", endpoint0.getProperties().get("testKey"));
-
-        EndpointDescription endpoint1 = endpoints.get(1);
-        assertEquals("myScheme://somewhere:12345", endpoint1.getId());
-        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint1.getInterfaces());
-
-        EndpointDescription endpoint2 = endpoints.get(2);
-        assertEquals("http://somewhere", endpoint2.getId());
-        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint2.getInterfaces());
-
-        EndpointDescription endpoint3 = endpoints.get(3);
-        assertEquals("http://somewhere:1/2/3/4?5", endpoint3.getId());
-        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint3.getInterfaces());
-    }
-
-    public void testAllEndpoints2() throws Exception {
-        URL ed2URL = getClass().getResource("/ed2.xml");
-
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.expect(b.findEntries(
-            EasyMock.eq("OSGI-INF/remote-service"),
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
-                Collections.enumeration(Arrays.asList(ed2URL))).anyTimes();
-        EasyMock.replay(b);
-
-        List<EndpointDescription> endpoints = EndpointUtils.getAllEndpointDescriptions(b);
-        assertEquals(2, endpoints.size());
-        EndpointDescription endpoint0 = endpoints.get(0);
-        assertEquals("foo:bar", endpoint0.getId());
-        assertEquals(Arrays.asList("com.acme.HelloService"), endpoint0.getInterfaces());
-        assertEquals(Arrays.asList("SOAP"), endpoint0.getIntents());
-        // changed from exported to imported
-        assertEquals("org.apache.cxf.ws", endpoint0.getProperties().get("service.imported.configs"));
-
-        EndpointDescription endpoint1 = endpoints.get(1);
-        Map<String, Object> props = endpoint1.getProperties();
-        assertEquals(Arrays.asList("com.acme.HelloService", "some.other.Service"), endpoint1.getInterfaces());
-        assertEquals("org.apache.cxf.ws", props.get("service.imported.configs"));
-        // exports should have been removed
-        assertNull(props.get("service.exported.configs"));
-
-        assertEquals(normXML("<other:t1 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0' "
-                             + "xmlns='http://www.acme.org/xmlns/other/v1.0.0'><foo type='bar'>haha</foo></other:t1>"),
-            normXML((String) props.get("someXML")));
-
-        assertEquals(Long.MAX_VALUE, props.get("long"));
-        assertEquals(-1L, props.get("long2"));
-        assertEquals(Double.MAX_VALUE, props.get("double"));
-        assertEquals(1.0d, props.get("Double2"));
-        assertEquals(42.24f, props.get("float"));
-        assertEquals(1.0f, props.get("Float2"));
-        assertEquals(17, props.get("int"));
-        assertEquals(42, props.get("Integer2"));
-        assertEquals((byte) 127, props.get("byte"));
-        assertEquals((byte) -128, props.get("Byte2"));
-        assertEquals(Boolean.TRUE, props.get("boolean"));
-        assertEquals(Boolean.TRUE, props.get("Boolean2"));
-        assertEquals((short) 99, props.get("short"));
-        assertEquals((short) -99, props.get("Short2"));
-        assertEquals('@', props.get("char"));
-        assertEquals('X', props.get("Character2"));
-
-        int[] intArray = (int[]) props.get("int-array");
-        assertTrue(Arrays.equals(new int[] {1, 2}, intArray));
-
-        Integer[] integerArray = (Integer[]) props.get("Integer-array");
-        assertTrue(Arrays.equals(new Integer[] {2, 1}, integerArray));
-
-        assertEquals(Arrays.asList(true, false), props.get("bool-list"));
-        assertEquals(new HashSet<Object>(), props.get("long-set"));
-        Set<String> stringSet = new HashSet<String>();
-        stringSet.add("Hello there");
-        stringSet.add("How are you?");
-        assertEquals(stringSet, props.get("string-set"));
-        assertEquals("Hello", props.get("other1").toString().trim());
-
-        List<?> l = (List<?>) props.get("other2");
-        assertEquals(1, l.size());
-        assertEquals(normXML("<other:t2 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0'/>"),
-            normXML((String) l.get(0)));
-    }
-
-    public void testLegacyServiceDescriptionFormat() {
-        URL sdURL = getClass().getResource("/sd.xml");
-
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.expect(b.findEntries(
-            EasyMock.eq("OSGI-INF/remote-service"),
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
-                Collections.enumeration(Arrays.asList(sdURL))).anyTimes();
-        EasyMock.replay(b);
-
-        List<EndpointDescription> endpoints = EndpointUtils.getAllEndpointDescriptions(b);
-        assertEquals(1, endpoints.size());
-        EndpointDescription endpoint = endpoints.get(0);
-        assertEquals("http://localhost:9090/greeter", endpoint.getId());
-        assertEquals(Arrays.asList("org.apache.cxf.ws"), endpoint.getConfigurationTypes());
-        assertEquals(Arrays.asList("org.apache.cxf.dosgi.samples.greeter.GreeterService"), endpoint.getInterfaces());
-        assertNull("Should not contain service.exported.*",
-                endpoint.getProperties().get(RemoteConstants.SERVICE_EXPORTED_INTERFACES));
-        assertNull("Should not contain service.exported.*",
-                endpoint.getProperties().get(RemoteConstants.SERVICE_EXPORTED_CONFIGS));
-    }
-
-    public void testLegacyServiceDescriptionFormat2() {
-        URL sdURL = getClass().getResource("/sd2.xml");
-
-        Bundle b = EasyMock.createNiceMock(Bundle.class);
-        EasyMock.expect(b.findEntries(
-            EasyMock.eq("OSGI-INF/remote-service"),
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
-                Collections.enumeration(Arrays.asList(sdURL))).anyTimes();
-        EasyMock.replay(b);
-
-        List<EndpointDescription> endpoints = EndpointUtils.getAllEndpointDescriptions(b);
-        assertEquals(2, endpoints.size());
-
-        EndpointDescription endpoint0 = endpoints.get(0);
-        assertEquals("http://localhost:9000/org/example/SomeService", endpoint0.getId());
-        assertEquals(Arrays.asList("org.apache.cxf.ws"), endpoint0.getConfigurationTypes());
-        assertEquals(Arrays.asList("org.example.SomeService"), endpoint0.getInterfaces());
-        assertEquals(Arrays.asList("confidentiality"), endpoint0.getIntents());
-
-        EndpointDescription endpoint1 = endpoints.get(1);
-        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint1.getInterfaces());
-        assertEquals("5", endpoint1.getProperties().get("blah"));
-    }
-
-    public void testCreateXML() throws Exception {
-        Map<String, Object> m = new LinkedHashMap<String, Object>();
-        m.put("service.imported.configs", "org.apache.cxf.ws");
-        m.put("endpoint.id", "foo:bar");
-        m.put("objectClass", new String[] {"com.acme.HelloService", "some.other.Service"});
-        m.put("SomeObject", new Object());
-        m.put("long", 9223372036854775807L);
-        m.put("Long2", -1L);
-        m.put("double", 1.7976931348623157E308);
-        m.put("Double2", 1.0d);
-        m.put("float", 42.24f);
-        m.put("Float2", 1.0f);
-        m.put("int", 17);
-        m.put("Integer2", 42);
-        m.put("byte", (byte) 127);
-        m.put("Byte2", (byte) -128);
-        m.put("boolean", true);
-        m.put("Boolean2", false);
-        m.put("short", (short) 99);
-        m.put("Short2", (short) -99);
-        m.put("char", '@');
-        m.put("Character2", 'X');
-
-        List<Boolean> boolList = new ArrayList<Boolean>();
-        boolList.add(true);
-        boolList.add(false);
-        m.put("bool-list", boolList);
-        m.put("empty-set", new HashSet<Object>());
-
-        Set<String> stringSet = new LinkedHashSet<String>();
-        stringSet.add("Hello there");
-        stringSet.add("How are you?");
-        m.put("string-set", stringSet);
-
-        int[] intArray = new int[] {1, 2};
-        m.put("int-array", intArray);
-
-        String xml = "<xml>" + LF
-            + "<t1 xmlns=\"http://www.acme.org/xmlns/other/v1.0.0\">" + LF
-            + "<foo type='bar'>haha</foo>" + LF
-            + "</t1>" + LF
-            + "</xml>";
-        m.put("someXML", xml);
-
-        String actual = EndpointUtils.getEndpointDescriptionXML(m);
-
-        URL edURL = getClass().getResource("/ed2-generated.xml");
-        String expected = new String(drainStream(edURL.openStream()));
-        assertEquals(normXML(expected), normXML(actual));
-    }
-
-    private static String normXML(String s) throws JDOMException, IOException {
-        String s2 = stripComment(s);
-        String s3 = stripProlog(s2);
-        Document d = new SAXBuilder().build(new ByteArrayInputStream(s3.getBytes()));
-        XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
-        return outputter.outputString(d);
-    }
-
-    private static String stripComment(String s) {
-        return Pattern.compile("<!--(.*?)-->", Pattern.DOTALL).matcher(s).replaceAll("");
-    }
-
-    private static String stripProlog(String s) {
-        return s.replaceAll("<\\?(.*?)\\?>", "");
-    }
-
-    public static void drainStream(InputStream is, OutputStream os) throws IOException {
-        byte[] bytes = new byte[8192];
-
-        int length;
-        int offset = 0;
-
-        while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) {
-            offset += length;
-
-            if (offset == bytes.length) {
-                os.write(bytes, 0, bytes.length);
-                offset = 0;
-            }
-        }
-        if (offset != 0) {
-            os.write(bytes, 0, offset);
-        }
-    }
-
-    public static byte[] drainStream(InputStream is) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        try {
-            drainStream(is, baos);
-            return baos.toByteArray();
-        } finally {
-            is.close();
-        }
-    }
-}
diff --git a/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java b/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java
new file mode 100644 (file)
index 0000000..4884c50
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.discovery.local.util.Utils;
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+public class EndpointDescriptionBundleParserTest extends TestCase {
+
+    private Bundle createBundleContaining(URL ed1URL) {
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(b.findEntries(
+            EasyMock.eq("OSGI-INF/remote-service"),
+            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
+                Collections.enumeration(Arrays.asList(ed1URL))).anyTimes();
+        EasyMock.replay(b);
+        return b;
+    }
+
+    public void testAllEndpoints1() {
+        URL ed1URL = getClass().getResource("/ed1.xml");
+
+        Bundle b = createBundleContaining(ed1URL);
+
+        List<EndpointDescription> endpoints = new EndpointDescriptionBundleParser().getAllEndpointDescriptions(b);
+        assertEquals(4, endpoints.size());
+        EndpointDescription endpoint0 = endpoints.get(0);
+        assertEquals("http://somewhere:12345", endpoint0.getId());
+        assertEquals(Arrays.asList("SomeService"), endpoint0.getInterfaces());
+        assertEquals(Arrays.asList("confidentiality"),
+            endpoint0.getProperties().get("osgi.remote.requires.intents"));
+        assertEquals("testValue", endpoint0.getProperties().get("testKey"));
+
+        EndpointDescription endpoint1 = endpoints.get(1);
+        assertEquals("myScheme://somewhere:12345", endpoint1.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint1.getInterfaces());
+
+        EndpointDescription endpoint2 = endpoints.get(2);
+        assertEquals("http://somewhere", endpoint2.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint2.getInterfaces());
+
+        EndpointDescription endpoint3 = endpoints.get(3);
+        assertEquals("http://somewhere:1/2/3/4?5", endpoint3.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint3.getInterfaces());
+    }
+
+    public void testAllEndpoints2() throws Exception {
+        URL ed2URL = getClass().getResource("/ed2.xml");
+
+        Bundle b = createBundleContaining(ed2URL);
+
+        List<EndpointDescription> endpoints = new EndpointDescriptionBundleParser().getAllEndpointDescriptions(b);
+        assertEquals(2, endpoints.size());
+        EndpointDescription endpoint0 = endpoints.get(0);
+        assertEquals("foo:bar", endpoint0.getId());
+        assertEquals(Arrays.asList("com.acme.HelloService"), endpoint0.getInterfaces());
+        assertEquals(Arrays.asList("SOAP"), endpoint0.getIntents());
+        // changed from exported to imported
+        assertEquals("org.apache.cxf.ws", endpoint0.getProperties().get("service.imported.configs"));
+
+        EndpointDescription endpoint1 = endpoints.get(1);
+        Map<String, Object> props = endpoint1.getProperties();
+        assertEquals(Arrays.asList("com.acme.HelloService", "some.other.Service"), endpoint1.getInterfaces());
+        assertEquals("org.apache.cxf.ws", props.get("service.imported.configs"));
+        // exports should have been removed
+        assertNull(props.get("service.exported.configs"));
+
+        assertEquals(Utils.normXML("<other:t1 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0' "
+            + "xmlns='http://www.acme.org/xmlns/other/v1.0.0'><foo type='bar'>haha</foo>\n"
+            + "        </other:t1>"),
+            Utils.normXML((String) props.get("someXML")));
+        assertEquals(Long.MAX_VALUE, props.get("long"));
+        assertEquals(-1L, props.get("long2"));
+        assertEquals(Double.MAX_VALUE, props.get("double"));
+        assertEquals(1.0d, props.get("Double2"));
+        assertEquals(42.24f, props.get("float"));
+        assertEquals(1.0f, props.get("Float2"));
+        assertEquals(17, props.get("int"));
+        assertEquals(42, props.get("Integer2"));
+        assertEquals((byte) 127, props.get("byte"));
+        assertEquals((byte) -128, props.get("Byte2"));
+        assertEquals(Boolean.TRUE, props.get("boolean"));
+        assertEquals(Boolean.TRUE, props.get("Boolean2"));
+        assertEquals((short) 99, props.get("short"));
+        assertEquals((short) -99, props.get("Short2"));
+        assertEquals('@', props.get("char"));
+        assertEquals('X', props.get("Character2"));
+
+        int[] intArray = (int[]) props.get("int-array");
+        assertTrue(Arrays.equals(new int[] {1, 2}, intArray));
+
+        Integer[] integerArray = (Integer[]) props.get("Integer-array");
+        assertTrue(Arrays.equals(new Integer[] {2, 1}, integerArray));
+
+        assertEquals(Arrays.asList(true, false), props.get("bool-list"));
+        assertEquals(new HashSet<Object>(), props.get("long-set"));
+        Set<String> stringSet = new HashSet<String>();
+        stringSet.add("Hello there");
+        stringSet.add("How are you?");
+        assertEquals(stringSet, props.get("string-set"));
+        assertEquals("Hello", props.get("other1").toString().trim());
+
+        List<?> l = (List<?>) props.get("other2");
+        assertEquals(1, l.size());
+        assertEquals(Utils.normXML("<other:t2 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0' " 
+                                   + "xmlns='http://www.osgi.org/xmlns/rsa/v1.0.0'/>"),
+                                   Utils.normXML((String) l.get(0)));
+    }
+
+}
diff --git a/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java b/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java
new file mode 100644 (file)
index 0000000..97e4b45
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+
+public class EndpointDescriptionParserTest {
+
+    @Test
+    public void testNoRemoteServicesXMLFiles() {
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.replay(b);
+
+        List<EndpointDescriptionType> rsElements = new EndpointDescriptionBundleParser().getAllDescriptionElements(b);
+        Assert.assertEquals(0, rsElements.size());
+    }
+
+    @Test
+    public void testEndpointDescriptionsFromURL() throws IOException {
+        URL ed1URL = getClass().getResource("/ed1.xml");
+        List<EndpointDescriptionType> edElements = new EndpointDescriptionParser().
+            getEndpointDescriptions(ed1URL.openStream());
+        Assert.assertEquals(4, edElements.size());
+    }
+}
diff --git a/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java b/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java
new file mode 100644 (file)
index 0000000..c1d9c3c
--- /dev/null
@@ -0,0 +1,130 @@
+/**
+ * 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.cxf.dosgi.endpointdesc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.dosgi.discovery.local.util.Utils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+
+public class PropertiesMapperTest {
+    private static final String LF = "\n";
+
+    @Test
+    public void testCreateXML() throws Exception {
+        Map<String, Object> m = new LinkedHashMap<String, Object>();
+        m.put("service.imported.configs", "org.apache.cxf.ws");
+        m.put("endpoint.id", "foo:bar");
+        m.put("objectClass", new String[] {"com.acme.HelloService", "some.other.Service"});
+        m.put("SomeObject", new Object());
+        m.put("long", 9223372036854775807L);
+        m.put("Long2", -1L);
+        m.put("double", 1.7976931348623157E308);
+        m.put("Double2", 1.0d);
+        m.put("float", 42.24f);
+        m.put("Float2", 1.0f);
+        m.put("int", 17);
+        m.put("Integer2", 42);
+        m.put("byte", (byte) 127);
+        m.put("Byte2", (byte) -128);
+        m.put("boolean", true);
+        m.put("Boolean2", false);
+        m.put("short", (short) 99);
+        m.put("Short2", (short) -99);
+        m.put("char", '@');
+        m.put("Character2", 'X');
+
+        List<Boolean> boolList = new ArrayList<Boolean>();
+        boolList.add(true);
+        boolList.add(false);
+        m.put("bool-list", boolList);
+        m.put("empty-set", new HashSet<Object>());
+
+        Set<String> stringSet = new LinkedHashSet<String>();
+        stringSet.add("Hello there");
+        stringSet.add("How are you?");
+        m.put("string-set", stringSet);
+
+        int[] intArray = new int[] {1, 2};
+        m.put("int-array", intArray);
+
+        String xml = "<xml>" + LF
+            + "<t1 xmlns=\"http://www.acme.org/xmlns/other/v1.0.0\">" + LF
+            + "<foo type='bar'>haha</foo>" + LF
+            + "</t1>" + LF
+            + "</xml>";
+        m.put("someXML", xml);
+
+        List<PropertyType> props = new PropertiesMapper().fromProps(m);
+        EndpointDescriptionType epd = new EndpointDescriptionType();
+        epd.getProperty().addAll(props);
+        byte[] epData = new EndpointDescriptionParser().getData(epd);
+        String actual = new String(epData, Charset.defaultCharset());
+
+        URL edURL = getClass().getResource("/ed2-generated.xml");
+        String expected = new String(drainStream(edURL.openStream()));
+        Assert.assertEquals(Utils.normXML(expected), Utils.normXML(actual));
+    }
+
+
+
+    private static void drainStream(InputStream is, OutputStream os) throws IOException {
+        byte[] bytes = new byte[8192];
+
+        int length;
+        int offset = 0;
+
+        while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) {
+            offset += length;
+
+            if (offset == bytes.length) {
+                os.write(bytes, 0, bytes.length);
+                offset = 0;
+            }
+        }
+        if (offset != 0) {
+            os.write(bytes, 0, offset);
+        }
+    }
+
+    private static byte[] drainStream(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            drainStream(is, baos);
+            return baos.toByteArray();
+        } finally {
+            is.close();
+        }
+    }
+}
index 5f67241..5e2a5ef 100644 (file)
@@ -1,53 +1,54 @@
 <?xml version="1.0" encoding="UTF-8"?>\r
 <endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">\r
-  <endpoint-description>\r
-    <property name="service.imported.configs" value="org.apache.cxf.ws"/>\r
-    <property name="endpoint.id" value="foo:bar"/>\r
-    <property name="objectClass">\r
-      <array>\r
-        <value>com.acme.HelloService</value>\r
-        <value>some.other.Service</value>\r
-      </array>\r
-    </property>\r
-\r
-    <property name="long" value-type="Long" value="9223372036854775807"/>\r
-    <property name="Long2" value-type="Long" value="-1"/>\r
-    <property name="double" value-type="Double" value="1.7976931348623157E308"/>\r
-    <property name="Double2" value-type="Double" value="1.0"/>\r
-    <property name="float" value-type="Float" value="42.24"/>\r
-    <property name="Float2" value-type="Float" value="1.0"/>\r
-    <property name="int" value-type="Integer" value="17"/>\r
-    <property name="Integer2" value-type="Integer" value="42"/>\r
-    <property name="byte" value-type="Byte" value="127"/>\r
-    <property name="Byte2" value-type="Byte" value="-128"/>\r
-    <property name="boolean" value-type="Boolean" value="true"/>\r
-    <property name="Boolean2" value-type="Boolean" value="false"/>\r
-    <property name="short" value-type="Short" value="99"/>\r
-    <property name="Short2" value-type="Short" value="-99"/>\r
-    <property name="char" value-type="Character" value="@"/>\r
-    <property name="Character2" value-type="Character" value="X"/>\r
-\r
-    <property name="bool-list" value-type="Boolean">\r
-      <list>\r
-        <value>true</value>\r
-        <value>false</value>\r
-      </list>\r
-    </property>\r
-    <property name="empty-set">\r
-      <set/>\r
-    </property>\r
-    <property name="string-set">\r
-      <set>\r
-        <value>Hello there</value>\r
-        <value>How are you?</value>\r
-      </set>\r
-    </property>\r
-    <property name="int-array" value-type="Integer">\r
-      <array>\r
-        <value>1</value>\r
-        <value>2</value>\r
-      </array>\r
-    </property>\r
-    <property name="someXML" value="&lt;xml&gt;&#xA;&lt;t1 xmlns=&quot;http://www.acme.org/xmlns/other/v1.0.0&quot;&gt;&#xA;&lt;foo type='bar'&gt;haha&lt;/foo&gt;&#xA;&lt;/t1&gt;&#xA;&lt;/xml&gt;"/>\r
-  </endpoint-description>\r
+    <endpoint-description>\r
+        <property name="service.imported.configs" value="org.apache.cxf.ws" />\r
+        <property name="endpoint.id" value="foo:bar" />\r
+        <property name="objectClass">\r
+            <array>\r
+                <value>com.acme.HelloService</value>\r
+                <value>some.other.Service</value>\r
+            </array>\r
+        </property>\r
+        <property name="long" value-type="Long" value="9223372036854775807" />\r
+        <property name="Long2" value-type="Long" value="-1" />\r
+        <property name="double" value-type="Double"\r
+            value="1.7976931348623157E308" />\r
+        <property name="Double2" value-type="Double" value="1.0" />\r
+        <property name="float" value-type="Float" value="42.24" />\r
+        <property name="Float2" value-type="Float" value="1.0" />\r
+        <property name="int" value-type="Integer" value="17" />\r
+        <property name="Integer2" value-type="Integer" value="42" />\r
+        <property name="byte" value-type="Byte" value="127" />\r
+        <property name="Byte2" value-type="Byte" value="-128" />\r
+        <property name="boolean" value-type="Boolean" value="true" />\r
+        <property name="Boolean2" value-type="Boolean" value="false" />\r
+        <property name="short" value-type="Short" value="99" />\r
+        <property name="Short2" value-type="Short" value="-99" />\r
+        <property name="char" value-type="Character" value="@" />\r
+        <property name="Character2" value-type="Character"\r
+            value="X" />\r
+        <property name="bool-list" value-type="Boolean">\r
+            <list>\r
+                <value>true</value>\r
+                <value>false</value>\r
+            </list>\r
+        </property>\r
+        <property name="empty-set">\r
+            <set />\r
+        </property>\r
+        <property name="string-set">\r
+            <set>\r
+                <value>Hello there</value>\r
+                <value>How are you?</value>\r
+            </set>\r
+        </property>\r
+        <property name="int-array" value-type="Integer">\r
+            <array>\r
+                <value>1</value>\r
+                <value>2</value>\r
+            </array>\r
+        </property>\r
+        <property name="someXML"\r
+            value="&lt;xml&gt;&#xA;&lt;t1 xmlns=&quot;http://www.acme.org/xmlns/other/v1.0.0&quot;&gt;&#xA;&lt;foo type='bar'&gt;haha&lt;/foo&gt;&#xA;&lt;/t1&gt;&#xA;&lt;/xml&gt;" />\r
+    </endpoint-description>\r
 </endpoint-descriptions>\r
index e6f16d4..899a11b 100644 (file)
@@ -25,7 +25,6 @@
         <feature>cxf-databinding-aegis</feature>
         <feature>cxf-http-jetty</feature>
         <bundle>mvn:org.osgi/org.osgi.enterprise/${osgi.enterprise.version}</bundle>
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jdom/${jdom.version}</bundle>
         <bundle>mvn:${project.groupId}/cxf-dosgi-ri-topology-manager/${project.version}</bundle>
         <bundle>mvn:${project.groupId}/cxf-dosgi-ri-dsw-cxf/${project.version}</bundle>
     </feature>
index ccc0d08..af6a44a 100644 (file)
             <version>2.6</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.jdom</artifactId>
-            <version>${jdom.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
             <version>${spring.version}</version>
index 9eab472..09690f0 100644 (file)
@@ -16,12 +16,6 @@ This product also includes WS-* schemas developed by International
    (http://www.w3.org/2005/08/addressing/ws-addr.xsd)\r
 \r
 \r
-This product contains includes JDOM:\r
-  Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.\r
-  All rights reserved.\r
-  See the NOTICE.jdom file for additional information\r
-\r
-\r
 The product contains code (StaxBuilder.java) that is\r
   Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.\r
   All rights reserved.\r
@@ -32,10 +26,8 @@ Java classes (source and binary) under org.apache.cxf.jaxws.javaee
 are generated from schema available here:\r
 (http://java.sun.com/xml/ns/javaee/javaee_5.xsd)\r
 \r
-\r
 Portions of the included XmlSchema library are Copyright 2006 International Business Machines Corp.\r
 \r
-\r
 Portions of the included xml-apis library were originally based on the following:\r
    - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.\r
    - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.\r
@@ -45,5 +37,3 @@ Portions of the included xml-apis library were originally based on the following
 Portions of the included xmlbeans library were originally based on the following:\r
    - software copyright (c) 2000-2003, BEA Systems, <http://www.bea.com/>.\r
 \r
-\r
-\r
index 9b23a7b..2844317 100644 (file)
       <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
     </fileSet>
     <fileSet>
-      <directory>src/main/resources/META-INF</directory>
-      <includes>
-        <include>NOTICE.jdom</include>
-      </includes>
-      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
-    </fileSet>
-    <fileSet>
       <directory>src/main/release</directory>
       <includes>
         <include>README</include>
diff --git a/distribution/multi-bundle/src/main/resources/META-INF/NOTICE.jdom b/distribution/multi-bundle/src/main/resources/META-INF/NOTICE.jdom
deleted file mode 100644 (file)
index 2566668..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
- Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.\r
- All rights reserved.\r
-\r
- Redistribution and use in source and binary forms, with or without\r
- modification, are permitted provided that the following conditions\r
- are met:\r
-\r
- 1. Redistributions of source code must retain the above copyright\r
- notice, this list of conditions, and the following disclaimer.\r
-\r
- 2. Redistributions in binary form must reproduce the above copyright\r
- notice, this list of conditions, and the disclaimer that follows\r
- these conditions in the documentation and/or other materials\r
- provided with the distribution.\r
-\r
- 3. The name "JDOM" must not be used to endorse or promote products\r
- derived from this software without prior written permission.  For\r
- written permission, please contact <request_AT_jdom_DOT_org>.\r
-\r
- 4. Products derived from this software may not be called "JDOM", nor\r
- may "JDOM" appear in their name, without prior written permission\r
- from the JDOM Project Management <request_AT_jdom_DOT_org>.\r
-\r
- In addition, we request (but do not require) that you include in the\r
- end-user documentation provided with the redistribution and/or in the\r
- software itself an acknowledgement equivalent to the following:\r
- "This product includes software developed by the\r
- JDOM Project (http://www.jdom.org/)."\r
- Alternatively, the acknowledgment may be graphical using the logos\r
- available at http://www.jdom.org/images/logos.\r
-\r
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\r
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
- DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT\r
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\r
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\r
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
- SUCH DAMAGE.\r
-\r
- This software consists of voluntary contributions made by many\r
- individuals on behalf of the JDOM Project and was originally\r
- created by Jason Hunter <jhunter_AT_jdom_DOT_org> and\r
- Brett McLaughlin <brett_AT_jdom_DOT_org>.  For more information\r
- on the JDOM Project, please see <http://www.jdom.org/>.\r
index 14cfb27..7d7d4f5 100644 (file)
@@ -7,7 +7,6 @@
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/geronimo-javamail_1.4_spec-1.7.1.jar</bundle>
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/geronimo-servlet_3.0_spec-1.0.jar</bundle>
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/geronimo-ws-metadata_2.0_spec-1.1.3.jar</bundle>
-  <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/org.apache.servicemix.bundles.jdom-${jdom.version}.jar</bundle>
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/commons-lang-2.6.jar</bundle>
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/spring-core-${spring.version}.jar</bundle>
   <bundle>cxf-dosgi-ri-multibundle-distribution-${project.version}-dir/apache-cxf-dosgi-ri-${project.version}/dosgi_bundles/spring-beans-${spring.version}.jar</bundle>
index 9b23a7b..2844317 100644 (file)
       <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
     </fileSet>
     <fileSet>
-      <directory>src/main/resources/META-INF</directory>
-      <includes>
-        <include>NOTICE.jdom</include>
-      </includes>
-      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
-    </fileSet>
-    <fileSet>
       <directory>src/main/release</directory>
       <includes>
         <include>README</include>
index cf48143..73ceb01 100644 (file)
         </dependency>
 
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.jdom</artifactId>
-            <version>${jdom.version}</version>
-        </dependency>
-        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
     <build>
         <plugins>
             <plugin>
+                <groupId>org.jvnet.jaxb2.maven2</groupId>
+                <artifactId>maven-jaxb2-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
diff --git a/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java b/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java
new file mode 100644 (file)
index 0000000..c7a8f96
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * 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.cxf.dosgi.dsw.decorator;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.xml.sax.SAXException;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationsType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class DecorationParser {
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceDecoratorImpl.class);
+    private JAXBContext jaxbContext;
+    private Schema schema;
+
+    DecorationParser() {
+        try {
+            jaxbContext = JAXBContext.newInstance(ServiceDecorationsType.class.getPackage().getName(),
+                                                  this.getClass().getClassLoader());
+            SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            URL resource = getClass().getResource("/service-decoration.xsd");
+            schema = schemaFactory.newSchema(resource);
+        } catch (JAXBException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } catch (SAXException e) {
+            throw new RuntimeException("Error loading decorations schema", e);
+        }
+
+    }
+
+    List<ServiceDecorationType> getDecorations(URL resourceURL) {
+        if (resourceURL == null) {
+            return new ArrayList<ServiceDecorationType>();
+        }
+        try {
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            unmarshaller.setSchema(schema);
+            InputStream is = resourceURL.openStream();
+            Source source = new StreamSource(is);
+            JAXBElement<ServiceDecorationsType> jaxb = unmarshaller.unmarshal(source, ServiceDecorationsType.class);
+            ServiceDecorationsType decorations = jaxb.getValue();
+            return decorations.getServiceDecoration();
+        } catch (Exception ex) {
+            LOG.warn("Problem parsing: " + resourceURL, ex);
+            return new ArrayList<ServiceDecorationType>();
+        }
+    }
+}
index 44639b2..14b1ab8 100644 (file)
@@ -51,7 +51,7 @@ public class InterfaceRule implements Rule {
     public synchronized void addProperty(String name, String value, String type) {
         Object obj = value;
 
-        if (!String.class.getName().equals(type)) {
+        if (type != null && !String.class.getName().equals(type)) {
             try {
                 Class<?> cls = getClass().getClassLoader().loadClass(type);
                 Constructor<?> ctor = cls.getConstructor(new Class[] {String.class});
index 73e46e0..b67c1d6 100644 (file)
@@ -26,72 +26,56 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.Namespace;
-import org.jdom.input.SAXBuilder;
+import org.apache.cxf.xmlns.service_decoration._1_0.AddPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ServiceDecoratorImpl implements ServiceDecorator {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ServiceDecoratorImpl.class);
-
     final List<Rule> decorations = new CopyOnWriteArrayList<Rule>();
 
+    private DecorationParser parser;
+
+    public ServiceDecoratorImpl() {
+        parser = new DecorationParser();
+    }
+    
     public void decorate(ServiceReference sref, Map<String, Object> target) {
         for (Rule matcher : decorations) {
             matcher.apply(sref, target);
         }
     }
 
-    @SuppressWarnings("unchecked")
     void addDecorations(Bundle bundle) {
-        Namespace ns = Namespace.getNamespace("http://cxf.apache.org/xmlns/service-decoration/1.0.0");
-        for (Element decoration : getDecorationElements(bundle)) {
-            for (Element match : (List<Element>) decoration.getChildren("match", ns)) {
-                InterfaceRule m = new InterfaceRule(bundle, match.getAttributeValue("interface"));
-                for (Element propMatch : (List<Element>) match.getChildren("match-property", ns)) {
-                    m.addPropMatch(propMatch.getAttributeValue("name"), propMatch.getAttributeValue("value"));
-                }
-                for (Element addProp : (List<Element>) match.getChildren("add-property", ns)) {
-                    m.addProperty(addProp.getAttributeValue("name"),
-                                  addProp.getAttributeValue("value"),
-                                  addProp.getAttributeValue("type", String.class.getName()));
-                }
-                decorations.add(m);
+        for (ServiceDecorationType decoration : getDecorationElements(bundle)) {
+            for (MatchType match : decoration.getMatch()) {
+                decorations.add(getRule(bundle, match));
             }
         }
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    static List<Element> getDecorationElements(Bundle bundle) {
-        Enumeration entries = bundle.findEntries("OSGI-INF/remote-service", "*.xml", false);
-        return getDecorationElementsForEntries(entries);
+    private Rule getRule(Bundle bundle, MatchType match) {
+        InterfaceRule m = new InterfaceRule(bundle, match.getInterface());
+        for (MatchPropertyType propMatch : match.getMatchProperty()) {
+            m.addPropMatch(propMatch.getName(), propMatch.getValue());
+        }
+        for (AddPropertyType addProp : match.getAddProperty()) {
+            m.addProperty(addProp.getName(), addProp.getValue(), addProp.getType());
+        }
+        return m;
     }
 
-    /**
-     * Only for tests
-     * @param entries
-     * @return
-     */
-    @SuppressWarnings("unchecked")
-    static List<Element> getDecorationElementsForEntries(Enumeration<URL> entries) {
+    List<ServiceDecorationType> getDecorationElements(Bundle bundle) {
+        @SuppressWarnings("rawtypes")
+        Enumeration entries = bundle.findEntries("OSGI-INF/remote-service", "*.xml", false);
         if (entries == null) {
             return Collections.emptyList();
         }
-        List<Element> elements = new ArrayList<Element>();
+        List<ServiceDecorationType> elements = new ArrayList<ServiceDecorationType>();
         while (entries.hasMoreElements()) {
-            URL resourceURL = entries.nextElement();
-            try {
-                Document d = new SAXBuilder().build(resourceURL.openStream());
-                Namespace ns = Namespace.getNamespace("http://cxf.apache.org/xmlns/service-decoration/1.0.0");
-                elements.addAll(d.getRootElement().getChildren("service-decoration", ns));
-            } catch (Exception ex) {
-                LOG.warn("Problem parsing: " + resourceURL, ex);
-            }
+            elements.addAll(parser.getDecorations((URL)entries.nextElement()));
         }
         return elements;
     }
diff --git a/dsw/cxf-dsw/src/main/resources/service-decoration.xsd b/dsw/cxf-dsw/src/main/resources/service-decoration.xsd
new file mode 100644 (file)
index 0000000..66e8d30
--- /dev/null
@@ -0,0 +1,67 @@
+<?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.
+-->
+<schema targetNamespace="http://cxf.apache.org/xmlns/service-decoration/1.0.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+    <element name="service-decorations" type="tns:ServiceDecorationsType"></element>
+
+    <complexType name="ServiceDecorationsType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:service-decoration">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="ServiceDecorationType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:match">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="MatchType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:match-property">
+            </element>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:add-property">
+            </element>
+        </sequence>
+        <attribute name="interface" type="string"></attribute>
+    </complexType>
+
+    <complexType name="MatchPropertyType">
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+    </complexType>
+
+    <complexType name="AddPropertyType">
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+        <attribute name="type" type="string"></attribute>
+    </complexType>
+    <element name="service-decoration"
+        type="tns:ServiceDecorationType">
+    </element>
+    <element name="match" type="tns:MatchType"></element>
+    <element name="match-property" type="tns:MatchPropertyType"></element>
+    <element name="add-property" type="tns:AddPropertyType"></element>
+</schema>
\ No newline at end of file
diff --git a/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java b/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java
new file mode 100644 (file)
index 0000000..37c018a
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * 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.cxf.dosgi.dsw.decorator;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.cxf.xmlns.service_decoration._1_0.AddPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class DecorationParserTest {
+
+    @Test
+    public void testGetDecoratorForSD() {
+        URL resource = getClass().getResource("/test-resources/sd.xml");
+        List<ServiceDecorationType> elements = new DecorationParser().getDecorations(resource);
+        assertEquals(1, elements.size());
+        ServiceDecorationType decoration = elements.get(0);
+        assertEquals(1, decoration.getMatch().size());
+        MatchType match = decoration.getMatch().get(0);
+        assertEquals("org.acme.foo.*", match.getInterface());
+        assertEquals(1, match.getMatchProperty().size());
+        MatchPropertyType matchProp = match.getMatchProperty().get(0);
+        assertEquals("test.prop", matchProp.getName());
+        assertEquals("xyz", matchProp.getValue());
+        assertEquals(1, match.getAddProperty().size());
+        AddPropertyType addProp = match.getAddProperty().get(0);
+        assertEquals("test.too", addProp.getName());
+        assertEquals("ahaha", addProp.getValue());
+        assertEquals("java.lang.String", addProp.getType());
+    }
+
+    @Test
+    public void testGetDecorationForNull() {
+        List<ServiceDecorationType> elements = new DecorationParser().getDecorations(null);
+        Assert.assertEquals(0, elements.size());
+    }
+}
index 93347fe..b770b89 100644 (file)
@@ -21,9 +21,7 @@ package org.apache.cxf.dosgi.dsw.decorator;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import junit.framework.Assert;
@@ -31,7 +29,6 @@ import junit.framework.TestCase;
 
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
-import org.jdom.Element;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
@@ -44,20 +41,6 @@ public class ServiceDecoratorImplTest extends TestCase {
     private static final URL RES_SD0 = getResource("/test-resources/sd0.xml");
     private static final URL RES_SD_1 = getResource("/test-resources/sd-1.xml");
 
-    public void testGetDecoratorElements() {
-        Enumeration<URL> urls = Collections.enumeration(Collections.singletonList(RES_SD));
-
-        List<Element> elements = ServiceDecoratorImpl.getDecorationElementsForEntries(urls);
-        assertEquals(1, elements.size());
-        assertEquals("service-decoration", elements.get(0).getName());
-        assertEquals("http://cxf.apache.org/xmlns/service-decoration/1.0.0", elements.get(0).getNamespaceURI());
-    }
-
-    public void testGetDecoratorElements2() {
-        List<Element> elements = ServiceDecoratorImpl.getDecorationElementsForEntries(null);
-        assertEquals(0, elements.size());
-    }
-
     public void testAddRemoveDecorations() {
         final Map<String, Object> serviceProps = new HashMap<String, Object>();
         serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.acme.foo.Bar"});
index 41c557a..46c2db2 100644 (file)
@@ -75,8 +75,6 @@
         <slf4j.version>1.6.4</slf4j.version>
         <felix.plugin.version>2.4.0</felix.plugin.version>
         <exam.version>2.6.0</exam.version>
-        <jdom.version>1.1.2_1</jdom.version>
-
         <cxf.resources.base.path />
         <cxf.checkstyle.extension />
     </properties>