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;


Reply via email to