You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ui...@apache.org on 2014/03/23 20:59:01 UTC
svn commit: r1580585 - in /felix/sandbox/pderop/dependencymanager-prototype:
cnf/localrepo/ cnf/localrepo/org.mockito.mockito-all/ dm.it/src/dm/it/ dm/
dm/src/dm/impl/ dm/src/dm/impl/index/ dm/src/dm/impl/index/multiproperty/
dm/src/tracker/ dm/test/tr...
Author: uiterlix
Date: Sun Mar 23 19:59:00 2014
New Revision: 1580585
URL: http://svn.apache.org/r1580585
Log:
Added customizerSwapped support to ServiceTracker for use by ServiceDependency when a swap callback is specified.
Added:
felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/org.mockito.mockito-all/
felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/org.mockito.mockito-all/org.mockito.mockito-all-1.9.5.jar (with props)
felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/AspectServiceDependencyTest.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractCustomizerActionSet.java
felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/
felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/TrackedTest.java
Modified:
felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/index.xml
felix/sandbox/pderop/dependencymanager-prototype/dm/bnd.bnd
felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ServiceDependencyImpl.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/AbstractFactoryFilterIndex.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/multiproperty/MultiPropertyFilterIndex.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractTracked.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/BundleTracker.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTracker.java
felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTrackerCustomizer.java
Modified: felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/index.xml
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/index.xml?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
Binary files - no diff available.
Added: felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/org.mockito.mockito-all/org.mockito.mockito-all-1.9.5.jar
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/org.mockito.mockito-all/org.mockito.mockito-all-1.9.5.jar?rev=1580585&view=auto
==============================================================================
Binary file - no diff available.
Propchange: felix/sandbox/pderop/dependencymanager-prototype/cnf/localrepo/org.mockito.mockito-all/org.mockito.mockito-all-1.9.5.jar
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/AspectServiceDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/AspectServiceDependencyTest.java?rev=1580585&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/AspectServiceDependencyTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/AspectServiceDependencyTest.java Sun Mar 23 19:59:00 2014
@@ -0,0 +1,90 @@
+/*
+ * 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 dm.it;
+
+import dm.Component;
+import dm.DependencyManager;
+
+
+public class AspectServiceDependencyTest extends TestBase {
+ public void testServiceRegistrationAndConsumption() {
+ DependencyManager m = new DependencyManager(context);
+ // helper class that ensures certain steps get executed in sequence
+ Ensure e = new Ensure();
+ // create a service provider and consumer
+ Component sp = m.createComponent().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+ Component sc = m.createComponent().setImplementation(new ServiceConsumer(e)).add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true));
+ m.add(sp);
+ m.add(sc);
+ m.remove(sc);
+ m.remove(sp);
+
+ // TODO: Further implementation when aspect services have been implemented.
+
+ // ensure we executed all steps inside the component instance
+ e.step(4);
+ }
+
+ static interface ServiceInterface {
+ public void invoke();
+ }
+
+ static class ServiceProvider implements ServiceInterface {
+ private final Ensure m_ensure;
+ public ServiceProvider(Ensure e) {
+ m_ensure = e;
+ }
+ public void invoke() {
+ m_ensure.step(2);
+ }
+ }
+
+ static class ServiceConsumer {
+ private volatile ServiceInterface m_service;
+ private final Ensure m_ensure;
+
+ public ServiceConsumer(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void init() {
+ m_ensure.step(1);
+ m_service.invoke();
+ }
+
+ public void destroy() {
+ m_ensure.step(3);
+ }
+ }
+
+ static class ServiceConsumerCallbacks {
+ private final Ensure m_ensure;
+
+ public ServiceConsumerCallbacks(Ensure e) {
+ m_ensure = e;
+ }
+
+ public void add(ServiceInterface service) {
+ m_ensure.step(4);
+ }
+ public void remove(ServiceInterface service) {
+ m_ensure.step(5);
+ }
+ }
+}
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/bnd.bnd
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/bnd.bnd?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/bnd.bnd (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/bnd.bnd Sun Mar 23 19:59:00 2014
@@ -1,6 +1,6 @@
--buildpath: \
- osgi.cmpn,\
- osgi.core;version=4.2
+-buildpath: osgi.cmpn,\
+ osgi.core;version=4.2,\
+ org.mockito.mockito-all
Private-Package: \
dm.impl,\
dm.context,\
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ServiceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ServiceDependencyImpl.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ServiceDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/ServiceDependencyImpl.java Sun Mar 23 19:59:00 2014
@@ -25,6 +25,7 @@ import dm.context.Event;
public class ServiceDependencyImpl extends DependencyImpl<ServiceDependency> implements ServiceDependency, ServiceTrackerCustomizer {
protected volatile ServiceTracker m_tracker;
private final Logger m_logger;
+ protected String m_swap;
protected volatile Class<?> m_trackedServiceName;
private volatile String m_trackedServiceFilter;
private volatile String m_trackedServiceFilterUnmodified;
@@ -130,13 +131,13 @@ public class ServiceDependencyImpl exten
public ServiceDependency setCallbacks(Object instance, String added, String changed, String removed, String swapped) {
setCallbacks(instance, added, changed, removed);
- // TODO handle the swapped parameter
+ m_swap = swapped;
return this;
}
public ServiceDependency setCallbacks(String added, String changed, String removed, String swapped) {
setCallbacks(added, changed, removed);
- // TODO handle the swapped parameter
+ m_swap = swapped;
return this;
}
@@ -423,4 +424,17 @@ public class ServiceDependencyImpl exten
}
return m_defaultImplementationInstance;
}
+
+ @Override
+ public void swappedService(ServiceReference reference, Object service,
+ ServiceReference newReference, Object newService) {
+ System.out.println("### SWAPPED");
+ if (m_swap != null) {
+ // TODO: invoke swap callback
+ } else {
+ addedService(newReference, newService);
+ removedService(newReference, newService);
+ }
+ }
+
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/AbstractFactoryFilterIndex.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/AbstractFactoryFilterIndex.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/AbstractFactoryFilterIndex.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/AbstractFactoryFilterIndex.java Sun Mar 23 19:59:00 2014
@@ -49,6 +49,12 @@ public abstract class AbstractFactoryFil
remove(reference);
}
+ public void swappedService(ServiceReference reference, Object service,
+ ServiceReference newReference, Object newService) {
+ addedService(newReference, newService);
+ removedService(reference, service);
+ }
+
public void add(ServiceReference reference) {
Long sid = ServiceUtil.getServiceIdObject(reference);
synchronized (m_sidToServiceReferencesMap) {
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/multiproperty/MultiPropertyFilterIndex.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/multiproperty/MultiPropertyFilterIndex.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/multiproperty/MultiPropertyFilterIndex.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/index/multiproperty/MultiPropertyFilterIndex.java Sun Mar 23 19:59:00 2014
@@ -484,4 +484,11 @@ public class MultiPropertyFilterIndex im
sb.append("]");
return sb.toString();
}
+
+ @Override
+ public void swappedService(ServiceReference reference, Object service,
+ ServiceReference newReference, Object newService) {
+ addedService(newReference, newService);
+ removedService(reference, service);
+ }
}
Added: felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractCustomizerActionSet.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractCustomizerActionSet.java?rev=1580585&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractCustomizerActionSet.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractCustomizerActionSet.java Sun Mar 23 19:59:00 2014
@@ -0,0 +1,95 @@
+/*
+ * 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 tracker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbstractCustomizerActionSet {
+
+ enum Type { ADDED, MODIFIED, REMOVED };
+
+ final List<CustomizerAction> m_actions = new ArrayList<>();
+
+ public void addCustomizerAdded(Object item, Object related, Object object) {
+ m_actions.add(new CustomizerAction(Type.ADDED, item, related, object));
+ }
+
+ public void addCustomizerModified(Object item, Object related, Object object) {
+ m_actions.add(new CustomizerAction(Type.MODIFIED, item, related, object));
+ }
+
+ public void addCustomizerRemoved(Object item, Object related, Object object) {
+ m_actions.add(new CustomizerAction(Type.REMOVED, item, related, object));
+ }
+
+ public void appendActionSet(AbstractCustomizerActionSet actionSet) {
+ for (CustomizerAction action : actionSet.getActions()) {
+ m_actions.add(action);
+ }
+ }
+
+ abstract void execute();
+
+ public List<CustomizerAction> getActions() {
+ return m_actions;
+ }
+
+ @Override
+ public String toString() {
+ return "AbstractCustomizerActionSet [m_actions=" + m_actions + "]";
+ }
+
+ static class CustomizerAction {
+ private final Type m_type;
+ private final Object m_item;
+ private final Object m_related;
+ private final Object m_object;
+
+ public CustomizerAction(Type type, Object item, Object related, Object object) {
+ m_type = type;
+ m_item = item;
+ m_related = related;
+ m_object = object;
+ }
+
+ public Type getType() {
+ return m_type;
+ }
+
+ public Object getItem() {
+ return m_item;
+ }
+
+ public Object getRelated() {
+ return m_related;
+ }
+
+ public Object getObject() {
+ return m_object;
+ }
+
+ @Override
+ public String toString() {
+ return "CustomizerAction [m_type=" + m_type + ", m_item=" + m_item
+ + ", m_related=" + m_related + ", m_object=" + m_object
+ + "]";
+ }
+ }
+}
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractTracked.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractTracked.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractTracked.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/AbstractTracked.java Sun Mar 23 19:59:00 2014
@@ -184,7 +184,7 @@ abstract class AbstractTracked {
if (DEBUG) {
System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$
}
- trackAdding(item, null); /*
+ trackAdding(item, null).execute(); /*
* Begin tracking it. We call trackAdding
* since we have already put the item in the
* adding list.
@@ -199,17 +199,20 @@ abstract class AbstractTracked {
closed = true;
}
+ abstract AbstractCustomizerActionSet createCustomizerActionSet();
+
/**
* Begin to track an item.
*
* @param item Item to be tracked.
* @param related Action related object.
*/
- void track(final Object item, final Object related) {
+ AbstractCustomizerActionSet track(final Object item, final Object related) {
final Object object;
+ final AbstractCustomizerActionSet actionSet = createCustomizerActionSet();
synchronized (this) {
if (closed) {
- return;
+ return actionSet;
}
object = tracked.get(item);
if (object == null) { /* we are not tracking the item */
@@ -219,7 +222,7 @@ abstract class AbstractTracked {
System.out
.println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$
}
- return;
+ return actionSet;
}
adding.add(item); /* mark this item is being added */
}
@@ -233,16 +236,17 @@ abstract class AbstractTracked {
}
if (object == null) { /* we are not tracking the item */
- trackAdding(item, related);
+ actionSet.appendActionSet(trackAdding(item, related));
}
else {
/* Call customizer outside of synchronized region */
- customizerModified(item, related, object);
+ actionSet.addCustomizerModified(item, related, object);
/*
* If the customizer throws an unchecked exception, it is safe to
* let it propagate
*/
}
+ return actionSet;
}
/**
@@ -253,7 +257,8 @@ abstract class AbstractTracked {
* @param item Item to be tracked.
* @param related Action related object.
*/
- private void trackAdding(final Object item, final Object related) {
+ private AbstractCustomizerActionSet trackAdding(final Object item, final Object related) {
+ final AbstractCustomizerActionSet actionSet = createCustomizerActionSet();
if (DEBUG) {
System.out.println("AbstractTracked.trackAdding: " + item); //$NON-NLS-1$
}
@@ -287,7 +292,7 @@ abstract class AbstractTracked {
}
}
if (needToCallback) {
- customizerAdded(item, related, object);
+ actionSet.addCustomizerAdded(item, related, object);
}
}
/*
@@ -299,12 +304,13 @@ abstract class AbstractTracked {
.println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$
}
/* Call customizer outside of synchronized region */
- customizerRemoved(item, related, object);
+ actionSet.addCustomizerRemoved(item, related, object);
/*
* If the customizer throws an unchecked exception, it is safe to
* let it propagate
*/
}
+ return actionSet;
}
/**
@@ -313,7 +319,8 @@ abstract class AbstractTracked {
* @param item Item to be untracked.
* @param related Action related object.
*/
- void untrack(final Object item, final Object related) {
+ AbstractCustomizerActionSet untrack(final Object item, final Object related) {
+ AbstractCustomizerActionSet actionSet = createCustomizerActionSet();
final Object object;
synchronized (this) {
if (initial.remove(item)) { /*
@@ -324,7 +331,7 @@ abstract class AbstractTracked {
System.out
.println("AbstractTracked.untrack[removed from initial]: " + item); //$NON-NLS-1$
}
- return; /*
+ return actionSet; /*
* we have removed it from the list and it will not be
* processed
*/
@@ -338,7 +345,7 @@ abstract class AbstractTracked {
System.out
.println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$
}
- return; /*
+ return actionSet; /*
* in case the item is untracked while in the process of
* adding
*/
@@ -348,7 +355,7 @@ abstract class AbstractTracked {
* calling customizer callback
*/
if (object == null) { /* are we actually tracking the item */
- return;
+ return actionSet;
}
modified(); /* increment modification count */
}
@@ -356,11 +363,12 @@ abstract class AbstractTracked {
System.out.println("AbstractTracked.untrack[removed]: " + item); //$NON-NLS-1$
}
/* Call customizer outside of synchronized region */
- customizerRemoved(item, related, object);
+ actionSet.addCustomizerRemoved(item, related, object);
/*
* If the customizer throws an unchecked exception, it is safe to let it
* propagate
*/
+ return actionSet;
}
/**
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/BundleTracker.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/BundleTracker.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/BundleTracker.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/BundleTracker.java Sun Mar 23 19:59:00 2014
@@ -474,5 +474,32 @@ public class BundleTracker implements Bu
customizer.removedBundle((Bundle) item, (BundleEvent) related,
object);
}
+
+ @Override
+ AbstractCustomizerActionSet createCustomizerActionSet() {
+ return new AbstractCustomizerActionSet() {
+
+ @Override
+ public void addCustomizerAdded(Object item, Object related, Object object) {
+ customizerAdded(item, related, object);
+ }
+
+ @Override
+ public void addCustomizerModified(Object item, Object related,
+ Object object) {
+ customizerModified(item, related, object);
+ }
+ @Override
+ public void addCustomizerRemoved(Object item, Object related,
+ Object object) {
+ customizerRemoved(item, related, object);
+ }
+
+ @Override
+ void execute() {
+ // nothing to be done here, since this actionSet executes the actions immediately.
+ }
+ };
+ }
}
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTracker.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTracker.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTracker.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTracker.java Sun Mar 23 19:59:00 2014
@@ -20,6 +20,7 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -444,7 +445,7 @@ public class ServiceTracker implements S
}
if (references != null) {
for (int i = 0; i < references.length; i++) {
- outgoing.untrack(references[i], null);
+ outgoing.untrack(references[i], null).execute();
}
}
if (DEBUG) {
@@ -797,7 +798,7 @@ public class ServiceTracker implements S
if (t == null) { /* if ServiceTracker is not open */
return;
}
- t.untrack(reference, null);
+ t.untrack(reference, null).execute();
}
/**
@@ -1052,38 +1053,43 @@ public class ServiceTracker implements S
if (list == null) {
return;
}
- Map highestRankedServiceMap = new HashMap(); // <Long, RankedService>
- for (int i = 0; i < list.length; i++) {
- ServiceReference sr = (ServiceReference) list[i];
- if (sr != null) {
- Long serviceId = ServiceUtil.getServiceIdAsLong(sr);
- int ranking = ServiceUtil.getRanking(sr);
-
- RankedService rs = (RankedService) highestRankedServiceMap.get(serviceId);
- if (rs == null) {
- // the service did not exist yet in our map
- highestRankedServiceMap.put(serviceId, new RankedService(ranking, sr));
- }
- else if (ranking > rs.getRanking()) {
- // the service replaces a lower ranked one
- hide(rs.getServiceReference());
- rs.update(ranking, sr);
- }
- else {
- // the service does NOT replace a lower ranked one
- hide(sr);
+ if (m_trackAllAspects) {
+ // not hiding aspects
+ super.setInitial(list);
+ } else {
+ Map highestRankedServiceMap = new HashMap(); // <Long, RankedService>
+ for (int i = 0; i < list.length; i++) {
+ ServiceReference sr = (ServiceReference) list[i];
+ if (sr != null) {
+ Long serviceId = ServiceUtil.getServiceIdAsLong(sr);
+ int ranking = ServiceUtil.getRanking(sr);
+
+ RankedService rs = (RankedService) highestRankedServiceMap.get(serviceId);
+ if (rs == null) {
+ // the service did not exist yet in our map
+ highestRankedServiceMap.put(serviceId, new RankedService(ranking, sr));
+ }
+ else if (ranking > rs.getRanking()) {
+ // the service replaces a lower ranked one
+ hide(rs.getServiceReference());
+ rs.update(ranking, sr);
+ }
+ else {
+ // the service does NOT replace a lower ranked one
+ hide(sr);
+ }
}
- }
- }
- if (highestRankedServiceMap.size() > 0) {
- Object[] result = new Object[highestRankedServiceMap.size()];
- int index = 0;
- for(Iterator it = highestRankedServiceMap.entrySet().iterator(); it.hasNext(); ) {
- Entry entry = (Entry) it.next();
- result[index] = ((RankedService)entry.getValue()).getServiceReference();
- index++;
- }
- super.setInitial(result);
+ }
+ if (highestRankedServiceMap.size() > 0) {
+ Object[] result = new Object[highestRankedServiceMap.size()];
+ int index = 0;
+ for(Iterator it = highestRankedServiceMap.entrySet().iterator(); it.hasNext(); ) {
+ Entry entry = (Entry) it.next();
+ result[index] = ((RankedService)entry.getValue()).getServiceReference();
+ index++;
+ }
+ super.setInitial(result);
+ }
}
}
@@ -1123,7 +1129,7 @@ public class ServiceTracker implements S
case ServiceEvent.MODIFIED :
if (listenerFilter != null) { // service listener added with
// filter
- track(reference, event);
+ track(reference, event).execute();
/*
* If the customizer throws an unchecked exception, it
* is safe to let it propagate
@@ -1131,14 +1137,14 @@ public class ServiceTracker implements S
}
else { // service listener added without filter
if (filter.match(reference)) {
- track(reference, event);
+ track(reference, event).execute();
/*
* If the customizer throws an unchecked exception,
* it is safe to let it propagate
*/
}
else {
- untrack(reference, event);
+ untrack(reference, event).execute();
/*
* If the customizer throws an unchecked exception,
* it is safe to let it propagate
@@ -1148,7 +1154,7 @@ public class ServiceTracker implements S
break;
case 8 /* ServiceEvent.MODIFIED_ENDMATCH */ :
case ServiceEvent.UNREGISTERING :
- untrack(reference, event);
+ untrack(reference, event).execute();
/*
* If the customizer throws an unchecked exception, it is
* safe to let it propagate
@@ -1156,6 +1162,10 @@ public class ServiceTracker implements S
break;
}
}
+
+ private boolean isModifiedEndmatchSupported() {
+ return listenerFilter != null;
+ }
public void serviceChangedHideAspects(final ServiceEvent event) {
/*
@@ -1176,119 +1186,43 @@ public class ServiceTracker implements S
switch (event.getType()) {
case ServiceEvent.REGISTERED :
case ServiceEvent.MODIFIED :
- ServiceReference higher = null;
- ServiceReference lower = null;
- ServiceReference sr = highestTrackedCache(sid);
- if (sr != null) {
+ ServiceReference higherRankedReference = null;
+ ServiceReference lowerRankedReference = null;
+ ServiceReference highestTrackedReference = highestTrackedCache(sid);
+ if (highestTrackedReference != null) {
int ranking = ServiceUtil.getRanking(reference);
- int trackedRanking = ServiceUtil.getRanking(sr);
- if (ranking > trackedRanking) {
+ int highestTrackedRanking = ServiceUtil.getRanking(highestTrackedReference);
+ if (ranking > highestTrackedRanking) {
// found a higher ranked one!
if (DEBUG) {
- System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: Found a higher ranked aspect: " + ServiceUtil.toString(reference) + " vs " + ServiceUtil.toString(sr));
+ System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: Found a higher ranked aspect: " + ServiceUtil.toString(reference) + " vs " + ServiceUtil.toString(highestTrackedReference));
}
- higher = sr;
+ higherRankedReference = highestTrackedReference;
}
- else if (ranking < trackedRanking) {
+ else if (ranking < highestTrackedRanking) {
// found lower ranked one!
if (DEBUG) {
- System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: Found a lower ranked aspect: " + ServiceUtil.toString(reference) + " vs " + ServiceUtil.toString(sr));
+ System.out.println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: Found a lower ranked aspect: " + ServiceUtil.toString(reference) + " vs " + ServiceUtil.toString(highestTrackedReference));
}
- lower = sr;
+ lowerRankedReference = highestTrackedReference;
}
}
- if (listenerFilter != null) { // service listener added with filter
- if (lower != null) {
- hide(reference);
- }
- else {
- try {
- track(reference, event);
- }
- finally {
- if (higher != null) {
- try {
- untrack(higher, null);
- }
- finally {
- hide(higher);
- }
- }
- }
- }
- /*
- * If the customizer throws an unchecked exception, it
- * is safe to let it propagate
- */
+ if (isModifiedEndmatchSupported()) { // either registered or modified
+ registerOrUpdate(event, reference, higherRankedReference, lowerRankedReference);
}
else { // service listener added without filter
if (filter.match(reference)) {
- if (lower != null) {
- hide(reference);
- }
- else {
- try {
- track(reference, event);
- }
- finally {
- if (higher != null) {
- try {
- untrack(higher, null);
- }
- finally {
- hide(higher);
- }
- }
- }
- }
- /*
- * If the customizer throws an unchecked exception,
- * it is safe to let it propagate
- */
+ registerOrUpdate(event, reference, higherRankedReference, lowerRankedReference);
}
else {
- ServiceReference ht = highestTrackedCache(sid);
- if (reference.equals(ht)) {
- try {
- ServiceReference hh = highestHiddenCache(sid);
- if (hh != null) {
- unhide(hh);
- track(hh, null);
- }
- }
- finally {
- untrack(reference, event);
- }
- }
- else {
- unhide(reference);
- }
- /*
- * If the customizer throws an unchecked exception,
- * it is safe to let it propagate
- */
+ unregister(event, reference, sid);
}
}
break;
- case 8 /* ServiceEvent.MODIFIED_ENDMATCH */ :
+ case 8 /* ServiceEvent.MODIFIED_ENDMATCH */ : // handle as unregister
case ServiceEvent.UNREGISTERING :
- ServiceReference ht = highestTrackedCache(sid);
- if (reference.equals(ht)) {
- try {
- ServiceReference hh = highestHiddenCache(sid);
- if (hh != null) {
- unhide(hh);
- track(hh, null);
- }
- }
- finally {
- untrack(reference, event);
- }
- }
- else {
- unhide(reference);
- }
+ unregister(event, reference, sid);
/*
* If the customizer throws an unchecked exception, it is
* safe to let it propagate
@@ -1297,6 +1231,50 @@ public class ServiceTracker implements S
}
}
+ private void registerOrUpdate(final ServiceEvent event,
+ final ServiceReference reference, ServiceReference higher,
+ ServiceReference lower) {
+ if (lower != null) {
+ hide(reference);
+ }
+ else {
+ AbstractCustomizerActionSet actionSet = track(reference, event);
+ if (higher != null) {
+ actionSet.appendActionSet(untrack(higher, null));
+ hide(higher);
+ }
+ actionSet.execute();
+ }
+ /*
+ * If the customizer throws an unchecked exception, it
+ * is safe to let it propagate
+ */
+ }
+
+ private void unregister(final ServiceEvent event,
+ final ServiceReference reference, long sid) {
+ ServiceReference ht = highestTrackedCache(sid);
+ if (reference.equals(ht)) {
+ ServiceReference hh = highestHiddenCache(sid);
+ AbstractCustomizerActionSet actionSet = null;
+ if (hh != null) {
+ unhide(hh);
+ actionSet = track(hh, null);
+ }
+ if (actionSet == null) {
+ actionSet = untrack(reference, event);
+ } else {
+ actionSet.appendActionSet(untrack(reference, event));
+ }
+ actionSet.execute();
+ }
+ else {
+ unhide(reference);
+ }
+ }
+
+
+
/**
* Increment the tracking count and tell the tracker there was a
* modification.
@@ -1352,7 +1330,7 @@ public class ServiceTracker implements S
customizer.removedService((ServiceReference) item, object);
}
- class HashMapCache extends HashMap {
+ class HashMapCache extends LinkedHashMap {
public Object put(Object key, Object value) {
addHighestTrackedCache((ServiceReference) key);
return super.put(key, value);
@@ -1376,6 +1354,44 @@ public class ServiceTracker implements S
super.clear();
}
}
+
+ @Override
+ AbstractCustomizerActionSet createCustomizerActionSet() {
+ // This actions set deliberately postpones invocation of the customizer methods to be able to combine added and removed
+ // into a single swap call.
+ return new AbstractCustomizerActionSet() {
+ @Override
+ void execute() {
+ // inspect the actions and check whether we should perform a swap
+ List<CustomizerAction> actions = getActions();
+ if (actions.size() == 2 && actions.get(0).getType() == Type.ADDED && actions.get(1).getType() == Type.REMOVED) {
+ // ignore related
+ // item = ServiceReference
+ // object = service
+ customizer.swappedService((ServiceReference)actions.get(1).getItem(), actions.get(1).getObject(), (ServiceReference)actions.get(0).getItem(), actions.get(0).getObject());
+ } else {
+ // just sequentially call the customizer methods
+ for (CustomizerAction action : getActions()) {
+ try {
+ switch (action.getType()) {
+ case ADDED:
+ customizerAdded(action.getItem(), action.getRelated(), action.getObject());
+ break;
+ case MODIFIED:
+ customizerModified(action.getItem(), action.getRelated(), action.getObject());
+ break;
+ case REMOVED:
+ customizerRemoved(action.getItem(), action.getRelated(), action.getObject());
+ }
+ } catch (Exception e) {
+ // just continue. log messages will be printed elsewhere.
+ }
+ }
+ }
+ }
+ };
+ }
+
}
/**
@@ -1420,4 +1436,15 @@ public class ServiceTracker implements S
return m_serviceReference;
}
}
+
+ @Override
+ public void swappedService(ServiceReference reference, Object service,
+ ServiceReference newReference, Object newService) {
+
+ }
+
+ // Package private, used for unit testing Tracked
+ Tracked getTracked() {
+ return tracked;
+ }
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTrackerCustomizer.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTrackerCustomizer.java?rev=1580585&r1=1580584&r2=1580585&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTrackerCustomizer.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/tracker/ServiceTrackerCustomizer.java Sun Mar 23 19:59:00 2014
@@ -81,6 +81,25 @@ public interface ServiceTrackerCustomize
* @param service The service object for the specified referenced service.
*/
public void modifiedService(ServiceReference reference, Object service);
+
+ /**
+ * A service tracked by the <code>ServiceTracker</code> has an aspect service
+ * added or removed for a tracked service.
+ *
+ * <p>
+ * This method is called when an aspect service has been either added or removed
+ * for a tracked service. This method will only be called when there's a new
+ * highest ranked service as result of adding or removal of the aspect service.
+ * In this case the previously highest ranked service is 'swapped' for the new
+ * highest ranked service ensuring the client always gets the highest ranked
+ * aspect.
+ *
+ * @param reference The reference for the old highest ranked service.
+ * @param service The service object for the old highest ranked service.
+ * @param newReference The reference to the new highest ranked service.
+ * @param newService The service object for the new highest ranked service.
+ */
+ public void swappedService(ServiceReference reference, Object service, ServiceReference newReference, Object newService);
/**
* A service tracked by the <code>ServiceTracker</code> has been removed.
Added: felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/TrackedTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/TrackedTest.java?rev=1580585&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/TrackedTest.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/test/tracker/TrackedTest.java Sun Mar 23 19:59:00 2014
@@ -0,0 +1,290 @@
+package tracker;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+
+import tracker.ServiceTracker.Tracked;
+import dm.DependencyManager;
+
+public class TrackedTest {
+
+ @Test
+ public void testSetInitialHideAspects() {
+ System.out.println("testSetInitialHideAspects");
+ TestCustomizer customizer = new TestCustomizer();
+
+ ServiceTracker tracker = new TestTracker(customizer);
+ tracker.open();
+ Tracked tracked = tracker.getTracked();
+
+ Object[] initialReferences = new Object[] {
+ createServiceReference(1L),
+ createServiceReference(2L, 1L, 10),
+ createServiceReference(3L),
+ createServiceReference(4L, 1L, 5),
+ createServiceReference(5L, 3L, 5),
+ };
+ tracked.setInitial(initialReferences);
+ tracked.trackInitial();
+ assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
+ }
+
+ @Test
+ public void testUnHideAspect() {
+ System.out.println("testUnhideAspect");
+ TestCustomizer customizer = new TestCustomizer();
+
+ ServiceTracker tracker = new TestTracker(customizer);
+ tracker.open();
+ Tracked tracked = tracker.getTracked();
+
+ ServiceReference[] initialReferences = new ServiceReference[] {
+ createServiceReference(1L),
+ createServiceReference(2L, 1L, 10),
+ createServiceReference(3L),
+ createServiceReference(4L, 1L, 5),
+ createServiceReference(5L, 3L, 5),
+ };
+ tracked.setInitial(initialReferences);
+ tracked.trackInitial();
+ assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
+
+ // create a service event that unregisters service with id 2, we would expect it to be swapped with 4.
+ ServiceEvent event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[1]);
+ tracked.serviceChanged(event);
+ assertArrayEquals(new Long[] { 5L, 4L }, customizer.getServiceReferenceIds());
+ // create a service event that unregisters service with id 4, we would expect it to be swapped with 1.
+ event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[3]);
+ tracked.serviceChanged(event);
+ assertArrayEquals(new Long[] { 5L, 1L }, customizer.getServiceReferenceIds());
+ }
+
+ @Test
+ public void testHideAspect() {
+ System.out.println("testHideAspect");
+ TestCustomizer customizer = new TestCustomizer();
+
+ ServiceTracker tracker = new TestTracker(customizer);
+ tracker.open();
+ Tracked tracked = tracker.getTracked();
+
+ ServiceReference[] initialReferences = new ServiceReference[] {
+ createServiceReference(1L),
+ createServiceReference(2L, 1L, 10),
+ createServiceReference(3L),
+ createServiceReference(4L, 1L, 5),
+ createServiceReference(5L, 3L, 5),
+ };
+ tracked.setInitial(initialReferences);
+ tracked.trackInitial();
+ assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
+
+ // create a service event that registers another but lower ranked aspect for service with id 1.
+ ServiceReference newReference = createServiceReference(6L, 1L, 8);
+ ServiceEvent event = new ServiceEvent(ServiceEvent.REGISTERED, newReference);
+ tracked.serviceChanged(event);
+ assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
+
+ // create a service event that unregisters service with id 2, we would expect it to be swapped with 6.
+ event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[1]);
+ tracked.serviceChanged(event);
+ assertArrayEquals(new Long[] { 5L, 6L }, customizer.getServiceReferenceIds());
+
+ // create a service event that unregisters service with id 6, we would expect it to be swapped with 4.
+ event = new ServiceEvent(ServiceEvent.UNREGISTERING, newReference);
+ tracked.serviceChanged(event);
+ assertArrayEquals(new Long[] { 5L, 4L }, customizer.getServiceReferenceIds());
+
+ // create a service event that registers a higher ranked aspect for service with id 1.
+ ServiceReference higherRankedReference = createServiceReference(7L, 1L, 15);
+ ServiceEvent addHigherRankedEvent = new ServiceEvent(ServiceEvent.REGISTERED, higherRankedReference);
+ tracked.serviceChanged(addHigherRankedEvent);
+ assertArrayEquals(new Long[] { 5L, 7L }, customizer.getServiceReferenceIds());
+ }
+
+ @Test
+ public void testSetInitialTrackAspects() {
+ System.out.println("testSetInitialTrackAspects");
+ TestCustomizer customizer = new TestCustomizer();
+
+ ServiceTracker tracker = new TestTracker(customizer);
+ tracker.open(false, true);
+ Tracked tracked = tracker.getTracked();
+
+ Object[] initialReferences = new Object[] {
+ createServiceReference(1L),
+ createServiceReference(2L, 1L, 10),
+ createServiceReference(3L, 1L, 5)
+ };
+ tracked.setInitial(initialReferences);
+ tracked.trackInitial();
+ assertArrayEquals(new Long[] { 1L, 2L, 3L }, customizer.getServiceReferenceIds());
+ }
+
+ private static BundleContext createBundleContext() {
+ BundleContext context = mock(BundleContext.class);
+ when(context.getProperty(Constants.FRAMEWORK_VERSION)).thenReturn(null);
+ return context;
+ }
+
+ private ServiceReference createServiceReference(Long serviceId) {
+ return createServiceReference(serviceId, null, null);
+ }
+
+ private ServiceReference createServiceReference(Long serviceId, Long aspectId, Integer ranking) {
+ return new TestServiceReference(serviceId, aspectId, ranking);
+ }
+
+ class TestTracker extends ServiceTracker {
+
+ public TestTracker(ServiceTrackerCustomizer customizer) {
+ super(createBundleContext(), "(objectClass=*)", customizer);
+ }
+
+ }
+
+ class TestCustomizer implements ServiceTrackerCustomizer {
+
+ List<ServiceReference> serviceReferences = new ArrayList<>();
+
+ @Override
+ public Object addingService(ServiceReference reference) {
+ System.out.println("adding service: " + reference);
+ return new Object();
+ }
+
+ @Override
+ public void addedService(ServiceReference reference, Object service) {
+ System.out.println("added service: " + reference);
+ serviceReferences.add(reference);
+ }
+
+ @Override
+ public void modifiedService(ServiceReference reference, Object service) {
+ System.out.println("modified service: " + reference);
+ }
+
+ @Override
+ public void swappedService(ServiceReference reference, Object service,
+ ServiceReference newReference, Object newService) {
+ System.out.println("swapped service: " + reference);
+ serviceReferences.remove(reference);
+ serviceReferences.add(newReference);
+ }
+
+ @Override
+ public void removedService(ServiceReference reference, Object service) {
+ System.out.println("removed service: " + reference);
+ serviceReferences.remove(reference);
+ }
+
+ public Long[] getServiceReferenceIds() {
+ Long[] ids = new Long[serviceReferences.size()];
+ for (int i = 0; i < serviceReferences.size(); i++) {
+ ids[i] = (Long) serviceReferences.get(i).getProperty(Constants.SERVICE_ID);
+ }
+ return ids;
+ }
+
+ }
+
+ class TestServiceReference implements ServiceReference {
+
+ Properties props = new Properties();
+
+ public TestServiceReference(Long serviceId, Long aspectId,
+ Integer ranking) {
+ props.put(Constants.SERVICE_ID, serviceId);
+ if (aspectId != null) {
+ props.put(DependencyManager.ASPECT, aspectId);
+ }
+ if (ranking != null) {
+ props.put(Constants.SERVICE_RANKING, ranking);
+ }
+ }
+
+ @Override
+ public Object getProperty(String key) {
+ return props.get(key);
+ }
+
+ @Override
+ public String[] getPropertyKeys() {
+ return props.keySet().toArray(new String[]{});
+ }
+
+ @Override
+ public Bundle getBundle() {
+ return null;
+ }
+
+ @Override
+ public Bundle[] getUsingBundles() {
+ return null;
+ }
+
+ @Override
+ public boolean isAssignableTo(Bundle bundle, String className) {
+ return false;
+ }
+
+ @Override
+ public int compareTo(Object reference) // Kindly borrowed from the Apache Felix ServiceRegistrationImpl.ServiceReferenceImpl
+ {
+ ServiceReference other = (ServiceReference) reference;
+
+ Long id = (Long) getProperty(Constants.SERVICE_ID);
+ Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);
+
+ if (id.equals(otherId))
+ {
+ return 0; // same service
+ }
+
+ Object rankObj = getProperty(Constants.SERVICE_RANKING);
+ Object otherRankObj = other.getProperty(Constants.SERVICE_RANKING);
+
+ // If no rank, then spec says it defaults to zero.
+ rankObj = (rankObj == null) ? new Integer(0) : rankObj;
+ otherRankObj = (otherRankObj == null) ? new Integer(0) : otherRankObj;
+
+ // If rank is not Integer, then spec says it defaults to zero.
+ Integer rank = (rankObj instanceof Integer)
+ ? (Integer) rankObj : new Integer(0);
+ Integer otherRank = (otherRankObj instanceof Integer)
+ ? (Integer) otherRankObj : new Integer(0);
+
+ // Sort by rank in ascending order.
+ if (rank.compareTo(otherRank) < 0)
+ {
+ return -1; // lower rank
+ }
+ else if (rank.compareTo(otherRank) > 0)
+ {
+ return 1; // higher rank
+ }
+
+ // If ranks are equal, then sort by service id in descending order.
+ return (id.compareTo(otherId) < 0) ? 1 : -1;
+ }
+
+ @Override
+ public String toString() {
+ return "TestServiceReference [props=" + props + "]";
+ }
+
+ }
+
+}