cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject svn commit: r891650 [9/10] - in /cxf/dosgi/trunk: ./ discovery/distributed/cxf-discovery/ discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ discovery/distributed/cxf-discovery/src/main/java/org/osgi/service/dis...
Date Thu, 17 Dec 2009 11:28:41 GMT
Added: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.remoteserviceadmin;
+
+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;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+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;
+import org.osgi.framework.ServiceReference;
+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 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.
+ * 
+ * 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.
+ * 
+ * @Immutable
+ * @version $Revision$
+ */
+
+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.
+	 * 
+	 * <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();
+		}
+	}
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointDescription.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) OSGi Alliance (2000, 2009). 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.remoteserviceadmin;
+
+// TODO Hacked from ServiePermission
+
+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;
+import java.util.Collection;
+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 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.
+ * <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.
+ * </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.
+ * 
+ * @ThreadSafe
+ * @version $Revision$
+ */
+
+public final class EndpointPermission extends BasicPermission {
+	static final long						serialVersionUID	= -7662148639076511574L;
+	/**
+	 * The action string <code>export</code>.
+	 */
+	public final static String				EXPORT				= "export";
+	/**
+	 * The action string <code>import</code>.
+	 */
+	public final static String				IMPORT				= "import";
+	/**
+	 * The action string <code>read</code>.
+	 */
+	public final static String				READ				= "read";
+
+	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;
+
+	/**
+	 * The actions 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;
+
+	/**
+	 * If this EndpointPermission was constructed with a filter, this holds a
+	 * Filter matching object used to evaluate the filter in implies.
+	 */
+	transient Filter						filter;
+
+	/**
+	 * 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 ".*".
+	 */
+	private transient boolean				wildcard;
+
+	/**
+	 * 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.
+	 * 
+	 * <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.
+	 * 
+	 * <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");
+		}
+	}
+
+	/**
+	 * 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
+	 */
+	public EndpointPermission(EndpointDescription endpoint, 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");
+		}
+	}
+
+	/**
+	 * Create a permission name from a EndpointDescription TODO Needs work
+	 * 
+	 * @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");
+		}
+		StringBuffer sb = new StringBuffer("(service.id=");
+		// TODO sb.append(endpoint.getProperty(Constants.SERVICE_ID));
+		sb.append(")");
+		return sb.toString();
+	}
+
+	/**
+	 * Package private constructor used by EndpointPermissionCollection.
+	 * 
+	 * @param name class name
+	 * @param mask action mask
+	 */
+	EndpointPermission(String name, int mask) {
+		super(name);
+		setTransients(parseFilter(name), mask);
+		this.endpoint = null;
+		this.objectClass = null;
+	}
+
+	/**
+	 * Called by constructors and when deserialized.
+	 * 
+	 * @param mask action mask
+	 */
+	private void setTransients(Filter f, int mask) {
+		if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
+			throw new IllegalArgumentException("invalid action string");
+		}
+		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);
+			}
+		}
+	}
+
+	/**
+	 * Parse action string into action mask.
+	 * 
+	 * @param actions Action string.
+	 * @return action mask.
+	 */
+	private static int parseActions(String actions) {
+		boolean seencomma = false;
+
+		int mask = ACTION_NONE;
+
+		if (actions == null) {
+			return mask;
+		}
+
+		char[] a = actions.toCharArray();
+
+		int i = a.length - 1;
+		if (i < 0)
+			return mask;
+
+		while (i != -1) {
+			char c;
+
+			// skip whitespace
+			while ((i != -1)
+					&& ((c = a[i]) == ' ' || c == '\r' || c == '\n'
+							|| c == '\f' || c == '\t'))
+				i--;
+
+			// 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')
+					&& (a[i] == 't' || a[i] == 'T')) {
+				matchlen = 3;
+				mask |= ACTION_EXPORT;
+
+			}
+			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;
+
+				}
+				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.
+			seencomma = false;
+			while (i >= matchlen && !seencomma) {
+				switch (a[i - matchlen]) {
+					case ',' :
+						seencomma = true;
+						/* FALLTHROUGH */
+					case ' ' :
+					case '\r' :
+					case '\n' :
+					case '\f' :
+					case '\t' :
+						break;
+					default :
+						throw new IllegalArgumentException(
+								"invalid permission: " + actions);
+				}
+				i--;
+			}
+
+			// point i at the location of the comma minus one (or -1).
+			i -= matchlen;
+		}
+
+		if (seencomma) {
+			throw new IllegalArgumentException("invalid permission: " + actions);
+		}
+
+		return mask;
+	}
+
+	/**
+	 * 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.
+	 * @throws IllegalArgumentException If the filter syntax is invalid.
+	 */
+	private static Filter parseFilter(String filterString) {
+		filterString = filterString.trim();
+		if (filterString.charAt(0) != '(') {
+			return null;
+		}
+
+		try {
+			return FrameworkUtil.createFilter(filterString);
+		}
+		catch (InvalidSyntaxException e) {
+			IllegalArgumentException iae = new IllegalArgumentException(
+					"invalid filter");
+			iae.initCause(e);
+			throw iae;
+		}
+	}
+
+	/**
+	 * Determines if a <code>EndpointPermission</code> object "implies" the
+	 * specified permission.
+	 * 
+	 * @param p The target permission to check.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
+	 */
+	public boolean implies(Permission p) {
+		if (!(p instanceof EndpointPermission)) {
+			return false;
+		}
+		EndpointPermission requested = (EndpointPermission) p;
+		if (endpoint != null) {
+			return false;
+		}
+		// if requested permission has a filter, then it is an invalid argument
+		if (requested.filter != null) {
+			return false;
+		}
+		return implies0(requested, ACTION_NONE);
+	}
+
+	/**
+	 * Internal implies method. Used by the implies and the permission
+	 * collection implies methods.
+	 * 
+	 * @param requested The requested EndpointPermission which has already be
+	 *        validated as a proper argument. The requested EndpointPermission
+	 *        must not have a filter expression.
+	 * @param effective The effective actions with which to start.
+	 * @return <code>true</code> if the specified permission is implied by this
+	 *         object; <code>false</code> otherwise.
+	 */
+	boolean implies0(EndpointPermission requested, int effective) {
+		/* check actions first - much faster */
+		effective |= action_mask;
+		final int desired = requested.action_mask;
+		if ((effective & desired) != desired) {
+			return false;
+		}
+		/* we have name of "*" */
+		if (wildcard && (prefix == null)) {
+			return true;
+		}
+		/* if we have a 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;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns the canonical string representation of the actions. Always
+	 * returns present actions in the following order: <code>get</code>,
+	 * <code>register</code>.
+	 * 
+	 * @return The canonical string representation of the actions.
+	 */
+	public String getActions() {
+		String result = actions;
+		if (result == null) {
+			StringBuffer sb = new StringBuffer();
+			boolean comma = false;
+
+			int mask = action_mask;
+			if ((mask & ACTION_EXPORT) == ACTION_EXPORT) {
+				sb.append(EXPORT);
+				comma = true;
+			}
+
+			if ((mask & ACTION_IMPORT) == ACTION_IMPORT) {
+				if (comma)
+					sb.append(',');
+				sb.append(IMPORT);
+			}
+
+			actions = result = sb.toString();
+		}
+
+		return result;
+	}
+
+	/**
+	 * Returns a new <code>PermissionCollection</code> object for storing
+	 * <code>EndpointPermission<code> objects.
+	 * 
+	 * @return A new <code>PermissionCollection</code> object suitable for
+	 *         storing <code>EndpointPermission</code> objects.
+	 */
+	public PermissionCollection newPermissionCollection() {
+		return new EndpointPermissionCollection();
+	}
+
+	/**
+	 * Determines the equality of two EndpointPermission objects.
+	 * 
+	 * Checks that specified object has the same class name and action 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
+	 *         <code>EndpointPermission</code> object; <code>false</code>
+	 *         otherwise.
+	 */
+	public boolean equals(Object obj) {
+		if (obj == this) {
+			return true;
+		}
+
+		if (!(obj instanceof EndpointPermission)) {
+			return false;
+		}
+
+		EndpointPermission sp = (EndpointPermission) obj;
+
+		return (action_mask == sp.action_mask)
+				&& getName().equals(sp.getName())
+				&& ((endpoint == sp.endpoint) || ((endpoint != null)
+						&& (sp.endpoint != null) && endpoint
+						.equals(sp.endpoint)));
+	}
+
+	/**
+	 * Returns the hash code value for this object.
+	 * 
+	 * @return Hash code value for this object.
+	 */
+	public int hashCode() {
+		int h = 31 * 17 + getName().hashCode();
+		h = 31 * h + getActions().hashCode();
+		if (endpoint != null) {
+			h = 31 * h + endpoint.hashCode();
+		}
+		return h;
+	}
+
+	/**
+	 * WriteObject is called to save the state of this permission to a stream.
+	 * The actions are serialized, and the superclass takes care of the name.
+	 */
+	private synchronized void writeObject(java.io.ObjectOutputStream s)
+			throws IOException {
+		if (endpoint != null) {
+			throw new NotSerializableException("cannot serialize");
+		}
+		// Write out the actions. The superclass takes care of the name
+		// call getActions to make sure actions field is initialized
+		if (actions == null)
+			getActions();
+		s.defaultWriteObject();
+	}
+
+	/**
+	 * readObject is called to restore the state of this permission from a
+	 * stream.
+	 */
+	private synchronized void readObject(java.io.ObjectInputStream s)
+			throws IOException, ClassNotFoundException {
+		// Read in the action, then initialize the rest
+		s.defaultReadObject();
+		setTransients(parseFilter(getName()), parseActions(actions));
+	}
+
+	/**
+	 * Called by <code><@link EndpointPermission#implies(Permission)></code>.
+	 * 
+	 * @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();
+		}
+	}
+}
+
+/**
+ * Stores a set of EndpointPermission permissions.
+ * 
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ */
+final class EndpointPermissionCollection extends PermissionCollection {
+	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;
+
+	/**
+	 * Table of permissions with filter expressions.
+	 * 
+	 * @serial
+	 * @GuardedBy this
+	 */
+	private Map				filterPermissions;
+
+	/**
+	 * Creates an empty EndpointPermissions object.
+	 */
+	public EndpointPermissionCollection() {
+		permissions = new HashMap();
+		all_allowed = false;
+	}
+
+	/**
+	 * Adds a permission to this permission collection.
+	 * 
+	 * @param permission The Permission object to add.
+	 * @throws IllegalArgumentException If the specified permission is not a
+	 *         EndpointPermission object.
+	 * @throws SecurityException If this
+	 *         <code>EndpointPermissionCollection</code> object has been marked
+	 *         read-only.
+	 */
+	public void add(final Permission permission) {
+		if (!(permission instanceof EndpointPermission)) {
+			throw new IllegalArgumentException("invalid permission: "
+					+ permission);
+		}
+		if (isReadOnly()) {
+			throw new SecurityException("attempt to add a Permission to a "
+					+ "readonly PermissionCollection");
+		}
+
+		final EndpointPermission sp = (EndpointPermission) permission;
+		if (sp.endpoint != null) {
+			throw new IllegalArgumentException("cannot add to collection: "
+					+ sp);
+		}
+
+		final String name = sp.getName();
+		final Filter f = sp.filter;
+		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;
+			}
+			final EndpointPermission existing = (EndpointPermission) pc
+					.get(name);
+
+			if (existing != null) {
+				final int oldMask = existing.action_mask;
+				final int newMask = sp.action_mask;
+				if (oldMask != newMask) {
+					pc.put(name,
+							new EndpointPermission(name, oldMask | newMask));
+				}
+			}
+			else {
+				pc.put(name, sp);
+			}
+
+			if (!all_allowed) {
+				if (name.equals("*")) {
+					all_allowed = true;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Determines if a set of permissions implies the permissions expressed in
+	 * <code>permission</code>.
+	 * 
+	 * @param permission The Permission object to compare.
+	 * @return <code>true</code> if <code>permission</code> is a proper subset
+	 *         of a permission in the set; <code>false</code> otherwise.
+	 */
+	public boolean implies(final Permission permission) {
+		if (!(permission instanceof EndpointPermission)) {
+			return false;
+		}
+		final EndpointPermission requested = (EndpointPermission) permission;
+		/* if requested permission has a filter, then it is an invalid argument */
+		if (requested.filter != null) {
+			return false;
+		}
+
+		int effective = EndpointPermission.ACTION_NONE;
+		Collection 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;
+					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();
+		}
+
+		/* iterate one by one over filteredPermissions */
+		for (Iterator iter = perms.iterator(); iter.hasNext();) {
+			if (((EndpointPermission) iter.next()).implies0(requested,
+					effective)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 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());
+		}
+		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)	};
+
+	private synchronized void writeObject(ObjectOutputStream out)
+			throws IOException {
+		Hashtable hashtable = new Hashtable(permissions);
+		ObjectOutputStream.PutField pfields = out.putFields();
+		pfields.put("permissions", hashtable);
+		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);
+		all_allowed = gfields.get("all_allowed", false);
+		filterPermissions = (HashMap) gfields.get("filterPermissions", null);
+	}
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/EndpointPermission.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) OSGi Alliance (2009). 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.osgi.service.remoteserviceadmin;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An Import Reference associates an active proxy service to a remote endpoint.
+ * 
+ * The Import Reference can be used to reference an imported service. When the
+ * service is no longer imported, all methods must return <code>null</code>;
+ * 
+ * @ThreadSafe
+ * @version $Revision$
+ */
+public interface ImportReference {
+	/**
+	 * Answer the associated Service Reference for the proxy to the endpoint.
+	 * 
+	 * @return A Service Reference to the proxy for the endpoint.
+	 */
+	ServiceReference getImportedService();
+
+	/**
+	 * Answer the associated remote Endpoint Description.
+	 * 
+	 * @return A Endpoint Description for the remote endpoint.
+	 */
+	EndpointDescription getImportedEndpoint();
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-osgi-remote-service-admin-interfaces/src/main/java/org/osgi/service/remoteserviceadmin/ImportReference.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml (added)
+++ cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml Thu Dec 17 11:28:30 2009
@@ -0,0 +1,113 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <!--
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-topology-manager</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF OSGi Topology Manager implementation</name>
+    <version>1.2-SNAPSHOT</version>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.2-SNAPSHOT</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+        <bundle.import.package>*</bundle.import.package>
+        <bundle.export.package>
+            org.apache.cxf.dosgi.*;version="${pom.version}",
+            org.osgi.service.remoteserviceadmin;version="${remote.service.admin.interfaces.version}"
+        </bundle.export.package>
+    </properties>
+
+    <dependencies>
+        <!--
+            <dependency> <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-bundle-minimal</artifactId>
+            <version>${cxf.version}</version> </dependency>
+        -->
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>${felix.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>org.osgi.foundation</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.cxf.dosgi</groupId>
+            <artifactId>cxf-dosgi-remote-service-admin-interfaces</artifactId>
+            <version>${remote.service.admin.interfaces.version}</version>
+            <!-- <scope>provided</scope>    Include the interfaces -->
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <version>2.4</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <manifestLocation>META-INF</manifestLocation>
+                    <instructions>
+                        <Bundle-Name>CXF dOSGi Topology Manager</Bundle-Name>
+                        <Bundle-Description>TODO</Bundle-Description>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+                        <Bundle-Activator>org.apache.cxf.dosgi.topologymanager.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Export-Package>${bundle.export.package}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>**/TestUtils*</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+
+        </plugins>
+    </build>
+
+</project>

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Added: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,87 @@
+/** 
+  * Licensed to the Apache Software Foundation (ASF) under one 
+  * or more contributor license agreements. See the NOTICE file 
+  * distributed with this work for additional information 
+  * regarding copyright ownership. The ASF licenses this file 
+  * to you under the Apache License, Version 2.0 (the 
+  * "License"); you may not use this file except in compliance 
+  * with the License. You may obtain a copy of the License at 
+  * 
+  * http://www.apache.org/licenses/LICENSE-2.0 
+  * 
+  * Unless required by applicable law or agreed to in writing, 
+  * software distributed under the License is distributed on an 
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+  * KIND, either express or implied. See the License for the 
+  * specific language governing permissions and limitations 
+  * under the License. 
+  */
+package org.apache.cxf.dosgi.topologymanager;
+
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+    private static final Logger LOG = Logger.getLogger(Activator.class.getName());
+
+    private TopologyManager topManager;
+    private TopologyManagerImport topManagerImport;
+
+    private RemoteServiceAdminList remoteServiceAdminList;
+    
+    protected RemoteServiceAdminListenerImpl remoteServiceAdminListener;
+    
+    // separated for testing
+    protected TopologyManager createTopologyManager(BundleContext bc,RemoteServiceAdminList rl) {
+        return new TopologyManager(bc,rl);
+    }
+
+ // separated for testing
+    protected TopologyManagerImport createTopologyManagerImport(BundleContext bc,RemoteServiceAdminList rl) {
+        return new TopologyManagerImport(bc,rl);
+    }
+    
+ // separated for testing
+    protected RemoteServiceAdminList createRemoteServiceAdminList(BundleContext bc) {
+        return new RemoteServiceAdminList(bc);
+    }
+
+    // separated for testing
+    protected RemoteServiceAdminListenerImpl createRemoteServiceAdminListenerImpl(BundleContext bc,TopologyManager topManager,TopologyManagerImport topManagerImport) {
+        return new RemoteServiceAdminListenerImpl(bc, topManager, topManagerImport);
+    }
+    
+    public void start(BundleContext bc) throws Exception {
+        LOG.info("TopologyManager: start()");
+        remoteServiceAdminList = createRemoteServiceAdminList(bc);
+        topManager = createTopologyManager(bc,remoteServiceAdminList);
+        topManagerImport = createTopologyManagerImport(bc,remoteServiceAdminList);
+
+        remoteServiceAdminList.setTopologyManager(topManager);
+        remoteServiceAdminList.setTopologyManagerImport(topManagerImport);
+        
+        remoteServiceAdminListener = createRemoteServiceAdminListenerImpl(bc, topManager, topManagerImport);        
+        
+        remoteServiceAdminListener.start();
+        
+        topManager.start();
+        
+        remoteServiceAdminList.start();
+        
+        topManagerImport.start();
+        
+        
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        LOG.info("TopologyManager: stop()");
+        topManager.stop();
+        topManagerImport.stop();
+        remoteServiceAdminList.stop();
+        remoteServiceAdminListener.stop();
+    }
+
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,84 @@
+/** 
+  * Licensed to the Apache Software Foundation (ASF) under one 
+  * or more contributor license agreements. See the NOTICE file 
+  * distributed with this work for additional information 
+  * regarding copyright ownership. The ASF licenses this file 
+  * to you under the Apache License, Version 2.0 (the 
+  * "License"); you may not use this file except in compliance 
+  * with the License. You may obtain a copy of the License at 
+  * 
+  * http://www.apache.org/licenses/LICENSE-2.0 
+  * 
+  * Unless required by applicable law or agreed to in writing, 
+  * software distributed under the License is distributed on an 
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+  * KIND, either express or implied. See the License for the 
+  * specific language governing permissions and limitations 
+  * under the License. 
+  */
+package org.apache.cxf.dosgi.topologymanager;
+
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class ServiceListenerImpl implements ServiceListener {
+    
+    private Logger LOG = Logger.getLogger(ServiceListenerImpl.class.getName());
+
+    private BundleContext bctx;
+    private TopologyManager topManager;
+    
+    public ServiceListenerImpl(BundleContext bc,TopologyManager tm) {
+        bctx = bc; topManager = tm;
+    }
+    
+    
+    protected void start(){
+        bctx.addServiceListener(this);
+    }
+    
+    protected void stop(){
+        bctx.removeServiceListener(this);
+    }
+    
+    
+    
+    
+    
+    
+    
+    public void serviceChanged(ServiceEvent event) {
+        LOG.fine("Received ServiceEvent: " + event);
+
+        ServiceReference sref = event.getServiceReference();
+
+        if (event.getType() == ServiceEvent.REGISTERED) {
+            LOG.fine("Registered");
+            if (analyzeService(sref)) {
+                LOG.info("calling TopologyManager -> registered service");
+                topManager.exportService(sref);
+            }
+        } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+            topManager.removeService(sref);
+        }
+    }
+
+    
+    /**
+     * checks if a Service is intended to be exported
+     */
+    private boolean analyzeService(ServiceReference sref) {
+
+        if ("*".equals(sref.getProperty(RemoteConstants.SERVICE_EXPORTED_INTERFACES))) {
+            return true;
+        }
+        return false;
+    }
+    
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/ServiceListenerImpl.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,334 @@
+/** 
+  * Licensed to the Apache Software Foundation (ASF) under one 
+  * or more contributor license agreements. See the NOTICE file 
+  * distributed with this work for additional information 
+  * regarding copyright ownership. The ASF licenses this file 
+  * to you under the Apache License, Version 2.0 (the 
+  * "License"); you may not use this file except in compliance 
+  * with the License. You may obtain a copy of the License at 
+  * 
+  * http://www.apache.org/licenses/LICENSE-2.0 
+  * 
+  * Unless required by applicable law or agreed to in writing, 
+  * software distributed under the License is distributed on an 
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+  * KIND, either express or implied. See the License for the 
+  * specific language governing permissions and limitations 
+  * under the License. 
+  */
+package org.apache.cxf.dosgi.topologymanager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+public class TopologyManagerImport {
+
+    private final static Logger LOG = Logger.getLogger(TopologyManagerImport.class.getName());
+    private ExecutorService execService = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS,
+                                                                 new LinkedBlockingQueue<Runnable>());
+
+    private EndpointListenerImpl endpointListener;
+    private BundleContext bctx;
+    private RemoteServiceAdminList remoteServiceAdminList;
+    private ListenerHookImpl listenerHook;
+
+    /**
+     * If set to false only one service is imported for each import interest even it multiple services are
+     * available. If set to true, all available services are imported.
+     * 
+     * TODO: Make this available as a configuration option
+     */
+    private boolean importAllAvailable = true;
+
+    /**
+     * Contains an instance of the Class Import Interest for each distinct import request. If the same filter
+     * is requested multiple times the existing instance of the Object increments an internal reference
+     * counter. If an interest is removed, the related ServiceInterest object is used to reduce the reference
+     * counter until it reaches zero. in this case the interest is removed.
+     */
+    private Map<String/* filter */, ImportInterest> importInterests = new HashMap<String, ImportInterest>();
+
+    private static class ImportInterest {
+        String filter;
+        int refs;
+
+        public ImportInterest(String filter) {
+            this.filter = filter;
+            refs = 1;
+        }
+
+        public int addReference() {
+            return ++refs;
+        }
+
+        public int removeReference() {
+            return --refs;
+        }
+
+    }
+
+    /**
+     * FIXME: Documnet me .... !
+     */
+    private Map<String /* filter */, List<EndpointDescription>> importPossibilities = new HashMap<String, List<EndpointDescription>>();
+    private Map<String /* filter */, List<ImportRegistration>> importedServices = new HashMap<String, List<ImportRegistration>>();
+
+    public TopologyManagerImport(BundleContext bc, RemoteServiceAdminList rsaList) {
+        bctx = bc;
+        remoteServiceAdminList = rsaList;
+        endpointListener = new EndpointListenerImpl(bctx, this);
+        listenerHook = new ListenerHookImpl(bctx, this);
+    }
+
+    public void start() {
+        // / register the EndpointListener for discovery
+        endpointListener.start();
+        listenerHook.start();
+    }
+
+    public void stop() {
+        execService.shutdown();
+        endpointListener.stop();
+        listenerHook.stop();
+    }
+
+    protected void addServiceInterest(String filter) {
+
+        String exFilter = Utils.extendFilter(filter, bctx);
+
+        synchronized (importInterests) {
+            ImportInterest i = importInterests.get(exFilter);
+            if (i != null) {
+                i.addReference();
+            } else {
+                importInterests.put(exFilter, new ImportInterest(exFilter));
+                endpointListener.extendScope(exFilter);
+            }
+        }
+
+    }
+
+    public void removeServiceInterest(String filter) {
+
+        String exFilter = Utils.extendFilter(filter, bctx);
+
+        synchronized (importInterests) {
+            ImportInterest i = importInterests.get(exFilter);
+            if (i != null) {
+                // remove reference
+                if (i.removeReference() <= 0) {
+                    // last reference, remove from scope
+                    LOG.fine("last reference to import interest is gone -> removing interest  filter:"
+                             + exFilter);
+                    endpointListener.reduceScope(exFilter);
+                    importInterests.remove(exFilter);
+                    List<ImportRegistration> irs = importedServices.remove(exFilter);
+                    for (ImportRegistration ir : irs) {
+                        if (ir != null) {
+                            ir.close();
+                        }
+                    }
+                }
+            } else {
+                // unhandled service ... do nothing
+            }
+        }
+
+    }
+
+    public void removeImportableService(String filter, EndpointDescription epd) {
+
+        synchronized (importPossibilities) {
+            List<EndpointDescription> ips = importPossibilities.get(filter);
+            if (ips != null) {
+                ips.remove(epd);
+            } else {
+                // should not happen
+            }
+        }
+
+        triggerImport(filter);
+
+    }
+
+    public void addImportableService(String filter, EndpointDescription epd) {
+
+        LOG.fine("importable service added for filter " + filter + " -> " + epd);
+        synchronized (importPossibilities) {
+            List<EndpointDescription> ips = importPossibilities.get(filter);
+            if (ips == null) {
+                ips = new ArrayList<EndpointDescription>();
+                importPossibilities.put(filter, ips);
+            }
+
+            ips.add(epd);
+        }
+
+        triggerImport(filter);
+    }
+
+    private void triggerImport(final String filter) {
+
+        LOG.fine("import of a service for filter " + filter + " was queued");
+
+        execService.execute(new Runnable() {
+            public void run() {
+                synchronized (importedServices) { // deadlock possibility ?
+                    synchronized (importPossibilities) {
+                        if (importAllAvailable) {
+                            importAllServicesStrategy(filter);
+                        } else {
+                            importSingleServiceStrategy(filter);
+                        }
+                    }
+                }
+                // Notify EndpointListeners ? NO!
+            }
+
+        });
+
+    }
+
+    private void importAllServicesStrategy(String filter) {
+
+        List<ImportRegistration> irs = importedServices.get(filter);
+        if (irs == null) {
+            irs = new ArrayList<ImportRegistration>();
+            importedServices.put(filter, irs);
+        }
+
+        if (irs.size() > 0) { // remove old services that are not available anymore
+            List<EndpointDescription> ips = importPossibilities.get(filter);
+            Iterator<ImportRegistration> it = irs.iterator();
+            while (it.hasNext()) {
+                ImportRegistration ir = it.next();
+                EndpointDescription ep = ir.getImportReference().getImportedEndpoint();
+
+                // if service is already imported, check if endpoint is still in the list of
+                // possible imports
+                if ((ips != null && !ips.contains(ep)) || ips == null) {
+                    // unexport service
+                    ir.close();
+                    it.remove();
+                }
+
+            }
+        }
+
+        for (EndpointDescription epd : importPossibilities.get(filter)) {
+            if (!irs.contains(epd)) {
+                // service not imported yet -> import it now
+                ImportRegistration ir = importService(epd);
+                if (ir != null) {
+                    // import was successful
+                    irs.add(ir);
+                }
+            }
+        }
+
+    }
+
+    private void importSingleServiceStrategy(final String filter) {
+
+        if (importedServices.containsKey(filter) && importedServices.get(filter) != null
+            && importedServices.get(filter).size() > 0) {
+            // a service was already imported ....
+            List<ImportRegistration> irs = importedServices.get(filter);
+            List<EndpointDescription> ips = importPossibilities.get(filter);
+
+            Iterator<ImportRegistration> it = irs.iterator();
+            while (it.hasNext()) {
+                ImportRegistration ir = it.next();
+                EndpointDescription ep = ir.getImportReference().getImportedEndpoint();
+
+                // if service is already imported, check if endpoint is still in the list of
+                // possible imports
+                if ((ips != null && !ips.contains(ep)) || ips == null) {
+                    // unexport service
+                    ir.close();
+                    it.remove();
+                }
+            }
+
+            if (irs.size() == 0) {
+                // if there are other import possibilities available, try to import them...
+                if (ips != null && ips.size() > 0) {
+                    triggerImport(filter);
+                }
+            }
+
+            // TODO but optional: if the service is already imported and the endpoint is still
+            // in the list
+            // of possible imports check if a "better" endpoint is now in the list ?
+
+        } else {
+            // if the service is not yet imported, try ...
+            if (importPossibilities.get(filter).size() > 0) {
+                for (EndpointDescription ep : importPossibilities.get(filter)) {
+                    ImportRegistration ir = importService(ep);
+                    if (ir != null) {
+                        // import was successful
+                        List<ImportRegistration> irs = importedServices.get(filter);
+                        if (irs == null) {
+                            irs = new ArrayList<ImportRegistration>(1);
+                            importedServices.put(filter, irs);
+                        }
+                        irs.add(ir);
+                        break;
+                    } else {
+                        // import of endpoint failed -> try next one
+                    }
+                }
+            }
+
+        }
+    }
+
+    private ImportRegistration importService(EndpointDescription ep) {
+        synchronized (remoteServiceAdminList) {
+            for (RemoteServiceAdmin rsa : remoteServiceAdminList) {
+                ImportRegistration ir = rsa.importService(ep);
+                if (ir != null && ir.getException() == null) {
+                    // successful
+                    LOG.fine("service impoort was successful: " + ir);
+                    return ir;
+                } else {
+                    // failed -> next RSA
+                }
+            }
+        }
+        return null;
+    }
+
+    public void removeImportRegistration(ImportRegistration importRegistration) {
+        synchronized (importedServices) {
+            if (importedServices.remove(importRegistration) != null) {
+                LOG.fine("removed imported service reference: " + importRegistration);
+            }
+        }
+    }
+
+    public void triggerExportImportForRemoteSericeAdmin(RemoteServiceAdmin rsa) {
+        LOG.severe("NOT IMPLEMENTED !!!");
+    }
+
+    public void removeImportReference(ImportReference anyObject) {
+        LOG.severe("NOT IMPLEMENTED !!!");
+    }
+
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/TopologyManagerImport.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java?rev=891650&view=auto
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java (added)
+++ cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java Thu Dec 17 11:28:30 2009
@@ -0,0 +1,131 @@
+/** 
+  * Licensed to the Apache Software Foundation (ASF) under one 
+  * or more contributor license agreements. See the NOTICE file 
+  * distributed with this work for additional information 
+  * regarding copyright ownership. The ASF licenses this file 
+  * to you under the Apache License, Version 2.0 (the 
+  * "License"); you may not use this file except in compliance 
+  * with the License. You may obtain a copy of the License at 
+  * 
+  * http://www.apache.org/licenses/LICENSE-2.0 
+  * 
+  * Unless required by applicable law or agreed to in writing, 
+  * software distributed under the License is distributed on an 
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
+  * KIND, either express or implied. See the License for the 
+  * specific language governing permissions and limitations 
+  * under the License. 
+  */
+package org.apache.cxf.dosgi.topologymanager;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class EndpointListenerImplTest {
+   
+    int testCase = 0;
+
+    @Test
+    public void testScopeChange(){
+        
+        
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        TopologyManagerImport tm = EasyMock.createNiceMock(TopologyManagerImport.class);
+        ServiceRegistration sr = EasyMock.createNiceMock(ServiceRegistration.class);
+        
+        // expect Listener registration
+        EasyMock.expect(bc.registerService((String)EasyMock.anyObject(),EasyMock.anyObject() , (Dictionary)EasyMock.anyObject())).andReturn(sr).atLeastOnce();
+        
+        
+        sr.setProperties((Dictionary)EasyMock.anyObject());
+        
+        
+        // expect property changes based on later calls
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            
+            public Object answer() throws Throwable {
+                Object[] args =  EasyMock.getCurrentArguments();
+                Dictionary props = (Dictionary)args[0];
+                List<String> scope = (List<String>)props.get(EndpointListener.ENDPOINT_LISTENER_SCOPE);
+                
+                //System.out.println("Test: change scope -> case: "+testCase);
+                //System.out.println(scope);
+                
+                switch (testCase) {
+                case 1:
+                    assertEquals(1,scope.size());
+                    assertEquals("(a=b)",scope.get(0));
+                    break;
+                    
+                case 2:
+                    assertEquals(0,scope.size());
+                    break;
+                    
+                    
+                case 3:
+                    assertEquals("adding entry to empty list failed",1,scope.size());
+                    assertEquals("(a=b)",scope.get(0));
+                    break;
+                    
+                case 4:
+                    assertEquals("adding second entry failed",2,scope.size());
+                    assertNotNull(scope.contains("(a=b)"));
+                    assertNotNull(scope.contains("(c=d)"));
+                    break;
+                    
+                case 5:
+                    assertEquals("remove failed",1,scope.size());
+                    assertEquals("(c=d)",scope.get(0));
+                    break;
+                    
+                default:
+                    assertTrue("This should not happen !", false);
+                }
+                
+                
+                
+                
+                return null;
+            }
+        }).atLeastOnce();
+        
+        
+        EasyMock.replay(bc);
+        EasyMock.replay(tm);
+        EasyMock.replay(sr);
+        
+        EndpointListenerImpl endpointListener = new EndpointListenerImpl(bc, tm);
+                
+        endpointListener.start();
+
+        
+        testCase = 1;
+        endpointListener.extendScope("(a=b)");        
+        testCase = 2;
+        endpointListener.reduceScope("(a=b)");
+        
+        testCase = 3;
+        endpointListener.extendScope("(a=b)");
+        testCase = 4;
+        endpointListener.extendScope("(c=d)");
+        testCase = 5;       
+        endpointListener.reduceScope("(a=b)");
+                
+        endpointListener.stop();
+        
+        EasyMock.verify(bc);
+        EasyMock.verify(tm);
+        EasyMock.verify(sr);
+    }
+    
+}

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/dosgi/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/EndpointListenerImplTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date



Mime
View raw message