diff options
Diffstat (limited to 'sca-java-2.x/trunk')
21 files changed, 709 insertions, 735 deletions
diff --git a/sca-java-2.x/trunk/distribution/all/manifests/axiom-api-1.2.7.MF b/sca-java-2.x/trunk/distribution/all/manifests/axiom-api-1.2.7.MF index 400fdc58e8..3a692b6c06 100644 --- a/sca-java-2.x/trunk/distribution/all/manifests/axiom-api-1.2.7.MF +++ b/sca-java-2.x/trunk/distribution/all/manifests/axiom-api-1.2.7.MF @@ -3,7 +3,6 @@ Bundle-ManifestVersion: 2 Bundle-Name: Axiom API
Bundle-SymbolicName: org.apache.ws.commons.axiom.axiom-api
Bundle-Version: 1.2.7
-Bundle-ClassPath: axiom-api-1.2.7.jar
Bundle-Vendor: Apache Software Foundation
Export-Package: org.apache.axiom.attachments,
org.apache.axiom.attachments.impl,
diff --git a/sca-java-2.x/trunk/features/osgi/pom.xml b/sca-java-2.x/trunk/features/osgi/pom.xml new file mode 100644 index 0000000000..429b8c626d --- /dev/null +++ b/sca-java-2.x/trunk/features/osgi/pom.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-feature</artifactId> + <version>2.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>tuscany-feature-osgi</artifactId> + <name>Apache Tuscany SCA OSGi Remote Services Feature</name> + <packaging>pom</packaging> + + <dependencies> + + <!-- Core distribution --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-feature-core</artifactId> + <type>pom</type> + <version>2.0-SNAPSHOT</version> + </dependency> + + <!-- Bindings --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-binding-rmi-runtime</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <!-- WebService --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-feature-webservice</artifactId> + <type>pom</type> + <version>2.0-SNAPSHOT</version> + </dependency> + + <!-- Hosts --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-rmi</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <!-- Implementations --> + + <!-- OSGi Remote Services --> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-implementation-osgi-runtime</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-contribution-osgi</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-node-impl-osgi</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.eclipse.osgi</groupId> + <artifactId>services</artifactId> + <version>3.2.0-v20090520-1800</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-endpoint-tribes</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <!-- Policies --> +<!-- + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-policy-transaction</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> +--> + </dependencies> + + +</project> diff --git a/sca-java-2.x/trunk/features/pom.xml b/sca-java-2.x/trunk/features/pom.xml index 9baf8fef0d..358d1c380e 100644 --- a/sca-java-2.x/trunk/features/pom.xml +++ b/sca-java-2.x/trunk/features/pom.xml @@ -35,6 +35,7 @@ <module>api</module> <module>core</module> <module>ejava</module> + <module>osgi</module> <module>process</module> <module>webservice</module> <module>web20</module> diff --git a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/ServiceDescriptions.java b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/ServiceDescriptions.java index 35866938d6..a5322429ff 100644 --- a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/ServiceDescriptions.java +++ b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/ServiceDescriptions.java @@ -29,8 +29,10 @@ import javax.xml.namespace.QName; public interface ServiceDescriptions extends List<ServiceDescription> { String REMOTE_SERVICE_FOLDER = "OSGI-INF/remote-service"; - String OSGI_SD_NS = "http://www.osgi.org/xmlns/sd/v1.0.0"; - QName SERVICE_DESCRIPTIONS_QNAME = new QName(OSGI_SD_NS, "service-descriptions"); - QName SERVICE_DESCRIPTION_QNAME = new QName(OSGI_SD_NS, "service-description"); + String OSGI_SD_NS = "http://www.osgi.org/xmlns/rsa/v1.0.0"; + QName SERVICE_DESCRIPTIONS_QNAME = new QName(OSGI_SD_NS, "endpoint-descriptions"); + QName SERVICE_DESCRIPTION_QNAME = new QName(OSGI_SD_NS, "endpoint-description"); + QName PROPERTY_QNAME = new QName(OSGI_SD_NS, "property"); + QName XML_QNAME = new QName(OSGI_SD_NS, "xml"); String REMOTE_SERVICE_HEADER = "Remote-Service"; } diff --git a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/ServiceDescriptionImpl.java b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/ServiceDescriptionImpl.java index b990cf5980..1ffe16bf71 100644 --- a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/ServiceDescriptionImpl.java +++ b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/ServiceDescriptionImpl.java @@ -19,18 +19,18 @@ package org.apache.tuscany.sca.implementation.osgi.impl; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.tuscany.sca.implementation.osgi.ServiceDescription; +import org.osgi.framework.Constants; /** * The OSGi RFC 119 description of a remote OSGi service */ public class ServiceDescriptionImpl implements ServiceDescription { - private List<String> interfaces = new ArrayList<String>(); private Map<String, Object> properties = new HashMap<String, Object>(); protected ServiceDescriptionImpl() { @@ -38,7 +38,7 @@ public class ServiceDescriptionImpl implements ServiceDescription { } public List<String> getInterfaces() { - return interfaces; + return Arrays.asList((String[])properties.get(Constants.OBJECTCLASS)); } public Map<String, Object> getProperties() { @@ -46,6 +46,6 @@ public class ServiceDescriptionImpl implements ServiceDescription { } public String toString() { - return "service-description: interfaces=" + interfaces + " properties=" + properties; + return "service-description: " + properties; } } diff --git a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java index fc6e44d8d6..891fed13d0 100644 --- a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java +++ b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java @@ -19,6 +19,9 @@ package org.apache.tuscany.sca.implementation.osgi.xml; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.StringTokenizer; import javax.xml.namespace.QName; @@ -39,98 +42,118 @@ import org.apache.tuscany.sca.core.FactoryExtensionPoint; import org.apache.tuscany.sca.implementation.osgi.ServiceDescription; import org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions; import org.apache.tuscany.sca.implementation.osgi.ServiceDescriptionsFactory; +import org.osgi.framework.Constants; /* <?xml version="1.0" encoding="UTF-8"?> -<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"> - <service-description> - <provide interface="com.iona.soa.pojo.hello.HelloService"/> - <property name="service.intents">SOAP HTTP</property> - <property name="osgi.remote.configuration.type">pojo</property> - <property name="osgi.remote.configuration.pojo.address"> - http://localhost:9000/hello +<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0"> + <endpoint-description> + <property name="service.intents"> + <list> + <value>SOAP</value> + <value>HTTP</value> + </list> </property> - </service-description> - <service-description> - <provide interface="com.iona.soa.pojo.hello.GreeterService"/> - <property name="service.intents">SOAP HTTP</property> - <property name="osgi.remote.configuration.type">pojo</property> - <property name="osgi.remote.configuration.pojo.address"> - http://localhost:9005/greeter + <property name="endpoint.id" value="http://ws.acme.com:9000/hello"/> + <property name="objectClass" value="com.acme.Foo"/> + <property name="endpoint.package.version.com.acme" value="4.2"/> + <property name="service.imported.configs" value="com.acme"/> + <property name="com.acme.ws.xml"> + <xml> + <config xmlns="http://acme.com/defs"> + <port>1029</port> + <host>www.acme.com</host> + </config> + </xml> </property> - </service-description> -</service-descriptions> + </endpoint-description> +</endpoint-descriptions> */ public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor implements StAXArtifactProcessor<ServiceDescriptions> { private ServiceDescriptionsFactory factory; private StAXArtifactProcessor processor; - - public ServiceDescriptionsProcessor(ExtensionPointRegistry registry, - StAXArtifactProcessor processor) { + public ServiceDescriptionsProcessor(ExtensionPointRegistry registry, StAXArtifactProcessor processor) { this.processor = processor; FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); this.factory = modelFactories.getFactory(ServiceDescriptionsFactory.class); } - public ServiceDescriptions read(XMLStreamReader reader, ProcessorContext context) throws XMLStreamException, ContributionReadException { + public ServiceDescriptions read(XMLStreamReader reader, ProcessorContext context) throws XMLStreamException, + ContributionReadException { int event = reader.getEventType(); - ServiceDescriptions sds = factory.createServiceDescriptions(); + ServiceDescriptions sds = null; ServiceDescription sd = null; + String propertyName = null; + String propertyType = "String"; + Object propertyValue = null; + String propertyLiteral = null; + boolean xml = false; + boolean multiValued = false; while (true) { switch (event) { case XMLStreamConstants.START_ELEMENT: QName name = reader.getName(); - if (ServiceDescriptions.SERVICE_DESCRIPTION_QNAME.equals(name)) { + if (ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME.equals(name)) { + sds = factory.createServiceDescriptions(); + } else if (ServiceDescriptions.SERVICE_DESCRIPTION_QNAME.equals(name)) { sd = factory.createServiceDescription(); sds.add(sd); - } else if ("provide".equals(name.getLocalPart())) { - String interfaceName = reader.getAttributeValue(null, "interface"); - if (interfaceName != null) { - sd.getInterfaces().add(interfaceName); - } } else if ("property".equals(name.getLocalPart())) { - String propName = reader.getAttributeValue(null, "name"); - String propValue = reader.getAttributeValue(null, "value"); - String propType = reader.getAttributeValue(null, "type"); - if (propType == null) { - propType = "String"; + multiValued = false; + propertyName = reader.getAttributeValue(null, "name"); + propertyType = reader.getAttributeValue(null, "value-type"); + if (propertyType == null) { + propertyType = "String"; + } + propertyLiteral = reader.getAttributeValue(null, "value"); + // if (propertyLiteral == null) { + // propertyLiteral = reader.getElementText(); + // } + if (propertyLiteral != null) { + propertyLiteral = propertyLiteral.trim(); + propertyValue = getPropertyValue(reader, propertyName, propertyLiteral, propertyType); } - if (propValue == null) { - propValue = reader.getElementText(); + } else if ("list".equals(name.getLocalPart())) { + if (propertyValue != null) { + throw new IllegalArgumentException("@value and <list> are both present"); } - if (propValue != null) { - propValue = propValue.trim(); + propertyValue = new ArrayList<Object>(); + multiValued = true; + } else if ("array".equals(name.getLocalPart())) { + if (propertyValue != null) { + throw new IllegalArgumentException("@value and <array> are both present"); } - Object prop = propValue; - if ("Integer".equals(propType)) { - prop = Integer.valueOf(propValue); - } else if ("Long".equals(propType)) { - prop = Long.valueOf(propValue); - } else if ("Float".equals(propType)) { - prop = Float.valueOf(propValue); - } else if ("Double".equals(propType)) { - prop = Double.valueOf(propValue); - } else if ("Short".equals(propType)) { - prop = Short.valueOf(propValue); - } else if ("Character".equals(propType)) { - prop = propValue.charAt(0); - } else if ("Byte".equals(propType)) { - prop = Byte.valueOf(propValue); - } else if ("Boolean".equals(propType)) { - prop = Boolean.valueOf(propValue); + propertyValue = new ArrayList<Object>(); + multiValued = true; + } else if ("set".equals(name.getLocalPart())) { + if (propertyValue != null) { + throw new IllegalArgumentException("@value and <set> are both present"); } - if (propName.endsWith(".intents")) { - prop = toQNames(reader, propValue); + propertyValue = new HashSet<Object>(); + multiValued = true; + } else if ("xml".equals(name.getLocalPart())) { + xml = true; + } else if ("value".equals(name.getLocalPart())) { + propertyLiteral = reader.getElementText(); + if (propertyLiteral != null) { + propertyLiteral = propertyLiteral.trim(); + Object value = getPropertyValue(reader, propertyName, propertyLiteral, propertyType); + if (multiValued && (propertyValue instanceof Collection)) { + ((Collection)propertyValue).add(value); + } else if (propertyValue == null) { + propertyValue = value; + } } - sd.getProperties().put(propName, prop); } else { - name = reader.getName(); - if (!ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME.equals(name)) { - Object ext = processor.read(reader, context); - if (sd != null) { - sd.getProperties().put(name.toString(), ext); + // FIXME: [rfeng] The rsa spec says the XML should be saved as String + Object value = processor.read(reader, context); + if (xml) { + if (multiValued && (propertyValue instanceof Collection)) { + ((Collection)propertyValue).add(value); + } else if (propertyValue == null) { + propertyValue = value; } } } @@ -140,8 +163,20 @@ public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor impl if (ServiceDescriptions.SERVICE_DESCRIPTION_QNAME.equals(name)) { // Reset the sd sd = null; - } - if (ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME.equals(name)) { + } else if (ServiceDescriptions.PROPERTY_QNAME.equals(name)) { + if (sd != null && propertyName != null) { + if (propertyValue == null) { + throw new IllegalArgumentException("No value is defined for " + propertyName); + } + sd.getProperties().put(propertyName, propertyValue); + } + propertyName = null; + propertyType = "String"; + propertyValue = null; + multiValued = false; + } else if (ServiceDescriptions.XML_QNAME.equals(name)) { + xml = false; + } else if (ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME.equals(name)) { return sds; } break; @@ -154,6 +189,35 @@ public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor impl } } + private Object getPropertyValue(XMLStreamReader reader, String propertyName, String propertyLiteral, String propType) { + Object propertyValue = null; + propertyValue = propertyLiteral; + if ("Integer".equals(propType) || "int".equals(propType)) { + propertyValue = Integer.valueOf(propertyLiteral); + } else if ("Long".equals(propType) || "long".equals(propType)) { + propertyValue = Long.valueOf(propertyLiteral); + } else if ("Float".equals(propType) || "float".equals(propType)) { + propertyValue = Float.valueOf(propertyLiteral); + } else if ("Double".equals(propType) || "double".equals(propType)) { + propertyValue = Double.valueOf(propertyLiteral); + } else if ("Short".equals(propType) || "short".equals(propType)) { + propertyValue = Short.valueOf(propertyLiteral); + } else if ("Character".equals(propType) || "char".equals(propType)) { + propertyValue = propertyLiteral.charAt(0); + } else if ("Byte".equals(propType) || "byte".equals(propType)) { + propertyValue = Byte.valueOf(propertyLiteral); + } else if ("Boolean".equals(propType) || "boolean".equals(propType)) { + propertyValue = Boolean.valueOf(propertyLiteral); + } + if (propertyName.endsWith(".intents")) { + propertyValue = toQNames(reader, propertyLiteral); + } + if (Constants.OBJECTCLASS.equals(propertyName)) { + return propertyLiteral.split("( |\t|\n|\r|\f)+"); + } + return propertyValue; + } + /** * Convert ns1:e1 ns2:e2 to {http://ns1}e1 {http://ns2}e2 * @param reader @@ -176,8 +240,8 @@ public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor impl return ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME; } - public void write(ServiceDescriptions model, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, - XMLStreamException { + public void write(ServiceDescriptions model, XMLStreamWriter writer, ProcessorContext context) + throws ContributionWriteException, XMLStreamException { // TODO: To be implemented } @@ -185,7 +249,7 @@ public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor impl return ServiceDescriptions.class; } - public void resolve(ServiceDescriptions model, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { - // TODO: To be implemented + public void resolve(ServiceDescriptions model, ModelResolver resolver, ProcessorContext context) + throws ContributionResolveException { } } diff --git a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor index c3af0902a3..e8973a91db 100644 --- a/sca-java-2.x/trunk/modules/implementation-osgi/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor +++ b/sca-java-2.x/trunk/modules/implementation-osgi/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor @@ -17,6 +17,6 @@ # Implementation class for the artifact processor extension org.apache.tuscany.sca.implementation.osgi.xml.OSGiImplementationProcessor;qname=http://tuscany.apache.org/xmlns/sca/1.1#implementation.osgi,model=org.apache.tuscany.sca.implementation.osgi.OSGiImplementation -org.apache.tuscany.sca.implementation.osgi.xml.ServiceDescriptionsProcessor;qname=http://www.osgi.org/xmlns/sd/v1.0.0#service-descriptions,model=org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions +org.apache.tuscany.sca.implementation.osgi.xml.ServiceDescriptionsProcessor;qname=http://www.osgi.org/xmlns/rsa/v1.0.0#endpoint-descriptions,model=org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions org.apache.tuscany.sca.implementation.osgi.xml.OSGiPropertyProcessor;qname=http://tuscany.apache.org/xmlns/sca/1.1#osgi.property,model=org.apache.tuscany.sca.implementation.osgi.OSGiProperty org.apache.tuscany.sca.implementation.osgi.xml.SCAConfigProcessor;qname=http://www.osgi.org/xmlns/scact/v1.0.0#sca-config,model=org.apache.tuscany.sca.implementation.osgi.SCAConfig
diff --git a/sca-java-2.x/trunk/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java b/sca-java-2.x/trunk/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java index cef99f5625..0e7acc354a 100644 --- a/sca-java-2.x/trunk/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java +++ b/sca-java-2.x/trunk/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java @@ -41,32 +41,34 @@ import org.junit.Test; */ public class ServiceDescriptionsTestCase { private static final String xml = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<service-descriptions xmlns=\"http://www.osgi.org/xmlns/sd/v1.0.0\" " + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<endpoint-descriptions xmlns=\"http://www.osgi.org/xmlns/rsa/v1.0.0\" " + "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\">" - + "<service-description>" - + "<provide interface=\"calculator.operations.AddService\"/>" - + "<property name=\"service.intents\">sca:SOAP sca:HTTP</property>" - + "<property name=\"osgi.remote.configuration.type\">sca</property>" - + "<property name=\"osgi.remote.configuration.sca.componentType\">" - + "OSGI-INF/sca/bundle.componentType" + + "<endpoint-description>" + + "<property name=\"objectClass\" value=\"calculator.operations.AddService\"/>" + + "<property name=\"service.intents\" value=\"sca:SOAP sca:HTTP\"/>" + + "<property name=\"service.imported.configs\" value=\"org.osgi.sca\"/>" + + "</endpoint-description>" + + "<endpoint-description>" + + "<property name=\"service.intents\">" + + " <list>" + + " <value>SOAP</value>" + + " <value>HTTP</value>" + + " </list>" + "</property>" - + "<property name=\"osgi.remote.configuration.sca.reference\">" - + "addService" - + "</property>" - + "</service-description>" - + "<service-description>" - + "<provide interface=\"calculator.operations.SubtractService\"/>" - + "<property name=\"service.intents\">sca:SOAP sca:HTTP</property>" - + "<property name=\"osgi.remote.configuration.type\">sca</property>" - + "<property name=\"osgi.remote.configuration.sca.componentType\">" - + "OSGI-INF/sca/bundle.componentType" - + "</property>" - + "<property name=\"osgi.remote.configuration.sca.reference\">" - + "subtractService" - + "</property>" - + "</service-description>" - + "</service-descriptions>"; + + "<property name=\"endpoint.id\" value=\"http://ws.acme.com:9000/hello\"/>" + + "<property name=\"objectClass\" value=\"com.acme.Foo\"/>" + + "<property name=\"endpoint.package.version.com.acme\" value=\"4.2\"/>" + + "<property name=\"service.imported.configs\" value=\"com.acme\"/>" + + "<property name=\"com.acme.ws.xml\">" + + "<xml>" + + " <config xmlns=\"http://acme.com/defs\">" + + " <port>1029</port>" + + " <host>www.acme.com</host>" + + " </config>" + + " </xml>" + + " </property>" + + "</endpoint-description>" + + "</endpoint-descriptions>"; private static ServiceDescriptionsProcessor processor; private static XMLStreamReader reader; diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointHelper.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointHelper.java index 3a21674139..949d2d8af7 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointHelper.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointHelper.java @@ -67,11 +67,11 @@ public class EndpointHelper { String serviceID = (String)props.get(Constants.SERVICE_ID); if (serviceID != null) { - props.put(RemoteConstants.ENDPOINT_ID, Long.parseLong(serviceID)); + props.put(RemoteConstants.ENDPOINT_SERVICE_ID, Long.parseLong(serviceID)); } - props.put(RemoteConstants.ENDPOINT_URI, endpoint.getURI()); + props.put(RemoteConstants.ENDPOINT_ID, endpoint.getURI()); // FIXME: [rfeng] How to pass in the remote service id from the endpoint XML - props.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, new String[] {"org.osgi.sca"}); + props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, new String[] {"org.osgi.sca"}); props.put(Endpoint.class.getName(), endpoint); List<String> interfaces = getInterfaces(endpoint); props.put(Constants.OBJECTCLASS, interfaces.toArray(new String[interfaces.size()])); diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java index bfc5b97ee8..916761f129 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/EndpointIntrospector.java @@ -425,10 +425,13 @@ public class EndpointIntrospector { JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); Class<?> interfaceClass = bundle.loadClass(intf); JavaInterface javaInterface = javaInterfaceFactory.createJavaInterface(interfaceClass); + // [rfeng] For OSGi, the interfaces should be marked as remote + javaInterface.setRemotable(true); interfaceContract.setInterface(javaInterface); if (javaInterface.getCallbackClass() != null) { - interfaceContract.setCallbackInterface(javaInterfaceFactory.createJavaInterface(javaInterface - .getCallbackClass())); + JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(javaInterface.getCallbackClass()); + callbackInterface.setRemotable(true); + interfaceContract.setCallbackInterface(callbackInterface); } return interfaceContract; } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java index 9b31931b6c..2335d31020 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ExportRegistrationImpl.java @@ -30,10 +30,8 @@ import org.osgi.service.remoteserviceadmin.ExportRegistration; */ public class ExportRegistrationImpl implements ExportRegistration { private Node node; - private ServiceReference exportedService; - private EndpointDescription endpointDescription; - private Throwable exception; private ExportReference exportReference; + private Throwable exception; /** * @param exportedService @@ -46,8 +44,7 @@ public class ExportRegistrationImpl implements ExportRegistration { Throwable exception) { super(); this.node = node; - this.exportedService = exportedService; - this.endpointDescription = endpointDescription; + this.exportReference = new ExportReferenceImpl(exportedService, endpointDescription); this.exception = exception; } @@ -68,16 +65,15 @@ public class ExportRegistrationImpl implements ExportRegistration { node = null; } exception = null; - endpointDescription = null; - exportedService = null; + exportReference = new ExportReferenceImpl(null, null); } public ServiceReference getExportedService() { - return exportedService; + return exportReference.getExportedService(); } public EndpointDescription getEndpointDescription() { - return endpointDescription; + return exportReference.getExportedEndpoint(); } public Throwable getException() { @@ -89,8 +85,7 @@ public class ExportRegistrationImpl implements ExportRegistration { } public ExportReference getExportReference() throws IllegalStateException { - // TODO Auto-generated method stub - return null; + return exportReference; } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java index 2526f70a6b..8961d031cc 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/ImportRegistrationImpl.java @@ -67,7 +67,7 @@ public class ImportRegistrationImpl implements ImportRegistration { node = null; } exception = null; - importReference = null; + importReference = new ImportReferenceImpl(null, null); } public Throwable getException() { diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java index 49dc8c7461..b644ca14c9 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/OSGiServiceExporter.java @@ -25,7 +25,7 @@ import static org.apache.tuscany.sca.osgi.remoteserviceadmin.impl.OSGiHelper.get import static org.apache.tuscany.sca.osgi.remoteserviceadmin.impl.OSGiHelper.getOSGiProperties; import static org.osgi.framework.Constants.SERVICE_ID; import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID; -import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID; +import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_SERVICE_ID; import java.util.ArrayList; import java.util.Collections; @@ -88,7 +88,7 @@ public class OSGiServiceExporter extends AbstractOSGiServiceHandler implements S ENDPOINT_FRAMEWORK_UUID, getFrameworkUUID(reference.getBundle() .getBundleContext()))); - service.getExtensions().add(createOSGiProperty(registry, ENDPOINT_ID, reference + service.getExtensions().add(createOSGiProperty(registry, ENDPOINT_SERVICE_ID, reference .getProperty(SERVICE_ID))); // FIXME: Configure the domain and node URI diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java index 994fb29e9b..608c74bcfc 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/remoteserviceadmin/impl/RemoteServiceAdminImpl.java @@ -41,6 +41,7 @@ import org.osgi.service.remoteserviceadmin.ExportReference; import org.osgi.service.remoteserviceadmin.ExportRegistration; import org.osgi.service.remoteserviceadmin.ImportReference; import org.osgi.service.remoteserviceadmin.ImportRegistration; +import org.osgi.service.remoteserviceadmin.RemoteConstants; import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin; import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent; import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener; @@ -70,8 +71,15 @@ public class RemoteServiceAdminImpl implements RemoteServiceAdmin, ManagedServic this.importer = new OSGiServiceImporter(context); exporter.start(); importer.start(); - registration = context.registerService(RemoteServiceAdmin.class.getName(), this, null); Hashtable<String, Object> props = new Hashtable<String, Object>(); + props.put(RemoteConstants.REMOTE_CONFIGS_SUPPORTED, new String[] {"org.osgi.sca"}); + // FIXME: We should ask SCA domain for the supported intents + props.put(RemoteConstants.REMOTE_INTENTS_SUPPORTED, new String[] {}); + // FIXME: We should ask SCA domain for the supported binding types + props.put("org.osgi.sca.binding.types", new String[] {}); + registration = context.registerService(RemoteServiceAdmin.class.getName(), this, props); + + props = new Hashtable<String, Object>(); props.put(Constants.SERVICE_PID, RemoteServiceAdminImpl.class.getName()); managedService = context.registerService(ManagedService.class.getName(), this, props); listeners = new ServiceTracker(this.context, RemoteServiceAdminListener.class.getName(), null); @@ -213,17 +221,17 @@ public class RemoteServiceAdminImpl implements RemoteServiceAdmin, ManagedServic props.put("bundle-symbolicname", rsaBundle.getSymbolicName()); props.put("bundle-version", rsaBundle.getHeaders().get(Constants.BUNDLE_VERSION)); props.put("cause", rsaEvent.getException()); - props.put("import.reference", rsaEvent.getImportReference()); - props.put("export.reference", rsaEvent.getExportReference()); + props.put("import.registration", rsaEvent.getImportReference()); + props.put("export.registration", rsaEvent.getExportReference()); EndpointDescription ep = null; if (rsaEvent.getImportReference() != null) { ep = rsaEvent.getImportReference().getImportedEndpoint(); } else { ep = rsaEvent.getExportReference().getExportedEndpoint(); } - props.put("service.remote.id", ep.getRemoteServiceID()); - props.put("service.remote.uuid", ep.getRemoteFrameworkUUID()); - props.put("service.remote.uri", ep.getRemoteURI()); + props.put("endpoint.service.id", ep.getRemoteServiceID()); + props.put("endpoint.framework.uuid", ep.getRemoteFrameworkUUID()); + props.put("endpoint.id", ep.getRemoteID()); props.put("objectClass", ep.getInterfaces()); props.put("service.imported.configs", ep.getConfigurationTypes()); props.put("timestamp", new Long(System.currentTimeMillis())); diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java index 0efa0cd20b..f6e9855556 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java @@ -25,10 +25,13 @@ import java.util.Dictionary; import org.apache.tuscany.sca.assembly.Endpoint; import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.core.LifeCycleListener; import org.apache.tuscany.sca.core.UtilityExtensionPoint; import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation; +import org.apache.tuscany.sca.node.configuration.NodeConfiguration; import org.apache.tuscany.sca.runtime.DomainRegistryFactory; import org.apache.tuscany.sca.runtime.EndpointListener; +import org.apache.tuscany.sca.runtime.EndpointRegistry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.service.remoteserviceadmin.EndpointDescription; @@ -38,6 +41,7 @@ import org.osgi.service.remoteserviceadmin.EndpointDescription; */ public class DomainDiscoveryService extends AbstractDiscoveryService implements EndpointListener { private DomainRegistryFactory domainRegistryFactory; + private EndpointRegistry endpointRegistry; public DomainDiscoveryService(BundleContext context) { super(context); @@ -49,6 +53,18 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements this.domainRegistryFactory = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(DomainRegistryFactory.class); domainRegistryFactory.addListener(this); + // The following code forced the start() of the domain registry in absense of services + String domainRegistry = context.getProperty("org.osgi.sca.domain.registry"); + if (domainRegistry == null) { + domainRegistry = NodeConfiguration.DEFAULT_DOMAIN_REGISTRY_URI; + } + String domainURI = context.getProperty("org.osgi.sca.domain.uri"); + if (domainURI == null) { + domainURI = NodeConfiguration.DEFAULT_DOMAIN_URI; + } + if (domainRegistry != null) { + endpointRegistry = domainRegistryFactory.getEndpointRegistry(domainRegistry, domainURI); + } } public void endpointAdded(Endpoint endpoint) { @@ -111,6 +127,9 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements public void stop() { domainRegistryFactory.removeListener(this); + if (endpointRegistry instanceof LifeCycleListener) { + ((LifeCycleListener)endpointRegistry).stop(); + } super.stop(); } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java index 45c563dc21..a4c9414b92 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java @@ -19,6 +19,9 @@ package org.apache.tuscany.sca.osgi.service.discovery.impl; import static org.apache.tuscany.sca.osgi.remoteserviceadmin.impl.OSGiHelper.getConfiguration; +import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_FRAMEWORK_UUID; +import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_ID; +import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_SERVICE_ID; import java.net.URL; import java.util.ArrayList; @@ -45,7 +48,6 @@ import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.remoteserviceadmin.EndpointDescription; -import org.osgi.service.remoteserviceadmin.RemoteConstants; import org.osgi.util.tracker.BundleTracker; import org.osgi.util.tracker.BundleTrackerCustomizer; import org.osgi.util.tracker.ServiceTracker; @@ -88,14 +90,14 @@ public class LocalDiscoveryService extends AbstractDiscoveryService implements B private EndpointDescription createEndpointDescription(ServiceDescription sd) { Map<String, Object> props = new HashMap<String, Object>(sd.getProperties()); props.put(Constants.OBJECTCLASS, sd.getInterfaces().toArray(new String[sd.getInterfaces().size()])); - if (!props.containsKey(RemoteConstants.ENDPOINT_ID)) { - props.put(RemoteConstants.ENDPOINT_ID, new Long(System.currentTimeMillis())); + if (!props.containsKey(ENDPOINT_SERVICE_ID)) { + props.put(ENDPOINT_SERVICE_ID, new Long(System.currentTimeMillis())); } - if (!props.containsKey(RemoteConstants.ENDPOINT_FRAMEWORK_UUID)) { - props.put(RemoteConstants.ENDPOINT_FRAMEWORK_UUID, OSGiHelper.getFrameworkUUID(context)); + if (!props.containsKey(ENDPOINT_FRAMEWORK_UUID)) { + props.put(ENDPOINT_FRAMEWORK_UUID, OSGiHelper.getFrameworkUUID(context)); } - if (!props.containsKey(RemoteConstants.ENDPOINT_URI)) { - props.put(RemoteConstants.ENDPOINT_URI, UUID.randomUUID().toString()); + if (!props.containsKey(ENDPOINT_ID)) { + props.put(ENDPOINT_ID, UUID.randomUUID().toString()); } EndpointDescription sed = new EndpointDescription(props); diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java index 4bc3b34c7c..65f1000265 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved. + * Copyright (c) OSGi Alliance (2008, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,18 +42,21 @@ import org.osgi.framework.Version; * A description of an endpoint that provides sufficient information for a * compatible distribution provider to create a connection to this endpoint * - * An Endpoint Description is easy to transfer between different systems. This - * allows it to be used as a communications device to convey available endpoint - * information to nodes in a network. + * An Endpoint Description is easy to transfer between different systems because + * it is property based where the property keys are strings and the values are + * simple types. This allows it to be used as a communications device to convey + * available endpoint information to nodes in a network. * - * An Endpoint Description reflects the perspective of an importer. That is, the - * property keys have been chosen to match filters that are created by client - * bundles that need a service. Therefore the map must not contain any - * service.exported.* property and must contain the service.imported.* ones. + * An Endpoint Description reflects the perspective of an <i>importer</i>. That + * is, the property keys have been chosen to match filters that are created by + * client bundles that need a service. Therefore the map must not contain any + * <code>service.exported.*</code> property and must contain the corresponding + * <code>service.imported.*</code> ones. * - * The service.intents property contains the intents provided by the service - * itself combined with the intents added by the exporting distribution - * provider. Qualified intents appear expanded on this property. + * The <code>service.intents</code> property must contain the intents provided + * by the service itself combined with the intents added by the exporting + * distribution provider. Qualified intents appear fully expanded on this + * property. * * @Immutable * @version $Revision$ @@ -62,15 +65,17 @@ import org.osgi.framework.Version; public class EndpointDescription { private final Map<String, Object> properties; private final List<String> interfaces; - private final long remoteServiceId; + private final long remoteServiceID; private final String remoteFrameworkUUID; - private final String remoteUri; + private final String remoteID; /** - * Create an Endpoint Description based on a Map. + * Create an Endpoint Description from a Map. * * <p> - * The {@link RemoteConstants#ENDPOINT_URI} property must be set. + * The {@link RemoteConstants#ENDPOINT_ID endpoint.id}, + * {@link RemoteConstants#SERVICE_IMPORTED_CONFIGS service.imported.configs} + * and <code>objectClass</code> properties must be set. * * @param properties The map from which to create the Endpoint Description. * The keys in the map must be type <code>String</code> and, since @@ -94,28 +99,46 @@ public class EndpointDescription { } if (props.size() < properties.size()) { throw new IllegalArgumentException( - "duplicate keys with different cases in properties"); + "duplicate keys with different cases in properties: " + + new ArrayList<String>(props.keySet()) + .removeAll(properties.keySet())); } + if (!props.containsKey(SERVICE_IMPORTED)) { + props.put(SERVICE_IMPORTED, Boolean.toString(true)); + } this.properties = Collections.unmodifiableMap(props); /* properties must be initialized before calling the following methods */ interfaces = verifyObjectClassProperty(); - remoteServiceId = verifyLongProperty(ENDPOINT_ID); + remoteServiceID = verifyLongProperty(ENDPOINT_SERVICE_ID); remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); - remoteUri = verifyStringProperty(ENDPOINT_URI); - if (remoteUri == null) { - throw new IllegalArgumentException(ENDPOINT_URI + remoteID = verifyStringProperty(ENDPOINT_ID); + if (remoteID == null) { + throw new IllegalArgumentException(ENDPOINT_ID + " property must be set"); } + if (getConfigurationTypes().isEmpty()) { + throw new IllegalArgumentException(SERVICE_IMPORTED_CONFIGS + + " property must be set and non-empty"); + } } /** - * Create an Endpoint Description based on a service reference and a map of + * Create an Endpoint Description based on a Service Reference and a Map of * properties. The properties in the map take precedence over the properties - * in the service reference. + * in the Service Reference. * * <p> - * The {@link RemoteConstants#ENDPOINT_URI} property must be set. + * This method will automatically set the + * {@link RemoteConstants#ENDPOINT_FRAMEWORK_UUID endpoint.framework.uuid} + * and {@link RemoteConstants#ENDPOINT_SERVICE_ID endpoint.service.id} + * properties based on the specified Service Reference as well as the + * {@link RemoteConstants#SERVICE_IMPORTED service.imported} property if + * they are not specified as properties. + * <p> + * The {@link RemoteConstants#ENDPOINT_ID endpoint.id}, + * {@link RemoteConstants#SERVICE_IMPORTED_CONFIGS service.imported.configs} + * and <code>objectClass</code> properties must be set. * * @param reference A service reference that can be exported. * @param properties Map of properties. This argument can be @@ -142,7 +165,9 @@ public class EndpointDescription { } if (props.size() < properties.size()) { throw new IllegalArgumentException( - "duplicate keys with different cases in properties"); + "duplicate keys with different cases in properties: " + + new ArrayList<String>(props.keySet()) + .removeAll(properties.keySet())); } } @@ -152,8 +177,8 @@ public class EndpointDescription { } } - if (!props.containsKey(ENDPOINT_ID)) { - props.put(ENDPOINT_ID, reference.getProperty(Constants.SERVICE_ID)); + if (!props.containsKey(ENDPOINT_SERVICE_ID)) { + props.put(ENDPOINT_SERVICE_ID, reference.getProperty(Constants.SERVICE_ID)); } if (!props.containsKey(ENDPOINT_FRAMEWORK_UUID)) { String uuid = null; @@ -173,36 +198,43 @@ public class EndpointDescription { props.put(ENDPOINT_FRAMEWORK_UUID, uuid); } } + if (!props.containsKey(SERVICE_IMPORTED)) { + props.put(SERVICE_IMPORTED, Boolean.toString(true)); + } this.properties = Collections.unmodifiableMap(props); /* properties must be initialized before calling the following methods */ interfaces = verifyObjectClassProperty(); - remoteServiceId = verifyLongProperty(ENDPOINT_ID); + remoteServiceID = verifyLongProperty(ENDPOINT_SERVICE_ID); remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID); - remoteUri = verifyStringProperty(ENDPOINT_URI); - if (remoteUri == null) { - throw new IllegalArgumentException(ENDPOINT_URI + remoteID = verifyStringProperty(ENDPOINT_ID); + if (remoteID == null) { + throw new IllegalArgumentException(ENDPOINT_ID + " property must be set"); } + if (getConfigurationTypes().isEmpty()) { + throw new IllegalArgumentException(SERVICE_IMPORTED_CONFIGS + + " property must be set and non-empty"); + } } /** * Verify and obtain the interface list from the properties. * * @return A list with the interface names. - * @throws IllegalArgumentException When the properties do not contain the - * right values for and interface list. - * + * @throws IllegalArgumentException If the objectClass property is not set + * or is empty or if the package version property values are + * malformed. */ private List<String> verifyObjectClassProperty() { Object o = properties.get(Constants.OBJECTCLASS); - if (o == null) { - return Collections.EMPTY_LIST; - } if (!(o instanceof String[])) { throw new IllegalArgumentException( "objectClass value must be of type String[]"); } String[] objectClass = (String[]) o; + if (objectClass.length < 1) { + throw new IllegalArgumentException("objectClass is empty"); + } for (String interf : objectClass) { int index = interf.lastIndexOf('.'); if (index == -1) { @@ -269,19 +301,19 @@ public class EndpointDescription { } /** - * Returns the endpoint's URI. + * Returns the endpoint's id. * - * The URI is an opaque id for an endpoint in URI form. No two different - * endpoints must have the same URI, two Endpoint Descriptions with the same - * URI must represent the same endpoint. + * The id is an opaque id for an endpoint. No two different endpoints must + * have the same id. Two Endpoint Descriptions with the same id must + * represent the same endpoint. * - * The value of the URI is stored in the - * {@link RemoteConstants#ENDPOINT_URI} property. + * The value of the id is stored in the + * {@link RemoteConstants#ENDPOINT_ID} property. * - * @return The URI of the endpoint, never <code>null</code>. + * @return The id of the endpoint, never <code>null</code>. */ - public String getRemoteURI() { - return remoteUri; + public String getRemoteID() { + return remoteID; } /** @@ -344,14 +376,14 @@ public class EndpointDescription { * id for a service. * * The value of the remote service id is stored in the - * {@link RemoteConstants#ENDPOINT_ID} endpoint property. + * {@link RemoteConstants#ENDPOINT_SERVICE_ID} endpoint property. * * @return Service id of a service or 0 if this Endpoint Description does - * not relate to an OSGi service + * not relate to an OSGi service. * */ public long getRemoteServiceID() { - return remoteServiceId; + return remoteServiceID; } /** @@ -426,7 +458,7 @@ public class EndpointDescription { List<String> result = new ArrayList<String>(values.size()); for (Iterator< ? > iter = values.iterator(); iter.hasNext();) { Object v = iter.next(); - if ((v != null) && (v instanceof String)) { + if (v instanceof String) { result.add((String) v); } } @@ -464,7 +496,7 @@ public class EndpointDescription { * as the given Endpoint Description. * * Two Endpoint Descriptions point to the same service if they have the same - * URI or their framework UUIDs and remote service ids are equal. + * id or their framework UUIDs and remote service ids are equal. * * @param other The Endpoint Description to look at * @return True if this endpoint description points to the same service as @@ -490,7 +522,7 @@ public class EndpointDescription { * @return An integer which is a hash code value for this object. */ public int hashCode() { - return getRemoteURI().hashCode(); + return getRemoteID().hashCode(); } /** @@ -498,7 +530,7 @@ public class EndpointDescription { * * <p> * An Endpoint Description is considered to be <b>equal to</b> another - * Endpoint Description if their URIs are equal. + * Endpoint Description if their ids are equal. * * @param other The <code>EndpointDescription</code> object to be compared. * @return <code>true</code> if <code>object</code> is a @@ -512,13 +544,13 @@ public class EndpointDescription { if (!(other instanceof EndpointDescription)) { return false; } - return getRemoteURI().equals( - ((EndpointDescription) other).getRemoteURI()); + return getRemoteID().equals( + ((EndpointDescription) other).getRemoteID()); } /** - * Tests the properties of this <code>EndpointDescription</code> against the - * given filter using a case insensitive match. + * Tests the properties of this <code>EndpointDescription</code> against + * the given filter using a case insensitive match. * * @param filter The filter to test. * @return <code>true</code> If the properties of this @@ -548,9 +580,10 @@ public class EndpointDescription { } /** - * Unmodifiable Dictionary wrapper for a Map. + * Unmodifiable Dictionary wrapper for a Map. This class is also used by + * EndpointPermission. */ - private static class UnmodifiableDictionary<K, V> extends Dictionary<K, V> { + static class UnmodifiableDictionary<K, V> extends Dictionary<K, V> { private final Map<K, V> wrapped; UnmodifiableDictionary(Map<K, V> wrapped) { @@ -584,5 +617,9 @@ public class EndpointDescription { public int size() { return wrapped.size(); } + + public String toString() { + return wrapped.toString(); + } } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java index 0bfdcd334b..84a7ba512e 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2000, 2009). All Rights Reserved. + * Copyright (c) OSGi Alliance (2000, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,13 @@ package org.osgi.service.remoteserviceadmin; -// TODO Hacked from ServiePermission +import static org.osgi.service.remoteserviceadmin.RemoteConstants.*; import java.io.IOException; import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; -import java.security.BasicPermission; import java.security.Permission; import java.security.PermissionCollection; import java.util.ArrayList; @@ -32,205 +31,166 @@ import java.util.Collections; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; -import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.TreeMap; -import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; /** - * <pre> - * ------------------------------------------------------------- - * THIS CLASS IS A PLACEHOLDER (COPIED FROM SERVICE PERMISSION)! - * ------------------------------------------------------------- - * </pre> - * - * A bundle's authority to register or get a service. + * A bundle's authority to export, import or read an Endpoint. * <ul> - * <li>The <code>register</code> action allows a bundle to register a service on - * the specified names. - * <li>The <code>get</code> action allows a bundle to detect a service and get - * it. + * <li>The <code>export</code> action allows a bundle to export a service as an + * Endpoint.</li> + * <li>The <code>import</code> action allows a bundle to import a service from + * an Endpoint.</li> + * <li>The <code>read</code> action allows a bundle to read references to an + * Endpoint.</li> * </ul> - * Permission to get a service is required in order to detect events regarding - * the service. Untrusted bundles should not be able to detect the presence of - * certain services unless they have the appropriate - * <code>EndpointPermission</code> to get the specific service. + * Permission to read an Endpoint is required in order to detect events + * regarding an Endpoint. Untrusted bundles should not be able to detect the + * presence of certain Endpoints unless they have the appropriate + * <code>EndpointPermission</code> to read the specific service. * * @ThreadSafe * @version $Revision$ */ -public final class EndpointPermission extends BasicPermission { - static final long serialVersionUID = -7662148639076511574L; +public final class EndpointPermission extends Permission { + static final long serialVersionUID = -7662148639076511574L; /** - * The action string <code>export</code>. + * The action string <code>read</code>. */ - public final static String EXPORT = "export"; + public final static String READ = "read"; /** - * The action string <code>import</code>. + * The action string <code>import</code>. The <code>import</code> action + * implies the <code>read</code> action. */ - public final static String IMPORT = "import"; + public final static String IMPORT = "import"; /** - * The action string <code>read</code>. + * The action string <code>export</code>. The <code>export</code> action + * implies the <code>read</code> action. */ - public final static String READ = "read"; + public final static String EXPORT = "export"; - private final static int ACTION_EXPORT = 0x00000001; - private final static int ACTION_IMPORT = 0x00000002; - private final static int ACTION_READ = 0x00000004; - private final static int ACTION_ALL = ACTION_EXPORT - | ACTION_IMPORT - | ACTION_READ; - final static int ACTION_NONE = 0; + private final static int ACTION_READ = 0x00000001; + private final static int ACTION_IMPORT = 0x00000002; + private final static int ACTION_EXPORT = 0x00000004; + private final static int ACTION_ALL = ACTION_EXPORT + | ACTION_IMPORT + | ACTION_READ; + final static int ACTION_NONE = 0; /** * The actions mask. */ - transient int action_mask; + transient int action_mask; /** * The actions in canonical form. * * @serial */ - private volatile String actions = null; - - /** - * The service used by this EndpointPermission. Must be null if not - * constructed with a service. - */ - transient final EndpointDescription endpoint; - - /** - * The object classes for this EndpointPermission. Must be null if not - * constructed with a service. - */ - transient final String[] objectClass; + private volatile String actions = null; /** - * If this EndpointPermission was constructed with a filter, this holds a - * Filter matching object used to evaluate the filter in implies. + * The endpoint used by this EndpointPermission. Must be null if not + * constructed with a endpoint. */ - transient Filter filter; - + transient final EndpointDescription endpoint; + /** * This dictionary holds the properties of the permission, used to match a - * filter in implies. This is not initialized until necessary, and then - * cached in this object. - */ - private transient volatile Dictionary properties; - - /** - * True if constructed with a name and the name is "*" or ends with ".*". + * filter in implies. */ - private transient boolean wildcard; + private transient final Dictionary<String, Object> properties; /** - * If constructed with a name and the name ends with ".*", this contains the - * name without the final "*". + * If this EndpointPermission was not constructed with an + * EndpointDescription, this holds a Filter matching object used to evaluate + * the filter in implies or null for wildcard. */ - private transient String prefix; + transient Filter filter; /** - * Create a new EndpointPermission. + * Create a new EndpointPermission with the specified filter. * * <p> - * The name of the service is specified as a fully qualified class name. - * Wildcards may be used. - * - * <pre> - * name ::= <class name> | <class name ending in ".*"> | * - * </pre> - * - * Examples: - * - * <pre> - * org.osgi.service.http.HttpService - * org.osgi.service.http.* - * * - * </pre> - * - * For the <code>get</code> action, the name can also be a filter - * expression. The filter gives access to the service properties as well as - * the following attributes: - * <ul> - * <li>signer - A Distinguished Name chain used to sign the bundle - * publishing the service. Wildcards in a DN are not matched according to - * the filter string rules, but according to the rules defined for a DN - * chain.</li> - * <li>location - The location of the bundle publishing the service.</li> - * <li>id - The bundle ID of the bundle publishing the service.</li> - * <li>name - The symbolic name of the bundle publishing the service.</li> - * </ul> - * Since the above attribute names may conflict with service property names - * used by a service, you can prefix an attribute name with '@' in the - * filter expression to match against the service property and not one of - * the above attributes. Filter attribute names are processed in a case - * sensitive manner unless the attribute references a service property. - * Service properties names are case insensitive. + * The filter will be evaluated against the endpoint properties of a + * requested EndpointPermission. * * <p> - * There are two possible actions: <code>get</code> and - * <code>register</code>. The <code>get</code> permission allows the owner - * of this permission to obtain a service with this name. The - * <code>register</code> permission allows the bundle to register a service - * under that name. + * There are three possible actions: <code>read</code>, <code>import</code> + * and <code>export</code>. The <code>read</code> action allows the owner of + * this permission to see the presence of distributed services. The + * <code>import</code> action allows the owner of this permission to import + * an endpoint. The <code>export</code> action allows the owner of this + * permission to export a service. * - * @param name The service class name - * @param actions <code>get</code>,<code>register</code> (canonical order) - * @throws IllegalArgumentException If the specified name is a filter - * expression and either the specified action is not - * <code>get</code> or the filter has an invalid syntax. - */ - public EndpointPermission(String name, String actions) { - this(name, parseActions(actions)); - if ((filter != null) && ((action_mask & ACTION_ALL) != ACTION_EXPORT)) { - throw new IllegalArgumentException( - "invalid action string for filter expression"); - } + * @param filterString The filter string or "*" to match all + * endpoints. + * @param actions The actions <code>read</code>, <code>import</code>, or + * <code>export</code>. + * @throws IllegalArgumentException If the filter has an invalid syntax or + * the actions are not valid. + */ + public EndpointPermission(String filterString, String actions) { + this(filterString, parseActions(actions)); } /** * Creates a new requested <code>EndpointPermission</code> object to be used - * by code that must perform <code>checkPermission</code> for the - * <code>get</code> action. <code>EndpointPermission</code> objects created - * with this constructor cannot be added to a - * <code>EndpointPermission</code> permission collection. + * by code that must perform <code>checkPermission</code>. + * <code>EndpointPermission</code> objects created with this constructor + * cannot be added to an <code>EndpointPermission</code> permission + * collection. * - * @param endpoint The requested service. - * @param actions The action <code>get</code>. - * @throws IllegalArgumentException If the specified action is not - * <code>get</code> or reference is <code>null</code>. - * @since 1.5 - */ - public EndpointPermission(EndpointDescription endpoint, String actions) { + * @param endpoint The requested endpoint. + * @param localFrameworkUUID The UUID of the local framework. This is used + * to support matching the + * {@link RemoteConstants#ENDPOINT_FRAMEWORK_UUID + * endpoint.framework.uuid} endpoint property to the + * <code><<LOCAL>></code> value in the filter expression. + * @param actions The actions <code>read</code>, <code>import</code>, or + * <code>export</code>. + * @throws IllegalArgumentException If the endpoint is <code>null</code> or + * the actions are not valid. + */ + public EndpointPermission(EndpointDescription endpoint, + String localFrameworkUUID, String actions) { super(createName(endpoint)); setTransients(null, parseActions(actions)); - this.endpoint = endpoint; - this.objectClass = (String[]) endpoint.getProperties().get( - Constants.OBJECTCLASS); - if ((action_mask & ACTION_ALL) != ACTION_EXPORT) { - throw new IllegalArgumentException("invalid action string"); + Map<String, Object> props; + if ((localFrameworkUUID != null) + && localFrameworkUUID.equals(endpoint.getRemoteFrameworkUUID())) { + props = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER); + props.putAll(endpoint.getProperties()); + props.put(ENDPOINT_FRAMEWORK_UUID, new String[] { + endpoint.getRemoteFrameworkUUID(), "<<LOCAL>>"}); + } + else { + props = endpoint.getProperties(); } + this.endpoint = endpoint; + this.properties = new EndpointDescription.UnmodifiableDictionary<String, Object>( + props); } /** - * Create a permission name from a EndpointDescription TODO Needs work + * Create a permission name from a EndpointDescription. * * @param endpoint EndpointDescription to use to create permission name. * @return permission name. */ private static String createName(EndpointDescription endpoint) { if (endpoint == null) { - throw new IllegalArgumentException("reference must not be null"); + throw new IllegalArgumentException("invalid endpoint: null"); } - StringBuffer sb = new StringBuffer("(service.id="); - // TODO sb.append(endpoint.getProperty(Constants.SERVICE_ID)); + StringBuffer sb = new StringBuffer("(" + ENDPOINT_ID + "="); + sb.append(endpoint.getRemoteID()); sb.append(")"); return sb.toString(); } @@ -245,7 +205,7 @@ public final class EndpointPermission extends BasicPermission { super(name); setTransients(parseFilter(name), mask); this.endpoint = null; - this.objectClass = null; + this.properties = null; } /** @@ -259,16 +219,6 @@ public final class EndpointPermission extends BasicPermission { } action_mask = mask; filter = f; - if (f == null) { - String name = getName(); - int l = name.length(); - /* if "*" or endsWith ".*" */ - wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name - .charAt(l - 2) == '.'))); - if (wildcard && (l > 1)) { - prefix = name.substring(0, l - 1); - } - } } /** @@ -304,34 +254,45 @@ public final class EndpointPermission extends BasicPermission { // check for the known strings int matchlen; - if (i >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G') - && (a[i - 1] == 'e' || a[i - 1] == 'E') + if (i >= 5 && (a[i - 5] == 'i' || a[i - 5] == 'I') + && (a[i - 4] == 'm' || a[i - 4] == 'M') + && (a[i - 3] == 'p' || a[i - 3] == 'P') + && (a[i - 2] == 'o' || a[i - 2] == 'O') + && (a[i - 1] == 'r' || a[i - 1] == 'R') && (a[i] == 't' || a[i] == 'T')) { - matchlen = 3; - mask |= ACTION_EXPORT; + matchlen = 6; + mask |= ACTION_IMPORT | ACTION_READ; } else - if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R') - && (a[i - 6] == 'e' || a[i - 6] == 'E') - && (a[i - 5] == 'g' || a[i - 5] == 'G') - && (a[i - 4] == 'i' || a[i - 4] == 'I') - && (a[i - 3] == 's' || a[i - 3] == 'S') - && (a[i - 2] == 't' || a[i - 2] == 'T') - && (a[i - 1] == 'e' || a[i - 1] == 'E') - && (a[i] == 'r' || a[i] == 'R')) { - matchlen = 8; - mask |= ACTION_IMPORT; + if (i >= 5 && (a[i - 5] == 'e' || a[i - 5] == 'E') + && (a[i - 4] == 'x' || a[i - 4] == 'X') + && (a[i - 3] == 'p' || a[i - 3] == 'P') + && (a[i - 2] == 'o' || a[i - 2] == 'O') + && (a[i - 1] == 'r' || a[i - 1] == 'R') + && (a[i] == 't' || a[i] == 'T')) { + matchlen = 6; + mask |= ACTION_EXPORT | ACTION_READ; } else { - // parse error - throw new IllegalArgumentException("invalid permission: " - + actions); + if (i >= 3 && (a[i - 3] == 'r' || a[i - 3] == 'R') + && (a[i - 2] == 'e' || a[i - 2] == 'E') + && (a[i - 1] == 'a' || a[i - 1] == 'A') + && (a[i] == 'd' || a[i] == 'D')) { + matchlen = 4; + mask |= ACTION_READ; + + } + else { + // parse error + throw new IllegalArgumentException( + "invalid permission: " + actions); + } } // make sure we didn't just match the tail of a word - // like "ackbarfregister". Also, skip to the comma. + // like "ackbarfread". Also, skip to the comma. seencomma = false; while (i >= matchlen && !seencomma) { switch (a[i - matchlen]) { @@ -366,16 +327,17 @@ public final class EndpointPermission extends BasicPermission { * Parse filter string into a Filter object. * * @param filterString The filter string to parse. - * @return a Filter for this bundle. If the specified filterString is not a - * filter expression, then <code>null</code> is returned. + * @return a Filter for this bundle. * @throws IllegalArgumentException If the filter syntax is invalid. */ private static Filter parseFilter(String filterString) { + if (filterString == null) { + throw new IllegalArgumentException("invalid filter: null"); + } filterString = filterString.trim(); - if (filterString.charAt(0) != '(') { - return null; + if (filterString.equals("*")) { + return null; // wildcard } - try { return FrameworkUtil.createFilter(filterString); } @@ -428,46 +390,19 @@ public final class EndpointPermission extends BasicPermission { if ((effective & desired) != desired) { return false; } - /* we have name of "*" */ - if (wildcard && (prefix == null)) { - return true; - } - /* if we have a filter */ + /* if we have no filter */ Filter f = filter; - if (f != null) { - return f.matchCase(requested.getProperties()); - } - /* if requested permission not created with EndpointDescription */ - String[] requestedNames = requested.objectClass; - if (requestedNames == null) { - return super.implies(requested); - } - /* requested permission created with EndpointDescription */ - if (wildcard) { - int pl = prefix.length(); - for (int i = 0, l = requestedNames.length; i < l; i++) { - String requestedName = requestedNames[i]; - if ((requestedName.length() > pl) - && requestedName.startsWith(prefix)) { - return true; - } - } - } - else { - String name = getName(); - for (int i = 0, l = requestedNames.length; i < l; i++) { - if (requestedNames[i].equals(name)) { - return true; - } - } + if (f == null) { + // it's "*" + return true; } - return false; + return f.matchCase(requested.getProperties()); } /** * Returns the canonical string representation of the actions. Always - * returns present actions in the following order: <code>get</code>, - * <code>register</code>. + * returns present actions in the following canonical order: + * <code>read</code>, <code>import</code>, <code>export</code>. * * @return The canonical string representation of the actions. */ @@ -478,8 +413,8 @@ public final class EndpointPermission extends BasicPermission { boolean comma = false; int mask = action_mask; - if ((mask & ACTION_EXPORT) == ACTION_EXPORT) { - sb.append(EXPORT); + if ((mask & ACTION_READ) == ACTION_READ) { + sb.append(READ); comma = true; } @@ -489,6 +424,12 @@ public final class EndpointPermission extends BasicPermission { sb.append(IMPORT); } + if ((mask & ACTION_EXPORT) == ACTION_EXPORT) { + if (comma) + sb.append(','); + sb.append(EXPORT); + } + actions = result = sb.toString(); } @@ -509,12 +450,12 @@ public final class EndpointPermission extends BasicPermission { /** * Determines the equality of two EndpointPermission objects. * - * Checks that specified object has the same class name and action as this - * <code>EndpointPermission</code>. + * Checks that specified object has the same name, actions and endpoint as + * this <code>EndpointPermission</code>. * * @param obj The object to test for equality. * @return true if obj is a <code>EndpointPermission</code>, and has the - * same class name and actions as this + * same name, actions and endpoint as this * <code>EndpointPermission</code> object; <code>false</code> * otherwise. */ @@ -527,13 +468,13 @@ public final class EndpointPermission extends BasicPermission { return false; } - EndpointPermission sp = (EndpointPermission) obj; + EndpointPermission ep = (EndpointPermission) obj; - return (action_mask == sp.action_mask) - && getName().equals(sp.getName()) - && ((endpoint == sp.endpoint) || ((endpoint != null) - && (sp.endpoint != null) && endpoint - .equals(sp.endpoint))); + return (action_mask == ep.action_mask) + && getName().equals(ep.getName()) + && ((endpoint == ep.endpoint) || ((endpoint != null) + && (ep.endpoint != null) && endpoint + .equals(ep.endpoint))); } /** @@ -561,8 +502,9 @@ public final class EndpointPermission extends BasicPermission { } // Write out the actions. The superclass takes care of the name // call getActions to make sure actions field is initialized - if (actions == null) + if (actions == null) { getActions(); + } s.defaultWriteObject(); } @@ -582,109 +524,8 @@ public final class EndpointPermission extends BasicPermission { * * @return a dictionary of properties for this permission. */ - private Dictionary/* <String,Object> */getProperties() { - Dictionary/* <String, Object> */result = properties; - if (result != null) { - return result; - } - if (endpoint == null) { - result = new Hashtable/* <String, Object> */(1); - if (filter == null) { - result.put(Constants.OBJECTCLASS, new String[] {getName()}); - } - return properties = result; - } - final Map props = new HashMap(4); - // TODO needs work - /* - * final Bundle bundle = endpoint.getBundle(); if (bundle != null) { - * AccessController.doPrivileged(new PrivilegedAction() { public Object - * run() { props.put("id", new Long(bundle.getBundleId())); - * props.put("location", bundle.getLocation()); String name = - * bundle.getSymbolicName(); if (name != null) { props.put("name", - * name); } SignerProperty signer = new SignerProperty(bundle); if - * (signer.isBundleSigned()) { props.put("signer", signer); } return - * null; } }); } - */ - return properties = new Properties(props, endpoint); - } - - private static class Properties extends Dictionary { - private final Map properties; - private final EndpointDescription service; - - Properties(Map properties, EndpointDescription service) { - this.properties = properties; - this.service = service; - } - - public Object get(Object k) { - if (!(k instanceof String)) { - return null; - } - String key = (String) k; - if (key.charAt(0) == '@') { - return service.getProperties().get(key.substring(1)); - } - Object value = properties.get(key); - if (value != null) { // fall back to service properties - return value; - } - return service.getProperties().get(key); - } - - public int size() { - return properties.size() + service.getProperties().size(); - } - - public boolean isEmpty() { - // we can return false because this must never be empty - return false; - } - - public Enumeration keys() { - Collection pk = properties.keySet(); - String spk[] = (String[]) service.getProperties().keySet().toArray( - new String[service.getProperties().size()]); - List all = new ArrayList(pk.size() + spk.length); - all.addAll(pk); - add: for (int i = 0, length = spk.length; i < length; i++) { - String key = spk[i]; - for (Iterator iter = pk.iterator(); iter.hasNext();) { - if (key.equalsIgnoreCase((String) iter.next())) { - continue add; - } - } - all.add(key); - } - return Collections.enumeration(all); - } - - public Enumeration elements() { - Collection pk = properties.keySet(); - String spk[] = (String[]) service.getProperties().keySet().toArray( - new String[service.getProperties().size()]); - List all = new ArrayList(pk.size() + spk.length); - all.addAll(properties.values()); - add: for (int i = 0, length = spk.length; i < length; i++) { - String key = spk[i]; - for (Iterator iter = pk.iterator(); iter.hasNext();) { - if (key.equalsIgnoreCase((String) iter.next())) { - continue add; - } - } - all.add(service.getProperties().get(key)); - } - return Collections.enumeration(all); - } - - public Object put(Object key, Object value) { - throw new UnsupportedOperationException(); - } - - public Object remove(Object key) { - throw new UnsupportedOperationException(); - } + private Dictionary<String, Object> getProperties() { + return properties; } } @@ -696,35 +537,28 @@ public final class EndpointPermission extends BasicPermission { * @see java.security.PermissionCollection */ final class EndpointPermissionCollection extends PermissionCollection { - static final long serialVersionUID = 662615640374640621L; + static final long serialVersionUID = 662615640374640621L; /** * Table of permissions. * - * @GuardedBy this - */ - private transient Map permissions; - - /** - * Boolean saying if "*" is in the collection. - * * @serial * @GuardedBy this */ - private boolean all_allowed; + private Map<String, EndpointPermission> permissions; /** - * Table of permissions with filter expressions. + * Boolean saying if "*" is in the collection. * * @serial * @GuardedBy this */ - private Map filterPermissions; + private boolean all_allowed; /** * Creates an empty EndpointPermissions object. */ public EndpointPermissionCollection() { - permissions = new HashMap(); + permissions = new HashMap<String, EndpointPermission>(); all_allowed = false; } @@ -748,39 +582,29 @@ final class EndpointPermissionCollection extends PermissionCollection { + "readonly PermissionCollection"); } - final EndpointPermission sp = (EndpointPermission) permission; - if (sp.endpoint != null) { + final EndpointPermission ep = (EndpointPermission) permission; + if (ep.endpoint != null) { throw new IllegalArgumentException("cannot add to collection: " - + sp); + + ep); } - final String name = sp.getName(); - final Filter f = sp.filter; + final String name = ep.getName(); synchronized (this) { /* select the bucket for the permission */ - Map pc; - if (f != null) { - pc = filterPermissions; - if (pc == null) { - filterPermissions = pc = new HashMap(); - } - } - else { - pc = permissions; - } + Map<String, EndpointPermission> pc = permissions; final EndpointPermission existing = (EndpointPermission) pc .get(name); if (existing != null) { final int oldMask = existing.action_mask; - final int newMask = sp.action_mask; + final int newMask = ep.action_mask; if (oldMask != newMask) { pc.put(name, new EndpointPermission(name, oldMask | newMask)); } } else { - pc.put(name, sp); + pc.put(name, ep); } if (!all_allowed) { @@ -808,50 +632,27 @@ final class EndpointPermissionCollection extends PermissionCollection { if (requested.filter != null) { return false; } - int effective = EndpointPermission.ACTION_NONE; - Collection perms; + Collection<EndpointPermission> perms; synchronized (this) { final int desired = requested.action_mask; /* short circuit if the "*" Permission was added */ if (all_allowed) { - EndpointPermission sp = (EndpointPermission) permissions - .get("*"); - if (sp != null) { - effective |= sp.action_mask; + EndpointPermission ep = permissions.get("*"); + if (ep != null) { + effective |= ep.action_mask; if ((effective & desired) == desired) { return true; } } } - - String[] requestedNames = requested.objectClass; - /* if requested permission not created with EndpointDescription */ - if (requestedNames == null) { - effective |= effective(requested.getName(), desired, effective); - if ((effective & desired) == desired) { - return true; - } - } - /* requested permission created with EndpointDescription */ - else { - for (int i = 0, l = requestedNames.length; i < l; i++) { - if ((effective(requestedNames[i], desired, effective) & desired) == desired) { - return true; - } - } - } - Map pc = filterPermissions; - if (pc == null) { - return false; - } - perms = pc.values(); + perms = permissions.values(); } - /* iterate one by one over filteredPermissions */ - for (Iterator iter = perms.iterator(); iter.hasNext();) { - if (((EndpointPermission) iter.next()).implies0(requested, - effective)) { + /* iterate one by one over permissions */ + for (Iterator<EndpointPermission> iter = perms.iterator(); iter + .hasNext();) { + if (iter.next().implies0(requested, effective)) { return true; } } @@ -859,85 +660,34 @@ final class EndpointPermissionCollection extends PermissionCollection { } /** - * Consult permissions map to compute the effective permission for the - * requested permission name. - * - * @param requestedName The requested service name. - * @param desired The desired actions. - * @param effective The effective actions. - * @return The new effective actions. - */ - private int effective(String requestedName, final int desired, int effective) { - final Map pc = permissions; - EndpointPermission sp = (EndpointPermission) pc.get(requestedName); - // strategy: - // Check for full match first. Then work our way up the - // name looking for matches on a.b.* - if (sp != null) { - // we have a direct hit! - effective |= sp.action_mask; - if ((effective & desired) == desired) { - return effective; - } - } - // work our way up the tree... - int last; - int offset = requestedName.length() - 1; - while ((last = requestedName.lastIndexOf(".", offset)) != -1) { - requestedName = requestedName.substring(0, last + 1) + "*"; - sp = (EndpointPermission) pc.get(requestedName); - if (sp != null) { - effective |= sp.action_mask; - if ((effective & desired) == desired) { - return effective; - } - } - offset = last - 1; - } - /* - * we don't have to check for "*" as it was already checked before we - * were called. - */ - return effective; - } - - /** * Returns an enumeration of all the <code>EndpointPermission</code> objects * in the container. * * @return Enumeration of all the EndpointPermission objects. */ - public synchronized Enumeration elements() { - List all = new ArrayList(permissions.values()); - Map pc = filterPermissions; - if (pc != null) { - all.addAll(pc.values()); - } + public synchronized Enumeration<Permission> elements() { + List<Permission> all = new ArrayList<Permission>(permissions.values()); return Collections.enumeration(all); } /* serialization logic */ private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("permissions", Hashtable.class), - new ObjectStreamField("all_allowed", Boolean.TYPE), - new ObjectStreamField("filterPermissions", HashMap.class) }; + new ObjectStreamField("permissions", HashMap.class), + new ObjectStreamField("all_allowed", Boolean.TYPE) }; private synchronized void writeObject(ObjectOutputStream out) throws IOException { - Hashtable hashtable = new Hashtable(permissions); ObjectOutputStream.PutField pfields = out.putFields(); - pfields.put("permissions", hashtable); + pfields.put("permissions", permissions); pfields.put("all_allowed", all_allowed); - pfields.put("filterPermissions", filterPermissions); out.writeFields(); } private synchronized void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gfields = in.readFields(); - Hashtable hashtable = (Hashtable) gfields.get("permissions", null); - permissions = new HashMap(hashtable); + permissions = (HashMap<String, EndpointPermission>) gfields.get( + "permissions", new HashMap<String, EndpointPermission>()); all_allowed = gfields.get("all_allowed", false); - filterPermissions = (HashMap) gfields.get("filterPermissions", null); } } diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java index 93e6bb0c24..cf2194ec12 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) OSGi Alliance (2009). All Rights Reserved. + * Copyright (c) OSGi Alliance (2009, 2010). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +30,9 @@ public class RemoteConstants { * Service property identifying the configuration types supported by a * distribution provider. Registered by the distribution provider on one of * its services to indicate the supported configuration types. - * * <p> * The value of this property must be of type <code>String</code>, - * <code>String[]</code>, or <code>Collection</code> of <code>String</code>. + * <code>String[]</code>, or <code>Collection<String></code>. */ public static final String REMOTE_CONFIGS_SUPPORTED = "remote.configs.supported"; @@ -44,7 +43,7 @@ public class RemoteConstants { * * <p> * The value of this property must be of type <code>String</code>, - * <code>String[]</code>, or <code>Collection</code> of <code>String</code>. + * <code>String[]</code>, or <code>Collection<String></code>. */ public static final String REMOTE_INTENTS_SUPPORTED = "remote.intents.supported"; @@ -59,7 +58,7 @@ public class RemoteConstants { * <code>Dictionary</code> object passed to the * <code>BundleContext.registerService</code> method. The value of this * property must be of type <code>String</code>, <code>String[]</code>, or - * <code>Collection</code> of <code>String</code>. + * <code>Collection<String></code>. */ public static final String SERVICE_EXPORTED_CONFIGS = "service.exported.configs"; @@ -75,7 +74,7 @@ public class RemoteConstants { * <code>Dictionary</code> object passed to the * <code>BundleContext.registerService</code> method. The value of this * property must be of type <code>String</code>, <code>String[]</code>, or - * <code>Collection</code> of <code>String</code>. + * <code>Collection<String></code>. */ public static final String SERVICE_EXPORTED_INTENTS = "service.exported.intents"; @@ -94,7 +93,7 @@ public class RemoteConstants { * <code>Dictionary</code> object passed to the * <code>BundleContext.registerService</code> method. The value of this * property must be of type <code>String</code>, <code>String[]</code>, or - * <code>Collection</code> of <code>String</code>. + * <code>Collection<String></code>. */ public static final String SERVICE_EXPORTED_INTENTS_EXTRA = "service.exported.intents.extra"; @@ -113,7 +112,7 @@ public class RemoteConstants { * <code>Dictionary</code> object passed to the * <code>BundleContext.registerService</code> method. The value of this * property must be of type <code>String</code>, <code>String[]</code>, or - * <code>Collection</code> of <code>String</code>. + * <code>Collection<String></code>. */ public static final String SERVICE_EXPORTED_INTERFACES = "service.exported.interfaces"; @@ -139,7 +138,7 @@ public class RemoteConstants { * * <p> * The value of this property must be of type <code>String</code>, - * <code>String[]</code>, or <code>Collection</code> of <code>String</code>. + * <code>String[]</code>, or <code>Collection<String></code>. * * @see #SERVICE_EXPORTED_CONFIGS */ @@ -153,34 +152,30 @@ public class RemoteConstants { * provider that these intents are already implemented by the exported * service object.</li> * <li>A distribution provider must use this property to convey the combined - * intents of:</li> - * <ul> - * <li>The exporting service, and</li> - * <li>the intents that the exporting distribution provider adds, and</li> - * <li>the intents that the importing distribution provider adds.</li> + * intents of: The exporting service, and, the intents that the exporting + * distribution provider adds, and the intents that the importing + * distribution provider adds.</li> * </ul> - * <i></i> - * - * </ul> To export a service, a distribution provider must expand any - * qualified intents. Both the exporting and importing distribution - * providers must recognize all intents before a service can be distributed. + * To export a service, a distribution provider must expand any qualified + * intents. Both the exporting and importing distribution providers must + * recognize all intents before a service can be distributed. * * <p> * The value of this property must be of type <code>String</code>, - * <code>String[]</code>, or <code>Collection</code> of <code>String</code>. + * <code>String[]</code>, or <code>Collection<String></code>. */ public static final String SERVICE_INTENTS = "service.intents"; /* above are from Ch 13 Remote Service spec. */ /** - * Endpoint property identifying the URI for this endpoint. This service + * Endpoint property identifying the id for this endpoint. This service * property must always be set. * * <p> * The value of this property must be of type <code>String</code>. */ - public final static String ENDPOINT_URI = "endpoint.uri"; + public final static String ENDPOINT_ID = "endpoint.id"; /** * Endpoint property identifying the service id of the exported service. Can @@ -189,7 +184,7 @@ public class RemoteConstants { * <p> * The value of this property must be of type <code>Long</code>. */ - public final static String ENDPOINT_ID = "endpoint.id"; + public final static String ENDPOINT_SERVICE_ID = "endpoint.service.id"; /** * Endpoint property identifying the universally unique id of the exporting diff --git a/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml b/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml index e7369833f9..8306fa9834 100644 --- a/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml +++ b/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml @@ -17,51 +17,39 @@ * specific language governing permissions and limitations * under the License. --> -<!-- A consumer-side service description file for RFC 119 --> -<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"> +<!-- A consumer-side service description file for OSGi Remote Service Admin --> +<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"> <!-- Describe a remote OSGi service --> - <service-description> - <provide interface="calculator.dosgi.operations.AddService" /> - <property name="service.intents">sca:SOAP sca:HTTP</property> - <property name="osgi.remote.configuration.type">org.osgi.sca</property> - <property name="osgi.remote.configuration.sca.componentType"> - OSGI-INF/sca/bundle.componentType - </property> - <property name="osgi.remote.configuration.sca.reference"> - addService - </property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.SubtractService" /> - <property name="service.intents">sca:SOAP sca:HTTP</property> - <property name="osgi.remote.configuration.type">org.osgi.sca</property> - <property name="osgi.remote.configuration.sca.componentType"> - OSGI-INF/sca/bundle.componentType - </property> - <property name="osgi.remote.configuration.sca.reference"> - subtractService - </property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.MultiplyService" /> - <property name="service.intents">sca:SOAP sca:HTTP</property> - <property name="osgi.remote.configuration.type">org.osgi.sca</property> - <property name="osgi.remote.configuration.sca.componentType"> - OSGI-INF/sca/bundle.componentType - </property> - <property name="osgi.remote.configuration.sca.reference"> - multiplyService - </property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.DivideService" /> - <property name="service.intents">sca:SOAP sca:HTTP</property> - <property name="osgi.remote.configuration.type">org.osgi.sca</property> - <property name="osgi.remote.configuration.sca.componentType"> - OSGI-INF/sca/bundle.componentType - </property> - <property name="osgi.remote.configuration.sca.reference"> - divideService - </property> - </service-description> -</service-descriptions>
\ No newline at end of file + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.AddService" /> + <property name="service.intents" value="sca:SOAP sca:HTTP" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="osgi.remote.configuration.type" value="org.osgi.sca" /> + <property name="osgi.remote.configuration.sca.componentType" value="OSGI-INF/sca/bundle.componentType" /> + <property name="osgi.remote.configuration.sca.reference" value="addService" /> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.SubtractService" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="service.intents" value="sca:SOAP sca:HTTP" /> + <property name="osgi.remote.configuration.type" value="org.osgi.sca" /> + <property name="osgi.remote.configuration.sca.componentType" value="OSGI-INF/sca/bundle.componentType" /> + <property name="osgi.remote.configuration.sca.reference" value="subtractService" /> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.MultiplyService" /> + <property name="service.intents" value="sca:SOAP sca:HTTP" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="osgi.remote.configuration.type" value="org.osgi.sca" /> + <property name="osgi.remote.configuration.sca.componentType" value="OSGI-INF/sca/bundle.componentType" /> + <property name="osgi.remote.configuration.sca.reference" value="multiplyService" /> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.DivideService" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="service.intents" value="sca:SOAP sca:HTTP" /> + <property name="osgi.remote.configuration.type" value="org.osgi.sca" /> + <property name="osgi.remote.configuration.sca.componentType" value="OSGI-INF/sca/bundle.componentType" /> + <property name="osgi.remote.configuration.sca.reference" value="divideService" /> + </endpoint-description> +</endpoint-descriptions>
\ No newline at end of file diff --git a/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml b/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml index 79e79f9471..ded82797b5 100644 --- a/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml +++ b/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml @@ -18,44 +18,44 @@ * under the License. --> <!-- A consumer-side service description file for RFC 119 --> -<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0" +<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"> <!-- Describe a remote OSGi service --> - <service-description> - <provide interface="calculator.dosgi.operations.AddService" /> - <property name="remote.exported.intents"></property> - <property name="remote.configs.supported">org.osgi.sca</property> - <property name="sca.reference"> - addService - </property> - <property name="org.osgi.sca.bindings">{http://sample}Add</property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.SubtractService" /> - <property name="remote.exported.intents"></property> - <property name="remote.configs.supported">org.osgi.sca</property> - <property name="sca.reference"> - subtractService - </property> - <property name="org.osgi.sca.bindings">{http://sample}Subtract</property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.MultiplyService" /> - <property name="remote.exported.intents"></property> - <property name="remote.configs.supported">org.osgi.sca</property> - <property name="sca.reference"> - multiplyService - </property> - <property name="org.osgi.sca.bindings">{http://sample}Multiply</property> - </service-description> - <service-description> - <provide interface="calculator.dosgi.operations.DivideService" /> - <property name="remote.exported.intents"></property> - <property name="remote.configs.supported">org.osgi.sca</property> - <property name="sca.reference"> - divideService - </property> - <property name="org.osgi.sca.bindings">{http://sample}Divide</property> - </service-description> -</service-descriptions>
\ No newline at end of file + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.AddService" /> + <property name="remote.configs.supported" value="org.osgi.sca"/> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="sca.reference" value="addService"/> + <property name="org.osgi.sca.bindings"> + <list> + <value>{http://sample}Add</value> + </list> + </property> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.SubtractService" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="remote.configs.supported" value="org.osgi.sca"/> + <property name="sca.reference" value="subtractService"/> + <property name="org.osgi.sca.bindings"> + <list> + <value>{http://sample}Subtract</value> + </list> + </property> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.MultiplyService" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="remote.configs.supported" value="org.osgi.sca"/> + <property name="sca.reference" value="multiplyService"/> + <property name="org.osgi.sca.bindings" value="{http://sample}Multiply"/> + </endpoint-description> + <endpoint-description> + <property name="objectClass" value="calculator.dosgi.operations.DivideService" /> + <property name="service.imported.configs" value="org.osgi.sca"/> + <property name="remote.configs.supported" value="org.osgi.sca"/> + <property name="sca.reference" value="divideService"/> + <property name="org.osgi.sca.bindings" value="{http://sample}Divide"/> + </endpoint-description> +</endpoint-descriptions>
\ No newline at end of file |