You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by rf...@apache.org on 2010/01/09 19:00:26 UTC

svn commit: r897502 [2/2] - in /tuscany/sca-java-2.x/trunk: distribution/all/manifests/ features/ features/osgi/ modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/ modules/implementation-osgi/src/main/java/org/apache/...

Modified: tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java?rev=897502&r1=897501&r2=897502&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java Sat Jan  9 18:00:24 2010
@@ -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.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.
+	 * filter in implies.
 	 */
-	private transient volatile Dictionary	properties;
+	private transient final Dictionary<String, Object>	properties;
 
 	/**
-	 * True if constructed with a name and the name is "*" or ends with ".*".
+	 * 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 boolean				wildcard;
+	transient Filter					filter;
 
 	/**
-	 * If constructed with a name and the name ends with ".*", this contains the
-	 * name without the final "*".
-	 */
-	private transient String				prefix;
-
-	/**
-	 * 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 ::= &lt;class name&gt; | &lt;class name ending in &quot;.*&quot;&gt; | *
-	 * </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.
-	 * 
-	 * @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");
-		}
+	 * 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 filterString The filter string or &quot;*&quot; 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.
-	 * 
-	 * @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
+	 * 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 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>&lt;&lt;LOCAL&gt;&gt;</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 actions) {
+	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 @@
 		super(name);
 		setTransients(parseFilter(name), mask);
 		this.endpoint = null;
-		this.objectClass = null;
+		this.properties = null;
 	}
 
 	/**
@@ -259,16 +219,6 @@
 		}
 		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 @@
 			// 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 @@
 	 * 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 @@
 		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 @@
 			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 @@
 				sb.append(IMPORT);
 			}
 
+			if ((mask & ACTION_EXPORT) == ACTION_EXPORT) {
+				if (comma)
+					sb.append(',');
+				sb.append(EXPORT);
+			}
+
 			actions = result = sb.toString();
 		}
 
@@ -509,12 +450,12 @@
 	/**
 	 * 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 @@
 			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 @@
 		}
 		// 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 @@
 	 * 
 	 * @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 @@
  * @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 @@
 					+ "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 @@
 		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 @@
 	}
 
 	/**
-	 * 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);
 	}
 }

Modified: tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java?rev=897502&r1=897501&r2=897502&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java (original)
+++ tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/main/java/org/osgi/service/remoteserviceadmin/RemoteConstants.java Sat Jan  9 18:00:24 2010
@@ -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 @@
 	 * 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&lt;String&gt;</code>.
 	 */
 	public static final String	REMOTE_CONFIGS_SUPPORTED		= "remote.configs.supported";
 
@@ -44,7 +43,7 @@
 	 * 
 	 * <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&lt;String&gt;</code>.
 	 */
 	public static final String	REMOTE_INTENTS_SUPPORTED		= "remote.intents.supported";
 
@@ -59,7 +58,7 @@
 	 * <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&lt;String&gt;</code>.
 	 */
 	public static final String	SERVICE_EXPORTED_CONFIGS		= "service.exported.configs";
 
@@ -75,7 +74,7 @@
 	 * <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&lt;String&gt;</code>.
 	 */
 	public static final String	SERVICE_EXPORTED_INTENTS		= "service.exported.intents";
 
@@ -94,7 +93,7 @@
 	 * <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&lt;String&gt;</code>.
 	 */
 	public static final String	SERVICE_EXPORTED_INTENTS_EXTRA	= "service.exported.intents.extra";
 
@@ -113,7 +112,7 @@
 	 * <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&lt;String&gt;</code>.
 	 */
 	public static final String	SERVICE_EXPORTED_INTERFACES		= "service.exported.interfaces";
 
@@ -139,7 +138,7 @@
 	 * 
 	 * <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&lt;String&gt;</code>.
 	 * 
 	 * @see #SERVICE_EXPORTED_CONFIGS
 	 */
@@ -153,34 +152,30 @@
 	 * 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&lt;String&gt;</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 @@
 	 * <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

Modified: tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml?rev=897502&r1=897501&r2=897502&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml (original)
+++ tuscany/sca-java-2.x/trunk/modules/node-impl-osgi/src/test/resources/calculator/dosgi/OSGI-INF/remote-service/calculator-service-descriptions.xml Sat Jan  9 18:00:24 2010
@@ -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

Modified: tuscany/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml?rev=897502&r1=897501&r2=897502&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml (original)
+++ tuscany/sca-java-2.x/trunk/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml Sat Jan  9 18:00:24 2010
@@ -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