/tags/menta-container-0.9.5/src/test/java/org/mentacontainer/impl/GenericComponentTest.java |
---|
New file |
0,0 → 1,43 |
package org.mentacontainer.impl; |
import junit.framework.Assert; |
import org.junit.Test; |
import org.mentacontainer.Component; |
import org.mentacontainer.Container; |
public class GenericComponentTest { |
public static class SomeFactory { |
public String giveMeSomething() { |
return String.valueOf(System.nanoTime()); |
} |
} |
@Test |
public void testGenericComponent() throws Exception { |
// in real life this will be a SessionFactory, a ConnectionPool or any factory... |
SomeFactory factory = new SomeFactory(); |
Container c = new MentaContainer(); |
// giveMeSomething => method that will be called to return object |
Component generic = new GenericComponent(factory, "giveMeSomething"); |
c.ioc("myFactory", generic); |
String s1 = c.get("myFactory"); |
Thread.sleep(5); // so strings are different... my cpu is fast! :-) |
String s2 = c.get("myFactory"); |
Assert.assertNotNull(s1); |
Assert.assertNotNull(s2); |
Assert.assertTrue(s1 != s2); |
Assert.assertTrue(!s1.equals(s2)); |
} |
} |
/tags/menta-container-0.9.5/src/test/java/org/mentacontainer/impl/MentaDependencyTest.java |
---|
New file |
0,0 → 1,50 |
package org.mentacontainer.impl; |
import java.lang.reflect.Method; |
import junit.framework.Assert; |
import org.junit.Test; |
import org.mentacontainer.Dependency; |
public class MentaDependencyTest { |
private static class User { |
private String username; |
public User() { } |
public User(String username) { |
this.username = username; |
} |
public String getUsername() { |
return username; |
} |
public void setUsername(String username) { |
this.username = username; |
} |
} |
@Test |
public void testDependency() { |
Dependency d = new MentaDependency("username", String.class, "theUsername"); |
Assert.assertEquals("username", d.getTarget()); |
Assert.assertEquals(String.class, d.getType()); |
Assert.assertEquals("theUsername", d.getSource()); |
Method m = d.check(User.class); |
Assert.assertNotNull(m); |
Assert.assertEquals("setUsername", m.getName()); |
Assert.assertEquals(String.class, m.getParameterTypes()[0]); |
} |
} |
/tags/menta-container-0.9.5/src/test/java/org/mentacontainer/impl/InstanceComponentTest.java |
---|
New file |
0,0 → 1,31 |
package org.mentacontainer.impl; |
import junit.framework.Assert; |
import org.junit.Test; |
import org.mentacontainer.Component; |
import org.mentacontainer.Container; |
public class InstanceComponentTest { |
@Test |
public void testInstanceComponent() throws Exception { |
String s = new String("saoj"); |
Component ic = new InstanceComponent(s); |
Container c = new MentaContainer(); |
c.ioc("myString", ic); |
String s1 = c.get("myString"); |
String s2 = c.get("myString"); |
Assert.assertNotNull(s1); |
Assert.assertNotNull(s2); |
Assert.assertTrue(s == s1); |
Assert.assertTrue(s1 == s2); |
} |
} |
/tags/menta-container-0.9.5/src/test/java/org/mentacontainer/impl/MentaComponentTest.java |
---|
New file |
0,0 → 1,44 |
package org.mentacontainer.impl; |
import junit.framework.Assert; |
import org.junit.Test; |
import org.mentacontainer.Component; |
public class MentaComponentTest { |
private static class User { |
private String username; |
public User() { } |
public User(String username) { |
this.username = username; |
} |
public String getUsername() { |
return username; |
} |
public void setUsername(String username) { |
this.username = username; |
} |
} |
@Test |
public void testComponent() { |
Component c1 = new MentaComponent(User.class).addInitValue("saoj"); |
Component c2 = new MentaComponent(User.class).addProperty("username", "soliveira"); |
User u1 = c1.getInstance(); |
User u2 = c2.getInstance(); |
Assert.assertTrue(u1 != u2); |
Assert.assertTrue(!u1.getUsername().equals(u2.getUsername())); |
} |
} |
/tags/menta-container-0.9.5/src/test/java/org/mentacontainer/impl/MentaContainerTest.java |
---|
New file |
0,0 → 1,416 |
package org.mentacontainer.impl; |
import junit.framework.Assert; |
import org.junit.Test; |
import org.mentacontainer.Clearable; |
import org.mentacontainer.Component; |
import org.mentacontainer.Container; |
import org.mentacontainer.Scope; |
public class MentaContainerTest { |
@Test |
public void testSimpleGet() { |
Container c = new MentaContainer(); |
c.ioc("myStr", String.class); |
Assert.assertEquals("", c.get("myStr")); |
String s1 = c.get("myStr"); |
String s2 = c.get("myStr"); |
Assert.assertTrue(s1 != s2); |
Assert.assertTrue(s1.equals(s2)); |
} |
@Test |
public void testConstructorInit() { |
Container c = new MentaContainer(); |
c.ioc("myStr", String.class).addInitValue("hello"); |
Assert.assertEquals("hello", c.get("myStr")); |
String s1 = c.get("myStr"); |
String s2 = c.get("myStr"); |
Assert.assertTrue(s1 != s2); |
Assert.assertTrue(s1.equals(s2)); |
c.ioc("anotherStr", String.class).addInitValue("hi"); |
String s3 = c.get("anotherStr"); |
Assert.assertTrue(s1 != s3); |
Assert.assertFalse(s1.equals(s3)); |
} |
@Test |
public void testSingleton() { |
Container c = new MentaContainer(); |
c.ioc("myStr", String.class, Scope.SINGLETON).addInitValue("hello"); |
Assert.assertEquals("hello", c.get("myStr")); |
String s1 = c.get("myStr"); |
String s2 = c.get("myStr"); |
Assert.assertTrue(s1 == s2); |
Assert.assertTrue(s1.equals(s2)); |
} |
@Test |
public void testCheckAndClear() { |
Container c = new MentaContainer(); |
c.ioc("myStr", String.class, Scope.SINGLETON).addInitValue("hello"); |
Assert.assertEquals(false, c.check("myStr")); |
String s1 = c.get("myStr"); |
Assert.assertEquals(true, c.check("myStr")); |
String s2 = c.get("myStr"); |
Assert.assertTrue(s1 == s2); |
c.clear(Scope.SINGLETON); |
Assert.assertEquals(false, c.check("myStr")); |
String s3 = c.get("myStr"); |
Assert.assertTrue(s3 != 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 testScopes() { |
Container c = new MentaContainer(); |
// if you don't provide a scope the Scope is NONE |
// meaning a new instance is created on every |
// request for the component |
c.ioc("myString", String.class).addInitValue("saoj"); |
String s1 = c.get("myString"); |
String s2 = c.get("myString"); |
Assert.assertTrue(s1 != s2); |
// then you can use SINGLETON |
// always get the same instance no matter what |
c.ioc("myString", String.class, Scope.SINGLETON).addInitValue("saoj"); |
s1 = c.get("myString"); |
s2 = c.get("myString"); |
Assert.assertTrue(s1 == s2); |
// then you can use THREAD |
// each thread will get a different instance |
c.ioc("myString", String.class, Scope.THREAD).addInitValue("saoj"); |
s1 = c.get("myString"); |
s2 = c.get("myString"); |
Assert.assertTrue(s1 == s2); // same thread |
} |
@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 { |
public Object getSomething(); |
} |
public static class SomeDependency { |
private String name; |
public SomeDependency() { } |
public void setName(String name) { |
this.name = name; |
} |
public String getName() { |
return name; |
} |
} |
public static class Connection { |
private final String name; |
private SomeDependency dep; |
public Connection(String name) { |
this.name = name; |
} |
public String toString() { |
return getClass().getName() + ": " + name; |
} |
public String getName() { return name; } |
public void setMyDep(SomeDependency dep) { this.dep = dep; } |
public SomeDependency getMyDep() { return dep; } |
} |
public static class JdbcMyDAO implements MyDAO { |
private Connection conn; |
public void setConn(Connection conn) { this.conn = conn; } |
public Connection getConn() { return conn; } |
public Object getSomething() { |
// use the connection to do something... |
Assert.assertNotNull(conn); // it cannot be null! |
// also test if the connection also received the myDep dependency... |
Assert.assertNotNull(conn.getMyDep()); |
return conn.toString(); |
} |
} |
private Container getConfiguredContainer() { |
Container c = new MentaContainer(); |
c.ioc("myDAO", JdbcMyDAO.class); |
c.ioc("aDependency", SomeDependency.class, Scope.SINGLETON).addProperty("name", "A super dependency!"); |
c.ioc("connection", Connection.class).addInitValue("A super JDBC connection!"); |
c.autowire("conn" /* the property name that will receive the dependency */, |
Connection.class /* the type of the property that will receive the dependency */, |
"connection" /* the source inside the container */); |
c.autowire("myDep" /* notice this is the setter of the Connection class */, |
SomeDependency.class /* the type - it could be an interface for better decoupling */, |
"aDependency" /* again this is the name of the bean/component inside the container */); |
return c; |
} |
@Test |
public void testAutoWiring() { |
Container c = getConfiguredContainer(); |
MyDAO myDAO = c.get("myDAO"); |
// check implementation... |
Assert.assertEquals(JdbcMyDAO.class, myDAO.getClass()); |
// check dependency... |
Connection conn = ((JdbcMyDAO) myDAO).getConn(); |
Assert.assertNotNull(conn); |
Assert.assertEquals("A super JDBC connection!", conn.getName()); |
// check dependency of dependency... |
Assert.assertEquals(c.get("aDependency"), conn.getMyDep()); |
Assert.assertTrue(c.get("aDependency") == conn.getMyDep()); // singleton! |
// check DAO can do its job... |
Assert.assertNotNull(myDAO.getSomething()); |
} |
public static class SomeAction { |
private MyDAO myDAO = null; |
public void setMyDAO(MyDAO myDAO) { |
this.myDAO = myDAO; |
} |
public MyDAO getMyDAO() { return myDAO; } |
} |
@Test |
public void testPopulate() { |
Container c = getConfiguredContainer(); |
SomeAction a = new SomeAction(); |
c.populate(a); // great... properties of SomeAction were populated by container... |
// let's check if myDAO was injected... |
Assert.assertNotNull(a.getMyDAO()); |
// also check if myDAO was corrected wired... |
Connection conn = ((JdbcMyDAO) a.getMyDAO()).getConn(); |
Assert.assertNotNull(conn); |
// check if conn was also wired... |
Assert.assertNotNull(conn.getMyDep()); |
} |
private static class SomeObject { |
private boolean cleared = false; |
public void clear() { this.cleared = true; } |
public boolean isCleared() { return cleared; } |
} |
private static class SomeComponent implements Component, Clearable<SomeObject> { |
public <T> T getInstance() { |
return (T) new SomeObject(); |
} |
public void onCleared(SomeObject obj) { |
obj.clear(); |
} |
} |
@Test |
public void testClearable() { |
Container c = new MentaContainer(); |
c.ioc("o", new SomeComponent(), Scope.SINGLETON); |
SomeObject o = c.get("o"); |
c.clear(Scope.SINGLETON); |
Assert.assertEquals(true, o.isCleared()); |
c.ioc("o", new SomeComponent(), Scope.THREAD); |
o = c.get("o"); |
c.clear(Scope.SINGLETON); |
Assert.assertEquals(false, o.isCleared()); |
c.clear(Scope.THREAD); |
Assert.assertEquals(true, o.isCleared()); |
c.ioc("o", new SomeComponent(), Scope.NONE); |
o = c.get("o"); |
o = c.clear("o"); |
Assert.assertNull(o); |
c.ioc("o", new SomeComponent(), Scope.THREAD); |
o = c.clear("o"); |
Assert.assertNull(o); |
o = c.get("o"); |
o = c.clear("o"); |
Assert.assertEquals(true, o.isCleared()); |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/impl/GenericComponent.java |
---|
New file |
0,0 → 1,42 |
package org.mentacontainer.impl; |
import java.lang.reflect.Method; |
import org.mentacontainer.Component; |
import org.mentacontainer.util.FindMethod; |
public class GenericComponent implements Component { |
private final Object factory; |
private final Method method; |
public GenericComponent(Object factory, String methodName) { |
this.factory = factory; |
try { |
this.method = FindMethod.getMethod(factory.getClass(), methodName, new Class[] { }); |
this.method.setAccessible(true); |
} catch(Exception e) { |
throw new RuntimeException(e); |
} |
} |
public <T> T getInstance() { |
try { |
return (T) method.invoke(factory, (Object[]) null); |
} catch(Exception e) { |
throw new RuntimeException("Cannot invoke method: " + method, e); |
} |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/impl/MentaDependency.java |
---|
New file |
0,0 → 1,113 |
package org.mentacontainer.impl; |
import java.lang.reflect.Method; |
import java.util.HashMap; |
import java.util.Map; |
import org.mentacontainer.Dependency; |
import org.mentacontainer.util.InjectionUtils; |
/** |
* A simple implementation of the Dependency interface. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public class MentaDependency implements Dependency { |
private final String target; |
private String source; |
private final Class<? extends Object> klass; |
private Map<String, Method> cache = new HashMap<String, Method>(); |
public MentaDependency(String target, Class<? extends Object> klass, String source) { |
this.klass = klass; |
this.target = target; |
this.source = source; |
} |
public MentaDependency(String target, Class<? extends Object> klass) { |
this(target, klass, target); |
} |
public String getTarget() { |
return target; |
} |
public String getSource() { |
return source; |
} |
public Class<? extends Object> getType() { |
return klass; |
} |
public int hashCode() { |
return klass.hashCode() * 62 + target.hashCode() * 31 + source.hashCode(); |
} |
public boolean equals(Object obj) { |
if (!(obj instanceof MentaDependency)) return false; |
MentaDependency d = (MentaDependency) obj; |
if (!d.target.equals(this.target)) return false; |
if (!d.klass.equals(this.klass)) return false; |
return true; |
} |
public Method check(Class<? extends Object> targetClass) { |
String className = targetClass.getName(); |
// first check cache... |
Method m = null; |
synchronized(cache) { |
m = cache.get(className); |
} |
if (m == null && cache.containsKey(className)) return null; // it is null... |
if (m != null) return m; |
m = InjectionUtils.findMethodToInject(targetClass, target, klass); |
if (m != null) { |
synchronized(cache) { |
cache.put(className, m); |
} |
return m; |
} |
synchronized(cache) { |
// save null to indicate there is no method here... (so you don't do again to find null !!! |
cache.put(className, null); |
} |
return null; |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/impl/InstanceComponent.java |
---|
New file |
0,0 → 1,19 |
package org.mentacontainer.impl; |
import org.mentacontainer.Component; |
public class InstanceComponent implements Component { |
private final Object instance; |
public InstanceComponent(Object instance) { |
this.instance = instance; |
} |
public <T> T getInstance() { |
return (T) instance; |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/impl/MentaComponent.java |
---|
New file |
0,0 → 1,239 |
package org.mentacontainer.impl; |
import java.lang.reflect.Constructor; |
import java.lang.reflect.Method; |
import java.util.HashMap; |
import java.util.Iterator; |
import java.util.LinkedList; |
import java.util.List; |
import java.util.Map; |
import org.mentacontainer.ConfigurableComponent; |
import org.mentacontainer.util.FindMethod; |
/** |
* A simple implementation of the Component interface. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public class MentaComponent implements ConfigurableComponent { |
private final Class<? extends Object> klass; |
private Map<String, Object> props = null; |
private List<Object> initValues = null; |
private Constructor<? extends Object> constructor = null; |
private Map<String, Method> cache = null; |
public MentaComponent(Class<? extends Object> klass) { |
this.klass = klass; |
} |
public ConfigurableComponent addProperty(String name, Object value) { |
if (props == null) { |
props = new HashMap<String, Object>(); |
cache = new HashMap<String, Method>(); |
} |
props.put(name, value); |
return this; |
} |
public ConfigurableComponent addInitValue(Object value) { |
if (initValues == null) { |
initValues = new LinkedList<Object>(); |
} |
initValues.add(value); |
return this; |
} |
private Class<? extends Object>[] getClasses(List<Object> values) { |
Class<? extends Object>[] types = (Class<? extends Object>[]) new Class[values.size()]; |
Iterator<Object> iter = values.iterator(); |
int index = 0; |
while(iter.hasNext()) { |
Object value = iter.next(); |
if (value != null) { |
types[index++] = value.getClass(); |
} else { |
types[index++] = null; |
} |
} |
return types; |
} |
private Object [] getValues(List<Object> values) throws InstantiationException { |
Object [] array = new Object[values.size()]; |
int index = 0; |
Iterator<Object> iter = values.iterator(); |
while(iter.hasNext()) { |
Object obj = iter.next(); |
array[index++] = obj; |
} |
return array; |
} |
/* |
* Use reflection to set a property in the bean |
*/ |
private void setValue(Object bean, String name, Object value) { |
try { |
StringBuffer sb = new StringBuffer(30); |
sb.append("set"); |
sb.append(name.substring(0,1).toUpperCase()); |
if (name.length() > 1) sb.append(name.substring(1)); |
String methodName = sb.toString(); |
if (!cache.containsKey(name)) { |
Method m = null; |
try { |
m = FindMethod.getMethod(klass, methodName, new Class[] { value.getClass() }); |
} catch(Exception e) { |
// try primitive... |
Class<? extends Object> primitive = getPrimitiveFrom(value); |
if (primitive != null) { |
try { |
m = klass.getMethod(methodName, new Class[] { primitive }); |
} catch(Exception ex) { |
// not found! |
} |
} |
if (m == null) { |
throw new InstantiationException("Cannot find method or field for property: " + name); |
} |
} |
if (m != null) { |
cache.put(name, m); |
m.setAccessible(true); |
} |
} |
Method m = cache.get(name); |
if (m != null) { |
m.invoke(bean, new Object[] { value }); |
} |
} catch(Exception e) { |
throw new RuntimeException("Error trying to set a property with reflection: " + name, e); |
} |
} |
private static Class<? extends Object> getPrimitiveFrom(Object w) { |
if (w instanceof Boolean) { return Boolean.TYPE; } |
else if (w instanceof Byte) { return Byte.TYPE; } |
else if (w instanceof Short) { return Short.TYPE; } |
else if (w instanceof Character) { return Character.TYPE; } |
else if (w instanceof Integer) { return Integer.TYPE; } |
else if (w instanceof Long) { return Long.TYPE; } |
else if (w instanceof Float) { return Float.TYPE; } |
else if (w instanceof Double) { return Double.TYPE; } |
return null; |
} |
public <T> T getInstance() { |
Object obj = null; |
if (initValues != null && initValues.size() > 0) { |
if (constructor == null) { |
try { |
constructor = klass.getConstructor(getClasses(initValues)); |
} catch(Exception e) { |
throw new RuntimeException("Cannot find a constructor for class: " + klass, e); |
} |
} |
try { |
obj = constructor.newInstance(getValues(initValues)); |
} catch(Exception e) { |
throw new RuntimeException("Cannot create instance from constructor: " + constructor, e); |
} |
} else { |
try { |
obj = klass.newInstance(); |
} catch(Exception e) { |
throw new RuntimeException("Cannot create instance from class: " + klass, e); |
} |
} |
if (props != null && props.size() > 0) { |
Iterator<String> iter = props.keySet().iterator(); |
while(iter.hasNext()) { |
String name = iter.next(); |
Object value = props.get(name); |
setValue(obj, name, value); |
} |
} |
return (T) obj; |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/impl/MentaContainer.java |
---|
New file |
0,0 → 1,461 |
package org.mentacontainer.impl; |
import java.lang.reflect.Method; |
import java.util.Collections; |
import java.util.HashSet; |
import java.util.Hashtable; |
import java.util.LinkedList; |
import java.util.List; |
import java.util.Map; |
import java.util.Set; |
import org.mentacontainer.Clearable; |
import org.mentacontainer.Component; |
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; |
/** |
* The implementation of the IoC container. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public class MentaContainer implements Container { |
private Map<String, Component> beans = new Hashtable<String, Component>(); |
private Map<String, Scope> scopes = new Hashtable<String, Scope>(); |
private Map<String, Object> singletonsCache = new Hashtable<String, Object>(); |
private Map<String, ThreadLocal<Object>> threadLocalsCache = new Hashtable<String, ThreadLocal<Object>>(); |
private Set<Dependency> dependencies = Collections.synchronizedSet(new HashSet<Dependency>()); |
public void clear(Scope scope) { |
if (scope == Scope.SINGLETON) { |
List<ClearablePair> listToClear = new LinkedList<ClearablePair>(); |
synchronized(this) { |
for(String key : singletonsCache.keySet()) { |
Component comp = beans.get(key); |
if (comp instanceof Clearable) { |
Clearable<Object> c = (Clearable<Object>) comp; |
Object value = singletonsCache.get(key); |
listToClear.add(new ClearablePair(c, value)); |
} |
} |
singletonsCache.clear(); |
} |
// clear everything inside a non-synchronized block... |
for(ClearablePair cp : listToClear) cp.c.onCleared(cp.value); |
} else if (scope == Scope.THREAD) { |
List<ClearablePair> listToClear = new LinkedList<ClearablePair>(); |
synchronized(this) { |
for(String key : threadLocalsCache.keySet()) { |
Component comp = beans.get(key); |
if (comp instanceof Clearable) { |
Clearable<Object> c = (Clearable<Object>) comp; |
ThreadLocal<Object> t = threadLocalsCache.get(key); |
Object value = t.get(); |
if (value != null) listToClear.add(new ClearablePair(c, value)); |
} |
} |
for(ThreadLocal<Object> t : threadLocalsCache.values()) { |
t.set(null); |
} |
} |
// clear everything inside a non-synchronized block... |
for(ClearablePair cp : listToClear) cp.c.onCleared(cp.value); |
} |
} |
public <T> T clear(String key) { |
if (!beans.containsKey(key)) return null; |
Scope scope = scopes.get(key); |
if (scope == Scope.SINGLETON) { |
ClearablePair cp = null; |
Object value = null; |
synchronized(this) { |
value = singletonsCache.remove(key); |
if (value != null) { |
Component comp = beans.get(key); |
if (comp instanceof Clearable) { |
Clearable<Object> c = (Clearable<Object>) comp; |
cp = new ClearablePair(c, value); |
} |
} |
} |
if (cp != null) cp.c.onCleared(cp.value); |
return (T) value; |
} else if (scope == Scope.THREAD) { |
ClearablePair cp = null; |
Object retVal = null; |
synchronized(this) { |
ThreadLocal<Object> t = threadLocalsCache.get(key); |
if (t != null) { |
Object o = t.get(); |
if (o != null) { |
Component comp = beans.get(key); |
if (comp instanceof Clearable) { |
Clearable<Object> c = (Clearable<Object>) comp; |
cp = new ClearablePair(c, o); |
} |
t.set(null); |
retVal = o; |
} |
} |
} |
if (cp != null) cp.c.onCleared(cp.value); |
return (T) retVal; |
} else if (scope == Scope.NONE) { |
return null; // always... |
} else { |
throw new UnsupportedOperationException("Scope not supported: " + scope); |
} |
} |
public <T> T get(String key) { |
if (!beans.containsKey(key)) return null; |
Component c = beans.get(key); |
Scope scope = scopes.get(key); |
Object target = null; |
try { |
if (scope == Scope.SINGLETON) { |
boolean needsToCreate = false; |
synchronized(this) { |
if (singletonsCache.containsKey(key)) { |
target = singletonsCache.get(key); |
return (T) target; // no need to wire again... |
} else { |
needsToCreate = true; |
} |
} |
if (needsToCreate) { |
// getInstance needs to be in a non-synchronized block |
target = c.getInstance(); |
synchronized(this) { |
singletonsCache.put(key, target); |
} |
} |
} else if (scope == Scope.THREAD) { |
boolean needsToCreate = false; |
boolean needsToAddToCache = false; |
ThreadLocal<Object> t = null; |
synchronized(this) { |
if (threadLocalsCache.containsKey(key)) { |
t = threadLocalsCache.get(key); |
target = t.get(); |
if (target == null) { // different thread... |
needsToCreate = true; |
// don't return... let it be wired... |
} else { |
return (T) target; // no need to wire again... |
} |
} else { |
t = new ThreadLocal<Object>(); |
needsToCreate = true; |
needsToAddToCache = true; |
// let it be wired... |
} |
} |
if (needsToCreate) { |
// getInstance needs to be in a non-synchronized block |
target = c.getInstance(); |
t.set(target); |
} |
if (needsToAddToCache) { |
synchronized(this) { |
threadLocalsCache.put(key, t); |
} |
} |
} else if (scope == Scope.NONE) { |
target = c.getInstance(); |
} else { |
throw new UnsupportedOperationException("Don't know how to handle scope: " + scope); |
} |
if (target != null) { |
for (Dependency d : dependencies) { |
// has dependency ? |
Method m = d.check(target.getClass()); |
if (m != null) { |
String sourceKey = d.getSource(); |
if (sourceKey.equals(key)) { |
// cannot depend on itself... also avoid recursive StackOverflow... |
continue; |
} |
Object source = get(sourceKey); |
boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass()); |
// check if we can find the dependency and if it is |
// assignable to the target dependency |
if (isAssignable) { |
try { |
// inject |
m.invoke(target, source); |
} catch (Exception e) { |
throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = " |
+ (source != null ? source : "NULL") + " / target = " + target, e); |
} |
} |
} |
} |
} |
return (T) target; // return target nicely with all the dependencies |
} catch (Exception e) { |
throw new RuntimeException(e); |
} |
} |
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... |
threadLocalsCache.remove(key); // just in case we are overriding a previous thread local... |
scopes.put(key, scope); |
return component; |
} |
public Component ioc(String key, Component component) { |
return ioc(key, component, Scope.NONE); |
} |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass) { |
ConfigurableComponent cc = new MentaComponent(klass); |
ioc(key, cc); |
return cc; |
} |
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) { |
ConfigurableComponent cc = new MentaComponent(klass); |
ioc(key, cc, scope); |
return cc; |
} |
public Dependency autowire(Dependency d) { |
dependencies.add(d); |
return d; |
} |
public Dependency autowire(String property, Class<? extends Object> klass) { |
return autowire(property, klass, property); |
} |
public Dependency autowire(String property, Class<? extends Object> klass, String source) { |
return autowire(new MentaDependency(property, klass, source)); |
} |
public Container populate(Object bean) { |
Provider p = new Provider() { |
public Object get(String key) { |
return MentaContainer.this.get(key); |
} |
public boolean hasValue(String key) { |
return MentaContainer.this.check(key); |
} |
}; |
try { |
InjectionUtils.getObject(bean, p, false, null, true, false, true); |
} catch(Exception e) { |
throw new RuntimeException("Error populating bean: " + bean, e); |
} |
return this; |
} |
public synchronized boolean check(String key) { |
if (!beans.containsKey(key)) return false; |
Scope scope = scopes.get(key); |
if (scope == Scope.NONE) { |
return false; // always... |
} else if (scope == Scope.SINGLETON) { |
return singletonsCache.containsKey(key); |
} else if (scope == Scope.THREAD) { |
ThreadLocal<Object> t = threadLocalsCache.get(key); |
if (t != null) return t.get() != null; |
return false; |
} else { |
throw new UnsupportedOperationException("This scope is not supported: " + scope); |
} |
} |
private static class ClearablePair { |
public ClearablePair(Clearable<Object> c, Object value) { |
this.c = c; |
this.value = value; |
} |
Clearable<Object> c; |
Object value; |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/Component.java |
---|
New file |
0,0 → 1,16 |
package org.mentacontainer; |
/** |
* An IoC component that knows how to create instances of itself. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public interface Component { |
/** |
* Instantiate the bean. |
* |
* @return The instantiated bean based on the container configuration. |
*/ |
public <T> T getInstance(); |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/Container.java |
---|
New file |
0,0 → 1,148 |
package org.mentacontainer; |
/** |
* A very simple container that provides: |
* <ul> |
* <li> Bean instantiation (duh!)</li> |
* <li> Constructor injection for bean setup</li> |
* <li> Setter injection for bean setup</li> |
* <li> Auto-wiring based on name and type</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> |
* |
* It does not get much simpler than that. |
* |
* @author sergio.oliveira.jr@gmail.com |
* |
*/ |
public interface Container { |
/** |
* Get an instance from the container. |
* |
* The instance will be fully initialized (constructor and/or setters) and fully wired. |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @return The fully initialized and wired bean. |
*/ |
public <T> T get(String key); |
/** |
* Configure a bean to be returned with the given implementation when {@link #get(String)} is called. |
* |
* @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 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, Scope scope); |
/** |
* 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. 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. |
* @return The component passed as a parameter. |
* @see Component |
*/ |
public Component ioc(String key, Component 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 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, Scope scope); |
/** |
* Configure a bean dependency to be auto-wired by the container. In general you want the |
* type of the dependency to be an interface, for loosely couple dependencies. It works like that:<br/><br/> |
* |
* Whenever the container returns a bean, it checks to see if it has a property named <i>property</i> |
* and if the type of the property is <i>klass</i>. If it does, then it looks for a bean named |
* <i>source</i> and injects it inside the first bean it is returning. This approach is recursive |
* so all properties are checked up the class hierarchy, until it reaches Object. |
* |
* @param property a bean property that will require another bean, in other words, the required |
* bean will be injected in the property of the bean been requested from the container. (auto-wiring by name) |
* @param klass the type of the dependency, in other words, the type of the auto-wiring. (auto-wiring by type) |
* @param source The dependency itself, coming from the container as well, in other words, the bean that will be injected in the original bean |
* @return The container itself. (Fluent API) |
*/ |
public Dependency autowire(String property, Class<? extends Object> klass, String source); |
/** |
* Same as {@link #autowire(String, Class, String)} except that it assumes that the property name will be the source name, in other words, |
* the property name is the same as the bean name that will be injected as the dependency. |
* |
* @param property |
* @param klass |
* @return The container itself. (Fluent API) |
*/ |
public Dependency autowire(String property, Class<? extends Object> klass); |
/** |
* Setup a dependency. |
* |
* @param dependency The dependency to setup |
* @return The dependency itself. (Fluent API) |
* @see Dependency |
*/ |
public Dependency autowire(Dependency dependency); |
/** |
* Take a given bean and populate its properties with other beans coming from this container. Perhaps you can call this auto-wiring. |
* You basically checking properties of the given bean and looking for values (by name and type!) inside the container. And injecting |
* in the given bean, in other words, populating it. |
* |
* @param bean The bean to be populated with other beans from the container. |
* @return The container itself. (Fluent API) |
*/ |
public Container populate(Object bean); |
/** |
* Check whether the container currently has a value for this key. For example, |
* if it is a singleton AND someone has requested it, the container will have it cached. |
* The method is useful to check for an instance without forcing her creation. |
* |
* @param key The key representing the bean inside the container. |
* @return true if the container has an instance cached in the scope for this key |
*/ |
public boolean check(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. It does not make |
* sense to clear a NONE scope (the method returns doing nothing). |
* |
* @param scope The scope to be cleared. |
*/ |
public void clear(Scope scope); |
/** |
* Clear a single key from cache and return the instance that was cached. |
* |
* @param key The key representing the bean inside the container. |
* @return The value that was cached and it is not anymore (was cleared) or null if nothing was cleared |
*/ |
public <T> T clear(String key); |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/ConfigurableComponent.java |
---|
New file |
0,0 → 1,29 |
package org.mentacontainer; |
/** |
* An IoC component that knows how to create instances of itself and |
* can be configured by accepting values for its constructor |
* and properties for its setters. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public interface ConfigurableComponent extends Component { |
/** |
* Add a constructor parameter to be used when the bean is instantiated. It can be called more than once to |
* use constructors with more than one argument. |
* |
* @param value A parameter value to be used by a constructor. |
* @return The component itself. (Fluent API) |
*/ |
public ConfigurableComponent addInitValue(Object value); |
/** |
* Add a property to be injected through a setter when the component is instantiated. |
* |
* @param name The property name. |
* @param value The property value. |
* @return The component itself. (Fluent API) |
*/ |
public ConfigurableComponent addProperty(String name, Object value); |
} |
/tags/menta-container-0.9.5/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 |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/Clearable.java |
---|
New file |
0,0 → 1,25 |
package org.mentacontainer; |
/** |
* Some components can also implement this interface to perform some cleanup |
* when the instance is cleared. For example, a connection pool will want |
* to know when the connection instance is cleared so it can return it to |
* the pool. |
* |
* It makes more sense to use this interface for components that will be placed |
* in the THREAD scope, but you can also use it with components in the SINGLETON |
* scope. |
* |
* This is particular useful for the THREAD scope for dealing with thread pools, so |
* when the thread is returned to the thread pool you will want to clear the THREAD |
* scope. That's pretty much how web containers work: one thread per request coming from |
* a thread pool. |
* |
* @author sergio.oliveira.jr@gmail.com |
* |
* @param <E> |
*/ |
public interface Clearable<E> { |
public void onCleared(E clearedObject); |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/example/BasicOperations.java |
---|
New file |
0,0 → 1,139 |
package org.mentacontainer.example; |
import java.util.Date; |
import org.mentacontainer.Container; |
import org.mentacontainer.Scope; |
import org.mentacontainer.impl.MentaContainer; |
public class BasicOperations { |
public static void main(String[] args) { |
case1(); |
case2(); |
case3(); |
case4(); |
} |
private static void case1() { |
Container c = new MentaContainer(); |
c.ioc("myString1", String.class); |
String myString1 = c.get("myString1"); |
System.out.println(myString1); // ==> "" ==> default constructor new String() was used |
c.ioc("myString2", String.class).addInitValue("saoj"); |
String myString2 = c.get("myString2"); |
System.out.println(myString2); // ==> "saoj" ==> constructor new String("saoj") was used |
c.ioc("myDate1", Date.class).addProperty("hours", 15) // setHours(15) |
.addProperty("minutes", 10) // setMinutes(10) |
.addProperty("seconds", 45); // setSeconds(45) |
Date myDate1 = c.get("myDate1"); |
System.out.println(myDate1); // ==> a date with time 15:10:45 |
} |
private static void case2() { |
Container c = new MentaContainer(); |
c.ioc("myString", String.class, Scope.SINGLETON).addInitValue("saoj"); |
String s1 = c.get("myString"); |
String s2 = c.get("myString"); |
System.out.println(s1 == s2); // ==> true ==> same instance |
System.out.println(s1.equals(s2)); // ==> true => of course |
} |
public static interface UserDAO { |
public String getUsername(int id); |
} |
public static class Connection { |
} |
public static class JdbcUserDAO implements UserDAO { |
private Connection conn; |
public void setConn(Connection conn) { this.conn = conn; } |
public String getUsername(int id) { |
// connection will be injected by the container... |
if (conn == null) throw new IllegalStateException("conn is null!"); |
// use the connection to get the username... |
return "saoj"; |
} |
} |
private static void case3() { |
Container c = new MentaContainer(); |
c.ioc("userDAO", JdbcUserDAO.class); |
c.ioc("connection", Connection.class); // in real life this would be a connection pool |
// or the hibernate SessionFactory |
// "conn" = the name of the property |
// Connection.class = the type of the property |
// "connection" = the source from where the dependency will come from |
c.autowire("conn", Connection.class, "connection"); |
UserDAO userDAO = c.get("userDAO"); |
// the container detects that userDAO has a dependency: name = "conn" and type = "Connection.class" |
// where does it go to get the dependency to insert? |
// In itself: it does a Container.get("connection") => "connection" => the source |
System.out.println(userDAO.getUsername(11)); // ==> "saoj" ==> connection is not null as expected... |
} |
public static class SomeService { |
private UserDAO userDAO; |
public void setUserDAO(UserDAO userDAO) { |
this.userDAO = userDAO; |
} |
public void doSomething() { |
System.out.println(userDAO.getUsername(11)); |
} |
} |
private static void case4() { |
Container c = new MentaContainer(); |
c.ioc("userDAO", JdbcUserDAO.class); |
c.ioc("connection", Connection.class); |
c.autowire("conn", Connection.class, "connection"); |
SomeService service = new SomeService(); |
c.populate(service); // populate (inject) all properties of SomeService with |
// beans from the container |
service.doSomething(); // ==> "saoj" |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/util/FindMethod.java |
---|
New file |
0,0 → 1,144 |
package org.mentacontainer.util; |
import java.lang.reflect.Method; |
import java.util.LinkedList; |
import java.util.List; |
/** |
* Find method with polymorphism! |
* Class.getMethod only finds an exact match. |
* |
* @author Jon Skeet (http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/921ab91865c8cc2e/9e141d3d62e7cb3f) |
*/ |
public class FindMethod { |
/** |
* Finds the most specific applicable method |
* |
* @param source Class to find method in |
* @param name Name of method to find |
* @param parameterTypes Parameter types to search for |
*/ |
public static Method getMethod(Class<? extends Object> source, |
String name, |
Class[] parameterTypes) |
throws NoSuchMethodException { |
return internalFind(source.getMethods(), |
name, |
parameterTypes); |
} |
/** |
* Finds the most specific applicable declared method |
* |
* @param source Class to find method in |
* @param name Name of method to find |
* @param parameterTypes Parameter types to search for |
*/ |
public static Method getDeclaredMethod(Class source, |
String name, |
Class[] parameterTypes) |
throws NoSuchMethodException { |
return internalFind(source.getDeclaredMethods(), |
name, |
parameterTypes); |
} |
/** |
* Internal method to find the most specific applicable method |
*/ |
private static Method internalFind(Method[] toTest, |
String name, |
Class[] parameterTypes) |
throws NoSuchMethodException { |
int l = parameterTypes.length; |
// First find the applicable methods |
List<Method> applicableMethods = new LinkedList<Method>(); |
for (int i = 0; i < toTest.length; i++) { |
// Check the name matches |
if (!toTest[i].getName().equals(name)) |
continue; |
// Check the parameters match |
Class[] params = toTest[i].getParameterTypes(); |
if (params.length != l) |
continue; |
int j; |
for (j = 0; j < l; j++) |
if (!params[j].isAssignableFrom(parameterTypes[j])) |
break; |
// If so, add it to the list |
if (j == l) |
applicableMethods.add(toTest[i]); |
} |
/* |
* If we've got one or zero methods, we can finish |
* the job now. |
*/ |
int size = applicableMethods.size(); |
if (size == 0) |
throw new NoSuchMethodException ("No such method: " + name); |
if (size == 1) |
return applicableMethods.get(0); |
/* |
* Now find the most specific method. Do this in a very primitive |
* way - check whether each method is maximally specific. If more |
* than one method is maximally specific, we'll throw an exception. |
* For a definition of maximally specific, see JLS section 15.11.2.2. |
* |
* I'm sure there are much quicker ways - and I could probably |
* set the second loop to be from i+1 to size. I'd rather not though, |
* until I'm sure... |
*/ |
int maximallySpecific = -1; // Index of maximally specific method |
for (int i = 0; i < size; i++) { |
int j; |
// In terms of the JLS, current is T |
Method current = applicableMethods.get(i); |
Class[] currentParams = current.getParameterTypes(); |
Class currentDeclarer = current.getDeclaringClass(); |
for (j = 0; j < size; j++) { |
if (i == j) |
continue; |
// In terms of the JLS, test is U |
Method test = applicableMethods.get(j); |
Class[] testParams = test.getParameterTypes(); |
Class testDeclarer = test.getDeclaringClass(); |
// Check if T is a subclass of U, breaking if not |
if (!testDeclarer.isAssignableFrom(currentDeclarer)) |
break; |
// Check if each parameter in T is a subclass of the |
// equivalent parameter in U |
int k; |
for (k = 0; k < l; k++) |
if (!testParams[k].isAssignableFrom(currentParams[k])) |
break; |
if (k != l) |
break; |
} |
// Maximally specific! |
if (j == size) { |
if (maximallySpecific != -1) |
throw new NoSuchMethodException |
("Ambiguous method search - more " + |
"than one maximally specific method"); |
maximallySpecific = i; |
} |
} |
if (maximallySpecific == -1) |
throw new NoSuchMethodException ("No maximally specific method."); |
return applicableMethods.get(maximallySpecific); |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/util/InjectionUtils.java |
---|
New file |
0,0 → 1,806 |
package org.mentacontainer.util; |
import java.lang.reflect.Field; |
import java.lang.reflect.InvocationTargetException; |
import java.lang.reflect.Method; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.Iterator; |
import java.util.List; |
import java.util.Map; |
public class InjectionUtils { |
/** |
* The character used to separate the prefix from the value name when you are using the getObject method with a prefix. You can change the value of this prefix if you want to |
* by changing this static variable. |
* |
* Ex: getObject(User.class, "user") will get all values that begin with "user.". |
*/ |
public static char PREFIX_SEPARATOR = '.'; |
private static Map<Class<? extends Object>, Map<String, Object>> settersMaps = new HashMap<Class<? extends Object>, Map<String, Object>>(); |
private static Map<Class<? extends Object>, Map<String, Object>> fieldsMaps = new HashMap<Class<? extends Object>, Map<String, Object>>(); |
public static void prepareForInjection(Class<? extends Object> klass, Map<String, Object> setters, Map<String, Object> fields) { |
StringBuffer sb = new StringBuffer(32); |
Method[] methods = klass.getMethods(); |
for (int i = 0; i < methods.length; i++) { |
Method m = methods[i]; |
String name = m.getName(); |
Class<?>[] types = m.getParameterTypes(); |
if (name.startsWith("set") && name.length() > 3 && types.length == 1) { |
String var = name.substring(3); |
if (var.length() > 1) { |
sb.delete(0, sb.length()); |
sb.append(var.substring(0, 1).toLowerCase()); |
sb.append(var.substring(1)); |
var = sb.toString(); |
} else { |
var = var.toLowerCase(); |
} |
m.setAccessible(true); |
if (setters.containsKey(var)) { |
Object obj = setters.get(var); |
if (obj instanceof List) { |
List<Method> list = (List<Method>) obj; |
list.add(m); |
} else if (obj instanceof Method) { |
List<Method> list = new ArrayList<Method>(); |
list.add((Method) obj); |
list.add(m); |
setters.put(var, list); |
} |
} else { |
setters.put(var, m); |
} |
} |
} |
if (fields == null) return; |
Field[] f = klass.getDeclaredFields(); |
for (int i = 0; i < f.length; i++) { |
Field field = f[i]; |
field.setAccessible(true); |
String name = field.getName(); |
if (setters.containsKey(name)) { |
Object obj = setters.get(name); |
if (obj instanceof Method) { |
Method m = (Method) obj; |
Class<?>[] types = m.getParameterTypes(); |
Class<?> type = field.getType(); |
if (type.isAssignableFrom(types[0])) continue; |
} else if (obj instanceof List) { |
List<Method> list = (List<Method>) obj; |
Iterator<Method> iter = list.iterator(); |
boolean found = false; |
while (iter.hasNext()) { |
Method m = iter.next(); |
Class<?>[] types = m.getParameterTypes(); |
Class<?> type = field.getType(); |
if (type.isAssignableFrom(types[0])) { |
found = true; |
break; |
} |
} |
if (found) continue; |
} |
} |
fields.put(name, field); |
} |
} |
public static boolean checkPrimitives(Class<? extends Object> target, Class<? extends Object> source) { |
if (target.equals(int.class) && source.equals(Integer.class)) return true; |
if (target.equals(boolean.class) && source.equals(Boolean.class)) return true; |
if (target.equals(byte.class) && source.equals(Byte.class)) return true; |
if (target.equals(short.class) && source.equals(Short.class)) return true; |
if (target.equals(char.class) && source.equals(Character.class)) return true; |
if (target.equals(long.class) && source.equals(Long.class)) return true; |
if (target.equals(float.class) && source.equals(Float.class)) return true; |
if (target.equals(double.class) && source.equals(Double.class)) return true; |
return false; |
} |
public static Object tryToConvert(Object source, Class<? extends Object> targetType) { |
return tryToConvert(source, targetType, false); |
} |
public static Object tryToConvert(Object source, Class<?> targetType, boolean tryNumber) { |
String value = null; |
if (source instanceof String) { |
value = (String) source; |
} else if (tryNumber && source instanceof Number) { |
value = source.toString(); |
} else { |
return null; |
} |
Object newValue = null; |
String className = targetType.getName(); |
if (className.equals("int") || className.equals("java.lang.Integer")) { |
int x = -1; |
try { |
x = Integer.parseInt(value); |
} catch (Exception e) { |
return null; |
} |
newValue = new Integer(x); |
} else if (className.equals("short") || className.equals("java.lang.Short")) { |
short x = -1; |
try { |
x = Short.parseShort(value); |
} catch (Exception e) { |
return null; |
} |
newValue = new Short(x); |
} else if (className.equals("char") || className.equals("java.lang.Character")) { |
if (value.length() != 1) { |
return null; |
} |
newValue = new Character(value.charAt(0)); |
} else if (className.equals("long") || className.equals("java.lang.Long")) { |
long x = -1; |
try { |
x = Long.parseLong(value); |
} catch (Exception e) { |
return null; |
} |
newValue = new Long(x); |
} else if (className.equals("float") || className.equals("java.lang.Float")) { |
float x = -1; |
try { |
x = Float.parseFloat(value); |
} catch (Exception e) { |
return null; |
} |
newValue = new Float(x); |
} else if (className.equals("double") || className.equals("java.lang.Double")) { |
double x = -1; |
try { |
x = Double.parseDouble(value); |
} catch (Exception e) { |
return null; |
} |
newValue = new Double(x); |
} else if (className.equals("boolean") || className.equals("java.lang.Boolean")) { |
try { |
int x = Integer.parseInt(value); |
if (x == 1) { |
newValue = Boolean.TRUE; |
} else if (x == 0) { |
newValue = Boolean.FALSE; |
} else { |
return null; |
} |
} catch (Exception e) { |
if (value.equalsIgnoreCase("true") || value.equals("on")) { |
newValue = Boolean.TRUE; |
} else if (value.equalsIgnoreCase("false")) { |
newValue = Boolean.FALSE; |
} else { |
return null; |
} |
} |
} else if (targetType.isEnum()) { |
try { |
Class k = (Class) targetType; // not sure how to avoid this raw type! |
newValue = Enum.valueOf(k, value); |
} catch (Exception e) { |
return null; |
} |
} |
return newValue; |
} |
public static Object shouldConvertToNull(Object value, Class<? extends Object> targetType) { |
if (targetType.equals(String.class)) { |
return value; |
} else if (targetType.isPrimitive()) { |
return value; |
} |
return null; |
} |
public static Class<? extends Object> getPrimitiveFrom(Object w) { |
if (w instanceof Boolean) { |
return Boolean.TYPE; |
} else if (w instanceof Byte) { |
return Byte.TYPE; |
} else if (w instanceof Short) { |
return Short.TYPE; |
} else if (w instanceof Character) { |
return Character.TYPE; |
} else if (w instanceof Integer) { |
return Integer.TYPE; |
} else if (w instanceof Long) { |
return Long.TYPE; |
} else if (w instanceof Float) { |
return Float.TYPE; |
} else if (w instanceof Double) { |
return Double.TYPE; |
} |
return null; |
} |
public static Class<? extends Object> getPrimitiveFrom(Class<? extends Object> klass) { |
String s = klass.getName(); |
if (s.equals("java.lang.Boolean")) { |
return Boolean.TYPE; |
} else if (s.equals("java.lang.Byte")) { |
return Byte.TYPE; |
} else if (s.equals("java.lang.Short")) { |
return Short.TYPE; |
} else if (s.equals("java.lang.Character")) { |
return Character.TYPE; |
} else if (s.equals("java.lang.Integer")) { |
return Integer.TYPE; |
} else if (s.equals("java.lang.Long")) { |
return Long.TYPE; |
} else if (s.equals("java.lang.Float")) { |
return Float.TYPE; |
} else if (s.equals("java.lang.Double")) { |
return Double.TYPE; |
} |
return null; |
} |
public static Field getField(Object target, String name) { |
return getField(target.getClass(), name); |
} |
public static Field getField(Class<? extends Object> target, String name) { |
Field fields[] = target.getDeclaredFields(); |
for (int i = 0; i < fields.length; i++) { |
if (name.equals(fields[i].getName())) { |
return fields[i]; |
} |
} |
return null; |
} |
public static Method findMethodToGet(Class<? extends Object> target, String name) { |
StringBuffer sb = new StringBuffer(128); |
sb.append("get").append(name.substring(0, 1).toUpperCase()); |
if (name.length() > 1) sb.append(name.substring(1)); |
try { |
return target.getMethod(sb.toString(), (Class[]) null); |
} catch (Exception e) { |
} |
sb.setLength(0); |
sb.append("is").append(name.substring(0, 1).toUpperCase()); |
if (name.length() > 1) { |
sb.append(name.substring(1)); |
} |
try { |
return target.getMethod(sb.toString(), (Class[]) null); |
} catch (Exception e) { |
} |
return null; |
} |
public static Method findMethodToInject(Class<? extends Object> target, String name, Class<? extends Object> source) { |
StringBuffer sb = new StringBuffer(128); |
sb.append("set").append(name.substring(0, 1).toUpperCase()); |
if (name.length() > 1) sb.append(name.substring(1)); |
String methodName = sb.toString(); |
Method m = null; |
try { |
m = FindMethod.getMethod(target, methodName, new Class[] { source }); |
} catch (Exception e) { |
} |
if (m == null) { |
Class<? extends Object> primitive = getPrimitiveFrom(source); |
if (primitive != null) { |
try { |
m = target.getMethod(methodName, new Class[] { primitive }); |
} catch (Exception e) { |
} |
} |
} |
if (m != null) { |
m.setAccessible(true); |
} |
return m; |
} |
public static Field findFieldToInject(Class<? extends Object> target, String name, Class<? extends Object> source) { |
Field f = getField(target, name); |
if (f != null) { |
Class<?> type = f.getType(); |
if (type.isAssignableFrom(source) || checkPrimitives(type, source)) { |
f.setAccessible(true); |
return f; |
} |
} |
return null; |
} |
private static final boolean isBlank(Object value) { |
if (value != null && value instanceof String) { |
String s = ((String) value).trim(); |
if (s.length() == 0) return true; |
} |
return false; |
} |
public static boolean inject(Method m, Object target, Object value, boolean tryToConvert, boolean tryingToConvertBoolean) throws Exception { |
Class<?> type = m.getParameterTypes()[0]; |
if (tryingToConvertBoolean) { |
if (value == null && (type.equals(Boolean.class) || type.equals(boolean.class))) { |
value = Boolean.FALSE; |
} else { |
// if trying to convert boolean, convert or don't do anything... |
return false; |
} |
} |
if (value == null |
|| (type.isAssignableFrom(value.getClass()) || checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull(value, |
type)) == null) || (value = tryToConvert(value, type)) != null)))) { |
try { |
m.invoke(target, new Object[] { value }); |
return true; |
} catch (Exception e) { |
System.err.println("Error injecting by method: " + value + " in " + target + " thru " + m); |
e.printStackTrace(); |
throw e; |
} |
} |
return false; |
} |
public static boolean hasDefaultConstructor(Class<? extends Object> klass) { |
try { |
return klass.getConstructor((Class[]) null) != null; |
} catch (Exception e) { |
return false; |
} |
} |
/** |
* Extract the value of a property of a bean! |
* |
* @param bean |
* the target bean |
* @param nameProperty |
* the property name |
* @return they value as String. The method toString is always called to every property! |
* @throws Exception |
*/ |
public static String getProperty(Object bean, String nameProperty) throws Exception { |
if (nameProperty == null || nameProperty.equals("")) return null; |
String methodName = getter(nameProperty); |
Class<? extends Object> clazz = bean.getClass(); |
Method[] methods = clazz.getMethods(); |
for (Method method : methods) { |
if (method.getName().equals(methodName) && method.getParameterTypes().length == 0) { |
Object value = method.invoke(bean, (Object[]) null); |
if (value == null) return null; |
return value.toString(); |
} |
} |
Field[] fields = clazz.getDeclaredFields(); |
for (Field field : fields) { |
field.setAccessible(true); |
if (field.getName().equals(nameProperty)) { |
Object value = field.get(bean); |
if (value == null) return null; |
return value.toString(); |
} |
} |
return null; |
} |
private static String getter(String name) { |
StringBuilder sb = new StringBuilder(name.length() + 3); |
sb.append("get").append(name.substring(0, 1).toUpperCase()); |
if (name.length() > 1) sb.append(name.substring(1)); |
return sb.toString(); |
} |
public static void beanToMap(Object bean, Map<String, String> map) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { |
if (bean != null) { |
for (Method method : bean.getClass().getMethods()) { |
String name = method.getName(); |
if (name.length() > 3 && name.startsWith("get") && !name.equals("getClass") && method.getParameterTypes().length == 0) { |
method.setAccessible(true); |
Object value = method.invoke(bean, new Object[0]); |
map.put(name, value.toString()); |
} |
} |
} |
} |
public static interface Provider { |
public Object get(String key); |
public boolean hasValue(String key); |
} |
public static void getObject(Object target, Provider provider, boolean tryField, String prefix, boolean tryToConvert, boolean convertBoolean, boolean allowRecursion) |
throws Exception { |
Class<? extends Object> targetClass = target.getClass(); |
Map<String, Object> setters, fields; |
// see if we have these in cache... |
synchronized (settersMaps) { |
setters = settersMaps.get(targetClass); |
fields = fieldsMaps.get(targetClass); |
} |
// if not in cache, prepare maps for injection... |
if (setters == null) { |
setters = new HashMap<String, Object>(); |
fields = null; |
if (tryField) { |
fields = new HashMap<String, Object>(); |
} |
prepareForInjection(targetClass, setters, fields); |
synchronized (settersMaps) { |
settersMaps.put(targetClass, setters); |
fieldsMaps.put(targetClass, fields); |
} |
} |
Iterator<String> iter = setters.keySet().iterator(); |
while (iter.hasNext()) { |
String var = iter.next(); |
boolean hasValue = provider.hasValue(var); |
Object value = provider.get(var); |
boolean tryingToConvertBoolean = false; |
if (value == null && !hasValue) { |
if (!convertBoolean) { |
continue; |
} else { |
tryingToConvertBoolean = true; |
} |
} |
// if (value == null) continue; |
Object obj = setters.get(var); |
// we may have a list of overloaded methods... |
List<Method> list = null; |
Method m = null; |
if (obj instanceof List) { |
list = (List<Method>) obj; |
} else { |
m = (Method) setters.get(var); |
} |
if (m != null) { |
if (!inject(m, target, value, tryToConvert, tryingToConvertBoolean) && allowRecursion) { |
// i did not inject... how about a VO object for this |
// setter? |
Class<?> type = m.getParameterTypes()[0]; |
if (!type.getName().startsWith("java.") && !type.isPrimitive() && hasDefaultConstructor(type)) { |
Object param = type.newInstance(); |
InjectionUtils.getObject(param, provider, true, prefix, true, true, false); // no |
// recursion... |
inject(m, target, param, false, false); |
} |
} |
} else { |
Iterator<Method> it = list.iterator(); |
boolean injected = false; |
while (it.hasNext()) { |
m = it.next(); |
if (inject(m, target, value, tryToConvert, tryingToConvertBoolean)) { |
injected = true; |
break; |
} |
} |
if (!injected && allowRecursion) { |
// i could not inject anything... how about a VO object for |
// this setter... |
it = list.iterator(); |
while (it.hasNext()) { |
m = (Method) it.next(); |
Class<?> type = m.getParameterTypes()[0]; |
if (!type.getName().startsWith("java.") && !type.isPrimitive() && hasDefaultConstructor(type)) { |
Object param = type.newInstance(); |
InjectionUtils.getObject(param, provider, true, prefix, true, true, false); // no |
// recursion... |
if (inject(m, target, param, false, false)) { |
break; // done... |
} |
} |
} |
} |
} |
} |
if (fields != null) { |
iter = fields.keySet().iterator(); |
while (iter.hasNext()) { |
String var = iter.next(); |
boolean hasValue = provider.hasValue(var); |
Object value = provider.get(var); |
Field f = (Field) fields.get(var); |
Class<?> type = f.getType(); |
// If there is no value in the action input, assume false for |
// booleans... |
// (checkboxes and radio buttons are not send when not |
// marked...) |
if (convertBoolean && value == null && !hasValue) { |
if (type.equals(Boolean.class) || type.equals(boolean.class)) { |
value = Boolean.FALSE; |
} |
} |
if (value == null && !hasValue) continue; |
// if (value == null) continue; |
if (value == null |
|| (type.isAssignableFrom(value.getClass()) || checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull( |
value, type)) == null) || (value = tryToConvert(value, type)) != null)))) { |
try { |
f.set(target, value); |
} catch (Exception e) { |
System.err.println("Error injecting by field: " + value + " in " + target); |
e.printStackTrace(); |
throw e; |
} |
} |
} |
} |
} |
} |
/tags/menta-container-0.9.5/src/main/java/org/mentacontainer/Dependency.java |
---|
New file |
0,0 → 1,43 |
package org.mentacontainer; |
import java.lang.reflect.Method; |
/** |
* A dependency used to setup auto-wiring based on name (target) and type. You also provide the source which is |
* the name of a component configured in the container that will be injected as a dependency. |
* |
* @author sergio.oliveira.jr@gmail.com |
*/ |
public interface Dependency { |
/** |
* The target, in other words, the name of the property which depends on something. |
* |
* @return The name of the property that needs to receive a dependency |
*/ |
public String getTarget(); |
/** |
* The type, in other words, the type of the property which depends on something. |
* |
* @return The type of the property that needs to receive a dependency |
*/ |
public Class<? extends Object> getType(); |
/** |
* The source component that will be used to fulfill the dependency, in other words, |
* a component with this name will be fetched from the container and inserted in the target. |
* |
* @return The name of the component from the container that will fulfill the dependency |
*/ |
public String getSource(); |
/** |
* Check whether the given class has this dependency, in other words, whether it has a property |
* with the name <i>'target'</i> and the type <i>'type'</i>. |
* |
* @param targetClass The class to be checked for this dependency |
* @return A method, in this case a setter, that can be used to insert the dependency, or null if the class does not have this dependency |
*/ |
public Method check(Class<? extends Object> targetClass); |
} |
/tags/menta-container-0.9.5/pom.xml |
---|
New file |
0,0 → 1,166 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
<properties> |
<build.final.name>mentacontainer</build.final.name> |
<svn.url>svn://saoj-la.dyndns.org/mentacontainer/trunk</svn.url> |
<svn.tags>svn://saoj-la.dyndns.org/mentacontainer/tags</svn.tags> |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
</properties> |
<modelVersion>4.0.0</modelVersion> |
<groupId>me.soliveirajr</groupId> |
<artifactId>menta-container</artifactId> |
<version>0.9.5</version> |
<packaging>jar</packaging> |
<description>A IOC container as simple and pragmatic as it can get with programmatic configuration through a Fluent API.</description> |
<name>MentaContainer</name> |
<url>http://maven.apache.org</url> |
<licenses> |
<license> |
<name>GNU Lesser General Public License (LGPL), Version 2.1</name> |
<url>http://www.fsf.org/licensing/licenses/lgpl.txt</url> |
<distribution>repo</distribution> |
</license> |
</licenses> |
<parent> |
<groupId>org.sonatype.oss</groupId> |
<artifactId>oss-parent</artifactId> |
<version>3</version> |
</parent> |
<scm> |
<developerConnection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.5</developerConnection> |
<url>svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.5</url> |
<connection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.5</connection> |
</scm> |
<reporting> |
<plugins> |
<plugin> |
<artifactId>maven-surefire-plugin</artifactId> |
</plugin> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-surefire-report-plugin</artifactId> |
<version>2.5</version> |
</plugin> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-javadoc-plugin</artifactId> |
<version>2.7</version> |
<configuration> |
... |
</configuration> |
</plugin> |
</plugins> |
</reporting> |
<profiles> |
<profile> |
<id>release-sign-artifacts</id> |
<activation> |
<property> |
<name>performRelease</name> |
<value>true</value> |
</property> |
</activation> |
<build> |
<plugins> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-gpg-plugin</artifactId> |
<executions> |
<execution> |
<id>sign-artifacts</id> |
<phase>verify</phase> |
<goals> |
<goal>sign</goal> |
</goals> |
</execution> |
</executions> |
</plugin> |
</plugins> |
</build> |
</profile> |
</profiles> |
<!-- distributionManagement> |
<repository> |
<id>nexus-releases</id> |
<name>Nexus Release Repository</name> |
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url> |
</repository> |
</distributionManagement --> |
<dependencies> |
<dependency> |
<groupId>junit</groupId> |
<artifactId>junit</artifactId> |
<version>4.8.1</version> |
<scope>test</scope> |
</dependency> |
</dependencies> |
<build> |
<finalName>${build.final.name}</finalName> |
<plugins> |
<!-- plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-gpg-plugin</artifactId> |
<executions> |
<execution> |
<id>sign-artifacts</id> |
<phase>verify</phase> |
<goals> |
<goal>sign</goal> |
</goals> |
</execution> |
</executions> |
</plugin --> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-source-plugin</artifactId> |
<executions> |
<execution> |
<id>attach-sources</id> |
<goals> |
<goal>jar</goal> |
</goals> |
</execution> |
</executions> |
</plugin> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-compiler-plugin</artifactId> |
<version>2.0.2</version> |
<configuration> |
<source>1.6</source> |
<target>1.6</target> |
</configuration> |
</plugin> |
<plugin> |
<groupId>org.apache.maven.plugins</groupId> |
<artifactId>maven-javadoc-plugin</artifactId> |
<executions> |
<execution> |
<id>attach-javadocs</id> |
<goals> |
<goal>jar</goal> |
</goals> |
</execution> |
</executions> |
</plugin> |
<plugin> |
<artifactId>maven-release-plugin</artifactId> |
<version>2.0</version> |
<configuration> |
<tagBase>${svn.tags}</tagBase> |
<connectionUrl>scm:svn:${svn.url}</connectionUrl> |
</configuration> |
</plugin> |
</plugins> |
</build> |
</project> |
/tags/menta-container-0.9.5/readme.txt |
---|
New file |
0,0 → 1,2 |
MentaContainer 2010 |
/tags/menta-container-0.9.5 |
---|
Property changes: |
Added: svn:ignore |
+ target |
.classpath |
.project |
.settings |