You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/06/15 14:32:12 UTC

svn commit: r954852 - in /cayenne/main/trunk/framework: cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/ cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/ cayenne...

Author: aadamchik
Date: Tue Jun 15 12:32:11 2010
New Revision: 954852

URL: http://svn.apache.org/viewvc?rev=954852&view=rev
Log:
Fixing DI scope event handling

* a generic scope implementation that can be used for any user-managed scope
* unregistering scoped objects at the end of the scope

Added:
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/BeforeScopeEnd.java
      - copied, changed from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/OnScopeEnd.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/AfterScopeEnd.java
      - copied, changed from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonScope.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScope.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScopeProvider.java
      - copied, changed from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonProvider.java
Removed:
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/OnScopeEnd.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/EventfulScope.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonProvider.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonScope.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/UnitTestScope.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/UnitTestScopedProvider.java
Modified:
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultBindingBuilder.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ScopeEventBinding.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotations.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotationsBase.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorScopeTest.java
    cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/event/DefaultEventManager.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DICaseSelfTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DefaultUnitTestLifecycleManager.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/CachingServerRuntimeFactory.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseLifecycleManager.java

Copied: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/BeforeScopeEnd.java (from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/OnScopeEnd.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/BeforeScopeEnd.java?p2=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/BeforeScopeEnd.java&p1=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/OnScopeEnd.java&r1=954823&r2=954852&rev=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/OnScopeEnd.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/BeforeScopeEnd.java Tue Jun 15 12:32:11 2010
@@ -36,6 +36,6 @@ import java.lang.annotation.Target;
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-public @interface OnScopeEnd {
+public @interface BeforeScopeEnd {
 
 }

Copied: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/AfterScopeEnd.java (from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonScope.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/AfterScopeEnd.java?p2=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/AfterScopeEnd.java&p1=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonScope.java&r1=954823&r2=954852&rev=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonScope.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/AfterScopeEnd.java Tue Jun 15 12:32:11 2010
@@ -18,20 +18,22 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
-import org.apache.cayenne.di.OnScopeEnd;
-import org.apache.cayenne.di.Provider;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
+ * A non-public event annotation used by scope object providers to unregister objects
+ * created within a scope. Registry objects within a given scope will never be able to
+ * receive this event, so never annotate custom objects with this.
+ * 
  * @since 3.1
  */
-class SingletonScope extends EventfulScope {
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@interface AfterScopeEnd {
 
-    SingletonScope() {
-        addEventAnnotation(OnScopeEnd.class);
-    }
-
-    @Override
-    public <T> Provider<T> scope(Provider<T> unscoped) {
-        return new SingletonProvider<T>(this, unscoped);
-    }
 }

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultBindingBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultBindingBuilder.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultBindingBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultBindingBuilder.java Tue Jun 15 12:32:11 2010
@@ -43,10 +43,7 @@ class DefaultBindingBuilder<T> implement
         Provider<T> provider0 = new ConstructorInjectingProvider<T>(
                 implementation,
                 injector);
-        Provider<T> provider1 = new FieldInjectingProvider<T>(
-                provider0,
-                injector,
-                bindingKey);
+        Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
 
         injector.putBinding(bindingKey, provider1);
         return this;
@@ -54,10 +51,7 @@ class DefaultBindingBuilder<T> implement
 
     public BindingBuilder<T> toInstance(T instance) throws ConfigurationException {
         Provider<T> provider0 = new InstanceProvider<T>(instance);
-        Provider<T> provider1 = new FieldInjectingProvider<T>(
-                provider0,
-                injector,
-                bindingKey);
+        Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
         injector.putBinding(bindingKey, provider1);
         return this;
     };
@@ -70,14 +64,10 @@ class DefaultBindingBuilder<T> implement
                 injector);
         Provider<Provider<? extends T>> provider1 = new FieldInjectingProvider<Provider<? extends T>>(
                 provider0,
-                injector,
-                bindingKey);
+                injector);
 
         Provider<T> provider2 = new CustomProvidersProvider<T>(provider1);
-        Provider<T> provider3 = new FieldInjectingProvider<T>(
-                provider2,
-                injector,
-                bindingKey);
+        Provider<T> provider3 = new FieldInjectingProvider<T>(provider2, injector);
 
         injector.putBinding(bindingKey, provider3);
         return this;
@@ -89,14 +79,10 @@ class DefaultBindingBuilder<T> implement
                 provider);
         Provider<Provider<? extends T>> provider1 = new FieldInjectingProvider<Provider<? extends T>>(
                 provider0,
-                injector,
-                bindingKey);
+                injector);
 
         Provider<T> provider2 = new CustomProvidersProvider<T>(provider1);
-        Provider<T> provider3 = new FieldInjectingProvider<T>(
-                provider2,
-                injector,
-                bindingKey);
+        Provider<T> provider3 = new FieldInjectingProvider<T>(provider2, injector);
 
         injector.putBinding(bindingKey, provider3);
         return this;

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java Tue Jun 15 12:32:11 2010
@@ -25,7 +25,6 @@ import org.apache.cayenne.ConfigurationE
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.OnScopeEnd;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.di.Scope;
 
@@ -36,7 +35,7 @@ import org.apache.cayenne.di.Scope;
  */
 public class DefaultInjector implements Injector {
 
-    private SingletonScope singletonScope;
+    private DefaultScope singletonScope;
     private Scope noScope;
 
     private Map<Key<?>, Binding<?>> bindings;
@@ -45,7 +44,7 @@ public class DefaultInjector implements 
 
     public DefaultInjector(Module... modules) throws ConfigurationException {
 
-        this.singletonScope = new SingletonScope();
+        this.singletonScope = new DefaultScope();
         this.noScope = NoScope.SINGLETON;
 
         // this is intentionally hardcoded and is not configurable
@@ -131,18 +130,15 @@ public class DefaultInjector implements 
 
     public void injectMembers(Object object) {
         Provider<Object> provider0 = new InstanceProvider<Object>(object);
-        Provider<Object> provider1 = new FieldInjectingProvider<Object>(
-                provider0,
-                this,
-                Key.get(object.getClass()));
+        Provider<Object> provider1 = new FieldInjectingProvider<Object>(provider0, this);
         provider1.get();
     }
 
     public void shutdown() {
-        singletonScope.postScopeEvent(OnScopeEnd.class);
-    };
+        singletonScope.shutdown();
+    }
 
-    SingletonScope getSingletonScope() {
+    DefaultScope getSingletonScope() {
         return singletonScope;
     }
 

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java Tue Jun 15 12:32:11 2010
@@ -53,10 +53,7 @@ class DefaultListBuilder<T> implements L
     public ListBuilder<T> add(T value) throws ConfigurationException {
 
         Provider<T> provider0 = new InstanceProvider<T>(value);
-        Provider<T> provider1 = new FieldInjectingProvider<T>(
-                provider0,
-                injector,
-                bindingKey);
+        Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
 
         getListProvider().add(provider1);
         return this;
@@ -68,10 +65,7 @@ class DefaultListBuilder<T> implements L
 
         for (T value : values) {
             Provider<T> provider0 = new InstanceProvider<T>(value);
-            Provider<T> provider1 = new FieldInjectingProvider<T>(
-                    provider0,
-                    injector,
-                    bindingKey);
+            Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
 
             listProvider.add(provider1);
         }

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java Tue Jun 15 12:32:11 2010
@@ -55,10 +55,7 @@ class DefaultMapBuilder<T> implements Ma
     public MapBuilder<T> put(String key, T value) throws ConfigurationException {
 
         Provider<T> provider0 = new InstanceProvider<T>(value);
-        Provider<T> provider1 = new FieldInjectingProvider<T>(
-                provider0,
-                injector,
-                bindingKey);
+        Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
 
         // TODO: andrus 11/15/2009 - report overriding the key??
         getMapProvider().put(key, provider1);
@@ -72,10 +69,7 @@ class DefaultMapBuilder<T> implements Ma
         for (Entry<String, T> entry : map.entrySet()) {
 
             Provider<T> provider0 = new InstanceProvider<T>(entry.getValue());
-            Provider<T> provider1 = new FieldInjectingProvider<T>(
-                    provider0,
-                    injector,
-                    bindingKey);
+            Provider<T> provider1 = new FieldInjectingProvider<T>(provider0, injector);
             provider.put(entry.getKey(), provider1);
         }
 

Added: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScope.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScope.java?rev=954852&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScope.java (added)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScope.java Tue Jun 15 12:32:11 2010
@@ -0,0 +1,151 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.di.spi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.cayenne.di.BeforeScopeEnd;
+import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.di.Scope;
+
+/**
+ * An implementation of a DI scopes with support scope events.
+ * 
+ * @since 3.1
+ */
+public class DefaultScope implements Scope {
+
+    protected Collection<Class<? extends Annotation>> eventTypes;
+    protected ConcurrentMap<String, Collection<ScopeEventBinding>> listeners;
+
+    private static final String SPECIAL_EVENT = AfterScopeEnd.class.getName();
+
+    public DefaultScope(Class<? extends Annotation>... customEventTypes) {
+        this.listeners = new ConcurrentHashMap<String, Collection<ScopeEventBinding>>();
+        this.eventTypes = new HashSet<Class<? extends Annotation>>();
+
+        // initialize the event listener data structures in constructor to avoid
+        // synchronization concerns on everything but per-event lists.
+
+        // standard event types
+        eventTypes.add(BeforeScopeEnd.class);
+        eventTypes.add(AfterScopeEnd.class);
+
+        // custom event types
+        if (customEventTypes != null) {
+            for (Class<? extends Annotation> type : customEventTypes) {
+                eventTypes.add(type);
+            }
+        }
+
+        for (Class<? extends Annotation> type : eventTypes) {
+            listeners.put(type.getName(), new ConcurrentLinkedQueue<ScopeEventBinding>());
+        }
+    }
+
+    /**
+     * Shuts down this scope, posting {@link BeforeScopeEnd} and {@link AfterScopeEnd}
+     * events.
+     */
+    public void shutdown() {
+        postScopeEvent(BeforeScopeEnd.class);
+
+        // this will notify providers that they should reset their state and unregister
+        // object event listeners that just went out of scope
+        postScopeEvent(AfterScopeEnd.class);
+    }
+
+    /**
+     * Registers annotated methods of an arbitrary object for this scope lifecycle events.
+     */
+    public void addScopeEventListener(Object object) {
+
+        // TODO: cache metadata for non-singletons scopes for performance
+
+        // 'getMethods' grabs public method from the class and its superclasses...
+        for (Method method : object.getClass().getMethods()) {
+
+            for (Class<? extends Annotation> annotationType : eventTypes) {
+
+                if (method.isAnnotationPresent(annotationType)) {
+                    String typeName = annotationType.getName();
+
+                    Collection<ScopeEventBinding> eventListeners = listeners
+                            .get(typeName);
+                    eventListeners.add(new ScopeEventBinding(object, method));
+                }
+            }
+        }
+    }
+
+    public void removeScopeEventListener(Object object) {
+
+        for (Entry<String, Collection<ScopeEventBinding>> entry : listeners.entrySet()) {
+
+            if (SPECIAL_EVENT.equals(entry.getKey())) {
+                // no scanning and removal of Scope providers ...
+                // for faster scan skip those
+                continue;
+            }
+
+            Iterator<ScopeEventBinding> it = entry.getValue().iterator();
+            while (it.hasNext()) {
+                ScopeEventBinding binding = it.next();
+                if (binding.getObject() == object) {
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    /**
+     * Posts a scope event to all registered listeners. There's no predetermined order of
+     * event dispatching. An exception thrown by any of the listeners stops further event
+     * processing and is rethrown.
+     */
+    public void postScopeEvent(
+            Class<? extends Annotation> type,
+            Object... eventParameters) {
+
+        Collection<ScopeEventBinding> eventListeners = listeners.get(type.getName());
+
+        if (eventListeners != null) {
+            Iterator<ScopeEventBinding> it = eventListeners.iterator();
+            while (it.hasNext()) {
+                ScopeEventBinding listener = it.next();
+                if (!listener.onScopeEvent(eventParameters)) {
+                    // remove listeners that were garbage collected
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    public <T> Provider<T> scope(Provider<T> unscoped) {
+        return new DefaultScopeProvider<T>(this, unscoped);
+    }
+}

Copied: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScopeProvider.java (from r954823, cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonProvider.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScopeProvider.java?p2=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScopeProvider.java&p1=cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonProvider.java&r1=954823&r2=954852&rev=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/SingletonProvider.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/DefaultScopeProvider.java Tue Jun 15 12:32:11 2010
@@ -22,19 +22,23 @@ import org.apache.cayenne.ConfigurationE
 import org.apache.cayenne.di.Provider;
 
 /**
+ * A provider that provides scoping for other provoders.
+ * 
  * @since 3.1
  */
-class SingletonProvider<T> implements Provider<T> {
+public class DefaultScopeProvider<T> implements Provider<T> {
 
     private Provider<T> delegate;
-    private SingletonScope scope;
+    private DefaultScope scope;
 
     // presumably "volatile" works in Java 5 and newer to prevent double-checked locking
     private volatile T instance;
 
-    public SingletonProvider(SingletonScope scope, Provider<T> delegate) {
+    public DefaultScopeProvider(DefaultScope scope, Provider<T> delegate) {
         this.scope = scope;
         this.delegate = delegate;
+
+        scope.addScopeEventListener(this);
     }
 
     public T get() {
@@ -58,4 +62,13 @@ class SingletonProvider<T> implements Pr
         return instance;
     }
 
+    @AfterScopeEnd
+    public void afterScopeEnd() throws Exception {
+        Object localInstance = instance;
+
+        if (localInstance != null) {
+            instance = null;
+            scope.removeScopeEventListener(localInstance);
+        }
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java Tue Jun 15 12:32:11 2010
@@ -30,15 +30,12 @@ import org.apache.cayenne.di.Provider;
  */
 class FieldInjectingProvider<T> implements Provider<T> {
 
-    private Key<?> bindingKey;
     private DefaultInjector injector;
     private Provider<T> delegate;
 
-    FieldInjectingProvider(Provider<T> delegate, DefaultInjector injector,
-            Key<?> bindingKey) {
+    FieldInjectingProvider(Provider<T> delegate, DefaultInjector injector) {
         this.delegate = delegate;
         this.injector = injector;
-        this.bindingKey = bindingKey;
     }
 
     public T get() throws ConfigurationException {
@@ -88,9 +85,9 @@ class FieldInjectingProvider<T> implemen
             value = injector.getProvider(Key.get(objectClass, bindingName));
         }
         else {
-            
+
             Key<?> key = Key.get(fieldType, bindingName);
-            
+
             stack.push(key);
             try {
                 value = injector.getInstance(key);

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ScopeEventBinding.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ScopeEventBinding.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ScopeEventBinding.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/main/java/org/apache/cayenne/di/spi/ScopeEventBinding.java Tue Jun 15 12:32:11 2010
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 
 import org.apache.cayenne.CayenneRuntimeException;
@@ -27,14 +28,17 @@ import org.apache.cayenne.CayenneRuntime
  * 
  * @since 3.1
  */
-class ScopeEventBinding {
+public class ScopeEventBinding {
 
-    private Object object;
+    private WeakReference<Object> objectReference;
     private Method eventHandlerMethod;
     private int argWidth;
 
-    ScopeEventBinding(Object object, Method eventHandlerMethod) {
-        this.object = object;
+    public ScopeEventBinding(Object object, Method eventHandlerMethod) {
+
+        // store weak references for objects to avoid retaining them when they go out of
+        // scope
+        this.objectReference = new WeakReference<Object>(object);
         this.eventHandlerMethod = eventHandlerMethod;
         this.argWidth = eventHandlerMethod.getParameterTypes().length;
 
@@ -42,7 +46,16 @@ class ScopeEventBinding {
         eventHandlerMethod.setAccessible(true);
     }
 
-    void onScopeEvent(Object... eventArgs) {
+    public Object getObject() {
+        return objectReference.get();
+    }
+
+    public boolean onScopeEvent(Object... eventArgs) {
+
+        Object object = objectReference.get();
+        if (object == null) {
+            return false;
+        }
 
         try {
             eventHandlerMethod.invoke(object, invocationArguments(eventArgs));
@@ -53,6 +66,8 @@ class ScopeEventBinding {
                     e,
                     eventHandlerMethod.getName());
         }
+
+        return true;
     }
 
     private Object[] invocationArguments(Object[] eventArgs) {

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotations.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotations.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotations.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotations.java Tue Jun 15 12:32:11 2010
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.di.mock;
 
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.BeforeScopeEnd;
 
 public class MockImplementation1_EventAnnotations extends
         MockImplementation1_EventAnnotationsBase implements MockInterface1 {
@@ -27,12 +27,12 @@ public class MockImplementation1_EventAn
         return "XuI";
     }
 
-    @OnScopeEnd
+    @BeforeScopeEnd
     public void onShutdown1() {
         shutdown1 = true;
     }
 
-    @OnScopeEnd
+    @BeforeScopeEnd
     public void onShutdown2() {
         shutdown2 = true;
     }

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotationsBase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotationsBase.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotationsBase.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_EventAnnotationsBase.java Tue Jun 15 12:32:11 2010
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.di.mock;
 
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.BeforeScopeEnd;
 
 public class MockImplementation1_EventAnnotationsBase {
 
@@ -32,7 +32,7 @@ public class MockImplementation1_EventAn
         shutdown3 = false;
     }
 
-    @OnScopeEnd
+    @BeforeScopeEnd
     public void onShutdown3() {
         shutdown3 = true;
     }

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorScopeTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorScopeTest.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorScopeTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorScopeTest.java Tue Jun 15 12:32:11 2010
@@ -22,7 +22,7 @@ import junit.framework.TestCase;
 
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.BeforeScopeEnd;
 import org.apache.cayenne.di.mock.MockImplementation1;
 import org.apache.cayenne.di.mock.MockImplementation1_EventAnnotations;
 import org.apache.cayenne.di.mock.MockImplementation1_Provider;
@@ -127,7 +127,7 @@ public class DefaultInjectorScopeTest ex
         assertFalse(MockImplementation1_EventAnnotations.shutdown2);
         assertFalse(MockImplementation1_EventAnnotations.shutdown3);
 
-        injector.getSingletonScope().postScopeEvent(OnScopeEnd.class);
+        injector.getSingletonScope().postScopeEvent(BeforeScopeEnd.class);
 
         assertTrue(MockImplementation1_EventAnnotations.shutdown1);
         assertTrue(MockImplementation1_EventAnnotations.shutdown2);

Modified: cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorTest.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-di-unpublished/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorTest.java Tue Jun 15 12:32:11 2010
@@ -22,7 +22,7 @@ import junit.framework.TestCase;
 
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.BeforeScopeEnd;
 import org.apache.cayenne.di.mock.MockImplementation1_EventAnnotations;
 import org.apache.cayenne.di.mock.MockInterface1;
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/event/DefaultEventManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/event/DefaultEventManager.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/event/DefaultEventManager.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/event/DefaultEventManager.java Tue Jun 15 12:32:11 2010
@@ -27,7 +27,7 @@ import java.util.Map;
 import java.util.WeakHashMap;
 
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.BeforeScopeEnd;
 import org.apache.cayenne.util.Invocation;
 
 /**
@@ -107,7 +107,7 @@ public class DefaultEventManager impleme
      * 
      * @since 3.0
      */
-    @OnScopeEnd
+    @BeforeScopeEnd
     public void shutdown() {
 
         if (!stopped) {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DICaseSelfTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DICaseSelfTest.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DICaseSelfTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DICaseSelfTest.java Tue Jun 15 12:32:11 2010
@@ -24,6 +24,7 @@ import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.spi.DefaultScope;
 
 public class DICaseSelfTest extends DICase {
 
@@ -33,7 +34,7 @@ public class DICaseSelfTest extends DICa
         Module selfTestModule = new Module() {
 
             public void configure(Binder binder) {
-                UnitTestScope testScope = new UnitTestScope();
+                DefaultScope testScope = new DefaultScope();
 
                 binder.bind(UnitTestLifecycleManager.class).toInstance(
                         new DefaultUnitTestLifecycleManager(testScope));

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DefaultUnitTestLifecycleManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DefaultUnitTestLifecycleManager.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DefaultUnitTestLifecycleManager.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/DefaultUnitTestLifecycleManager.java Tue Jun 15 12:32:11 2010
@@ -20,18 +20,19 @@ package org.apache.cayenne.unit.di;
 
 import junit.framework.TestCase;
 
+import org.apache.cayenne.di.BeforeScopeEnd;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.di.OnScopeEnd;
+import org.apache.cayenne.di.spi.DefaultScope;
 
 public class DefaultUnitTestLifecycleManager implements UnitTestLifecycleManager {
 
     @Inject
     protected Injector injector;
 
-    protected UnitTestScope scope;
+    protected DefaultScope scope;
 
-    public DefaultUnitTestLifecycleManager(UnitTestScope scope) {
+    public DefaultUnitTestLifecycleManager(DefaultScope scope) {
         this.scope = scope;
     }
 
@@ -39,8 +40,8 @@ public class DefaultUnitTestLifecycleMan
         injector.injectMembers(testCase);
     }
 
-    @OnScopeEnd
+    @BeforeScopeEnd
     public <T extends TestCase> void tearDown(T testCase) {
-        scope.postScopeEvent(OnScopeEnd.class);
+        scope.shutdown();
     }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/CachingServerRuntimeFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/CachingServerRuntimeFactory.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/CachingServerRuntimeFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/CachingServerRuntimeFactory.java Tue Jun 15 12:32:11 2010
@@ -28,27 +28,27 @@ import org.apache.cayenne.configuration.
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.spi.DefaultScope;
 import org.apache.cayenne.unit.CayenneResources;
-import org.apache.cayenne.unit.di.UnitTestScope;
 
 public class CachingServerRuntimeFactory implements ServerRuntimeFactory {
 
     protected CayenneResources resources;
-    protected UnitTestScope testScope;
+    protected DefaultScope testScope;
     protected Map<String, ServerRuntime> cache;
 
-    public CachingServerRuntimeFactory(CayenneResources resources, UnitTestScope testScope) {
+    public CachingServerRuntimeFactory(CayenneResources resources, DefaultScope testScope) {
         this.resources = resources;
         this.testScope = testScope;
         this.cache = new HashMap<String, ServerRuntime>();
     }
 
     public ServerRuntime get(String configurationLocation) {
-        
+
         if (configurationLocation == null) {
             throw new NullPointerException("Null 'configurationLocation'");
         }
-        
+
         ServerRuntime runtime = cache.get(configurationLocation);
 
         if (runtime == null) {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java Tue Jun 15 12:32:11 2010
@@ -27,12 +27,12 @@ import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.spi.DefaultScope;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.unit.AccessStackAdapter;
 import org.apache.cayenne.unit.CayenneResources;
 import org.apache.cayenne.unit.di.DICase;
 import org.apache.cayenne.unit.di.UnitTestLifecycleManager;
-import org.apache.cayenne.unit.di.UnitTestScope;
 
 public class ServerCase extends DICase {
 
@@ -54,7 +54,7 @@ public class ServerCase extends DICase {
         Module module = new Module() {
 
             public void configure(Binder binder) {
-                UnitTestScope testScope = new UnitTestScope();
+                DefaultScope testScope = new DefaultScope();
 
                 // these are the objects injectable in unit tests that subclass from
                 // ServerCase. Server runtime extensions are configured in

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseLifecycleManager.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseLifecycleManager.java?rev=954852&r1=954851&r2=954852&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseLifecycleManager.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseLifecycleManager.java Tue Jun 15 12:32:11 2010
@@ -23,8 +23,8 @@ import junit.framework.TestCase;
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.di.spi.DefaultScope;
 import org.apache.cayenne.unit.di.DefaultUnitTestLifecycleManager;
-import org.apache.cayenne.unit.di.UnitTestScope;
 
 public class ServerCaseLifecycleManager extends DefaultUnitTestLifecycleManager {
 
@@ -34,7 +34,7 @@ public class ServerCaseLifecycleManager 
     @Inject
     protected ServerRuntimeFactory runtimeFactory;
 
-    public ServerCaseLifecycleManager(UnitTestScope scope) {
+    public ServerCaseLifecycleManager(DefaultScope scope) {
         super(scope);
     }