(no commit message)
authorErik Brakkee <erik@brakkee.org>
Thu, 15 Jul 2010 13:50:11 +0000 (13:50 +0000)
committerErik Brakkee <erik@brakkee.org>
Thu, 15 Jul 2010 13:50:11 +0000 (13:50 +0000)
12 files changed:
support/inject/src/main/java/org/wamblee/inject/Injectable.java [new file with mode: 0644]
support/inject/src/main/java/org/wamblee/inject/Injector.java [new file with mode: 0644]
support/inject/src/main/java/org/wamblee/inject/InjectorCache.java [new file with mode: 0644]
support/inject/src/main/java/org/wamblee/inject/InjectorFactory.java [new file with mode: 0644]
support/inject/src/main/java/org/wamblee/inject/InjectorFactoryBuilder.java [new file with mode: 0644]
support/inject/src/main/java/org/wamblee/inject/SimpleInjector.java [new file with mode: 0644]
support/inject/src/test/java/org/wamblee/inject/InjectableTest.java [new file with mode: 0644]
support/inject/src/test/java/org/wamblee/inject/InjectorCacheTest.java [new file with mode: 0644]
support/inject/src/test/java/org/wamblee/inject/InjectorFactoryBuilderTest.java [new file with mode: 0644]
support/inject/src/test/java/org/wamblee/inject/Pojo.java [new file with mode: 0644]
support/inject/src/test/java/org/wamblee/inject/TestInjectorFactory.java [new file with mode: 0644]
support/inject/src/test/resources/META-INF/services/org.wamblee.inject.InjectorFactory [new file with mode: 0644]

diff --git a/support/inject/src/main/java/org/wamblee/inject/Injectable.java b/support/inject/src/main/java/org/wamblee/inject/Injectable.java
new file mode 100644 (file)
index 0000000..0c881d9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import java.util.ServiceLoader;
+
+
+/**
+ * This abstract base class performs injection at construction. Be sure not to
+ * initialize fields of derived classes to null as these will override the
+ * initializations of this base class.
+ * 
+ * Use this by subclassing through {@link #Injectable()).
+ * 
+ * To use this class, the {@link ServiceLoader} mechanism must be used to locate
+ * a {@link InjectorFactory}. The first implementation that is found will be
+ * used for injection.
+ * 
+ * @author Erik Brakkee
+ */
+public abstract class Injectable {
+
+    private static final SimpleInjector INJECTOR = new SimpleInjector(
+        InjectorFactoryBuilder.getInjectorFactory());
+
+    /**
+     * Inheritance style constructor.
+     */
+    protected Injectable() {
+        INJECTOR.inject(this);
+    }    
+}
diff --git a/support/inject/src/main/java/org/wamblee/inject/Injector.java b/support/inject/src/main/java/org/wamblee/inject/Injector.java
new file mode 100644 (file)
index 0000000..e42cc5f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+/**
+ * Interface used to perform injection with. An injector instance knows how to perform injection in 
+ * one or more specific classes. 
+ * 
+ * @author Erik Brakkee
+ */
+public interface Injector {
+
+    /**
+     * Injects beans into a given component of the required class.
+     * 
+     * @param aComponent
+     *            Component to inject into.
+     * @throws IllegalArgumentException In case the argument passed is not supported for injection
+     * @throws NullPointerException In case the argument passed is null. 
+     */
+    void inject(Object aComponent);
+
+}
\ No newline at end of file
diff --git a/support/inject/src/main/java/org/wamblee/inject/InjectorCache.java b/support/inject/src/main/java/org/wamblee/inject/InjectorCache.java
new file mode 100644 (file)
index 0000000..9bf6e2d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Cache of {@link CdiInjector}s for efficiency to avoid duplicate analysis of a
+ * given class.
+ * 
+ * @author Erik Brakkee
+ */
+public class InjectorCache {
+
+    private Map<String, Injector> injectors;
+
+    private InjectorFactory injectorFactory;
+
+    /**
+     * Constructs an empty cache.
+     * 
+     * @param aMgr
+     *            Bean manager.
+     */
+    public InjectorCache(InjectorFactory aInjectorFactory) {
+        injectorFactory = aInjectorFactory;
+        injectors = new ConcurrentHashMap<String, Injector>();
+    }
+
+    /**
+     * Gets the injector for a given class. This returns a cached injector or
+     * creates a new injector and caches it.
+     * 
+     * @param aClass
+     *            Class to find injector for.
+     * @return Injector.
+     */
+    public Injector getInjector(Class aClass) {
+        Injector injector = injectors.get(aClass.getName());
+        if (injector == null) {
+            // create and add injector
+            // NOTE: in rare circumstances this will lead to parallel
+            // creation of
+            // an injector for the same class. However, only one of them
+            // will be the final one
+            // in the map. There are no side effects of this duplicate
+            // creation of injectors.
+            injector = injectorFactory.create(aClass);
+            injectors.put(aClass.getName(), injector);
+        }
+        return injector;
+    }
+}
diff --git a/support/inject/src/main/java/org/wamblee/inject/InjectorFactory.java b/support/inject/src/main/java/org/wamblee/inject/InjectorFactory.java
new file mode 100644 (file)
index 0000000..84f7a66
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+
+/**
+ * Injector factory used. This creates an injector that is appropriate for a certain class. 
+ * May be subclassed for testing or other advanced usage (even replacing CDI with another
+ * injection framework).
+ * 
+ * Implementations of this calss must have a default no-arg constructor. 
+ * 
+ * @author Erik Brakkee
+ */
+public interface InjectorFactory {
+
+    /**
+     * Creates an injector.
+     * @return Injector fot he given class.
+     * @throws IllegalArgumentException In case the given class cannot be used. 
+     */
+    Injector create(Class aClass);
+
+}
diff --git a/support/inject/src/main/java/org/wamblee/inject/InjectorFactoryBuilder.java b/support/inject/src/main/java/org/wamblee/inject/InjectorFactoryBuilder.java
new file mode 100644 (file)
index 0000000..d600500
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import java.util.NoSuchElementException;
+import java.util.ServiceLoader;
+
+/**
+ * Utility for obtaining an implementation of the injector factory using
+ * {@link ServiceLoader}.
+ * 
+ * @author Erik Brakkee
+ */
+public class InjectorFactoryBuilder {
+
+    /**
+     * Gets the injector factory by using the first one found using 
+     * {@link ServiceLoader}. 
+     * 
+     * @return InjectorFactory. 
+     */
+    public static InjectorFactory getInjectorFactory() {
+        ServiceLoader<InjectorFactory> factories = ServiceLoader
+            .load(InjectorFactory.class);
+        try {
+            return (InjectorFactory) factories.iterator().next();
+        } catch (NoSuchElementException e) {
+            throw new RuntimeException("Can not find InjectorFactory to use");
+        }
+    }
+}
diff --git a/support/inject/src/main/java/org/wamblee/inject/SimpleInjector.java b/support/inject/src/main/java/org/wamblee/inject/SimpleInjector.java
new file mode 100644 (file)
index 0000000..61bb556
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import java.util.ServiceLoader;
+
+
+/**
+ * Singleton injector access. This should be used as main entry point for
+ * injection. A different {@link InjectorFactory} can be plugged in for testing.
+ * 
+ * Given the following class: 
+ * <pre> 
+ * class Pojo {
+ *   &#064;EJB
+ *   private Service service; 
+ *   
+ *   ...
+ * }
+ * </pre>
+ * injecting the EJB into a POJO using Contexts and Dependency Injection is accomplished as follows: 
+ * <pre>
+ *   Pojo pojo = new Pojo(); 
+ *   SimpleInjector injector = new SimpleInjector(new CdiInjectorFactory()); 
+ *   injector.inject(pojo);
+ * </pre>
+ * 
+ * Note that it is recommended to cache the injector because the injector does caching 
+ * of the types that it injects into. Caching the injector makes sure that a class is not
+ * analysed again for annotation every time injection is used. 
+ * 
+ * The {@link InjectorFactory} to be used can also be found using a {@link ServiceLoader} discovery
+ * mechanism as provided by {@link InjectorFactoryBuilder}. 
+ * 
+ * @author Erik Brakkee
+ */
+public class SimpleInjector {
+
+    private InjectorCache cache;
+
+    /**
+     * Constructs the injector. 
+     * @param aFactory Factory to use. 
+     */
+    public SimpleInjector(InjectorFactory aFactory) { 
+        cache = new InjectorCache(aFactory);
+    }
+    
+    /**
+     * Injects into a given object.
+     * 
+     * @param aObject
+     *            Object to inject into.
+     */
+    public void inject(Object aObject) {
+        cache.getInjector(aObject.getClass()).inject(aObject);
+    }
+}
diff --git a/support/inject/src/test/java/org/wamblee/inject/InjectableTest.java b/support/inject/src/test/java/org/wamblee/inject/InjectableTest.java
new file mode 100644 (file)
index 0000000..150d4ad
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import static junit.framework.Assert.*;
+
+import org.junit.Test;
+
+public class InjectableTest {
+
+    @Test
+    public void testInjectInDerivedClass() { 
+        Pojo pojo = new Pojo(); 
+        assertEquals(TestInjectorFactory.MAGIC_VALUE, pojo.getValue()); 
+    }
+}
diff --git a/support/inject/src/test/java/org/wamblee/inject/InjectorCacheTest.java b/support/inject/src/test/java/org/wamblee/inject/InjectorCacheTest.java
new file mode 100644 (file)
index 0000000..8a5b2de
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import static junit.framework.Assert.*;
+
+import org.junit.Test;
+
+public class InjectorCacheTest {
+    
+    private static class MyInjector implements Injector { 
+        private String classname; 
+        
+        public MyInjector(String aClassname) { 
+            classname = aClassname; 
+        }
+        @Override
+        public void inject(Object aComponent) {
+            throw new RuntimeException("not implemented");
+        }
+        public String getClassname() {
+            return classname;
+        }
+    }
+
+    @Test
+    public void testCache() { 
+        InjectorFactory factory = new InjectorFactory() {
+            
+            @Override
+            public Injector create(Class aClass) {
+                return new MyInjector(aClass.getName());
+            }
+        };
+        InjectorCache cache = new InjectorCache(factory); 
+        // Unrealistic exmaple, but sufficient for test.
+      
+        Injector injector = cache.getInjector(String.class);
+        assertEquals(String.class.getName(), ((MyInjector)injector).getClassname());
+        
+        Injector injector2 = cache.getInjector(String.class); 
+        assertSame(injector, injector2);
+        
+        // verify we get another one for another class. 
+        Injector injector3 = cache.getInjector(Long.class);
+        assertEquals(Long.class.getName(), ((MyInjector)injector3).getClassname());
+        
+    }
+}
diff --git a/support/inject/src/test/java/org/wamblee/inject/InjectorFactoryBuilderTest.java b/support/inject/src/test/java/org/wamblee/inject/InjectorFactoryBuilderTest.java
new file mode 100644 (file)
index 0000000..1b1bf27
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+import org.junit.Test;
+import static junit.framework.TestCase.*; 
+
+public class InjectorFactoryBuilderTest {
+
+    @Test
+    public void testGetInjectorFactory() { 
+        InjectorFactory factory = InjectorFactoryBuilder.getInjectorFactory(); 
+        assertTrue(factory instanceof TestInjectorFactory);
+    }
+}
diff --git a/support/inject/src/test/java/org/wamblee/inject/Pojo.java b/support/inject/src/test/java/org/wamblee/inject/Pojo.java
new file mode 100644 (file)
index 0000000..38afd7b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+public class Pojo extends Injectable {
+
+    private String value; 
+    
+    public void setValue(String aValue) {
+        value = aValue;
+    }
+    
+    public String getValue() {
+        return value;
+    }
+}
diff --git a/support/inject/src/test/java/org/wamblee/inject/TestInjectorFactory.java b/support/inject/src/test/java/org/wamblee/inject/TestInjectorFactory.java
new file mode 100644 (file)
index 0000000..5e3d1cf
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2005-2010 the original author or authors.
+ * 
+ * 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.wamblee.inject;
+
+public class TestInjectorFactory implements InjectorFactory {
+    
+    public static final String MAGIC_VALUE = "Hello";
+
+    public static class TestInjector implements Injector {
+        @Override
+        public void inject(Object aComponent) {
+            Pojo pojo = (Pojo) aComponent;
+            pojo.setValue(MAGIC_VALUE);
+        }
+    }
+
+    @Override
+    public Injector create(Class aClass) {
+        return new TestInjector();
+    }
+
+}
diff --git a/support/inject/src/test/resources/META-INF/services/org.wamblee.inject.InjectorFactory b/support/inject/src/test/resources/META-INF/services/org.wamblee.inject.InjectorFactory
new file mode 100644 (file)
index 0000000..43b1a97
--- /dev/null
@@ -0,0 +1,2 @@
+
+org.wamblee.inject.TestInjectorFactory