Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.mentacontainer.impl.MentaContainer Maven / Gradle / Ivy
Go to download
A IOC container as simple and pragmatic as it can get with programmatic configuration through a Fluent API.
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.ConfigurableFactory;
import org.mentacontainer.Container;
import org.mentacontainer.Factory;
import org.mentacontainer.Interceptor;
import org.mentacontainer.Scope;
import org.mentacontainer.util.InjectionUtils;
import org.mentacontainer.util.InjectionUtils.Provider;
/**
* The implementation of the IoC container.
*
* @author [email protected]
*/
public class MentaContainer implements Container {
private Map factoriesByName = new Hashtable();
private Map scopes = new Hashtable();
private Map singletonsCache = new Hashtable();
private Map> threadLocalsCache = new Hashtable>();
private Set setterDependencies = Collections.synchronizedSet(new HashSet());
private Set constructorDependencies = Collections.synchronizedSet(new HashSet());
private Set forConstructMethod = Collections.synchronizedSet(new HashSet());
@Override
public Class> getType(Object key) {
String k = InjectionUtils.getKeyName(key);
Factory factory = factoriesByName.get(k);
if (factory == null) return null;
return factory.getType();
}
@Override
public void clear(Scope scope) {
if (scope == Scope.SINGLETON) {
List listToClear = new LinkedList();
synchronized(this) {
for(String key : singletonsCache.keySet()) {
Factory factory = factoriesByName.get(key);
if (factory instanceof Interceptor) {
Interceptor c = (Interceptor) factory;
Object value = singletonsCache.get(key);
listToClear.add(new ClearableHolder(c, value));
}
}
singletonsCache.clear();
}
// clear everything inside a non-synchronized block...
for(ClearableHolder cp : listToClear) cp.clear();
} else if (scope == Scope.THREAD) {
List listToClear = new LinkedList();
synchronized(this) {
for(String key : threadLocalsCache.keySet()) {
Factory factory = factoriesByName.get(key);
if (factory instanceof Interceptor) {
Interceptor c = (Interceptor) factory;
ThreadLocal t = threadLocalsCache.get(key);
Object value = t.get();
// we are ONLY clearing if this thread has something in the threadlocal, in other words,
// if the thread has previously requested this key...
if (value != null) listToClear.add(new ClearableHolder(c, value));
}
}
// and now we clear all thread locals belonging to this thread...
// this will only clear the instances related to this thread...
for(ThreadLocal t : threadLocalsCache.values()) {
t.remove();
}
}
// clear everything inside a non-synchronized block...
for(ClearableHolder cp : listToClear) cp.clear();
}
}
@Override
public T clear(Object key) {
String keyString = InjectionUtils.getKeyName(key);
if (!factoriesByName.containsKey(keyString)) return null;
Scope scope = scopes.get(keyString);
if (scope == Scope.SINGLETON) {
ClearableHolder cp = null;
Object value = null;
synchronized(this) {
value = singletonsCache.remove(keyString);
if (value != null) {
Factory factory = factoriesByName.get(keyString);
if (factory instanceof Interceptor) {
Interceptor c = (Interceptor) factory;
cp = new ClearableHolder(c, value);
}
}
}
if (cp != null) cp.clear();
return (T) value;
} else if (scope == Scope.THREAD) {
ClearableHolder cp = null;
Object retVal = null;
synchronized(this) {
ThreadLocal t = threadLocalsCache.get(keyString);
if (t != null) {
Object o = t.get();
if (o != null) {
Factory factory = factoriesByName.get(keyString);
if (factory instanceof Interceptor) {
Interceptor c = (Interceptor) factory;
cp = new ClearableHolder(c, o);
}
t.remove();
retVal = o;
}
}
}
if (cp != null) cp.clear();
return (T) retVal;
} else if (scope == Scope.NONE) {
return null; // always...
} else {
throw new UnsupportedOperationException("Scope not supported: " + scope);
}
}
@Override
public T get(Object key) {
String keyString = InjectionUtils.getKeyName(key);
if (!factoriesByName.containsKey(keyString)) return null;
Factory c = factoriesByName.get(keyString);
Scope scope = scopes.get(keyString);
Object target = null;
try {
if (scope == Scope.SINGLETON) {
boolean needsToCreate = false;
synchronized(this) {
if (singletonsCache.containsKey(keyString)) {
target = singletonsCache.get(keyString);
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();
checkInterceptable(c, target);
synchronized(this) {
singletonsCache.put(keyString, target);
}
}
} else if (scope == Scope.THREAD) {
boolean needsToCreate = false;
boolean needsToAddToCache = false;
ThreadLocal t = null;
synchronized(this) {
if (threadLocalsCache.containsKey(keyString)) {
t = threadLocalsCache.get(keyString);
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();
needsToCreate = true;
needsToAddToCache = true;
// let it be wired...
}
}
if (needsToCreate) {
// getInstance needs to be in a non-synchronized block
target = c.getInstance();
checkInterceptable(c, target);
t.set(target);
}
if (needsToAddToCache) {
synchronized(this) {
threadLocalsCache.put(keyString, t);
}
}
} else if (scope == Scope.NONE) {
target = c.getInstance();
checkInterceptable(c, target);
} else {
throw new UnsupportedOperationException("Don't know how to handle scope: " + scope);
}
if (target != null) {
for (SetterDependency d : setterDependencies) {
// has dependency ?
Method m = d.check(target.getClass());
if (m != null) {
String sourceKey = d.getSource();
if (sourceKey.equals(keyString)) {
// cannot depend on itself... also avoid recursive StackOverflow...
continue;
}
Object source = get(sourceKey);
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);
}
}
private final void checkInterceptable(Factory f, Object value) {
if (f instanceof Interceptor) {
Interceptor i = (Interceptor) f;
((Interceptor) f).onCreated(value);
}
}
@Override
public Factory ioc(Object key, Factory factory, Scope scope) {
String keyString = InjectionUtils.getKeyName(key);
factoriesByName.put(keyString, factory);
singletonsCache.remove(keyString); // just in case we are overriding a previous singleton bean...
ThreadLocal threadLocal = threadLocalsCache.remove(keyString); // just in case we are overriding a previous thread local...
if (threadLocal != null) {
threadLocal.remove();
}
scopes.put(keyString, scope);
forConstructMethod.add(new ConstructorDependency(keyString, factory.getType()));
return factory;
}
@Override
public Factory ioc(Object key, Factory factory) {
return ioc(key, factory, Scope.NONE);
}
@Override
public ConfigurableFactory ioc(Object key, Class> klass) {
ConfigurableFactory cc = new ClassFactory(this, klass);
ioc(key, cc);
return cc;
}
@Override
public ConfigurableFactory ioc(Object key, Class> klass, Scope scope) {
ConfigurableFactory cc = new ClassFactory(this, klass);
ioc(key, cc, scope);
return cc;
}
@Override
public void autowire(Object sourceFromContainer) {
// autowire by constructor and setter...
String s = InjectionUtils.getKeyName(sourceFromContainer);
autowireBySetter(s);
autowireByConstructor(s);
}
@Override
public void autowire(Object sourceFromContainer, String beanProperty) {
// autowire by constructor and setter...
String s = InjectionUtils.getKeyName(sourceFromContainer);
autowireBySetter(beanProperty, s);
autowireByConstructor(s);
}
private void autowireBySetter(String targetProperty, String sourceFromContainer) {
Class> sourceType = getType(sourceFromContainer);
SetterDependency d = new SetterDependency(targetProperty, sourceFromContainer, sourceType);
setterDependencies.add(d);
}
private void autowireBySetter(String targetProperty) {
autowireBySetter(targetProperty, targetProperty);
}
private void autowireByConstructor(String sourceFromContainer) {
Class> sourceType = getType(sourceFromContainer);
ConstructorDependency d = new ConstructorDependency(sourceFromContainer, sourceType);
constructorDependencies.add(d);
}
Set getConstructorDependencies() {
return constructorDependencies;
}
@Override
public T construct(Class> klass) {
ClassFactory f = new ClassFactory(this, klass, forConstructMethod);
return (T) f.getInstance();
}
@Override
public void inject(Object bean) {
Provider p = new Provider() {
@Override
public Object get(String key) {
return MentaContainer.this.get(key);
}
@Override
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);
}
}
@Override
public synchronized boolean check(Object obj) {
String key = InjectionUtils.getKeyName(obj);
if (!factoriesByName.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 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 ClearableHolder {
private Interceptor c;
private Object value;
public ClearableHolder(Interceptor c, Object value) {
this.c = c;
this.value = value;
}
public void clear() {
c.onCleared(value);
}
}
}