summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/trunk/modules/node-impl-osgi/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/trunk/modules/node-impl-osgi/src/main')
-rw-r--r--sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java2
-rw-r--r--sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java1008
-rw-r--r--sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java15
3 files changed, 539 insertions, 486 deletions
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 90fe3f8fd1..572dd129a9 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
@@ -89,7 +89,7 @@ public class LocalDiscoveryService extends AbstractDiscoveryService implements B
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, String.valueOf(System.currentTimeMillis()));
+ props.put(RemoteConstants.ENDPOINT_ID, new Long(System.currentTimeMillis()));
}
if (!props.containsKey(RemoteConstants.ENDPOINT_FRAMEWORK_UUID)) {
props.put(RemoteConstants.ENDPOINT_FRAMEWORK_UUID, OSGiHelper.getFrameworkUUID(context));
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 c83a79337f..4bc3b34c7c 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
@@ -16,13 +16,10 @@
package org.osgi.service.remoteserviceadmin;
-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_INTERACE_VERSION_;
-import static org.osgi.service.remoteserviceadmin.RemoteConstants.ENDPOINT_URI;
-import static org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_IMPORTED_CONFIGS;
-import static org.osgi.service.remoteserviceadmin.RemoteConstants.SERVICE_INTENTS;
+import static org.osgi.service.remoteserviceadmin.RemoteConstants.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -63,478 +60,529 @@ 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 String remoteFrameworkUUID;
- private final String remoteUri;
-
- /**
- * Create an Endpoint Description based on a Map.
- *
- * @param properties The map to create the Endpoint Description from.
- * @throws IllegalArgumentException When the properties are not proper for
- * an Endpoint Description
- */
-
- public EndpointDescription(Map<String, Object> properties) {
- this(properties, null);
- if (properties == null) {
- throw new NullPointerException("properties must not be null");
- }
- }
-
- /**
- * Create an Endpoint Description based on a reference and optionally a map
- * of additional properties. The properties on the original service take
- * precedence over the ones in the map.
- *
- * @param reference A service reference that can be exported
- * @param properties Additional properties to add. Can be <code>null</code>.
- * @throws IllegalArgumentException When the properties are not proper for
- * an Endpoint Description
- */
- public EndpointDescription(ServiceReference reference,
- Map<String, Object> properties) {
- this(properties, reference);
- if (reference == null) {
- throw new NullPointerException("reference must not be null");
- }
- }
-
- private EndpointDescription(Map<String, Object> map,
- ServiceReference reference) {
- Map<String, Object> props = new TreeMap<String, Object>(
- String.CASE_INSENSITIVE_ORDER);
-
- if (map != null) {
- try {
- props.putAll(map);
- }
- catch (ClassCastException e) {
- IllegalArgumentException iae = new IllegalArgumentException(
- "non-String key in properties");
- iae.initCause(e);
- throw iae;
- }
- if (props.size() < map.size()) {
- throw new IllegalArgumentException(
- "duplicate keys with different cases in properties");
- }
- }
-
- if (reference != null) {
- for (String key : reference.getPropertyKeys()) {
- if (!props.containsKey(key)) {
- props.put(key, reference.getProperty(key));
- }
- }
- }
-
- properties = Collections.unmodifiableMap(props);
- /* properties must be initialized before calling the following methods */
- interfaces = verifyObjectClassProperty();
- remoteServiceId = verifyLongProperty(ENDPOINT_ID);
- remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID);
- remoteUri = verifyStringProperty(ENDPOINT_URI);
- }
-
- /**
- * 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.
- *
- */
- 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 must be of type String[]");
- }
- String[] objectClass = (String[]) o;
- for (String interf : objectClass) {
- try {
- getInterfaceVersion(interf);
- }
- catch (IllegalArgumentException e) {
- IllegalArgumentException iae = new IllegalArgumentException(
- "Improper version for interface " + interf);
- iae.initCause(e);
- throw iae;
- }
- }
- return Collections.unmodifiableList(Arrays.asList(objectClass));
- }
-
- /**
- * Verify and obtain a required String property.
- *
- * @param propName The name of the property
- * @return The value of the property.
- * @throws IllegalArgumentException when the property is not set or doesn't
- * have the correct data type.
- */
- private String verifyStringProperty(String propName) {
- Object r = properties.get(propName);
- if (r == null) {
- throw new IllegalArgumentException("Required property not set: "
- + propName);
- }
- if (!(r instanceof String)) {
- throw new IllegalArgumentException(
- "Required property is not a String: " + propName);
- }
- return (String) r;
- }
-
- /**
- * Verify and obtain a required long property.
- *
- * @param propName The name of the property
- * @return The value of the property.
- * @throws IllegalArgumentException when the property is not set or doesn't
- * have the correct data type.
- */
- private long verifyLongProperty(String propName) {
- Object r = properties.get(propName);
- if (r == null) {
- throw new IllegalArgumentException("Required property not set: "
- + propName);
- }
- if (!(r instanceof String)) {
- throw new IllegalArgumentException(
- "Required property is not a string: " + propName);
- }
- try {
- return Long.parseLong((String) r);
- }
- catch (NumberFormatException e) {
- IllegalArgumentException iae = new IllegalArgumentException(
- "Required property cannot be parsed as a long: " + propName);
- iae.initCause(e);
- throw iae;
- }
- }
-
- /**
- * Returns the endpoint's URI.
- *
- * 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 value of the URI is stored in the
- * {@link RemoteConstants#ENDPOINT_URI} property.
- *
- * @return The URI of the endpoint, never <code>null</code>.
- */
- public String getRemoteURI() {
- return remoteUri;
- }
-
- /**
- * Provide the list of interfaces implemented by the exported service.
- *
- * If this Endpoint Description does not map to a service, then this List
- * must be empty.
- *
- * The value of the interfaces is derived from the <code>objectClass</code>
- * property.
- *
- * @return The read only list of Java interface names accessible by this
- * endpoint.
- */
- public List<String> getInterfaces() {
- return interfaces;
- }
-
- /**
- * Provide the version of the given interface.
- *
- * The version is encoded by prefixing the given interface name with
- * <code>endpoint.interface.version.</code>, and then using this as an
- * endpoint property key. For example:
- *
- * <pre>
- * endpoint.interface.version.com.acme.Foo
- * </pre>
- *
- * The value of this property is in String format and will be converted to a
- * <code>Version</code> object by this method.
- *
- * @param name The name of the interface for which a version is requested.
- * @return The version of the given interface or <code>null</code> if the
- * interface has no version in this Endpoint Description.
- * @throws IllegalArgumentException If the version property value is not
- * String.
- */
- public Version getInterfaceVersion(String name) {
- String key = ENDPOINT_INTERACE_VERSION_ + name;
- Object version = properties.get(key);
- // [rfeng] Check for existence of the property
- if (version == null) {
- return null;
- }
- // [rfeng]
- if (!(version instanceof String)) {
- throw new IllegalArgumentException(key
- + " property is not a String");
- }
- return Version.parseVersion((String) version);
- }
-
- /**
- * Returns the service id for the service exported through this endpoint.
- *
- * This is the service id under which the framework has registered the
- * service. This field together with the Framework UUID is a globally unique
- * id for a service.
- *
- * The value of the remote service id is stored in the
- * {@link RemoteConstants#ENDPOINT_ID} endpoint property.
- *
- * @return Service id of a service or 0 if this Endpoint Description does
- * not relate to an OSGi service
- *
- */
- public long getRemoteServiceID() {
- return remoteServiceId;
- }
-
- /**
- * Returns the configuration types.
- *
- * A distribution provider exports a service with an endpoint. This endpoint
- * uses some kind of communications protocol with a set of configuration
- * parameters. There are many different types but each endpoint is
- * configured by only one configuration type. However, a distribution
- * provider can be aware of different configuration types and provide
- * synonyms to increase the change a receiving distribution provider can
- * create a connection to this endpoint.
- *
- * This value of the configuration types is stored in the
- * {@link RemoteConstants#SERVICE_IMPORTED_CONFIGS} service property.
- *
- * @return An unmodifiable list of the configuration types used for the
- * associated endpoint and optionally synonyms.
- */
- public List<String> getConfigurationTypes() {
- return getStringPlusProperty(SERVICE_IMPORTED_CONFIGS);
- }
-
- /**
- * Return the list of intents implemented by this endpoint.
- *
- * The intents are based on the service.intents on an imported service,
- * except for any intents that are additionally provided by the importing
- * distribution provider. All qualified intents must have been expanded.
- *
- * This value of the intents is stored in the
- * {@link RemoteConstants#SERVICE_INTENTS} service property.
- *
- * @return An unmodifiable list of expanded intents that are provided by
- * this endpoint.
- */
- public List<String> getIntents() {
- return getStringPlusProperty(SERVICE_INTENTS);
- }
-
- /**
- * Reads a 'String+' property from the properties map, which may be of type
- * String, String[] or Collection<String> and returns it as an unmodifiable
- * List.
- *
- * @param key The property
- * @return An unmodifiable list
- */
- private List<String> getStringPlusProperty(String key) {
- Object value = properties.get(key);
- if (value == null) {
- return Collections.EMPTY_LIST;
- }
-
- if (value instanceof String) {
- return Collections.singletonList((String) value);
- }
-
- if (value instanceof String[]) {
- String[] values = (String[]) value;
- List<String> result = new ArrayList<String>(values.length);
- for (String v : values) {
- if (v != null) {
- result.add(v);
- }
- }
- return Collections.unmodifiableList(result);
- }
-
- if (value instanceof Collection< ? >) {
- Collection< ? > values = (Collection< ? >) value;
- 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)) {
- result.add((String) v);
- }
- }
- return Collections.unmodifiableList(result);
- }
-
- return Collections.EMPTY_LIST;
- }
-
- /**
- * Return the framework UUID for the remote service, if present.
- *
- * The value of the remote framework uuid is stored in the
- * {@link RemoteConstants#ENDPOINT_FRAMEWORK_UUID} endpoint property.
- *
- * @return Remote Framework UUID, or null if this endpoint is not associated
- * with an OSGi service
- */
- public String getRemoteFrameworkUUID() {
- return remoteFrameworkUUID;
- }
-
- /**
- * Returns all endpoint properties.
- *
- * @return An unmodifiable map referring to the properties of this Endpoint
- * Description.
- */
- public Map<String, Object> getProperties() {
- return properties;
- }
-
- /**
- * Answers if this Endpoint Description refers to the same service instance
- * 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.
- *
- * @param other The Endpoint Description to look at
- * @return True if this endpoint description points to the same service as
- * the other
- */
- public boolean isSameService(EndpointDescription other) {
- if (this.equals(other)) {
- return true;
- }
-
- if (getRemoteFrameworkUUID() == null) {
- return false;
- }
-
- return (this.getRemoteServiceID() == other.getRemoteServiceID())
- && this.getRemoteFrameworkUUID().equals(
- other.getRemoteFrameworkUUID());
- }
-
- /**
- * Returns a hash code value for the object.
- *
- * @return An integer which is a hash code value for this object.
- */
- public int hashCode() {
- return getRemoteURI().hashCode();
- }
-
- /**
- * Compares this <code>EndpointDescription</code> object to another object.
- *
- * <p>
- * An Endpoint Description is considered to be <b>equal to</b> another
- * Endpoint Description if their URIs are equal.
- *
- * @param other The <code>EndpointDescription</code> object to be compared.
- * @return <code>true</code> if <code>object</code> is a
- * <code>EndpointDescription</code> and is equal to this object;
- * <code>false</code> otherwise.
- */
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof EndpointDescription)) {
- return false;
- }
- return getRemoteURI().equals(
- ((EndpointDescription) other).getRemoteURI());
- }
-
- /**
- * 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
- * <code>EndpointDescription</code> match the filter,
- * <code>false</code> otherwise.
- * @throws IllegalArgumentException If <code>filter</code> contains an
- * invalid filter string that cannot be parsed.
- */
- public boolean matches(String filter) {
- Filter f;
- try {
- f = FrameworkUtil.createFilter(filter);
- }
- catch (InvalidSyntaxException e) {
- IllegalArgumentException iae = new IllegalArgumentException(e
- .getMessage());
- iae.initCause(e);
- throw iae;
- }
- Dictionary<String, Object> d = new UnmodifiableDictionary<String, Object>(
- properties);
- /*
- * we can use matchCase here since properties already supports case
- * insensitive key lookup.
- */
- return f.matchCase(d);
- }
-
- /**
- * Unmodifiable wrapper for Dictionary.
- */
- private static class UnmodifiableDictionary<K, V> extends Dictionary<K, V> {
- private final Map<K, V> wrapped;
-
- UnmodifiableDictionary(Map<K, V> wrapped) {
- this.wrapped = wrapped;
- }
-
- public Enumeration<V> elements() {
- return Collections.enumeration(wrapped.values());
- }
-
- public V get(Object key) {
- return wrapped.get(key);
- }
-
- public boolean isEmpty() {
- return wrapped.isEmpty();
- }
-
- public Enumeration<K> keys() {
- return Collections.enumeration(wrapped.keySet());
- }
-
- public V put(K key, V value) {
- throw new UnsupportedOperationException();
- }
-
- public V remove(Object key) {
- throw new UnsupportedOperationException();
- }
-
- public int size() {
- return wrapped.size();
- }
- }
+ private final Map<String, Object> properties;
+ private final List<String> interfaces;
+ private final long remoteServiceId;
+ private final String remoteFrameworkUUID;
+ private final String remoteUri;
+
+ /**
+ * Create an Endpoint Description based on a Map.
+ *
+ * <p>
+ * The {@link RemoteConstants#ENDPOINT_URI} property 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
+ * the keys are case insensitive, there must be no duplicates with
+ * case variation.
+ * @throws IllegalArgumentException When the properties are not proper for
+ * an Endpoint Description.
+ */
+
+ public EndpointDescription(Map<String, Object> properties) {
+ Map<String, Object> props = new TreeMap<String, Object>(
+ String.CASE_INSENSITIVE_ORDER);
+ try {
+ props.putAll(properties);
+ }
+ catch (ClassCastException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "non-String key in properties");
+ iae.initCause(e);
+ throw iae;
+ }
+ if (props.size() < properties.size()) {
+ throw new IllegalArgumentException(
+ "duplicate keys with different cases in properties");
+ }
+
+ this.properties = Collections.unmodifiableMap(props);
+ /* properties must be initialized before calling the following methods */
+ interfaces = verifyObjectClassProperty();
+ remoteServiceId = verifyLongProperty(ENDPOINT_ID);
+ remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID);
+ remoteUri = verifyStringProperty(ENDPOINT_URI);
+ if (remoteUri == null) {
+ throw new IllegalArgumentException(ENDPOINT_URI
+ + " property must be set");
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * <p>
+ * The {@link RemoteConstants#ENDPOINT_URI} property must be set.
+ *
+ * @param reference A service reference that can be exported.
+ * @param properties Map of properties. This argument can be
+ * <code>null</code>. The keys in the map must be type
+ * <code>String</code> and, since the keys are case insensitive,
+ * there must be no duplicates with case variation.
+ * @throws IllegalArgumentException When the properties are not proper for
+ * an Endpoint Description
+ */
+ public EndpointDescription(final ServiceReference reference,
+ final Map<String, Object> properties) {
+ Map<String, Object> props = new TreeMap<String, Object>(
+ String.CASE_INSENSITIVE_ORDER);
+
+ if (properties != null) {
+ try {
+ props.putAll(properties);
+ }
+ catch (ClassCastException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "non-String key in properties");
+ iae.initCause(e);
+ throw iae;
+ }
+ if (props.size() < properties.size()) {
+ throw new IllegalArgumentException(
+ "duplicate keys with different cases in properties");
+ }
+ }
+
+ for (String key : reference.getPropertyKeys()) {
+ if (!props.containsKey(key)) {
+ props.put(key, reference.getProperty(key));
+ }
+ }
+
+ if (!props.containsKey(ENDPOINT_ID)) {
+ props.put(ENDPOINT_ID, reference.getProperty(Constants.SERVICE_ID));
+ }
+ if (!props.containsKey(ENDPOINT_FRAMEWORK_UUID)) {
+ String uuid = null;
+ try {
+ uuid = AccessController
+ .doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return reference.getBundle().getBundleContext()
+ .getProperty("org.osgi.framework.uuid");
+ }
+ });
+ }
+ catch (SecurityException e) {
+ // if we don't have permission, we can't get the property
+ }
+ if (uuid != null) {
+ props.put(ENDPOINT_FRAMEWORK_UUID, uuid);
+ }
+ }
+ this.properties = Collections.unmodifiableMap(props);
+ /* properties must be initialized before calling the following methods */
+ interfaces = verifyObjectClassProperty();
+ remoteServiceId = verifyLongProperty(ENDPOINT_ID);
+ remoteFrameworkUUID = verifyStringProperty(ENDPOINT_FRAMEWORK_UUID);
+ remoteUri = verifyStringProperty(ENDPOINT_URI);
+ if (remoteUri == null) {
+ throw new IllegalArgumentException(ENDPOINT_URI
+ + " property must be set");
+ }
+ }
+
+ /**
+ * 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.
+ *
+ */
+ 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;
+ for (String interf : objectClass) {
+ int index = interf.lastIndexOf('.');
+ if (index == -1) {
+ continue;
+ }
+ String packageName = interf.substring(0, index);
+ try {
+ /* Make sure any package version properties are well formed */
+ getPackageVersion(packageName);
+ }
+ catch (IllegalArgumentException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "Improper version for package " + packageName);
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+ return Collections.unmodifiableList(Arrays.asList(objectClass));
+ }
+
+ /**
+ * Verify and obtain a required String property.
+ *
+ * @param propName The name of the property
+ * @return The value of the property or null if the property is not set.
+ * @throws IllegalArgumentException when the property doesn't have the
+ * correct data type.
+ */
+ private String verifyStringProperty(String propName) {
+ Object r = properties.get(propName);
+ try {
+ return (String) r;
+ }
+ catch (ClassCastException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "property value is not a String: " + propName);
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Verify and obtain a required long property.
+ *
+ * @param propName The name of the property
+ * @return The value of the property or 0 if the property is not set.
+ * @throws IllegalArgumentException when the property doesn't have the
+ * correct data type.
+ */
+ private long verifyLongProperty(String propName) {
+ Object r = properties.get(propName);
+ if (r == null) {
+ return 0l;
+ }
+ try {
+ return ((Long) r).longValue();
+ }
+ catch (ClassCastException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(
+ "property value is not a Long: " + propName);
+ iae.initCause(e);
+ throw iae;
+ }
+ }
+
+ /**
+ * Returns the endpoint's URI.
+ *
+ * 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 value of the URI is stored in the
+ * {@link RemoteConstants#ENDPOINT_URI} property.
+ *
+ * @return The URI of the endpoint, never <code>null</code>.
+ */
+ public String getRemoteURI() {
+ return remoteUri;
+ }
+
+ /**
+ * Provide the list of interfaces implemented by the exported service.
+ *
+ * The value of the interfaces is derived from the <code>objectClass</code>
+ * property.
+ *
+ * @return An unmodifiable list of Java interface names implemented by this
+ * endpoint.
+ */
+ public List<String> getInterfaces() {
+ return interfaces;
+ }
+
+ /**
+ * Provide the version of the given package name.
+ *
+ * The version is encoded by prefixing the given package name with
+ * {@link RemoteConstants#ENDPOINT_PACKAGE_VERSION_
+ * endpoint.package.version.}, and then using this as an endpoint property
+ * key. For example:
+ *
+ * <pre>
+ * endpoint.package.version.com.acme
+ * </pre>
+ *
+ * The value of this property is in String format and will be converted to a
+ * <code>Version</code> object by this method.
+ *
+ * @param packageName The name of the package for which a version is
+ * requested.
+ * @return The version of the specified package or
+ * <code>Version.emptyVersion</code> if the package has no version
+ * in this Endpoint Description.
+ * @throws IllegalArgumentException If the version property value is not
+ * String.
+ */
+ public Version getPackageVersion(String packageName) {
+ String key = ENDPOINT_PACKAGE_VERSION_ + packageName;
+ Object value = properties.get(key);
+ String version;
+ try {
+ version = (String) value;
+ }
+ catch (ClassCastException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(key
+ + " property value is not a String");
+ iae.initCause(e);
+ throw iae;
+ }
+ return Version.parseVersion(version);
+ }
+
+ /**
+ * Returns the service id for the service exported through this endpoint.
+ *
+ * This is the service id under which the framework has registered the
+ * service. This field together with the Framework UUID is a globally unique
+ * id for a service.
+ *
+ * The value of the remote service id is stored in the
+ * {@link RemoteConstants#ENDPOINT_ID} endpoint property.
+ *
+ * @return Service id of a service or 0 if this Endpoint Description does
+ * not relate to an OSGi service
+ *
+ */
+ public long getRemoteServiceID() {
+ return remoteServiceId;
+ }
+
+ /**
+ * Returns the configuration types.
+ *
+ * A distribution provider exports a service with an endpoint. This endpoint
+ * uses some kind of communications protocol with a set of configuration
+ * parameters. There are many different types but each endpoint is
+ * configured by only one configuration type. However, a distribution
+ * provider can be aware of different configuration types and provide
+ * synonyms to increase the change a receiving distribution provider can
+ * create a connection to this endpoint.
+ *
+ * This value of the configuration types is stored in the
+ * {@link RemoteConstants#SERVICE_IMPORTED_CONFIGS} service property.
+ *
+ * @return An unmodifiable list of the configuration types used for the
+ * associated endpoint and optionally synonyms.
+ */
+ public List<String> getConfigurationTypes() {
+ return getStringPlusProperty(SERVICE_IMPORTED_CONFIGS);
+ }
+
+ /**
+ * Return the list of intents implemented by this endpoint.
+ *
+ * The intents are based on the service.intents on an imported service,
+ * except for any intents that are additionally provided by the importing
+ * distribution provider. All qualified intents must have been expanded.
+ *
+ * This value of the intents is stored in the
+ * {@link RemoteConstants#SERVICE_INTENTS} service property.
+ *
+ * @return An unmodifiable list of expanded intents that are provided by
+ * this endpoint.
+ */
+ public List<String> getIntents() {
+ return getStringPlusProperty(SERVICE_INTENTS);
+ }
+
+ /**
+ * Reads a 'String+' property from the properties map, which may be of type
+ * String, String[] or Collection<String> and returns it as an unmodifiable
+ * List.
+ *
+ * @param key The property
+ * @return An unmodifiable list
+ */
+ private List<String> getStringPlusProperty(String key) {
+ Object value = properties.get(key);
+ if (value == null) {
+ return Collections.EMPTY_LIST;
+ }
+
+ if (value instanceof String) {
+ return Collections.singletonList((String) value);
+ }
+
+ if (value instanceof String[]) {
+ String[] values = (String[]) value;
+ List<String> result = new ArrayList<String>(values.length);
+ for (String v : values) {
+ if (v != null) {
+ result.add(v);
+ }
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ if (value instanceof Collection< ? >) {
+ Collection< ? > values = (Collection< ? >) value;
+ 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)) {
+ result.add((String) v);
+ }
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ return Collections.EMPTY_LIST;
+ }
+
+ /**
+ * Return the framework UUID for the remote service, if present.
+ *
+ * The value of the remote framework uuid is stored in the
+ * {@link RemoteConstants#ENDPOINT_FRAMEWORK_UUID} endpoint property.
+ *
+ * @return Remote Framework UUID, or null if this endpoint is not associated
+ * with an OSGi framework having a framework uuid.
+ */
+ public String getRemoteFrameworkUUID() {
+ return remoteFrameworkUUID;
+ }
+
+ /**
+ * Returns all endpoint properties.
+ *
+ * @return An unmodifiable map referring to the properties of this Endpoint
+ * Description.
+ */
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ /**
+ * Answers if this Endpoint Description refers to the same service instance
+ * 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.
+ *
+ * @param other The Endpoint Description to look at
+ * @return True if this endpoint description points to the same service as
+ * the other
+ */
+ public boolean isSameService(EndpointDescription other) {
+ if (this.equals(other)) {
+ return true;
+ }
+
+ if (this.getRemoteFrameworkUUID() == null) {
+ return false;
+ }
+
+ return (this.getRemoteServiceID() == other.getRemoteServiceID())
+ && this.getRemoteFrameworkUUID().equals(
+ other.getRemoteFrameworkUUID());
+ }
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return An integer which is a hash code value for this object.
+ */
+ public int hashCode() {
+ return getRemoteURI().hashCode();
+ }
+
+ /**
+ * Compares this <code>EndpointDescription</code> object to another object.
+ *
+ * <p>
+ * An Endpoint Description is considered to be <b>equal to</b> another
+ * Endpoint Description if their URIs are equal.
+ *
+ * @param other The <code>EndpointDescription</code> object to be compared.
+ * @return <code>true</code> if <code>object</code> is a
+ * <code>EndpointDescription</code> and is equal to this object;
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof EndpointDescription)) {
+ return false;
+ }
+ return getRemoteURI().equals(
+ ((EndpointDescription) other).getRemoteURI());
+ }
+
+ /**
+ * 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
+ * <code>EndpointDescription</code> match the filter,
+ * <code>false</code> otherwise.
+ * @throws IllegalArgumentException If <code>filter</code> contains an
+ * invalid filter string that cannot be parsed.
+ */
+ public boolean matches(String filter) {
+ Filter f;
+ try {
+ f = FrameworkUtil.createFilter(filter);
+ }
+ catch (InvalidSyntaxException e) {
+ IllegalArgumentException iae = new IllegalArgumentException(e
+ .getMessage());
+ iae.initCause(e);
+ throw iae;
+ }
+ Dictionary<String, Object> d = new UnmodifiableDictionary<String, Object>(
+ properties);
+ /*
+ * we can use matchCase here since properties already supports case
+ * insensitive key lookup.
+ */
+ return f.matchCase(d);
+ }
+
+ /**
+ * Unmodifiable Dictionary wrapper for a Map.
+ */
+ private static class UnmodifiableDictionary<K, V> extends Dictionary<K, V> {
+ private final Map<K, V> wrapped;
+
+ UnmodifiableDictionary(Map<K, V> wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public Enumeration<V> elements() {
+ return Collections.enumeration(wrapped.values());
+ }
+
+ public V get(Object key) {
+ return wrapped.get(key);
+ }
+
+ public boolean isEmpty() {
+ return wrapped.isEmpty();
+ }
+
+ public Enumeration<K> keys() {
+ return Collections.enumeration(wrapped.keySet());
+ }
+
+ public V put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public V remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ return wrapped.size();
+ }
+ }
}
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 a44c03ea0e..93e6bb0c24 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
@@ -203,14 +203,19 @@ public class RemoteConstants {
/**
* Prefix for an endpoint property identifying the interface Java package
- * version for an interface For example, the property
- * endpoint.interface.version.com.acme.Foo=1.3 describes the version for the
- * com.acme.Foo interface. This endpoint property for an interface does not
- * have to be set. If not set, the value must be assumed to be 0.
+ * version for an interface. For example, the property
+ * endpoint.package.version.com.acme=1.3 describes the version of the
+ * package for the com.acme.Foo interface. This endpoint property for an
+ * interface package does not have to be set. If not set, the value must be
+ * assumed to be 0.
+ *
+ * <p>
+ * Since endpoint properties are stored in a case insensitive map, case
+ * variants of a package name are folded together.
*
* <p>
* The value of this property must be of type <code>String</code>.
*/
- public final static String ENDPOINT_INTERACE_VERSION_ = "endpoint.interface.version.";
+ public final static String ENDPOINT_PACKAGE_VERSION_ = "endpoint.package.version.";
}