/trunk/src/test/java/org/mentacontainer/impl/MentaContainerTest.java |
---|
4,6 → 4,7 |
import org.junit.Test; |
import org.mentacontainer.Container; |
import org.mentacontainer.Scope; |
public class MentaContainerTest { |
56,7 → 57,7 |
Container c = new MentaContainer(); |
c.ioc("myStr", String.class, true).addInitValue("hello"); |
c.ioc("myStr", String.class, Scope.SINGLETON).addInitValue("hello"); |
Assert.assertEquals("hello", c.get("myStr")); |
68,6 → 69,63 |
Assert.assertTrue(s1.equals(s2)); |
} |
private static class MyThread extends Thread { |
private final Container c; |
private final String key; |
private String value = null; |
public MyThread(Container c, String key) { |
super(); |
this.c = c; |
this.key = key; |
} |
@Override |
public void run() { |
for(int i = 0; i < 50; i++) { |
String v = c.get(key); |
if (this.value != null) { |
Assert.assertTrue(this.value == v); |
} |
this.value = v; |
} |
} |
public String getValue() { return value; } |
} |
@Test |
public void testThreadLocal() throws Exception { |
final Container c = new MentaContainer(); |
c.ioc("myStr", String.class, Scope.THREAD).addInitValue("saoj"); |
String s1 = c.get("myStr"); |
MyThread t1 = new MyThread(c, "myStr"); |
MyThread t2 = new MyThread(c, "myStr"); |
t1.start(); |
t2.start(); |
t1.join(); |
t2.join(); |
String s2 = t1.getValue(); |
String s3 = t2.getValue(); |
Assert.assertTrue(s1 != s2); |
Assert.assertTrue(s2 != s3); |
} |
public static interface MyDAO { |
141,7 → 199,7 |
c.ioc("myDAO", JdbcMyDAO.class); |
c.ioc("aDependency", SomeDependency.class, true /* singleton */).addProperty("name", "A super dependency!"); |
c.ioc("aDependency", SomeDependency.class, Scope.SINGLETON).addProperty("name", "A super dependency!"); |
c.ioc("connection", Connection.class).addInitValue("A super JDBC connection!"); |
/trunk/src/main/java/org/mentacontainer/impl/MentaContainer.java |
---|
10,6 → 10,7 |
import org.mentacontainer.ConfigurableComponent; |
import org.mentacontainer.Container; |
import org.mentacontainer.Dependency; |
import org.mentacontainer.Scope; |
import org.mentacontainer.util.InjectionUtils; |
import org.mentacontainer.util.InjectionUtils.Provider; |
22,11 → 23,28 |
private Map<String, Component> beans = new HashMap<String, Component>(); |
private Set<String> singletons = new HashSet<String>(); |
private Map<String, Scope> scopes = new HashMap<String, Scope>(); |
private Map<String, Object> singletonsCache = new HashMap<String, Object>(); |
private Map<String, ThreadLocal<Object>> threadLocalsCache = new HashMap<String, ThreadLocal<Object>>(); |
private Set<Dependency> dependencies = new HashSet<Dependency>(); |
public void clear(Scope scope) { |
if (scope == Scope.SINGLETON) { |
singletonsCache.clear(); |
} else if (scope == Scope.THREAD) { |
for(ThreadLocal<Object> t : threadLocalsCache.values()) { |
t.set(null); |
} |
} |
} |
public <T> T get(String key) { |
34,19 → 52,19 |
Component c = beans.get(key); |
boolean isSingleton = singletons.contains(key); |
Scope scope = scopes.get(key); |
Object target = null; |
try { |
if (isSingleton) { |
if (scope == Scope.SINGLETON) { |
if (singletonsCache.containsKey(key)) { |
target = singletonsCache.get(key); |
return (T) target; |
return (T) target; // no need to wire again... |
} else { |
54,11 → 72,50 |
singletonsCache.put(key, target); |
} |
} else if (scope == Scope.THREAD) { |
if (threadLocalsCache.containsKey(key)) { |
ThreadLocal<Object> t = threadLocalsCache.get(key); |
target = t.get(); |
if (target == null) { // different thread... |
target = c.getInstance(); |
t.set(target); |
// don't return... let it be wired... |
} else { |
return (T) target; // no need to wire again... |
} |
} else { |
ThreadLocal<Object> t = new ThreadLocal<Object>(); |
target = c.getInstance(); |
t.set(target); |
threadLocalsCache.put(key, t); |
// let it be wired... |
} |
} else if (scope == Scope.NONE) { |
} else { |
target = c.getInstance(); |
} else { |
throw new UnsupportedOperationException("Don't know how to handle scope: " + scope); |
} |
if (target != null) { |
113,27 → 170,22 |
} |
} |
public Component ioc(String key, Component component, boolean isSingleton) { |
public Component ioc(String key, Component component, Scope scope) { |
beans.put(key, component); |
singletonsCache.remove(key); // just in case we are overriding a previous singleton bean... |
if (isSingleton) { |
singletons.add(key); |
} else { |
threadLocalsCache.remove(key); // just in case we are overriding a previous thread local... |
singletons.remove(key); // just in case... |
} |
scopes.put(key, scope); |
return component; |
} |
public Component ioc(String key, Component component) { |
return ioc(key, component, false); |
return ioc(key, component, Scope.NONE); |
} |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass) { |
145,11 → 197,11 |
return cc; |
} |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, boolean singleton) { |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) { |
ConfigurableComponent cc = new MentaComponent(klass); |
ioc(key, cc, singleton); |
ioc(key, cc, scope); |
return cc; |
} |
/trunk/src/main/java/org/mentacontainer/Container.java |
---|
7,7 → 7,7 |
* <li> Constructor injection for bean setup</li> |
* <li> Setter injection for bean setup</li> |
* <li> Auto-wiring based on name and type</li> |
* <li> Singleton</li> |
* <li> Scopes: Singleton and ThreadLocal</li> |
* <li> Wiring of external beans with the beans configured in this container</li> |
* <li> Annotation and XML free (programmatic configuration is the way to go!) |
* </ul> |
34,23 → 34,25 |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @param klass The class used to instantiate the bean, in other words, its implementation. |
* @param singleton A boolean to indicate if this bean will be a singleton. |
* @param scope The scope of the component. |
* @return The component created as a ConfigurableComponent. (Fluent API) |
* @see Scope |
*/ |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, boolean singleton); |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope); |
/** |
* Same as {@link #ioc(String, Class, boolean)} except that it assumes |
* singleton is false. |
* Same as {@link #ioc(String, Class, Scope)} except that it assumes |
* there is no scope (Scope.NONE). |
* |
* @param key |
* @param klass |
* @return The component created as a ConfigurableComponent. (Fluent API) |
* @see Scope |
*/ |
public ConfigurableComponent ioc(String key, Class<?extends Object> klass); |
/** |
* Set up IoC based on the component passed. |
* Set up IoC based on the component passed. The scope assumed is NONE. |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @param component The component for the IoC. |
60,15 → 62,16 |
public Component ioc(String key, Component component); |
/** |
* Set up IoC based on the component passed. Specify whether this will be a singleton component. |
* Set up IoC based on the component passed. Specify the scope of the component. |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @param component The component for the IoC. |
* @param isSingleton Should this component be treated as a singleton? |
* @param scope The scope used by the component. |
* @return The component passed as a parameter. |
* @see Component |
* @see Scope |
*/ |
public Component ioc(String key, Component component, boolean isSingleton); |
public Component ioc(String key, Component component, Scope scope); |
/** |
* Configure a bean dependency to be auto-wired by the container. In general you want the |
123,4 → 126,12 |
* @return true if the container contains this bean. |
*/ |
public boolean contains(String key); |
/** |
* Clear all cached instances for that scope. If you have a thread pool for example you will |
* have to clear the THREAD scope when your thread is returned to the pool. |
* |
* @param scope The scope to be cleared. |
*/ |
public void clear(Scope scope); |
} |
/trunk/src/main/java/org/mentacontainer/Scope.java |
---|
New file |
0,0 → 1,19 |
package org.mentacontainer; |
public enum Scope { |
/** |
* The container calls component.get() on every request for the component, returning always new instances. |
*/ |
NONE, |
/** |
* The container calls component.get() only once and caches the value, returning always the same instance. |
*/ |
SINGLETON, |
/** |
* The container calls component.get() and caches the value on a thread local, so the same thread will always get the same instance. |
*/ |
THREAD |
} |
/trunk/src/main/java/org/mentacontainer/example/BasicOperations.java |
---|
3,6 → 3,7 |
import java.util.Date; |
import org.mentacontainer.Container; |
import org.mentacontainer.Scope; |
import org.mentacontainer.impl.MentaContainer; |
public class BasicOperations { |
44,7 → 45,7 |
Container c = new MentaContainer(); |
c.ioc("myString", String.class, true /* singleton */).addInitValue("saoj"); |
c.ioc("myString", String.class, Scope.SINGLETON).addInitValue("saoj"); |
String s1 = c.get("myString"); |