You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by eg...@apache.org on 2009/03/20 15:14:27 UTC

svn commit: r756476 [1/2] - in /cxf/dosgi/trunk: discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/ discovery/local/src/main/java/org/osgi/service/discovery/ dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ dsw/cxf-dsw/src/mai...

Author: eglynn
Date: Fri Mar 20 14:14:26 2009
New Revision: 756476

URL: http://svn.apache.org/viewvc?rev=756476&view=rev
Log:
[dOSGi] Updated to latest Discovery APIs & semantics

Modified:
    cxf/dosgi/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/LocalDiscoveryService.java
    cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
    cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
    cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/ServicePublication.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/AbstractClientHook.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHook.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtils.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/ServicePublication.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/BundleTestContext.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHookTest.java
    cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfPublishHookTest.java

Modified: cxf/dosgi/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/LocalDiscoveryService.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/LocalDiscoveryService.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/LocalDiscoveryService.java (original)
+++ cxf/dosgi/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/LocalDiscoveryService.java Fri Mar 20 14:14:26 2009
@@ -23,9 +23,11 @@
 import static org.osgi.service.discovery.DiscoveredServiceNotification.UNAVAILABLE;
 import static org.osgi.service.discovery.DiscoveredServiceTracker.PROP_KEY_MATCH_CRITERIA_FILTERS;
 import static org.osgi.service.discovery.DiscoveredServiceTracker.PROP_KEY_MATCH_CRITERIA_INTERFACES;
+import static org.osgi.service.discovery.ServicePublication.PROP_KEY_SERVICE_INTERFACE_NAME;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -317,13 +319,23 @@
     }
 
     private void triggerCallbacks(DiscoveredServiceTracker tracker,
-                                  String match, boolean isFilter, 
+                                  String toMatch, 
+                                  boolean isFilter, 
                                   ServiceEndpointDescription sd,
-                                  int notificationType) {
-        LOG.info("check if string: " + match + (isFilter ? " matches " : " contained by ") +  sd.getProvidedInterfaces());
-        if ((isFilter && filterMatches(match, sd))
-                || sd.getProvidedInterfaces().contains(match)) {
-            tracker.serviceChanged(new TrackerNotification(sd, notificationType));
+                                  int type) {
+        LOG.info("check if string: " + toMatch + (isFilter ? " matches " : " contained by ") +  sd.getProvidedInterfaces());
+
+        TrackerNotification notification = 
+            isFilter
+            ? (filterMatches(toMatch, sd)
+               ? new TrackerNotification(sd, true, toMatch, type)
+               : null)
+            : (sd.getProvidedInterfaces().contains(toMatch)
+               ? new TrackerNotification(sd, false, toMatch, type)
+               : null);
+
+        if (notification != null) {
+            tracker.serviceChanged(notification);
         }
     }    
 
@@ -339,10 +351,25 @@
         implements DiscoveredServiceNotification {
 
         private ServiceEndpointDescription sd;
+        private Collection interfaces;
+        private Collection filters;
         private int type;
 
-        TrackerNotification(ServiceEndpointDescription sd, int type) {
+        TrackerNotification(ServiceEndpointDescription sd, 
+                            boolean isFilter, 
+                            String match, 
+                            int type) {
             this.sd = sd;
+            if (isFilter) {
+                filters = new ArrayList();
+                filters.add(match);
+                interfaces = Collections.EMPTY_SET;
+            } else {
+                interfaces = new ArrayList();
+                interfaces.add(match);
+                filters = Collections.EMPTY_SET;
+            }
+
             this.type = type;
         }
 
@@ -353,6 +380,14 @@
         public int getType() {
             return type;
         }
+
+        public Collection getInterfaces() {
+            return interfaces; 
+        }
+
+        public Collection getFilters() {
+            return filters; 
+        }
     }
                 
     public void shutdown() {
@@ -391,7 +426,7 @@
         
         String[] interfaceNames = getProvidedInterfaces(sd, interfaceName);
         if (interfaceNames != null) {
-            d.put(Constants.OBJECTCLASS, interfaceNames);
+            d.put(PROP_KEY_SERVICE_INTERFACE_NAME, interfaceNames);
         }
         return d;
     }

Modified: cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java (original)
+++ cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java Fri Mar 20 14:14:26 2009
@@ -1,78 +1,102 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Interface for notification on discovered services.
- * 
- * @version $Revision$
- */
-public interface DiscoveredServiceNotification {
-
-	/**
-	 * Notification indicating that a service matching the listening criteria has been
-	 * discovered.
-	 * <p>
-	 * The value of <code>AVAILABLE</code> is 0x00000001.
-	 */
-	public final static int AVAILABLE = 0x00000001;
-
-	/**
-	 * Notification indicating that the properties of a previously discovered service
-	 * have changed.
-	 * <p>
-	 * The value of <code>MODIFIED</code> is 0x00000002.
-	 */
-	public final static int MODIFIED = 0x00000002;
-
-	/**
-	 * Notification indicating that a previously discovered service is no longer known
-	 * to discovery.
-	 * <p>
-	 * The value of <code>UNAVAILABLE</code> is 0x00000004.
-	 */
-	public final static int UNAVAILABLE = 0x00000004;
-
-	/**
-	 * Notification indicating that the properties of a previously discovered service
-	 * have changed and the new properties no longer match the listener's
-	 * filter.
-	 * <p>
-	 * The value of <code>MODIFIED_ENDMATCH</code> is 0x00000008.
-	 */
-	public final static int MODIFIED_ENDMATCH = 0x00000008;
-
-	/**
-	 * Returns information currently known to Discovery regarding the service
-	 * endpoint.
-	 * <p>
-	 * 
-	 * @return metadata of the service this Discovery notifies about.
-	 */
-	ServiceEndpointDescription getServiceEndpointDescription();
-
-	/**
-	 * Returns the type of notification. The type values are:
-	 * <ul>
-	 * <li>{@link #AVAILABLE} </li> <li>{@link #MODIFIED} </li> <li>
-	 * {@link #MODIFIED_ENDMATCH} </li> <li>{@link #UNAVAILABLE} </li>
-	 * </ul>
-	 * 
-	 * @return Type of notification regarding known service metadata.
-	 */
-	int getType();
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+import java.util.Collection;
+
+/**
+ * Interface for notification on discovered services.
+ * 
+ * @version $Revision: 6510 $
+ */
+public interface DiscoveredServiceNotification {
+
+	/**
+	 * Notification indicating that a service matching the listening criteria has been
+	 * discovered.
+	 * <p>
+	 * The value of <code>AVAILABLE</code> is 0x00000001.
+	 */
+	public final static int	AVAILABLE			= 0x00000001;
+
+	/**
+	 * Notification indicating that the properties of a previously discovered service
+	 * have changed.
+	 * <p>
+	 * The value of <code>MODIFIED</code> is 0x00000002.
+	 */
+	public final static int	MODIFIED			= 0x00000002;
+
+	/**
+	 * Notification indicating that a previously discovered service is no longer known
+	 * to discovery.
+	 * <p>
+	 * The value of <code>UNAVAILABLE</code> is 0x00000004.
+	 */
+	public final static int	UNAVAILABLE			= 0x00000004;
+
+	/**
+	 * Notification indicating that the properties of a previously discovered service
+	 * have changed and the new properties no longer match the listener's
+	 * filter.
+	 * <p>
+	 * The value of <code>MODIFIED_ENDMATCH</code> is 0x00000008.
+	 */
+	public final static int	MODIFIED_ENDMATCH	= 0x00000008;
+
+	/**
+	 * Returns information currently known to Discovery regarding the service
+	 * endpoint.
+	 * <p>
+	 * 
+	 * @return metadata of the service this Discovery notifies about.
+	 */
+	ServiceEndpointDescription getServiceEndpointDescription();
+
+	/**
+	 * Returns the type of notification. The type values are:
+	 * <ul>
+	 * <li>{@link #AVAILABLE}</li>
+	 * <li>{@link #MODIFIED}</li>
+	 * <li>{@link #MODIFIED_ENDMATCH}</li>
+	 * <li>{@link #UNAVAILABLE}</li>
+	 * </ul>
+	 * 
+	 * @return Type of notification regarding known service metadata.
+	 */
+	int getType();
+
+	/**
+	 * Returns interface name criteria of the {@link DiscoveredServiceTracker}
+	 * object matching with the interfaces of the ServiceEndpointDescription and
+	 * thus caused the notification.
+	 * 
+	 * @return matching interface name criteria of the
+	 *         {@link DiscoveredServiceTracker} object being notified.
+	 */
+	Collection/* <String> */getInterfaces();
+
+	/**
+	 * Returns filters of the {@link DiscoveredServiceTracker} object matching
+	 * with the ServiceEndpointDescription and thus caused the notification.
+	 * 
+	 * @return matching filters of the {@link DiscoveredServiceTracker} object
+	 *         being notified.
+	 */
+	Collection/* <String> */getFilters();
+}
+

Modified: cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java (original)
+++ cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java Fri Mar 20 14:14:26 2009
@@ -1,62 +1,72 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Interface of trackers for discovered remote services. <br>
- * When such a service is registered with the framework, then {@link Discovery}
- * will notify it about remote services matching one of the provided criteria
- * and will keep notifying it on changes of information known to Discovery
- * regarding this services.
- * 
- * <code>Discovery</code> may deliver notifications on discovered services to a
- * <code>DiscoveredServiceTracker</code> out of order and may concurrently call
- * and/or reenter a <code>DiscoveredServiceTracker</code>.
- * 
- * @version $Revision$
- */
-public interface DiscoveredServiceTracker {
-
-	/**
-	 * Property describing service interfaces this tracker is interested in.
-	 * Value of this property is of type Collection (<? extends String>).<br>
-	 * Property is optional, may be null.
-	 */
-	public static final String PROP_KEY_MATCH_CRITERIA_INTERFACES = "osgi.discovery.interest.interfaces";
-
-	/**
-	 * Property describing filters for services this tracker is interested in.
-	 * Value of this property is of type Collection (<? extends String>). See
-	 * {@link ServicePublication} for some standard property keys used to
-	 * publish service metadata. <br>
-	 * Property is optional, may be null.
-	 */
-	public static final String PROP_KEY_MATCH_CRITERIA_FILTERS = "osgi.discovery.interest.filters";
-
-	/**
-	 * Receives notification that information known to Discovery regarding a
-	 * remote service has changed. <br>
-	 * The tracker is only notified about remote services which fulfill the
-	 * matching criteria, either one of the interfaces or one of the filters,
-	 * provided as properties of this service.
-	 * 
-	 * @param notification
-	 *            the <code>DiscoveredServiceNotification</code> object
-	 *            describing the change.
-	 */
-	void serviceChanged(DiscoveredServiceNotification notification);
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+/**
+ * Interface of trackers for discovered remote services. <br>
+ * When such a service is registered with the framework, then {@link Discovery}
+ * will notify it about remote services matching one of the provided criteria
+ * and will keep notifying it on changes of information known to Discovery
+ * regarding this services.
+ * 
+ * <code>Discovery</code> may deliver notifications on discovered services to a
+ * <code>DiscoveredServiceTracker</code> out of order and may concurrently call
+ * and/or reenter a <code>DiscoveredServiceTracker</code>.
+ * 
+ * @version $Revision: 6553 $
+ */
+public interface DiscoveredServiceTracker {
+
+	/**
+	 * Optional ServiceRegistration property which contains service interfaces
+	 * this tracker is interested in. Value of this property is of type
+	 * Collection (<? extends String>). <br>
+	 * Property is optional, may be null.
+	 */
+	public static final String	PROP_KEY_MATCH_CRITERIA_INTERFACES	= "osgi.discovery.interest.interfaces";
+
+	/**
+	 * Optional ServiceRegistration property which contains filters for services
+	 * this tracker is interested in. <br>
+	 * Note that these filters need to take into account service publication
+	 * properties which are not necessarily the same as properties under which a
+	 * service is registered. See {@link ServicePublication} for some standard
+	 * properties used to publish service metadata. <br>
+	 * The following sample filter will make Discovery notify the
+	 * DiscoveredServiceTracker about services providing interface
+	 * 'my.company.foo' of version '1.0.1.3':<br>
+	 * "(&amp;(service.interface=my.company.foo)(service.interface.version=my.company.foo|1.0.1.3))". <br>
+	 * Value of this property is of type Collection (&lt;? extends String%gt;).
+	 * Property is optional, may be null.
+	 */
+	public static final String	PROP_KEY_MATCH_CRITERIA_FILTERS		= "osgi.discovery.interest.filters";
+
+	/**
+	 * Receives notification that information known to Discovery regarding a
+	 * remote service has changed. <br>
+	 * The tracker is only notified about remote services which fulfill the
+	 * matching criteria, either one of the interfaces or one of the filters,
+	 * provided as properties of this service. <br>
+	 * If multiple criteria match, then the tracker is notified about each of
+	 * them. This can be done either by a single notification callback or by
+	 * multiple subsequent ones.
+	 * 
+	 * @param notification the <code>DiscoveredServiceNotification</code> object
+	 *        describing the change.
+	 */
+	void serviceChanged(DiscoveredServiceNotification notification);
+}

Modified: cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/ServicePublication.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/ServicePublication.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/ServicePublication.java (original)
+++ cxf/dosgi/trunk/discovery/local/src/main/java/org/osgi/service/discovery/ServicePublication.java Fri Mar 20 14:14:26 2009
@@ -1,109 +1,116 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Register a service implementing the <code>ServicePublication</code> interface
- * in order to publish metadata of a particular service (endpoint) via
- * Discovery. Metadata which has to be published is given in form of properties
- * at registration. <br>
- * In order to update published service metadata, update the properties
- * registered with the <code>ServicePublication</code> service. Depending on
- * Discovery's implementation and underlying protocol it may result in an update
- * or new re-publication of the service. <br>
- * In order to unpublish the previously published service metadata, unregister
- * the <code>ServicePublication</code> service.<br>
- * 
- * Please note that providing the {@link #PROP_KEY_SERVICE_INTERFACE_NAME}
- * property is mandatory when a <code>ServicePublication</code> service is
- * registered.<br>
- * 
- * Also important is that it's not guaranteed that after registering a
- * <code>ServicePublication</code> object its service metadata is actually
- * published. Beside the fact that at least one Discovery service has to be
- * present, the provided properties have to be valid, e.g. shouldn't contain
- * case variants of the same key name, a supported publication strategy used and
- * the actual publication via Discovery mechanisms has to succeed.
- * 
- * @version $Revision$
- */
-public interface ServicePublication {
-
-	/**
-	 * Mandatory ServiceRegistration property which contains a collection of
-	 * full qualified interface names offered by the advertised service
-	 * endpoint. Value of this property is of type Collection (<? extends
-	 * String>).
-	 */
-	public static final String PROP_KEY_SERVICE_INTERFACE_NAME = "service.interface";
-
-	/**
-	 * Optional ServiceRegistration property which contains a collection of
-	 * interface names with their associated version attributes separated by
-	 * {@link #SEPARATOR} e.g. 'my.company.foo:1.3.5 my.company.zoo:2.3.5'. In
-	 * case no version has been provided for an interface, Discovery may use the
-	 * String-value of <code>org.osgi.framework.Version.emptyVersion</code>
-	 * constant. <br>
-	 * Value of this property is of type Collection (<? extends String>).
-	 */
-	public static final String PROP_KEY_SERVICE_INTERFACE_VERSION = "service.interface.version";
-
-	/**
-	 * Optional ServiceRegistration property which contains a collection of
-	 * interface names with their associated (non-Java) endpoint interface names
-	 * separated by {@link #SEPARATOR} e.g.:<br>
-	 * 'my.company.foo:MyWebService my.company.zoo:MyWebService'.<br>
-	 * This (non-Java) endpoint interface name is usually a communication
-	 * protocol specific interface, for instance a web service interface name.
-	 * Though this information is usually contained in accompanying properties
-	 * e.g. a wsdl file, Discovery usually doesn't read and interprets such
-	 * service meta-data. Providing this information explicitly, might allow
-	 * external non-Java applications find services based on this endpoint
-	 * interface.
-	 * 
-	 * Value of this property is of type Collection (<? extends String>).
-	 */
-	public static final String PROP_KEY_ENDPOINT_INTERFACE_NAME = "osgi.remote.endpoint.interface";
-
-	/**
-	 * Optional ServiceRegistration property which contains a map of properties
-	 * of the published service. <br>
-	 * Property keys are handled in a case insensitive manner (as OSGi Framework
-	 * does). Note that Discovery might make use of certain standard properties
-	 * e.g. defined by {@link ServiceEndpointDescription} for the publication
-	 * process if they are provided.<br>
-	 * Value of this property is of type <code>java.util.Map<code>.
-	 */
-	public static final String PROP_KEY_SERVICE_PROPERTIES = "service.properties";
-
-	/**
-	 * Optional property of the published service identifying its location.
-	 * Value of this property is of type <code>java.net.URL<code>.
-	 */
-	public static final String PROP_KEY_ENDPOINT_LOCATION = "osgi.remote.endpoint.location";
-
-	/**
-	 * Optional property of the published service uniquely identifying its
-	 * endpoint. Value of this property is of type <code>String<code>.
-	 */
-	public static final String PROP_KEY_ENDPOINT_ID = "osgi.remote.endpoint.id";
-
-	/**
-	 * Separator for key value pairs.
-	 */
-	public static final String SEPARATOR = ":";
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+/**
+ * Register a service implementing the <code>ServicePublication</code> interface
+ * in order to publish metadata of a particular service (endpoint) via
+ * Discovery. Metadata which has to be published is given in form of properties
+ * at registration. <br>
+ * In order to update published service metadata, update the properties
+ * registered with the <code>ServicePublication</code> service. Depending on
+ * Discovery's implementation and underlying protocol it may result in an update
+ * or new re-publication of the service. <br>
+ * In order to unpublish the previously published service metadata, unregister
+ * the <code>ServicePublication</code> service.<br>
+ * 
+ * Please note that providing the {@link #PROP_KEY_SERVICE_INTERFACE_NAME}
+ * property is mandatory when a <code>ServicePublication</code> service is
+ * registered. Note also that a Discovery implementation may require provision
+ * of additional properties, e.g. some of the standard properties defined below,
+ * or may make special use of them in case they are provided. For example an
+ * SLP-based Discovery might use the value provided with the
+ * {@link #PROP_KEY_ENDPOINT_LOCATION} property for construction of a SLP-URL
+ * used to publish the service.<br>
+ * 
+ * Also important is that it's not guaranteed that after registering a
+ * <code>ServicePublication</code> object its service metadata is actually
+ * published. Beside the fact that at least one Discovery service has to be
+ * present, the provided properties have to be valid, e.g. shouldn't contain
+ * case variants of the same key name, and the actual publication via Discovery
+ * mechanisms has to succeed.
+ * 
+ * @version $Revision: 6485 $
+ */
+public interface ServicePublication {
+
+	/**
+	 * Mandatory ServiceRegistration property which contains a collection of
+	 * full qualified interface names offered by the advertised service
+	 * endpoint. Value of this property is of type Collection (<? extends
+	 * String>).
+	 */
+	public static final String	PROP_KEY_SERVICE_INTERFACE_NAME		= "service.interface";
+
+	/**
+	 * Optional ServiceRegistration property which contains a collection of
+	 * interface names with their associated version attributes separated by
+	 * {@link #SEPARATOR} e.g. 'my.company.foo|1.3.5 my.company.zoo|2.3.5'. In
+	 * case no version has been provided for an interface, Discovery may use the
+	 * String-value of <code>org.osgi.framework.Version.emptyVersion</code>
+	 * constant. <br>
+	 * Value of this property is of type Collection (<? extends String>).
+	 */
+	public static final String	PROP_KEY_SERVICE_INTERFACE_VERSION	= "service.interface.version";
+
+	/**
+	 * Optional ServiceRegistration property which contains a collection of
+	 * interface names with their associated (non-Java) endpoint interface names
+	 * separated by {@link #SEPARATOR} e.g.:<br>
+	 * 'my.company.foo|MyWebService my.company.zoo|MyWebService'.<br>
+	 * This (non-Java) endpoint interface name is usually a communication
+	 * protocol specific interface, for instance a web service interface name.
+	 * Though this information is usually contained in accompanying properties
+	 * e.g. a wsdl file, Discovery usually doesn't read and interprets such
+	 * service meta-data. Providing this information explicitly, might allow
+	 * external non-Java applications find services based on this endpoint
+	 * interface.
+	 * 
+	 * Value of this property is of type Collection (<? extends String>).
+	 */
+	public static final String	PROP_KEY_ENDPOINT_INTERFACE_NAME	= "osgi.remote.endpoint.interface";
+
+	/**
+	 * Optional ServiceRegistration property which contains a map of properties
+	 * of the published service. <br>
+	 * Property keys are handled in a case insensitive manner (as OSGi Framework
+	 * does). <br>
+	 * Value of this property is of type <code>java.util.Map<code>.
+	 */
+	public static final String	PROP_KEY_SERVICE_PROPERTIES			= "service.properties";
+
+	/**
+	 * Optional property of the published service identifying its location.
+	 * Value of this property is of type <code>java.net.URL<code>.
+	 */
+	public static final String	PROP_KEY_ENDPOINT_LOCATION			= "osgi.remote.endpoint.location";
+
+	/**
+	 * Optional property of the published service uniquely identifying its
+	 * endpoint. Value of this property is of type <code>String<code>.
+	 */
+	public static final String	PROP_KEY_ENDPOINT_ID				= "osgi.remote.endpoint.id";
+
+	/**
+	 * Separator constant for association of interface-specific values with the
+	 * particular interface name. See also
+	 * {@link #PROP_KEY_SERVICE_INTERFACE_VERSION} and
+	 * {@link #PROP_KEY_ENDPOINT_INTERFACE_NAME} properties which describe such
+	 * interface-specific values.
+	 */
+	public static final String	SEPARATOR							= "|";
+}

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/AbstractClientHook.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/AbstractClientHook.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/AbstractClientHook.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/AbstractClientHook.java Fri Mar 20 14:14:26 2009
@@ -24,10 +24,13 @@
 import static org.osgi.service.discovery.DiscoveredServiceTracker.PROP_KEY_MATCH_CRITERIA_FILTERS;
 import static org.osgi.service.discovery.DiscoveredServiceTracker.PROP_KEY_MATCH_CRITERIA_INTERFACES;
 import static org.osgi.service.discovery.ServicePublication.PROP_KEY_ENDPOINT_ID;
+import static org.osgi.service.discovery.ServicePublication.PROP_KEY_SERVICE_INTERFACE_NAME;
+
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Dictionary;
+import java.util.Iterator;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
@@ -38,6 +41,8 @@
 import org.apache.cxf.dosgi.dsw.handlers.ConfigurationTypeHandler;
 import org.apache.cxf.dosgi.dsw.service.CxfDistributionProvider;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.discovery.DiscoveredServiceNotification;
@@ -52,8 +57,8 @@
     private DiscoveredServiceTracker tracker;
     private Dictionary trackerProperties = new Hashtable();
     private ServiceRegistration trackerRegistration;
-    private Map<String, ServiceEndpointDescription> discoveredServices =
-        new HashMap<String, ServiceEndpointDescription>();
+    private Map<String, ServiceRegistration> discoveredServices =
+        new HashMap<String, ServiceRegistration>();
 
     protected AbstractClientHook(BundleContext bc, CxfDistributionProvider dp) {
         super(bc, dp);
@@ -63,28 +68,40 @@
                                tracker,
                                trackerProperties);
     }
-    
-    protected void processClientDescriptions(BundleContext requestingContext, 
-                                             String interfaceName, 
-                                             String filter) {
         
-        lookupDiscoveryService(interfaceName, filter);
-    }
-    
-    protected void processServiceDescription(ServiceEndpointDescription sd,
-                                             BundleContext requestingContext, 
-                                             String interfaceName) {
+    protected void processNotification(DiscoveredServiceNotification notification,
+                                       BundleContext requestingContext) {
             
+        ServiceEndpointDescription sd = 
+            notification.getServiceEndpointDescription();
         if (sd.getProperty(Constants.REMOTE_INTERFACES_PROPERTY) == null) {
+            LOG.info("not proxifying service, enabling property unset: " 
+                     + Constants.REMOTE_INTERFACES_PROPERTY);
             return;
         }
             
         ConfigurationTypeHandler handler = 
             ServiceHookUtils.getHandler(getContext(), sd, getDistributionProvider(), getHandlerProperties());
         if (handler == null) {
+            LOG.info("not proxifying service, config type handler null");
             return;
         }
-            
+       
+        Collection<String> matchingInterfaces =
+            getMatchingInterfaces(notification, requestingContext);
+
+        for (String interfaceName : matchingInterfaces) {
+            proxifyMatchingInterface(interfaceName, sd, handler, requestingContext);
+        }
+
+    }
+    
+
+    private void proxifyMatchingInterface(String interfaceName,
+                                          ServiceEndpointDescription sd,
+                                          ConfigurationTypeHandler handler,
+                                          BundleContext requestingContext) {
+
         try {
             Class<?> iClass = getContext().getBundle().loadClass(interfaceName);
             if (iClass != null) {
@@ -99,19 +116,73 @@
                     actualContext = requestingContext;
                 }
 
-                synchronized(this) {
-                    if (cacheEndpointId(sd)) {
-                        actualContext.registerService(new String[]{interfaceName},
-                                                      new ClientServiceFactory(actualContext, iClass, sd, handler),
-                                                      new Hashtable<String, Object>(getProperties(sd)));
+                synchronized(discoveredServices) {
+                    if (unknownEndpointId(sd)) {
+                        ServiceRegistration proxyRegistration = 
+                            actualContext.registerService(interfaceName,
+                                                          new ClientServiceFactory(actualContext, iClass, sd, handler),
+                                                          new Hashtable<String, Object>(getProperties(sd)));
+                        cacheEndpointId(sd, proxyRegistration);
                     }
                 }
+            } else {
+                LOG.info("not proxifying service, cannot load interface class: "
+                + interfaceName);
             }
         } catch (ClassNotFoundException ex) {
             LOG.warning("No class can be found for " + interfaceName);
         }
     }
+
+    private Collection<String> getMatchingInterfaces(DiscoveredServiceNotification notification, BundleContext context) {
+      
+        Collection<String> matches = new ArrayList<String>();
+        Iterator interfaces = notification.getServiceEndpointDescription().getProvidedInterfaces().iterator();
+
+        while (interfaces.hasNext()) {
+            String currInterface = (String)interfaces.next();
+            boolean matched = false;
+            Iterator matchedInterfaces = 
+                notification.getInterfaces().iterator();
+            while (matchedInterfaces.hasNext() && !matched) {
+                matched = currInterface.equals(matchedInterfaces.next());
+                if (matched) {
+                    matches.add(currInterface);
+                }
+            }
+            Iterator matchedFilters =
+                notification.getFilters().iterator();
+            while (matchedFilters.hasNext() && !matched) {
+                String filterString = (String)matchedFilters.next();
+                try {
+                    Filter filter = context.createFilter(filterString);
+                    matched = 
+                        filter.match(getProperties(notification, currInterface));
+                } catch (InvalidSyntaxException ise) {
+                    LOG.warning("invalid filter syntax: " + filterString);
+                }
+                if (matched) {
+                    matches.add(currInterface);
+                }
+            }
+        }
+
+        return matches;
+    }
     
+    private Hashtable getProperties(DiscoveredServiceNotification notification,
+                                    String interfaceName) {
+        Hashtable ret = new Hashtable();
+        Map properties = notification.getServiceEndpointDescription().getProperties();
+        Iterator keys = notification.getServiceEndpointDescription().getPropertyKeys().iterator();
+        while (keys.hasNext()) {
+            String key = (String)keys.next();
+            ret.put(key, properties.get(key));
+        }
+        ret.put(PROP_KEY_SERVICE_INTERFACE_NAME, interfaceName);
+        return ret;
+    }
+
     @SuppressWarnings("unchecked")
     protected Map<String, Object> getProperties(ServiceEndpointDescription sd) {
         Map<String, Object> props = new HashMap<String, Object>();        
@@ -122,6 +193,8 @@
     }
 
     protected synchronized void lookupDiscoveryService(String interfaceName, String filterValue) {
+        LOG.info("lookup discovery service: interface: " + interfaceName
+                 + " filter: " + filterValue);
 
         if (interfaceName != null) {
             append(trackerProperties,
@@ -148,12 +221,14 @@
         existing.add(additional);
     }
 
-    private synchronized boolean cacheEndpointId(ServiceEndpointDescription notified) {
+    /**
+     * @pre called with discoveredServices mutex held
+     */
+    private boolean unknownEndpointId(ServiceEndpointDescription notified) {
         String endpointId = (String)notified.getProperty(PROP_KEY_ENDPOINT_ID);
         if (endpointId != null) {
             boolean duplicate = discoveredServices.containsKey(endpointId);
             if (!duplicate) {
-                discoveredServices.put(endpointId, notified);
                 LOG.info("registering proxy for endpoint ID: " + endpointId);
             } else {
                 LOG.warning("ignoring duplicate notification for endpoint ID: "
@@ -166,10 +241,31 @@
         }
     }
 
-    private synchronized void unCacheEndpointId(ServiceEndpointDescription notified) {
+    /**
+     * @pre called with discoveredServices mutex held
+     */
+    private void cacheEndpointId(ServiceEndpointDescription notified, ServiceRegistration registration) {
         String endpointId = (String)notified.getProperty(PROP_KEY_ENDPOINT_ID);
         if (endpointId != null) {
-            discoveredServices.remove(endpointId);
+            discoveredServices.put(endpointId, registration);
+            LOG.info("caching proxy registration for endpoint ID: " + endpointId);
+        } else {
+            LOG.warning("cannot cache proxy registration as endpoint ID unset");  
+        }
+    }
+
+    private void unCacheEndpointId(ServiceEndpointDescription notified) {
+        String endpointId = (String)notified.getProperty(PROP_KEY_ENDPOINT_ID);
+        ServiceRegistration proxyRegistration = null;
+        if (endpointId != null) {
+            synchronized (discoveredServices) {
+                proxyRegistration = discoveredServices.remove(endpointId);
+            }
+        }
+        if (proxyRegistration != null) {
+            LOG.info("unregistering proxy service for endpoint ID: "
+                     + endpointId);
+            proxyRegistration.unregister();
         }
     }
 
@@ -184,14 +280,7 @@
                          + notified.getProvidedInterfaces() 
                          + " endpoint id: " 
                          + notification.getServiceEndpointDescription().getProperty(PROP_KEY_ENDPOINT_ID));
-                // REVISIT: OSGi bug 1022 will allow the matching interface
-                // name to be gleaned from the notification, for now we just
-                // assume its the first interface exposed by the SED
-                String interfaceName =
-                    (String)notified.getProvidedInterfaces().toArray()[0];
-                processServiceDescription(notified,
-                                          getContext(),
-                                          interfaceName);
+                processNotification(notification, getContext());
                 break;
 
             case UNAVAILABLE:
@@ -200,8 +289,6 @@
                          + " endpoint id: " 
                          + notification.getServiceEndpointDescription().getProperty(PROP_KEY_ENDPOINT_ID));
                 unCacheEndpointId(notified);
-                // we don't currently use this notification, but we could do
-                // so to allow to drive transparent fail-over
                 break;
 
             case MODIFIED:

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHook.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHook.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHook.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHook.java Fri Mar 20 14:14:26 2009
@@ -31,6 +31,8 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.hooks.service.ListenerHook;
 
+import static org.osgi.service.discovery.ServicePublication.PROP_KEY_SERVICE_INTERFACE_NAME;
+
 public class CxfListenerHook extends AbstractClientHook implements ListenerHook {
 
     private static final Logger LOG = Logger.getLogger(CxfListenerHook.class.getName());
@@ -40,6 +42,8 @@
         ".*\\(" + Constants.OBJECTCLASS + "=([a-zA-Z_0-9.]+)\\).*";
     private final static Pattern CLASS_NAME_PATTERN = 
         Pattern.compile(CLASS_NAME_EXPRESSION);
+    private final static String CLASS_NAME_BASE =
+        "(" + Constants.OBJECTCLASS + "=";
     private static final Set<String> SYSTEM_PACKAGES;
     
     static {
@@ -50,6 +54,7 @@
         SYSTEM_PACKAGES.add("ch.ethz.iks.slp");
         SYSTEM_PACKAGES.add("org.ungoverned.osgi.service");
         SYSTEM_PACKAGES.add("org.springframework.osgi.context.event.OsgiBundleApplicationContextListener");
+        SYSTEM_PACKAGES.add("java.net.ContentHandler");
     }
     
     public CxfListenerHook(BundleContext bc, CxfDistributionProvider dp) {
@@ -68,44 +73,48 @@
         for (Iterator/*<? extends ListenerHook.ListenerInfo>*/ it = listeners.iterator(); it.hasNext(); ) {
             ListenerHook.ListenerInfo listener = (ListenerHook.ListenerInfo) it.next();
             
-            if (listener.getFilter() == null
-                    || listener.getBundleContext() == getContext()) {
-                    continue;
-                }
-                String className = getClassNameFromFilter(listener.getFilter());
-                if (!isClassSupported(className)) {
-                    continue;
-                }
+            String className = getClassNameFromFilter(listener.getFilter());
+
+            if (!(listener.getFilter() == null
+                  || listener.getBundleContext() == getContext()
+                  || isClassExcluded(className))) {
                 
-                processClientDescriptions(listener.getBundleContext(), 
-                                          className, 
-                                          listener.getFilter());            
+                if (onlyClassNameInFilter(className, listener.getFilter())) {
+                    lookupDiscoveryService(className, null);
+                } else {
+                    String filter = listener.getFilter().replaceAll("objectClass",
+                                                                    PROP_KEY_SERVICE_INTERFACE_NAME);
+                    lookupDiscoveryService(null, filter);
+                }
+            }
         }
     }
     
     private String getClassNameFromFilter(String filter) {
-        if (filter == null) {
-            return null;
-        }
-        Matcher matcher = CLASS_NAME_PATTERN.matcher(filter);
-        if (matcher.matches() && matcher.groupCount() >= 1) {
-            return matcher.group(1);
+        if (filter != null) {
+            Matcher matcher = CLASS_NAME_PATTERN.matcher(filter);
+            if (matcher.matches() && matcher.groupCount() >= 1) {
+                return matcher.group(1);
+            }
         }
-        
         return null;
     }
+
+    private boolean onlyClassNameInFilter(String className, String filter) {
+        return (CLASS_NAME_BASE + className + ")").equals(filter);
+    }
     
-    private static boolean isClassSupported(String className) {
+    private static boolean isClassExcluded(String className) {
         if (className == null) {
-            return false;
+            return true;
         }
         
         for (String p : SYSTEM_PACKAGES) {
             if (className.startsWith(p)) {
                 LOG.fine("Lookup for " + className + " is ignored");
-                return false;
+                return true;
             }
         }
-        return true;
+        return false;
     }
 }

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtils.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtils.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtils.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtils.java Fri Mar 20 14:14:26 2009
@@ -154,7 +154,7 @@
         props.put(PROP_KEY_SERVICE_PROPERTIES, getServiceProperties(sd));
         if (sd.getLocation() != null) {
             props.put(PROP_KEY_ENDPOINT_LOCATION, sd.getLocation());
-	}
+        }
         LOG.info("publication properties: " + props);
         return props;
     }

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java Fri Mar 20 14:14:26 2009
@@ -1,78 +1,102 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Interface for notification on discovered services.
- * 
- * @version $Revision$
- */
-public interface DiscoveredServiceNotification {
-
-	/**
-	 * Notification indicating that a service matching the listening criteria has been
-	 * discovered.
-	 * <p>
-	 * The value of <code>AVAILABLE</code> is 0x00000001.
-	 */
-	public final static int AVAILABLE = 0x00000001;
-
-	/**
-	 * Notification indicating that the properties of a previously discovered service
-	 * have changed.
-	 * <p>
-	 * The value of <code>MODIFIED</code> is 0x00000002.
-	 */
-	public final static int MODIFIED = 0x00000002;
-
-	/**
-	 * Notification indicating that a previously discovered service is no longer known
-	 * to discovery.
-	 * <p>
-	 * The value of <code>UNAVAILABLE</code> is 0x00000004.
-	 */
-	public final static int UNAVAILABLE = 0x00000004;
-
-	/**
-	 * Notification indicating that the properties of a previously discovered service
-	 * have changed and the new properties no longer match the listener's
-	 * filter.
-	 * <p>
-	 * The value of <code>MODIFIED_ENDMATCH</code> is 0x00000008.
-	 */
-	public final static int MODIFIED_ENDMATCH = 0x00000008;
-
-	/**
-	 * Returns information currently known to Discovery regarding the service
-	 * endpoint.
-	 * <p>
-	 * 
-	 * @return metadata of the service this Discovery notifies about.
-	 */
-	ServiceEndpointDescription getServiceEndpointDescription();
-
-	/**
-	 * Returns the type of notification. The type values are:
-	 * <ul>
-	 * <li>{@link #AVAILABLE} </li> <li>{@link #MODIFIED} </li> <li>
-	 * {@link #MODIFIED_ENDMATCH} </li> <li>{@link #UNAVAILABLE} </li>
-	 * </ul>
-	 * 
-	 * @return Type of notification regarding known service metadata.
-	 */
-	int getType();
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+import java.util.Collection;
+
+/**
+ * Interface for notification on discovered services.
+ * 
+ * @version $Revision: 6510 $
+ */
+public interface DiscoveredServiceNotification {
+
+	/**
+	 * Notification indicating that a service matching the listening criteria has been
+	 * discovered.
+	 * <p>
+	 * The value of <code>AVAILABLE</code> is 0x00000001.
+	 */
+	public final static int	AVAILABLE			= 0x00000001;
+
+	/**
+	 * Notification indicating that the properties of a previously discovered service
+	 * have changed.
+	 * <p>
+	 * The value of <code>MODIFIED</code> is 0x00000002.
+	 */
+	public final static int	MODIFIED			= 0x00000002;
+
+	/**
+	 * Notification indicating that a previously discovered service is no longer known
+	 * to discovery.
+	 * <p>
+	 * The value of <code>UNAVAILABLE</code> is 0x00000004.
+	 */
+	public final static int	UNAVAILABLE			= 0x00000004;
+
+	/**
+	 * Notification indicating that the properties of a previously discovered service
+	 * have changed and the new properties no longer match the listener's
+	 * filter.
+	 * <p>
+	 * The value of <code>MODIFIED_ENDMATCH</code> is 0x00000008.
+	 */
+	public final static int	MODIFIED_ENDMATCH	= 0x00000008;
+
+	/**
+	 * Returns information currently known to Discovery regarding the service
+	 * endpoint.
+	 * <p>
+	 * 
+	 * @return metadata of the service this Discovery notifies about.
+	 */
+	ServiceEndpointDescription getServiceEndpointDescription();
+
+	/**
+	 * Returns the type of notification. The type values are:
+	 * <ul>
+	 * <li>{@link #AVAILABLE}</li>
+	 * <li>{@link #MODIFIED}</li>
+	 * <li>{@link #MODIFIED_ENDMATCH}</li>
+	 * <li>{@link #UNAVAILABLE}</li>
+	 * </ul>
+	 * 
+	 * @return Type of notification regarding known service metadata.
+	 */
+	int getType();
+
+	/**
+	 * Returns interface name criteria of the {@link DiscoveredServiceTracker}
+	 * object matching with the interfaces of the ServiceEndpointDescription and
+	 * thus caused the notification.
+	 * 
+	 * @return matching interface name criteria of the
+	 *         {@link DiscoveredServiceTracker} object being notified.
+	 */
+	Collection/* <String> */getInterfaces();
+
+	/**
+	 * Returns filters of the {@link DiscoveredServiceTracker} object matching
+	 * with the ServiceEndpointDescription and thus caused the notification.
+	 * 
+	 * @return matching filters of the {@link DiscoveredServiceTracker} object
+	 *         being notified.
+	 */
+	Collection/* <String> */getFilters();
+}
+

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java Fri Mar 20 14:14:26 2009
@@ -1,62 +1,72 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Interface of trackers for discovered remote services. <br>
- * When such a service is registered with the framework, then {@link Discovery}
- * will notify it about remote services matching one of the provided criteria
- * and will keep notifying it on changes of information known to Discovery
- * regarding this services.
- * 
- * <code>Discovery</code> may deliver notifications on discovered services to a
- * <code>DiscoveredServiceTracker</code> out of order and may concurrently call
- * and/or reenter a <code>DiscoveredServiceTracker</code>.
- * 
- * @version $Revision$
- */
-public interface DiscoveredServiceTracker {
-
-	/**
-	 * Property describing service interfaces this tracker is interested in.
-	 * Value of this property is of type Collection (<? extends String>).<br>
-	 * Property is optional, may be null.
-	 */
-	public static final String PROP_KEY_MATCH_CRITERIA_INTERFACES = "osgi.discovery.interest.interfaces";
-
-	/**
-	 * Property describing filters for services this tracker is interested in.
-	 * Value of this property is of type Collection (<? extends String>). See
-	 * {@link ServicePublication} for some standard property keys used to
-	 * publish service metadata. <br>
-	 * Property is optional, may be null.
-	 */
-	public static final String PROP_KEY_MATCH_CRITERIA_FILTERS = "osgi.discovery.interest.filters";
-
-	/**
-	 * Receives notification that information known to Discovery regarding a
-	 * remote service has changed. <br>
-	 * The tracker is only notified about remote services which fulfill the
-	 * matching criteria, either one of the interfaces or one of the filters,
-	 * provided as properties of this service.
-	 * 
-	 * @param notification
-	 *            the <code>DiscoveredServiceNotification</code> object
-	 *            describing the change.
-	 */
-	void serviceChanged(DiscoveredServiceNotification notification);
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+/**
+ * Interface of trackers for discovered remote services. <br>
+ * When such a service is registered with the framework, then {@link Discovery}
+ * will notify it about remote services matching one of the provided criteria
+ * and will keep notifying it on changes of information known to Discovery
+ * regarding this services.
+ * 
+ * <code>Discovery</code> may deliver notifications on discovered services to a
+ * <code>DiscoveredServiceTracker</code> out of order and may concurrently call
+ * and/or reenter a <code>DiscoveredServiceTracker</code>.
+ * 
+ * @version $Revision: 6553 $
+ */
+public interface DiscoveredServiceTracker {
+
+	/**
+	 * Optional ServiceRegistration property which contains service interfaces
+	 * this tracker is interested in. Value of this property is of type
+	 * Collection (<? extends String>). <br>
+	 * Property is optional, may be null.
+	 */
+	public static final String	PROP_KEY_MATCH_CRITERIA_INTERFACES	= "osgi.discovery.interest.interfaces";
+
+	/**
+	 * Optional ServiceRegistration property which contains filters for services
+	 * this tracker is interested in. <br>
+	 * Note that these filters need to take into account service publication
+	 * properties which are not necessarily the same as properties under which a
+	 * service is registered. See {@link ServicePublication} for some standard
+	 * properties used to publish service metadata. <br>
+	 * The following sample filter will make Discovery notify the
+	 * DiscoveredServiceTracker about services providing interface
+	 * 'my.company.foo' of version '1.0.1.3':<br>
+	 * "(&amp;(service.interface=my.company.foo)(service.interface.version=my.company.foo|1.0.1.3))". <br>
+	 * Value of this property is of type Collection (&lt;? extends String%gt;).
+	 * Property is optional, may be null.
+	 */
+	public static final String	PROP_KEY_MATCH_CRITERIA_FILTERS		= "osgi.discovery.interest.filters";
+
+	/**
+	 * Receives notification that information known to Discovery regarding a
+	 * remote service has changed. <br>
+	 * The tracker is only notified about remote services which fulfill the
+	 * matching criteria, either one of the interfaces or one of the filters,
+	 * provided as properties of this service. <br>
+	 * If multiple criteria match, then the tracker is notified about each of
+	 * them. This can be done either by a single notification callback or by
+	 * multiple subsequent ones.
+	 * 
+	 * @param notification the <code>DiscoveredServiceNotification</code> object
+	 *        describing the change.
+	 */
+	void serviceChanged(DiscoveredServiceNotification notification);
+}

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/ServicePublication.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/ServicePublication.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/ServicePublication.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/main/java/org/osgi/service/discovery/ServicePublication.java Fri Mar 20 14:14:26 2009
@@ -1,109 +1,116 @@
-/*
- * Copyright (c) OSGi Alliance (2008). 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.discovery;
-
-/**
- * Register a service implementing the <code>ServicePublication</code> interface
- * in order to publish metadata of a particular service (endpoint) via
- * Discovery. Metadata which has to be published is given in form of properties
- * at registration. <br>
- * In order to update published service metadata, update the properties
- * registered with the <code>ServicePublication</code> service. Depending on
- * Discovery's implementation and underlying protocol it may result in an update
- * or new re-publication of the service. <br>
- * In order to unpublish the previously published service metadata, unregister
- * the <code>ServicePublication</code> service.<br>
- * 
- * Please note that providing the {@link #PROP_KEY_SERVICE_INTERFACE_NAME}
- * property is mandatory when a <code>ServicePublication</code> service is
- * registered.<br>
- * 
- * Also important is that it's not guaranteed that after registering a
- * <code>ServicePublication</code> object its service metadata is actually
- * published. Beside the fact that at least one Discovery service has to be
- * present, the provided properties have to be valid, e.g. shouldn't contain
- * case variants of the same key name, a supported publication strategy used and
- * the actual publication via Discovery mechanisms has to succeed.
- * 
- * @version $Revision$
- */
-public interface ServicePublication {
-
-	/**
-	 * Mandatory ServiceRegistration property which contains a collection of
-	 * full qualified interface names offered by the advertised service
-	 * endpoint. Value of this property is of type Collection (<? extends
-	 * String>).
-	 */
-	public static final String PROP_KEY_SERVICE_INTERFACE_NAME = "service.interface";
-
-	/**
-	 * Optional ServiceRegistration property which contains a collection of
-	 * interface names with their associated version attributes separated by
-	 * {@link #SEPARATOR} e.g. 'my.company.foo:1.3.5 my.company.zoo:2.3.5'. In
-	 * case no version has been provided for an interface, Discovery may use the
-	 * String-value of <code>org.osgi.framework.Version.emptyVersion</code>
-	 * constant. <br>
-	 * Value of this property is of type Collection (<? extends String>).
-	 */
-	public static final String PROP_KEY_SERVICE_INTERFACE_VERSION = "service.interface.version";
-
-	/**
-	 * Optional ServiceRegistration property which contains a collection of
-	 * interface names with their associated (non-Java) endpoint interface names
-	 * separated by {@link #SEPARATOR} e.g.:<br>
-	 * 'my.company.foo:MyWebService my.company.zoo:MyWebService'.<br>
-	 * This (non-Java) endpoint interface name is usually a communication
-	 * protocol specific interface, for instance a web service interface name.
-	 * Though this information is usually contained in accompanying properties
-	 * e.g. a wsdl file, Discovery usually doesn't read and interprets such
-	 * service meta-data. Providing this information explicitly, might allow
-	 * external non-Java applications find services based on this endpoint
-	 * interface.
-	 * 
-	 * Value of this property is of type Collection (<? extends String>).
-	 */
-	public static final String PROP_KEY_ENDPOINT_INTERFACE_NAME = "osgi.remote.endpoint.interface";
-
-	/**
-	 * Optional ServiceRegistration property which contains a map of properties
-	 * of the published service. <br>
-	 * Property keys are handled in a case insensitive manner (as OSGi Framework
-	 * does). Note that Discovery might make use of certain standard properties
-	 * e.g. defined by {@link ServiceEndpointDescription} for the publication
-	 * process if they are provided.<br>
-	 * Value of this property is of type <code>java.util.Map<code>.
-	 */
-	public static final String PROP_KEY_SERVICE_PROPERTIES = "service.properties";
-
-	/**
-	 * Optional property of the published service identifying its location.
-	 * Value of this property is of type <code>java.net.URL<code>.
-	 */
-	public static final String PROP_KEY_ENDPOINT_LOCATION = "osgi.remote.endpoint.location";
-
-	/**
-	 * Optional property of the published service uniquely identifying its
-	 * endpoint. Value of this property is of type <code>String<code>.
-	 */
-	public static final String PROP_KEY_ENDPOINT_ID = "osgi.remote.endpoint.id";
-
-	/**
-	 * Separator for key value pairs.
-	 */
-	public static final String SEPARATOR = ":";
-}
+/*
+ * Copyright (c) OSGi Alliance (2008). 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.discovery;
+
+/**
+ * Register a service implementing the <code>ServicePublication</code> interface
+ * in order to publish metadata of a particular service (endpoint) via
+ * Discovery. Metadata which has to be published is given in form of properties
+ * at registration. <br>
+ * In order to update published service metadata, update the properties
+ * registered with the <code>ServicePublication</code> service. Depending on
+ * Discovery's implementation and underlying protocol it may result in an update
+ * or new re-publication of the service. <br>
+ * In order to unpublish the previously published service metadata, unregister
+ * the <code>ServicePublication</code> service.<br>
+ * 
+ * Please note that providing the {@link #PROP_KEY_SERVICE_INTERFACE_NAME}
+ * property is mandatory when a <code>ServicePublication</code> service is
+ * registered. Note also that a Discovery implementation may require provision
+ * of additional properties, e.g. some of the standard properties defined below,
+ * or may make special use of them in case they are provided. For example an
+ * SLP-based Discovery might use the value provided with the
+ * {@link #PROP_KEY_ENDPOINT_LOCATION} property for construction of a SLP-URL
+ * used to publish the service.<br>
+ * 
+ * Also important is that it's not guaranteed that after registering a
+ * <code>ServicePublication</code> object its service metadata is actually
+ * published. Beside the fact that at least one Discovery service has to be
+ * present, the provided properties have to be valid, e.g. shouldn't contain
+ * case variants of the same key name, and the actual publication via Discovery
+ * mechanisms has to succeed.
+ * 
+ * @version $Revision: 6485 $
+ */
+public interface ServicePublication {
+
+	/**
+	 * Mandatory ServiceRegistration property which contains a collection of
+	 * full qualified interface names offered by the advertised service
+	 * endpoint. Value of this property is of type Collection (<? extends
+	 * String>).
+	 */
+	public static final String	PROP_KEY_SERVICE_INTERFACE_NAME		= "service.interface";
+
+	/**
+	 * Optional ServiceRegistration property which contains a collection of
+	 * interface names with their associated version attributes separated by
+	 * {@link #SEPARATOR} e.g. 'my.company.foo|1.3.5 my.company.zoo|2.3.5'. In
+	 * case no version has been provided for an interface, Discovery may use the
+	 * String-value of <code>org.osgi.framework.Version.emptyVersion</code>
+	 * constant. <br>
+	 * Value of this property is of type Collection (<? extends String>).
+	 */
+	public static final String	PROP_KEY_SERVICE_INTERFACE_VERSION	= "service.interface.version";
+
+	/**
+	 * Optional ServiceRegistration property which contains a collection of
+	 * interface names with their associated (non-Java) endpoint interface names
+	 * separated by {@link #SEPARATOR} e.g.:<br>
+	 * 'my.company.foo|MyWebService my.company.zoo|MyWebService'.<br>
+	 * This (non-Java) endpoint interface name is usually a communication
+	 * protocol specific interface, for instance a web service interface name.
+	 * Though this information is usually contained in accompanying properties
+	 * e.g. a wsdl file, Discovery usually doesn't read and interprets such
+	 * service meta-data. Providing this information explicitly, might allow
+	 * external non-Java applications find services based on this endpoint
+	 * interface.
+	 * 
+	 * Value of this property is of type Collection (<? extends String>).
+	 */
+	public static final String	PROP_KEY_ENDPOINT_INTERFACE_NAME	= "osgi.remote.endpoint.interface";
+
+	/**
+	 * Optional ServiceRegistration property which contains a map of properties
+	 * of the published service. <br>
+	 * Property keys are handled in a case insensitive manner (as OSGi Framework
+	 * does). <br>
+	 * Value of this property is of type <code>java.util.Map<code>.
+	 */
+	public static final String	PROP_KEY_SERVICE_PROPERTIES			= "service.properties";
+
+	/**
+	 * Optional property of the published service identifying its location.
+	 * Value of this property is of type <code>java.net.URL<code>.
+	 */
+	public static final String	PROP_KEY_ENDPOINT_LOCATION			= "osgi.remote.endpoint.location";
+
+	/**
+	 * Optional property of the published service uniquely identifying its
+	 * endpoint. Value of this property is of type <code>String<code>.
+	 */
+	public static final String	PROP_KEY_ENDPOINT_ID				= "osgi.remote.endpoint.id";
+
+	/**
+	 * Separator constant for association of interface-specific values with the
+	 * particular interface name. See also
+	 * {@link #PROP_KEY_SERVICE_INTERFACE_VERSION} and
+	 * {@link #PROP_KEY_ENDPOINT_INTERFACE_NAME} properties which describe such
+	 * interface-specific values.
+	 */
+	public static final String	SEPARATOR							= "|";
+}

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/BundleTestContext.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/BundleTestContext.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/BundleTestContext.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/BundleTestContext.java Fri Mar 20 14:14:26 2009
@@ -40,17 +40,21 @@
 public class BundleTestContext implements BundleContext {
 
     private Bundle bundle;
-    private Object serviceObject;
     private Map<String, ServiceReference> testReferences = new
         HashMap<String, ServiceReference>();
     private Map<String, ServiceRegistration> testRegistrations = new
         HashMap<String, ServiceRegistration>();
+    private Map<ServiceReference, Object> registeredServices = new
+        HashMap<ServiceReference, Object>();
+    private List<Object> registeredServiceList = new ArrayList<Object>();
     private Map<String, ServiceReference> registeredReferences = new
         HashMap<String, ServiceReference>();
     private Map<String, ServiceRegistration> registeredRegistrations = new
         HashMap<String, ServiceRegistration>();
     private Map<String, List<Dictionary>> registeredProperties = new
         HashMap<String, List<Dictionary>>();
+    private Map<String, Filter> filters = new HashMap<String, Filter>();
+
         
     public BundleTestContext(Bundle b) {
         bundle = b;
@@ -68,8 +72,8 @@
     public void addServiceListener(ServiceListener arg0, String arg1) throws InvalidSyntaxException {
     }
 
-    public Filter createFilter(String arg0) throws InvalidSyntaxException {
-        return null;
+    public Filter createFilter(String filterString) throws InvalidSyntaxException {
+        return filters.get(filterString);
     }
 
     public ServiceReference[] getAllServiceReferences(String arg0, String arg1) throws InvalidSyntaxException {
@@ -97,7 +101,7 @@
     }
 
     public Object getService(ServiceReference sref) {
-        return serviceObject;
+        return registeredServices.get(sref);
     }
 
     public ServiceReference getServiceReference(String name) {
@@ -120,17 +124,28 @@
     }
 
     public ServiceRegistration registerService(String[] names, Object service, Dictionary props) {
+
         for (String s : names) {
-            registeredReferences.put(s, testReferences.get(s));
+            registeredRegistrations.put(s, testRegistrations.get(s));
+            ServiceReference sref = testReferences.get(s);
+            registeredReferences.put(s, sref);
+            registeredServices.put(sref, service);
+            registeredServiceList.add(service);
+            cacheProperties(s, props);
         }
-        serviceObject = service;
-        return null;
+         
+        return testRegistrations.get(names[0]);
     }
 
     public ServiceRegistration registerService(String clz, Object obj, Dictionary props) {
-        registeredRegistrations.put(clz, testRegistrations.get(clz));
+        ServiceRegistration registration = testRegistrations.get(clz);
+        registeredRegistrations.put(clz, registration);
+        ServiceReference sref = testReferences.get(clz);
+        registeredReferences.put(clz, sref);
+        registeredServices.put(sref, obj);
+        registeredServiceList.add(obj);
         cacheProperties(clz, props);
-        return testRegistrations.get(clz);
+        return registration;
     }
 
     public void removeBundleListener(BundleListener arg0) {
@@ -154,6 +169,10 @@
     public void addServiceRegistration(String name, ServiceRegistration reg) {
         testRegistrations.put(name, reg);
     }
+
+    public void addFilter(String s, Filter filter) {
+        filters.put(s, filter);
+    }
     
     public Map<String, ServiceReference> getRegisteredReferences() {
         return registeredReferences;
@@ -163,6 +182,10 @@
         return registeredRegistrations;
     }
 
+    public List<Object> getRegisteredServices() {
+        return registeredServiceList;
+    }
+
     public Map<String, List<Dictionary>> getRegisteredProperties() {
         return registeredProperties;
     }

Modified: cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHookTest.java
URL: http://svn.apache.org/viewvc/cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHookTest.java?rev=756476&r1=756475&r2=756476&view=diff
==============================================================================
--- cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHookTest.java (original)
+++ cxf/dosgi/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfListenerHookTest.java Fri Mar 20 14:14:26 2009
@@ -18,14 +18,18 @@
   */
 package org.apache.cxf.dosgi.dsw.hooks;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.cxf.dosgi.dsw.service.CxfDistributionProvider;
+import org.apache.cxf.dosgi.dsw.service.ServiceEndpointDescriptionImpl;
 import org.easymock.classextension.EasyMock;
 import org.easymock.classextension.IMocksControl;
 import org.junit.Assert;
@@ -33,11 +37,18 @@
 import org.junit.Test;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.hooks.service.ListenerHook;
 
+import org.osgi.service.discovery.DiscoveredServiceNotification;
 import org.osgi.service.discovery.DiscoveredServiceTracker;
+import org.osgi.service.discovery.ServiceEndpointDescription;
+
+import static org.osgi.service.discovery.DiscoveredServiceNotification.AVAILABLE;
+import static org.osgi.service.discovery.DiscoveredServiceNotification.UNAVAILABLE;
+import static org.osgi.service.discovery.ServicePublication.PROP_KEY_SERVICE_INTERFACE_NAME;
 
 public class CxfListenerHookTest extends Assert {
 
@@ -89,38 +100,123 @@
         assertEquals(1, registeredRefs.size());        
     } */
     
-    //@Test
-    public void testListenerHook() throws Exception {
+    @Test
+    public void testTrackerPropertiesOnlyClassInFilterWithMatchingInterface() throws Exception {
+        String filter = "(objectClass=" + TestService.class.getName() + ")";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.interfaces",
+                                   TestService.class.getName(),
+                                   asList(TestService.class.getName()),
+                                   Collections.EMPTY_SET);
+    }
+
+    @Test
+    public void testTrackerPropertiesGenericFilterWithMatchingInterface() throws Exception {
+        String filter = "(&(objectClass=" + TestService.class.getName() 
+                        + ")(colour=blue))";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.filters",
+                                   replacePredicate(filter),
+                                   asList(TestService.class.getName()),
+                                   Collections.EMPTY_SET);
+    }
+
+    @Test
+    public void testTrackerPropertiesOnlyClassInFilterWithMatchingFilter() throws Exception {
+        String filter = "(objectClass=" + TestService.class.getName() + ")";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.interfaces",
+                                   TestService.class.getName(),
+                                   Collections.EMPTY_SET,
+                                   asList(replacePredicate(filter)));
+    }
+
+    @Test
+    public void testTrackerPropertiesGenericFilterWithMatchingFilter() throws Exception {
+        String filter = "(&(objectClass=" + TestService.class.getName() 
+                        + ")(colour=blue))";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.filters",
+				   replacePredicate(filter),
+                                   Collections.EMPTY_SET,
+                                   asList(replacePredicate(filter)));
+    }
+
+    @Test
+    public void testTrackerPropertiesOnlyClassInFilterWithMatchingBoth() throws Exception {
+        String filter = "(objectClass=" + TestService.class.getName() + ")";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.interfaces",
+                                   TestService.class.getName(),
+                                   asList(TestService.class.getName()),
+                                   asList(replacePredicate(filter)));
+    }
+
+    @Test
+    public void testTrackerPropertiesGenericFilterWithMatchingBoth() throws Exception {
+        String filter = "(&(objectClass=" + TestService.class.getName() 
+                        + ")(colour=blue))";
+        doTestTrackerPropertiesSet(filter,
+                                   "osgi.discovery.interest.filters",
+				   replacePredicate(filter),
+                                   Collections.EMPTY_SET,
+                                   asList(replacePredicate(filter)));
+    }
+
+    private void doTestTrackerPropertiesSet(final String filter,
+                                            String propKey,
+                                            String propValue,
+                                            Collection matchingInterfaces,
+                                            Collection matchingFilters) throws Exception {
         Bundle bundle = control.createMock(Bundle.class);
-        bundle.findEntries(EasyMock.eq("OSGI-INF/remote-service"), 
-            EasyMock.eq("*.xml"), EasyMock.anyBoolean());
-        EasyMock.expectLastCall().andReturn(Collections.enumeration(
-            Arrays.asList(getClass().getResource("/OSGI-INF/remote-service/remote-services.xml"))));
-        Dictionary<String, String> bundleHeaders = new Hashtable<String, String>();
+        Dictionary<String, String> bundleHeaders = 
+            new Hashtable<String, String>();
         bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_NAME, 
                           "Test Bundle");
         bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_VERSION, 
                           "1.0.0");
         bundle.getHeaders();
-        EasyMock.expectLastCall().andReturn(bundleHeaders).anyTimes();
+        EasyMock.expectLastCall().andReturn(bundleHeaders).times(2);
         final String serviceClass = TestService.class.getName();
         bundle.loadClass(serviceClass);
-        EasyMock.expectLastCall().andReturn(TestService.class).anyTimes();
-        final BundleContext requestingContext = control.createMock(BundleContext.class);
-        requestingContext.getBundle();
-        EasyMock.expectLastCall().andReturn(bundle).anyTimes();
+        EasyMock.expectLastCall().andReturn(TestService.class).times(2);
+        final BundleContext requestingContext = 
+            control.createMock(BundleContext.class);
         
         BundleTestContext dswContext = new BundleTestContext(bundle);
-	ServiceReference reference = control.createMock(ServiceReference.class);
-        dswContext.addServiceReference(serviceClass, reference);
+        ServiceRegistration serviceRegistration =
+            control.createMock(ServiceRegistration.class);
+        dswContext.addServiceRegistration(serviceClass, serviceRegistration);
+        serviceRegistration.unregister();
+        EasyMock.expectLastCall().times(1);
+        ServiceReference serviceReference = 
+            control.createMock(ServiceReference.class);
+        dswContext.addServiceReference(serviceClass, serviceReference);
 
         final String trackerClass = DiscoveredServiceTracker.class.getName();
-        ServiceRegistration registration =
+        ServiceRegistration trackerRegistration =
             control.createMock(ServiceRegistration.class);
-        dswContext.addServiceRegistration(trackerClass, registration);
-        registration.setProperties(EasyMock.isA(Dictionary.class));
+        dswContext.addServiceRegistration(trackerClass, trackerRegistration);
+        ServiceReference trackerReference = 
+            control.createMock(ServiceReference.class);
+        dswContext.addServiceReference(trackerClass, trackerReference);
+
+        List property = asList(propValue);
+        Dictionary properties = new Hashtable();
+        properties.put(propKey, property);
+        trackerRegistration.setProperties(properties);
         EasyMock.expectLastCall();
 
+        if (matchingInterfaces.size() == 0 && matchingFilters.size() > 0) {
+            Iterator filters = matchingFilters.iterator();
+            while (filters.hasNext()) {
+                Filter f = control.createMock(Filter.class);
+                dswContext.addFilter((String)filters.next(), f);
+                f.match(EasyMock.isA(Dictionary.class));
+                EasyMock.expectLastCall().andReturn(true);
+            }
+        } 
+
         control.replay();
      
         CxfListenerHook hook = new CxfListenerHook(dswContext, null);
@@ -131,24 +227,45 @@
             }
 
             public String getFilter() {
-                return "(objectClass=" + serviceClass + ")";
+                return filter;
             }            
         };
         hook.added(Collections.singleton(info));
+
+        DiscoveredServiceTracker tracker = (DiscoveredServiceTracker)
+            dswContext.getService(trackerReference);
+        assertNotNull(tracker);
+
+        Collection interfaces = asList(serviceClass);
+
+        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "1234");
+        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "5678");
+        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "1234");
         
+        notifyUnAvailable(tracker, "1234");
+        notifyUnAvailable(tracker, "5678");
+
+        notifyAvailable(tracker, matchingInterfaces, matchingFilters , "1234");
+
+        control.verify();
+
         Map<String, ServiceReference> registeredRefs = 
             dswContext.getRegisteredReferences();
         assertNotNull(registeredRefs);
-        assertEquals(1, registeredRefs.size());
+        assertEquals(2, registeredRefs.size());
         assertNotNull(registeredRefs.get(serviceClass));
-        assertSame(reference, registeredRefs.get(serviceClass));
+        assertSame(serviceReference, registeredRefs.get(serviceClass));
 
         Map<String, ServiceRegistration> registeredRegs = 
             dswContext.getRegisteredRegistrations();
         assertNotNull(registeredRegs);
-        assertEquals(1, registeredRegs.size());
+        assertEquals(2, registeredRegs.size());
         assertNotNull(registeredRegs.get(trackerClass));
-        assertSame(registration, registeredRegs.get(trackerClass));
+        assertSame(trackerRegistration, registeredRegs.get(trackerClass));
+
+        List<Object> registeredServices = dswContext.getRegisteredServices();
+        assertNotNull(registeredServices);
+        assertEquals(2, registeredServices.size());
     } 
 
     @Test
@@ -162,4 +279,74 @@
         assertSame(dp, clh.getDistributionProvider());
     }
 
+    private void notifyAvailable(DiscoveredServiceTracker tracker,
+                                 Collection interfaces,
+                                 Collection filters, 
+                                 String endpointId) {
+        Map<String, Object> props = new Hashtable<String, Object>();
+        props.put("osgi.remote.interfaces", "*");
+        props.put("osgi.remote.endpoint.id", endpointId);
+        tracker.serviceChanged(new Notification(AVAILABLE,
+                                                TestService.class.getName(),
+                                                interfaces,
+                                                filters, 
+                                                props));
+    }
+
+    private void notifyUnAvailable(DiscoveredServiceTracker tracker, 
+                                   String endpointId) {
+        Map<String, Object> props = new Hashtable<String, Object>();
+        props.put("osgi.remote.endpoint.id", endpointId);
+        tracker.serviceChanged(new Notification(UNAVAILABLE,
+                                                TestService.class.getName(),
+                                                Collections.EMPTY_SET,
+                                                Collections.EMPTY_SET,
+                                                props));
+    }
+
+    private List<String> asList(String s) {
+        List l = new ArrayList<String>();
+        l.add(s);
+        return l;
+    }
+
+    private String replacePredicate(String filter) {
+        return filter.replace("objectClass", "service.interface");
+    }
+
+    private class Notification implements DiscoveredServiceNotification {
+        private int type;
+        private ServiceEndpointDescription sed;
+        private Collection interfaces;
+        private Collection filters;
+
+        Notification(int type, 
+                     String interfaceName,
+                     Collection interfaces,
+                     Collection filters, 
+                     Map<String, Object> props) {
+            this.type = type;
+            this.sed = 
+                new ServiceEndpointDescriptionImpl(interfaceName, props);
+            this.interfaces = interfaces;
+            this.filters = filters;
+        }
+
+        public int getType() {
+            return type;
+        }
+
+        public ServiceEndpointDescription getServiceEndpointDescription() {
+            return sed;
+        }
+
+        public Collection getInterfaces() {
+            return interfaces; 
+        }
+
+        public Collection getFilters() {
+            return filters; 
+        }
+    }
+
 }