You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2013/08/01 14:34:19 UTC
svn commit: r1509205 - in
/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container:
AbstractServiceReferenceRecipe.java AbstractTracked.java
ReferenceListRecipe.java ReferenceRecipe.java
Author: gnodet
Date: Thu Aug 1 12:34:18 2013
New Revision: 1509205
URL: http://svn.apache.org/r1509205
Log:
[ARIES-896] Attempt at another fix for deadlock in references
Added:
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractTracked.java
Modified:
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java
aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java
Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java?rev=1509205&r1=1509204&r2=1509205&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractServiceReferenceRecipe.java Thu Aug 1 12:34:18 2013
@@ -26,11 +26,11 @@ import java.security.Permission;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -85,14 +85,14 @@ public abstract class AbstractServiceRef
/** The list of listeners for this reference. This list will be lazy created */
protected List<Listener> listeners;
- protected final Object monitor = new Object();
- private final List<ServiceReference> references = new ArrayList<ServiceReference>();
private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean satisfied = new AtomicBoolean();
private SatisfactionListener satisfactionListener;
private final AccessControlContext accessControlContext;
+ private final Tracked tracked = new Tracked();
+
protected AbstractServiceReferenceRecipe(String name,
ExtendedBlueprintContainer blueprintContainer,
ServiceReferenceMetadata metadata,
@@ -125,7 +125,6 @@ public abstract class AbstractServiceRef
return listenersRecipe;
}
- static boolean waited = false;
public void start(SatisfactionListener listener) {
if (listener == null) throw new NullPointerException("satisfactionListener is null");
if (started.compareAndSet(false, true)) {
@@ -134,18 +133,15 @@ public abstract class AbstractServiceRef
satisfied.set(optional);
// Synchronized block on references so that service events won't interfere with initial references tracking
// though this may not be sufficient because we don't control ordering of those events
- synchronized (monitor) {
+ synchronized (tracked) {
getBundleContextForServiceLookup().addServiceListener(this, getOsgiFilter());
ServiceReference[] references = getBundleContextForServiceLookup().getServiceReferences(null, getOsgiFilter());
- if (references != null) {
- for (ServiceReference reference : references) {
- this.references.add(reference);
- track(reference);
- }
- satisfied.set(optional || !this.references.isEmpty());
- }
- LOGGER.debug("Found initial references {} for OSGi service {}", references, getOsgiFilter());
+ tracked.setInitial(references != null ? references : new ServiceReference[0]);
}
+ tracked.trackInitial();
+ satisfied.set(optional || !tracked.isEmpty());
+ retrack();
+ LOGGER.debug("Found initial references {} for OSGi service {}", getServiceReferences(), getOsgiFilter());
} catch (InvalidSyntaxException e) {
throw new ComponentDefinitionException(e);
}
@@ -154,20 +150,17 @@ public abstract class AbstractServiceRef
public void stop() {
if (started.compareAndSet(true, false)) {
- synchronized (monitor) {
- try {
- getBundleContextForServiceLookup().removeServiceListener(this);
- } catch (IllegalStateException e) {
- // Ignore in case bundle context is already invalidated
- }
- doStop();
- for (Iterator<ServiceReference> it = references.iterator(); it.hasNext();) {
- ServiceReference ref = it.next();
- it.remove();
- untrack(ref);
- }
- satisfied.set(false);
+ tracked.close();
+ try {
+ getBundleContextForServiceLookup().removeServiceListener(this);
+ } catch (IllegalStateException e) {
+ // Ignore in case bundle context is already invalidated
}
+ doStop();
+ for (ServiceReference ref : getServiceReferences()) {
+ untrack(ref);
+ }
+ satisfied.set(false);
satisfactionListener = null;
}
}
@@ -350,56 +343,49 @@ public abstract class AbstractServiceRef
ServiceReference ref = event.getServiceReference();
switch (eventType) {
case ServiceEvent.REGISTERED:
- serviceAdded(ref);
+ serviceAdded(ref, event);
break;
case ServiceEvent.MODIFIED:
- serviceModified(ref);
+ serviceModified(ref, event);
break;
case ServiceEvent.UNREGISTERING:
- serviceRemoved(ref);
+ serviceRemoved(ref, event);
break;
}
}
- private void serviceAdded(ServiceReference ref) {
+ private void serviceAdded(ServiceReference ref, ServiceEvent event) {
LOGGER.debug("Tracking reference {} for OSGi service {}", ref, getOsgiFilter());
if (isStarted()) {
- synchronized (monitor) {
- if (references.contains(ref)) {
- return;
- }
- references.add(ref);
+ tracked.track(ref, event);
+ boolean satisfied;
+ synchronized (tracked) {
+ satisfied = optional || !tracked.isEmpty();
}
+ setSatisfied(satisfied);
track(ref);
- setSatisfied(true);
}
}
- private void serviceModified(ServiceReference ref) {
+ private void serviceModified(ServiceReference ref, ServiceEvent event) {
// ref must be in references and must be satisfied
if (isStarted()) {
- synchronized (monitor) {
- if (references.contains(ref)) {
- track(ref);
- }
- }
+ tracked.track(ref, event);
+ track(ref);
}
}
- private void serviceRemoved(ServiceReference ref) {
+ private void serviceRemoved(ServiceReference ref, ServiceEvent event) {
if (isStarted()) {
LOGGER.debug("Untracking reference {} for OSGi service {}", ref, getOsgiFilter());
- boolean removed;
+ tracked.untrack(ref, event);
boolean satisfied;
- synchronized (monitor) {
- removed = references.remove(ref);
- satisfied = optional || !references.isEmpty();
- }
- if (removed) {
- untrack(ref);
+ synchronized (tracked) {
+ satisfied = optional || !tracked.isEmpty();
}
setSatisfied(satisfied);
+ untrack(ref);
}
}
@@ -445,8 +431,12 @@ public abstract class AbstractServiceRef
protected abstract void retrack();
- protected void updateListeners() {
- if (references.isEmpty()) {
+ protected void updateListeners() {
+ boolean empty;
+ synchronized (tracked) {
+ empty = tracked.isEmpty();
+ }
+ if (empty) {
unbind(null, null);
} else {
retrack();
@@ -474,34 +464,36 @@ public abstract class AbstractServiceRef
}
public List<ServiceReference> getServiceReferences() {
- synchronized (monitor) {
- return new ArrayList<ServiceReference>(references);
+ ServiceReference[] refs;
+ synchronized (tracked) {
+ refs = new ServiceReference[tracked.size()];
+ tracked.copyKeys(refs);
}
+ return Arrays.asList(refs);
}
public ServiceReference getBestServiceReference() {
- synchronized (monitor) {
- int length = references.size();
- if (length == 0) { /* if no service is being tracked */
- return null;
- }
- int index = 0;
- if (length > 1) { /* if more than one service, select highest ranking */
- int maxRanking = Integer.MIN_VALUE;
- long minId = Long.MAX_VALUE;
- for (int i = 0; i < length; i++) {
- Object property = references.get(i).getProperty(Constants.SERVICE_RANKING);
- int ranking = (property instanceof Integer) ? (Integer) property : 0;
- long id = (Long) references.get(i).getProperty(Constants.SERVICE_ID);
- if ((ranking > maxRanking) || (ranking == maxRanking && id < minId)) {
- index = i;
- maxRanking = ranking;
- minId = id;
- }
+ List<ServiceReference> references = getServiceReferences();
+ int length = references.size();
+ if (length == 0) { /* if no service is being tracked */
+ return null;
+ }
+ int index = 0;
+ if (length > 1) { /* if more than one service, select highest ranking */
+ int maxRanking = Integer.MIN_VALUE;
+ long minId = Long.MAX_VALUE;
+ for (int i = 0; i < length; i++) {
+ Object property = references.get(i).getProperty(Constants.SERVICE_RANKING);
+ int ranking = (property instanceof Integer) ? (Integer) property : 0;
+ long id = (Long) references.get(i).getProperty(Constants.SERVICE_ID);
+ if ((ranking > maxRanking) || (ranking == maxRanking && id < minId)) {
+ index = i;
+ maxRanking = ranking;
+ minId = id;
}
}
- return references.get(index);
}
+ return references.get(index);
}
public static class Listener {
@@ -656,18 +648,17 @@ public abstract class AbstractServiceRef
return sb.toString();
}
- private static Class[] getInterfaces(Class[] classes) {
- Set<Class> interfaces = new HashSet<Class>();
- for (Class clazz : classes) {
- if (clazz.isInterface()) {
- interfaces.add(clazz);
- }
+ private class Tracked extends AbstractTracked<ServiceReference, ServiceReference, ServiceEvent> {
+ @Override
+ ServiceReference customizerAdding(ServiceReference item, ServiceEvent related) {
+ return item;
+ }
+ @Override
+ void customizerModified(ServiceReference item, ServiceEvent related, ServiceReference object) {
+ }
+ @Override
+ void customizerRemoved(ServiceReference item, ServiceEvent related, ServiceReference object) {
}
- return toClassArray(interfaces);
- }
-
- private static Class[] toClassArray(Set<Class> classes) {
- return classes.toArray(new Class [classes.size()]);
}
}
Added: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractTracked.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractTracked.java?rev=1509205&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractTracked.java (added)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/AbstractTracked.java Thu Aug 1 12:34:18 2013
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) OSGi Alliance (2007, 2012). 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.apache.aries.blueprint.container;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class to track items. If a Tracker is reused (closed then reopened),
+ * then a new AbstractTracked object is used. This class acts a map of tracked
+ * item -> customized object. Subclasses of this class will act as the listener
+ * object for the tracker. This class is used to synchronize access to the
+ * tracked items. This is not a public class. It is only for use by the
+ * implementation of the Tracker class.
+ *
+ * @param <S> The tracked item. It is the key.
+ * @param <T> The value mapped to the tracked item.
+ * @param <R> The reason the tracked item is being tracked or untracked.
+ * @ThreadSafe
+ * @version $Id: 16340086b98d308c2d12f13bcd87fc6467a5a367 $
+ * @since 1.4
+ */
+abstract class AbstractTracked<S, T, R> {
+ /* set this to true to compile in debug messages */
+ static final boolean DEBUG = false;
+
+ /**
+ * Map of tracked items to customized objects.
+ *
+ * @GuardedBy this
+ */
+ private final Map<S, T> tracked;
+
+ /**
+ * Modification count. This field is initialized to zero and incremented by
+ * modified.
+ *
+ * @GuardedBy this
+ */
+ private int trackingCount;
+
+ /**
+ * List of items in the process of being added. This is used to deal with
+ * nesting of events. Since events may be synchronously delivered, events
+ * can be nested. For example, when processing the adding of a service and
+ * the customizer causes the service to be unregistered, notification to the
+ * nested call to untrack that the service was unregistered can be made to
+ * the track method.
+ *
+ * Since the ArrayList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for
+ * thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final List<S> adding;
+
+ /**
+ * true if the tracked object is closed.
+ *
+ * This field is volatile because it is set by one thread and read by
+ * another.
+ */
+ volatile boolean closed;
+
+ /**
+ * Initial list of items for the tracker. This is used to correctly process
+ * the initial items which could be modified before they are tracked. This
+ * is necessary since the initial set of tracked items are not "announced"
+ * by events and therefore the event which makes the item untracked could be
+ * delivered before we track the item.
+ *
+ * An item must not be in both the initial and adding lists at the same
+ * time. An item must be moved from the initial list to the adding list
+ * "atomically" before we begin tracking it.
+ *
+ * Since the LinkedList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for
+ * thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final LinkedList<S> initial;
+
+ /**
+ * AbstractTracked constructor.
+ */
+ AbstractTracked() {
+ tracked = new HashMap<S, T>();
+ trackingCount = 0;
+ adding = new ArrayList<S>(6);
+ initial = new LinkedList<S>();
+ closed = false;
+ }
+
+ /**
+ * Set initial list of items into tracker before events begin to be
+ * received.
+ *
+ * This method must be called from Tracker's open method while synchronized
+ * on this object in the same synchronized block as the add listener call.
+ *
+ * @param list The initial list of items to be tracked. {@code null} entries
+ * in the list are ignored.
+ * @GuardedBy this
+ */
+ void setInitial(S[] list) {
+ if (list == null) {
+ return;
+ }
+ for (S item : list) {
+ if (item == null) {
+ continue;
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.setInitial: " + item); //$NON-NLS-1$
+ }
+ initial.add(item);
+ }
+ }
+
+ /**
+ * Track the initial list of items. This is called after events can begin to
+ * be received.
+ *
+ * This method must be called from Tracker's open method while not
+ * synchronized on this object after the add listener call.
+ *
+ */
+ void trackInitial() {
+ while (true) {
+ S item;
+ synchronized (this) {
+ if (closed || (initial.size() == 0)) {
+ /*
+ * if there are no more initial items
+ */
+ return; /* we are done */
+ }
+ /*
+ * move the first item from the initial list to the adding list
+ * within this synchronized block.
+ */
+ item = initial.removeFirst();
+ if (tracked.get(item) != null) {
+ /* if we are already tracking this item */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial[already tracked]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ if (adding.contains(item)) {
+ /*
+ * if this item is already in the process of being added.
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial[already adding]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ adding.add(item);
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$
+ }
+ trackAdding(item, null); /*
+ * Begin tracking it. We call trackAdding
+ * since we have already put the item in the
+ * adding list.
+ */
+ }
+ }
+
+ /**
+ * Called by the owning Tracker object when it is closed.
+ */
+ void close() {
+ closed = true;
+ }
+
+ /**
+ * Begin to track an item.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ void track(final S item, final R related) {
+ final T object;
+ synchronized (this) {
+ if (closed) {
+ return;
+ }
+ object = tracked.get(item);
+ if (object == null) { /* we are not tracking the item */
+ if (adding.contains(item)) {
+ /* if this item is already in the process of being added. */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$
+ }
+ return;
+ }
+ adding.add(item); /* mark this item is being added */
+ } else { /* we are currently tracking this item */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.track[modified]: " + item); //$NON-NLS-1$
+ }
+ modified(); /* increment modification count */
+ }
+ }
+
+ if (object == null) { /* we are not tracking the item */
+ trackAdding(item, related);
+ } else {
+ /* Call customizer outside of synchronized region */
+ customizerModified(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Common logic to add an item to the tracker used by track and
+ * trackInitial. The specified item must have been placed in the adding list
+ * before calling this method.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ private void trackAdding(final S item, final R related) {
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackAdding: " + item); //$NON-NLS-1$
+ }
+ T object = null;
+ boolean becameUntracked = false;
+ /* Call customizer outside of synchronized region */
+ try {
+ object = customizerAdding(item, related);
+ /*
+ * If the customizer throws an unchecked exception, it will
+ * propagate after the finally
+ */
+ } finally {
+ synchronized (this) {
+ if (adding.remove(item) && !closed) {
+ /*
+ * if the item was not untracked during the customizer
+ * callback
+ */
+ if (object != null) {
+ tracked.put(item, object);
+ modified(); /* increment modification count */
+ notifyAll(); /* notify any waiters */
+ }
+ } else {
+ becameUntracked = true;
+ }
+ }
+ }
+ /*
+ * The item became untracked during the customizer callback.
+ */
+ if (becameUntracked && (object != null)) {
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Discontinue tracking the item.
+ *
+ * @param item Item to be untracked.
+ * @param related Action related object.
+ */
+ void untrack(final S item, final R related) {
+ final T object;
+ synchronized (this) {
+ if (initial.remove(item)) { /*
+ * if this item is already in the list
+ * of initial references to process
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[removed from initial]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * we have removed it from the list and it will not be
+ * processed
+ */
+ }
+
+ if (adding.remove(item)) { /*
+ * if the item is in the process of
+ * being added
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * in case the item is untracked while in the process of
+ * adding
+ */
+ }
+ object = tracked.remove(item); /*
+ * must remove from tracker before
+ * calling customizer callback
+ */
+ if (object == null) { /* are we actually tracking the item */
+ return;
+ }
+ modified(); /* increment modification count */
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to let it
+ * propagate
+ */
+ }
+
+ /**
+ * Returns the number of tracked items.
+ *
+ * @return The number of tracked items.
+ *
+ * @GuardedBy this
+ */
+ int size() {
+ return tracked.size();
+ }
+
+ /**
+ * Returns if the tracker is empty.
+ *
+ * @return Whether the tracker is empty.
+ *
+ * @GuardedBy this
+ * @since 1.5
+ */
+ boolean isEmpty() {
+ return tracked.isEmpty();
+ }
+
+ /**
+ * Return the customized object for the specified item
+ *
+ * @param item The item to lookup in the map
+ * @return The customized object for the specified item.
+ *
+ * @GuardedBy this
+ */
+ T getCustomizedObject(final S item) {
+ return tracked.get(item);
+ }
+
+ /**
+ * Copy the tracked items into an array.
+ *
+ * @param list An array to contain the tracked items.
+ * @return The specified list if it is large enough to hold the tracked
+ * items or a new array large enough to hold the tracked items.
+ * @GuardedBy this
+ */
+ S[] copyKeys(final S[] list) {
+ return tracked.keySet().toArray(list);
+ }
+
+ /**
+ * Increment the modification count. If this method is overridden, the
+ * overriding method MUST call this method to increment the tracking count.
+ *
+ * @GuardedBy this
+ */
+ void modified() {
+ trackingCount++;
+ }
+
+ /**
+ * Returns the tracking count for this {@code ServiceTracker} object.
+ *
+ * The tracking count is initialized to 0 when this object is opened. Every
+ * time an item is added, modified or removed from this object the tracking
+ * count is incremented.
+ *
+ * @GuardedBy this
+ * @return The tracking count for this object.
+ */
+ int getTrackingCount() {
+ return trackingCount;
+ }
+
+ /**
+ * Copy the tracked items and associated values into the specified map.
+ *
+ * @param <M> Type of {@code Map} to hold the tracked items and associated
+ * values.
+ * @param map The map into which to copy the tracked items and associated
+ * values. This map must not be a user provided map so that user code
+ * is not executed while synchronized on this.
+ * @return The specified map.
+ * @GuardedBy this
+ * @since 1.5
+ */
+ <M extends Map<? super S, ? super T>> M copyEntries(final M map) {
+ map.putAll(tracked);
+ return map;
+ }
+
+ /**
+ * Call the specific customizer adding method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ * @return Customized object for the tracked item or {@code null} if the
+ * item is not to be tracked.
+ */
+ abstract T customizerAdding(final S item, final R related);
+
+ /**
+ * Call the specific customizer modified method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerModified(final S item, final R related, final T object);
+
+ /**
+ * Call the specific customizer removed method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerRemoved(final S item, final R related, final T object);
+}
Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java?rev=1509205&r1=1509204&r2=1509205&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceListRecipe.java Thu Aug 1 12:34:18 2013
@@ -51,6 +51,7 @@ public class ReferenceListRecipe extends
private final List<ManagedCollection> collections = new ArrayList<ManagedCollection>();
private final DynamicCollection<ServiceDispatcher> storage = new DynamicCollection<ServiceDispatcher>();
private final List<ServiceDispatcher> unboundDispatchers = new ArrayList<ServiceDispatcher>();
+ private final Object monitor = new Object();
public ReferenceListRecipe(String name,
ExtendedBlueprintContainer blueprintContainer,
Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java?rev=1509205&r1=1509204&r2=1509205&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java (original)
+++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/ReferenceRecipe.java Thu Aug 1 12:34:18 2013
@@ -59,6 +59,7 @@ public class ReferenceRecipe extends Abs
private final ReferenceMetadata metadata;
private Object proxy;
+ private final Object monitor = new Object();
private volatile ServiceReference trackedServiceReference;
private volatile Object trackedService;
private Object defaultBean;