cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aadamc...@apache.org
Subject svn commit: r1578076 - in /cayenne/main/trunk/cayenne-di/src: main/java/org/apache/cayenne/di/ main/java/org/apache/cayenne/di/spi/ test/java/org/apache/cayenne/di/mock/ test/java/org/apache/cayenne/di/spi/
Date Sun, 16 Mar 2014 14:07:58 GMT
Author: aadamchik
Date: Sun Mar 16 14:07:57 2014
New Revision: 1578076

URL: http://svn.apache.org/r1578076
Log:
CAY-1920 DI: add support for decorators

Added:
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/DecoratorBuilder.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Decoration.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DecoratorProvider.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultDecoratorBuilder.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator1.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator2.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator3.java
      - copied, changed from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
Modified:
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingProvider.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultBinder.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
    cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java Sun Mar
16 14:07:57 2014
@@ -58,4 +58,14 @@ public interface Binder {
      * DI capabilities.
      */
     <T> ListBuilder<T> bindList(String bindingName);
+    
+    /**
+     * @since 3.2
+     */
+    <T> DecoratorBuilder<T> decorate(Class<T> interfaceType);
+    
+    /**
+     * @since 3.2
+     */
+    <T> DecoratorBuilder<T> decorate(Key<T> key);
 }

Copied: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/DecoratorBuilder.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/DecoratorBuilder.java?p2=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/DecoratorBuilder.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/DecoratorBuilder.java
Sun Mar 16 14:07:57 2014
@@ -16,40 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.di.spi;
-
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
+package org.apache.cayenne.di;
 
 /**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
+ * @since 3.2
  */
-class Binding<T> {
-
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
-
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
-    }
-
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
+public interface DecoratorBuilder<T> {
 
-        scoped = scope.scope(unscoped);
-    }
+    DecoratorBuilder<T> after(Class<? extends T> decoratorImplementationType)
throws DIRuntimeException;
 
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
+    DecoratorBuilder<T> before(Class<? extends T> decoratorImplementationType)
throws DIRuntimeException;
 
-    Provider<T> getScoped() {
-        return scoped;
-    }
 }

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java Sun
Mar 16 14:07:57 2014
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
+import java.util.List;
+
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.di.Scope;
 
@@ -29,12 +31,16 @@ import org.apache.cayenne.di.Scope;
  */
 class Binding<T> {
 
-    private Provider<T> unscoped;
+    private Provider<T> original;
+    private Provider<T> decorated;
     private Provider<T> scoped;
+    private Scope scope;
 
     Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
+        this.original = provider;
+        this.decorated = provider;
+        
+        changeScope(initialScope);
     }
 
     void changeScope(Scope scope) {
@@ -42,11 +48,28 @@ class Binding<T> {
             scope = NoScope.INSTANCE;
         }
 
-        scoped = scope.scope(unscoped);
+        this.scoped = scope.scope(original);
+        this.scope = scope;
+    }
+    
+    void decorate(Decoration<T> decoration) {
+
+        List<DecoratorProvider<T>> decorators = decoration.decorators();
+        if (decorators.isEmpty()) {
+            return;
+        }
+
+        Provider<T> provider = this.original;
+        for (DecoratorProvider<T> decoratorProvider : decorators) {
+            provider = decoratorProvider.get(provider);
+        }
+        
+        this.decorated = provider;
+        this.scoped = scope.scope(decorated);
     }
 
-    Provider<T> getUnscoped() {
-        return unscoped;
+    Provider<T> getOriginal() {
+        return original;
     }
 
     Provider<T> getScoped() {

Copied: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java?p2=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingDecoratorProvider.java
Sun Mar 16 14:07:57 2014
@@ -18,38 +18,37 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
+import java.lang.reflect.Type;
+
+import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
 
 /**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
+ * @since 3.2
  */
-class Binding<T> {
+public class ConstructorInjectingDecoratorProvider<T> implements DecoratorProvider<T>
{
 
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
+    private Class<? extends T> implementation;
+    private DefaultInjector injector;
 
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
+    public ConstructorInjectingDecoratorProvider(Class<? extends T> implementation,
DefaultInjector injector) {
+        this.implementation = implementation;
+        this.injector = injector;
     }
 
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
-
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
+    @Override
+    public Provider<T> get(final Provider<T> undecorated) throws DIRuntimeException
{
 
-    Provider<T> getScoped() {
-        return scoped;
+        return new ConstructorInjectingProvider<T>(implementation, injector) {
+            @Override
+            protected Object value(Class<?> parameter, Type genericType, String bindingName,
InjectionStack stack) {
+
+                if (parameter.isAssignableFrom(implementation)) {
+                    return undecorated.get();
+                }
+
+                return super.value(parameter, genericType, bindingName, stack);
+            }
+        };
     }
 }

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingProvider.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingProvider.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingProvider.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorInjectingProvider.java
Sun Mar 16 14:07:57 2014
@@ -130,34 +130,7 @@ class ConstructorInjectingProvider<T> im
         InjectionStack stack = injector.getInjectionStack();
 
         for (int i = 0; i < constructorParameters.length; i++) {
-
-            Class<?> parameter = constructorParameters[i];
-
-            if (Provider.class.equals(parameter)) {
-
-                Class<?> objectClass = DIUtil.parameterClass(genericTypes[i]);
-
-                if (objectClass == null) {
-                    throw new DIRuntimeException(
-                            "Constructor provider parameter %s must be "
-                                    + "parameterized to be usable for injection",
-                            parameter.getName());
-                }
-
-                args[i] = injector.getProvider(Key.get(objectClass, bindingNames[i]));
-            }
-            else {
-
-                Key<?> key = Key.get(parameter, bindingNames[i]);
-
-                stack.push(key);
-                try {
-                    args[i] = injector.getInstance(key);
-                }
-                finally {
-                    stack.pop();
-                }
-            }
+            args[i] = value(constructorParameters[i], genericTypes[i], bindingNames[i], stack);
         }
 
         try {
@@ -170,5 +143,30 @@ class ConstructorInjectingProvider<T> im
                     constructor.getDeclaringClass().getName());
         }
     }
+    
+    protected Object value(Class<?> parameter, Type genericType, String bindingName,
InjectionStack stack) {
+
+        if (Provider.class.equals(parameter)) {
+
+            Class<?> objectClass = DIUtil.parameterClass(genericType);
+
+            if (objectClass == null) {
+                throw new DIRuntimeException("Constructor provider parameter %s must be "
+                        + "parameterized to be usable for injection", parameter.getName());
+            }
+
+            return injector.getProvider(Key.get(objectClass, bindingName));
+        } else {
+
+            Key<?> key = Key.get(parameter, bindingName);
+
+            stack.push(key);
+            try {
+                return injector.getInstance(key);
+            } finally {
+                stack.pop();
+            }
+        }
+    }
 
 }

Copied: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Decoration.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Decoration.java?p2=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Decoration.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Decoration.java
Sun Mar 16 14:07:57 2014
@@ -18,38 +18,27 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
+import java.util.LinkedList;
+import java.util.List;
 
-/**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
- */
-class Binding<T> {
-
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
-
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
-    }
+class Decoration<T> {
 
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
+    private List<DecoratorProvider<T>> decorators;
 
-        scoped = scope.scope(unscoped);
+    Decoration() {
+        this.decorators = new LinkedList<DecoratorProvider<T>>();
     }
 
-    Provider<T> getUnscoped() {
-        return unscoped;
+    void before(DecoratorProvider<T> decoratorProvider) {
+        decorators.add(0, decoratorProvider);
     }
 
-    Provider<T> getScoped() {
-        return scoped;
+    void after(DecoratorProvider<T> decoratorProvider) {
+        decorators.add(decoratorProvider);
+    }
+    
+    List<DecoratorProvider<T>> decorators() {
+        return decorators;
     }
+
 }

Copied: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DecoratorProvider.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DecoratorProvider.java?p2=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DecoratorProvider.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DecoratorProvider.java
Sun Mar 16 14:07:57 2014
@@ -18,38 +18,13 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
+import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
 
 /**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
+ * @since 3.2
  */
-class Binding<T> {
+interface DecoratorProvider<T> {
 
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
-
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
-    }
-
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
-
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
-
-    Provider<T> getScoped() {
-        return scoped;
-    }
+    Provider<T> get(Provider<T> undecorated) throws DIRuntimeException;
 }

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultBinder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultBinder.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultBinder.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultBinder.java
Sun Mar 16 14:07:57 2014
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.BindingBuilder;
+import org.apache.cayenne.di.DecoratorBuilder;
 import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.ListBuilder;
 import org.apache.cayenne.di.MapBuilder;
@@ -59,5 +60,14 @@ class DefaultBinder implements Binder {
                 (Class<Map<String, ?>>) mapClass,
                 bindingName), injector);
     }
-
+    
+    @Override
+    public <T> DecoratorBuilder<T> decorate(Class<T> interfaceType) {
+        return new DefaultDecoratorBuilder<T>(Key.get(interfaceType), injector);
+    }
+    
+    @Override
+    public <T> DecoratorBuilder<T> decorate(Key<T> key) {
+        return new DefaultDecoratorBuilder<T>(key, injector);
+    }
 }

Added: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultDecoratorBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultDecoratorBuilder.java?rev=1578076&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultDecoratorBuilder.java
(added)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultDecoratorBuilder.java
Sun Mar 16 14:07:57 2014
@@ -0,0 +1,56 @@
+/*****************************************************************
+ *   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 org.apache.cayenne.di.DIRuntimeException;
+import org.apache.cayenne.di.DecoratorBuilder;
+import org.apache.cayenne.di.Key;
+
+/**
+ * @since 3.2
+ */
+class DefaultDecoratorBuilder<T> implements DecoratorBuilder<T> {
+
+    private Key<T> bindingKey;
+    private DefaultInjector injector;
+
+    DefaultDecoratorBuilder(Key<T> bindingKey, DefaultInjector injector) {
+        this.bindingKey = bindingKey;
+        this.injector = injector;
+    }
+
+    @Override
+    public DecoratorBuilder<T> after(Class<? extends T> decoratorImplementationType)
throws DIRuntimeException {
+        injector.putDecorationAfter(bindingKey, decoratorProvider(decoratorImplementationType));
+        return this;
+    }
+
+    @Override
+    public DecoratorBuilder<T> before(Class<? extends T> decoratorImplementationType)
throws DIRuntimeException {
+        injector.putDecorationBefore(bindingKey, decoratorProvider(decoratorImplementationType));
+        return this;
+    }
+
+    private DecoratorProvider<T> decoratorProvider(Class<? extends T> decoratorType)
{
+        DecoratorProvider<T> provider0 = new ConstructorInjectingDecoratorProvider<T>(decoratorType,
injector);
+        DecoratorProvider<T> provider1 = new FieldInjectingDecoratorProvider<T>(decoratorType,
provider0, injector);
+        return provider1;
+    }
+
+}

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultInjector.java
Sun Mar 16 14:07:57 2014
@@ -20,6 +20,7 @@ package org.apache.cayenne.di.spi;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Injector;
@@ -39,6 +40,7 @@ public class DefaultInjector implements 
     private Scope noScope;
 
     private Map<Key<?>, Binding<?>> bindings;
+    private Map<Key<?>, Decoration<?>> decorations;
     private InjectionStack injectionStack;
     private Scope defaultScope;
 
@@ -51,6 +53,7 @@ public class DefaultInjector implements 
         this.defaultScope = singletonScope;
 
         this.bindings = new HashMap<Key<?>, Binding<?>>();
+        this.decorations = new HashMap<Key<?>, Decoration<?>>();
         this.injectionStack = new InjectionStack();
 
         DefaultBinder binder = new DefaultBinder(this);
@@ -64,6 +67,8 @@ public class DefaultInjector implements 
             for (Module module : modules) {
                 module.configure(binder);
             }
+            
+            applyDecorators();
         }
     }
 
@@ -85,6 +90,28 @@ public class DefaultInjector implements 
         // TODO: andrus 11/15/2009 - report overriding existing binding??
         bindings.put(bindingKey, new Binding<T>(provider, defaultScope));
     }
+    
+    <T> void putDecorationAfter(Key<T> bindingKey, DecoratorProvider<T>
decoratorProvider) {
+
+        Decoration<T> decoration = (Decoration<T>) decorations.get(bindingKey);
+        if (decoration == null) {
+            decoration = new Decoration<T>();
+            decorations.put(bindingKey, decoration);
+        }
+
+        decoration.after(decoratorProvider);
+    }
+    
+    <T> void putDecorationBefore(Key<T> bindingKey, DecoratorProvider<T>
decoratorProvider) {
+
+        Decoration<T> decoration = (Decoration<T>) decorations.get(bindingKey);
+        if (decoration == null) {
+            decoration = new Decoration<T>();
+            decorations.put(bindingKey, decoration);
+        }
+
+        decoration.before(decoratorProvider);
+    }
 
     <T> void changeBindingScope(Key<T> bindingKey, Scope scope) {
         if (scope == null) {
@@ -145,5 +172,17 @@ public class DefaultInjector implements 
     Scope getNoScope() {
         return noScope;
     }
+    
+    void applyDecorators() {
+        for (Entry<Key<?>, Decoration<?>> e : decorations.entrySet()) {
+
+            Binding b = bindings.get(e.getKey());
+            if (b == null) {
+                // TODO: print warning - decorator of a non-existing service..
+                continue;
+            }
 
+            b.decorate(e.getValue());
+        }
+    }
 }

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultListBuilder.java
Sun Mar 16 14:07:57 2014
@@ -83,7 +83,7 @@ class DefaultListBuilder<T> implements L
             injector.putBinding(bindingKey, provider);
         }
         else {
-            provider = (ListProvider) binding.getUnscoped();
+            provider = (ListProvider) binding.getOriginal();
         }
 
         return provider;

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultMapBuilder.java
Sun Mar 16 14:07:57 2014
@@ -85,7 +85,7 @@ class DefaultMapBuilder<T> implements Ma
             injector.putBinding(bindingKey, provider);
         }
         else {
-            provider = (MapProvider) binding.getUnscoped();
+            provider = (MapProvider) binding.getOriginal();
         }
 
         return provider;

Copied: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java?p2=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingDecoratorProvider.java
Sun Mar 16 14:07:57 2014
@@ -18,38 +18,39 @@
  ****************************************************************/
 package org.apache.cayenne.di.spi;
 
+import java.lang.reflect.Field;
+
+import org.apache.cayenne.di.DIRuntimeException;
 import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
 
 /**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
+ * @since 3.2
  */
-class Binding<T> {
-
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
-
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
-    }
-
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
+class FieldInjectingDecoratorProvider<T> implements DecoratorProvider<T> {
 
-    Provider<T> getUnscoped() {
-        return unscoped;
+    private Class<? extends T> implementation;
+    private DefaultInjector injector;
+    private DecoratorProvider<T> delegate;
+
+    FieldInjectingDecoratorProvider(Class<? extends T> implementation, DecoratorProvider<T>
delegate,
+            DefaultInjector injector) {
+        this.delegate = delegate;
+        this.injector = injector;
+        this.implementation = implementation;
     }
 
-    Provider<T> getScoped() {
-        return scoped;
+    @Override
+    public Provider<T> get(final Provider<T> undecorated) throws DIRuntimeException
{
+        return new FieldInjectingProvider<T>(delegate.get(undecorated), injector) {
+
+            @Override
+            protected Object value(Field field, String bindingName) {
+                if (field.getType().isAssignableFrom(implementation)) {
+                    return undecorated.get();
+                }
+
+                return super.value(field, bindingName);
+            }
+        };
     }
 }

Modified: cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java?rev=1578076&r1=1578075&r2=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
(original)
+++ cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
Sun Mar 16 14:07:57 2014
@@ -64,50 +64,47 @@ class FieldInjectingProvider<T> implemen
 
     private void injectMember(Object object, Field field, String bindingName) {
 
-        InjectionStack stack = injector.getInjectionStack();
+        Object value = value(field, bindingName);
+
+        field.setAccessible(true);
+        try {
+            field.set(object, value);
+        } catch (Exception e) {
+            String message = String.format("Error injecting into field %s.%s of type %s",
field.getDeclaringClass()
+                    .getName(), field.getName(), field.getType().getName());
+            throw new DIRuntimeException(message, e);
+        }
+    }
+    
+    /**
+     * @since 3.2
+     */
+    protected Object value(Field field, String bindingName) {
 
-        Object value;
         Class<?> fieldType = field.getType();
+        InjectionStack stack = injector.getInjectionStack();
 
         if (Provider.class.equals(fieldType)) {
 
             Class<?> objectClass = DIUtil.parameterClass(field.getGenericType());
 
             if (objectClass == null) {
-                throw new DIRuntimeException(
-                        "Provider field %s.%s of type %s must be "
-                                + "parameterized to be usable for injection",
-                        field.getDeclaringClass().getName(),
-                        field.getName(),
-                        fieldType.getName());
+                throw new DIRuntimeException("Provider field %s.%s of type %s must be "
+                        + "parameterized to be usable for injection", field.getDeclaringClass().getName(),
+                        field.getName(), fieldType.getName());
             }
 
-            value = injector.getProvider(Key.get(objectClass, bindingName));
-        }
-        else {
+            return injector.getProvider(Key.get(objectClass, bindingName));
+        } else {
 
             Key<?> key = Key.get(fieldType, bindingName);
 
             stack.push(key);
             try {
-                value = injector.getInstance(key);
-            }
-            finally {
+                return injector.getInstance(key);
+            } finally {
                 stack.pop();
             }
         }
-
-        field.setAccessible(true);
-        try {
-            field.set(object, value);
-        }
-        catch (Exception e) {
-            String message = String.format(
-                    "Error injecting into field %s.%s of type %s",
-                    field.getDeclaringClass().getName(),
-                    field.getName(),
-                    fieldType.getName());
-            throw new DIRuntimeException(message, e);
-        }
     }
 }

Copied: cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator1.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator1.java?p2=cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator1.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator1.java
Sun Mar 16 14:07:57 2014
@@ -16,40 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.di.spi;
+package org.apache.cayenne.di.mock;
 
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
+import org.apache.cayenne.di.Inject;
 
-/**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
- */
-class Binding<T> {
+public class MockInterface1_Decorator1 implements MockInterface1 {
 
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
+    @Inject
+    private MockInterface1 delegate;
 
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
-    }
-
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
-
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
-
-    Provider<T> getScoped() {
-        return scoped;
+    @Override
+    public String getName() {
+        return "[" + delegate.getName() + "]";
     }
 }

Copied: cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator2.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator2.java?p2=cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator2.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator2.java
Sun Mar 16 14:07:57 2014
@@ -16,40 +16,20 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.di.spi;
+package org.apache.cayenne.di.mock;
 
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
+import org.apache.cayenne.di.Inject;
 
-/**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
- */
-class Binding<T> {
+public class MockInterface1_Decorator2 implements MockInterface1 {
 
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
+    private MockInterface1 delegate;
 
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
+    public MockInterface1_Decorator2(@Inject MockInterface1 delegate) {
+        this.delegate = delegate;
     }
 
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
-
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
-
-    Provider<T> getScoped() {
-        return scoped;
+    @Override
+    public String getName() {
+        return "{" + delegate.getName() + "}";
     }
-}
+}
\ No newline at end of file

Copied: cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator3.java
(from r1577997, cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java)
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator3.java?p2=cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator3.java&p1=cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java&r1=1577997&r2=1578076&rev=1578076&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/main/java/org/apache/cayenne/di/spi/Binding.java (original)
+++ cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface1_Decorator3.java
Sun Mar 16 14:07:57 2014
@@ -16,40 +16,20 @@
  *  specific language governing permissions and limitations
  *  under the License.
  ****************************************************************/
-package org.apache.cayenne.di.spi;
+package org.apache.cayenne.di.mock;
 
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.di.Scope;
+import org.apache.cayenne.di.Inject;
 
-/**
- * A binding encapsulates DI provider scoping settings and allows to change them as many
- * times as needed.
- * 
- * @since 3.1
- */
-class Binding<T> {
+public class MockInterface1_Decorator3 implements MockInterface1 {
 
-    private Provider<T> unscoped;
-    private Provider<T> scoped;
+    private MockInterface1 delegate;
 
-    Binding(Provider<T> provider, Scope initialScope) {
-        this.unscoped = provider;
-        this.scoped = initialScope != null ? initialScope.scope(provider) : provider;
+    public MockInterface1_Decorator3(@Inject MockInterface1 delegate) {
+        this.delegate = delegate;
     }
 
-    void changeScope(Scope scope) {
-        if (scope == null) {
-            scope = NoScope.INSTANCE;
-        }
-
-        scoped = scope.scope(unscoped);
-    }
-
-    Provider<T> getUnscoped() {
-        return unscoped;
-    }
-
-    Provider<T> getScoped() {
-        return scoped;
+    @Override
+    public String getName() {
+        return "<" + delegate.getName() + ">";
     }
-}
+}
\ No newline at end of file

Added: cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java?rev=1578076&view=auto
==============================================================================
--- cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
(added)
+++ cayenne/main/trunk/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorDecorationTest.java
Sun Mar 16 14:07:57 2014
@@ -0,0 +1,90 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.di.spi;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.di.Binder;
+import org.apache.cayenne.di.Module;
+import org.apache.cayenne.di.mock.MockImplementation1;
+import org.apache.cayenne.di.mock.MockInterface1;
+import org.apache.cayenne.di.mock.MockInterface1_Decorator1;
+import org.apache.cayenne.di.mock.MockInterface1_Decorator2;
+import org.apache.cayenne.di.mock.MockInterface1_Decorator3;
+
+public class DefaultInjectorDecorationTest extends TestCase {
+
+    public void testSingleDecorator_After() {
+
+        Module module = new Module() {
+
+            @Override
+            public void configure(Binder binder) {
+                binder.bind(MockInterface1.class).to(MockImplementation1.class);
+                binder.decorate(MockInterface1.class).after(MockInterface1_Decorator1.class);
+            }
+        };
+
+        DefaultInjector injector = new DefaultInjector(module);
+
+        MockInterface1 service = injector.getInstance(MockInterface1.class);
+        assertNotNull(service);
+        assertEquals("[MyName]", service.getName());
+    }
+
+    public void testSingleDecorator_Before() {
+
+        Module module = new Module() {
+
+            @Override
+            public void configure(Binder binder) {
+                binder.bind(MockInterface1.class).to(MockImplementation1.class);
+                binder.decorate(MockInterface1.class).before(MockInterface1_Decorator1.class);
+            }
+        };
+
+        DefaultInjector injector = new DefaultInjector(module);
+
+        MockInterface1 service = injector.getInstance(MockInterface1.class);
+        assertNotNull(service);
+        assertEquals("[MyName]", service.getName());
+    }
+
+    public void testDecoratorChain() {
+
+        Module module = new Module() {
+
+            @Override
+            public void configure(Binder binder) {
+                binder.bind(MockInterface1.class).to(MockImplementation1.class);
+                binder.decorate(MockInterface1.class).before(MockInterface1_Decorator1.class);
+                binder.decorate(MockInterface1.class).before(MockInterface1_Decorator2.class);
+                binder.decorate(MockInterface1.class).after(MockInterface1_Decorator3.class);
+
+            }
+        };
+
+        DefaultInjector injector = new DefaultInjector(module);
+
+        MockInterface1 service = injector.getInstance(MockInterface1.class);
+        assertNotNull(service);
+        assertEquals("<[{MyName}]>", service.getName());
+    }
+
+}



Mime
View raw message