Skip to content

Commit

Permalink
Simplified IoC and bean management components.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Feb 17, 2016
1 parent af5cd80 commit bb03af1
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 131 deletions.
12 changes: 9 additions & 3 deletions rapidoid-commons/src/main/java/org/rapidoid/cls/Cls.java
Expand Up @@ -435,7 +435,7 @@ public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?>... para


@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T newInstance(Class<T> clazz, Map<String, Object> properties) { public static <T> T newInstance(Class<T> clazz, Map<String, Object> properties) {
if (properties == null) { if (U.isEmpty(properties)) {
return newInstance(clazz); return newInstance(clazz);
} }


Expand All @@ -444,6 +444,7 @@ public static <T> T newInstance(Class<T> clazz, Map<String, Object> properties)
for (Constructor<?> constr : clazz.getConstructors()) { for (Constructor<?> constr : clazz.getConstructors()) {
Class<?>[] paramTypes = constr.getParameterTypes(); Class<?>[] paramTypes = constr.getParameterTypes();
Object[] args = getAssignableArgs(paramTypes, values); Object[] args = getAssignableArgs(paramTypes, values);

if (args != null) { if (args != null) {
try { try {
return (T) constr.newInstance(args); return (T) constr.newInstance(args);
Expand Down Expand Up @@ -939,8 +940,13 @@ public static boolean isDataStructure(Class<?> clazz) {
} }


public static boolean isBeanType(Class<?> clazz) { public static boolean isBeanType(Class<?> clazz) {
return kindOf(clazz) == TypeKind.OBJECT && !(Collection.class.isAssignableFrom(clazz)) return kindOf(clazz) == TypeKind.OBJECT
&& !(Map.class.isAssignableFrom(clazz)) && !(Object[].class.isAssignableFrom(clazz)) && !clazz.isAnnotation()
&& !clazz.isEnum()
&& !clazz.isInterface()
&& !(Collection.class.isAssignableFrom(clazz))
&& !(Map.class.isAssignableFrom(clazz))
&& !(Object[].class.isAssignableFrom(clazz))
&& !clazz.getPackage().getName().startsWith("java.") && !clazz.getPackage().getName().startsWith("java.")
&& !clazz.getPackage().getName().startsWith("javax."); && !clazz.getPackage().getName().startsWith("javax.");
} }
Expand Down
Expand Up @@ -42,7 +42,7 @@ public class ClassMetadata {


final List<Field> localFields; final List<Field> localFields;


final Set<Object> injectors = Coll.synchronizedSet(); final Set<Object> providers = Coll.synchronizedSet();


final List<F3<Object, Object, Method, Object[]>> interceptors = Coll.synchronizedList(); final List<F3<Object, Object, Method, Object[]>> interceptors = Coll.synchronizedList();


Expand Down
20 changes: 14 additions & 6 deletions rapidoid-commons/src/main/java/org/rapidoid/ioc/IoC.java
Expand Up @@ -31,28 +31,36 @@ public class IoC {


private static final IoCContext DEFAULT_CONTEXT = new IoCContext(); private static final IoCContext DEFAULT_CONTEXT = new IoCContext();


public static synchronized IoCContext getDefault() { public static IoCContext defaultContext() {
return DEFAULT_CONTEXT; return DEFAULT_CONTEXT;
} }


public static synchronized void manage(Object... classesOrInstances) { public static void manage(Object... classesOrInstances) {
DEFAULT_CONTEXT.manage(classesOrInstances); DEFAULT_CONTEXT.manage(classesOrInstances);
} }


public static synchronized <T> T singleton(Class<T> type) { public static <T> T singleton(Class<T> type) {
return DEFAULT_CONTEXT.singleton(type); return DEFAULT_CONTEXT.singleton(type);
} }


public static synchronized <T> T autowire(T target) { public static <T> T autowire(T target) {
return DEFAULT_CONTEXT.autowire(target); return DEFAULT_CONTEXT.autowire(target);
} }


public static synchronized <T> T inject(T target) { public static <T> T inject(T target) {
return DEFAULT_CONTEXT.inject(target); return DEFAULT_CONTEXT.inject(target);
} }


public static synchronized <T> T inject(T target, Map<String, Object> properties) { public static <T> T inject(T target, Map<String, Object> properties) {
return DEFAULT_CONTEXT.inject(target, properties); return DEFAULT_CONTEXT.inject(target, properties);
} }


public boolean remove(Object bean) {
return DEFAULT_CONTEXT.remove(bean);
}

public static IoCContext createContext() {
return new IoCContext();
}

} }
140 changes: 79 additions & 61 deletions rapidoid-commons/src/main/java/org/rapidoid/ioc/IoCContext.java
Expand Up @@ -30,6 +30,7 @@
import org.rapidoid.lambda.Mapper; import org.rapidoid.lambda.Mapper;
import org.rapidoid.log.Log; import org.rapidoid.log.Log;
import org.rapidoid.u.U; import org.rapidoid.u.U;
import org.rapidoid.util.UTILS;


import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
Expand All @@ -43,13 +44,14 @@
@Since("5.1.0") @Since("5.1.0")
public class IoCContext { public class IoCContext {


private final Map<Class<?>, Object> singletons = U.map(); IoCContext() {
}


private final Set<Class<?>> managedClasses = U.set(); private final Set<Class<?>> providedClasses = U.set();


private final Set<Object> managedInstances = U.set(); private final Set<Object> providedInstances = U.set();


private final Map<Object, Object> iocInstances = U.map(); private final Map<Object, Object> proxies = U.map();


private final Map<Class<?>, ClassMetadata> metadata = Coll private final Map<Class<?>, ClassMetadata> metadata = Coll
.autoExpandingMap(new Mapper<Class<?>, ClassMetadata>() { .autoExpandingMap(new Mapper<Class<?>, ClassMetadata>() {
Expand All @@ -62,10 +64,9 @@ public ClassMetadata map(Class<?> clazz) throws Exception {
public synchronized void reset() { public synchronized void reset() {
Log.info("Resetting IoC context", "context", this); Log.info("Resetting IoC context", "context", this);


singletons.clear(); providedClasses.clear();
managedClasses.clear(); providedInstances.clear();
managedInstances.clear(); proxies.clear();
iocInstances.clear();
metadata.clear(); metadata.clear();
} }


Expand All @@ -74,41 +75,42 @@ private ClassMetadata meta(Class<?> type) {
} }


public synchronized void manage(Object... classesOrInstances) { public synchronized void manage(Object... classesOrInstances) {
List<Class<?>> autocreate = new ArrayList<Class<?>>(); List<Class<?>> autoCreate = new ArrayList<Class<?>>();


for (Object classOrInstance : classesOrInstances) { for (Object classOrInstance : classesOrInstances) {


boolean isClass = isClass(classOrInstance); boolean isClass = isClass(classOrInstance);
Class<?> clazz = isClass ? (Class<?>) classOrInstance : classOrInstance.getClass(); Class<?> clazz = isClass ? (Class<?>) classOrInstance : classOrInstance.getClass();


for (Class<?> interfacee : Cls.getImplementedInterfaces(clazz)) { for (Class<?> interfacee : Cls.getImplementedInterfaces(clazz)) {
addInjectionProvider(interfacee, classOrInstance); addProvider(interfacee, classOrInstance);
} }


if (isClass) { if (isClass) {
Log.debug("configuring managed class", "class", classOrInstance); Log.debug("configuring managed class", "class", classOrInstance);
managedClasses.add(clazz); providedClasses.add(clazz);


if (!clazz.isInterface() && !clazz.isEnum() && !clazz.isAnnotation()) { if (!clazz.isInterface() && !clazz.isEnum() && !clazz.isAnnotation()) {
// if the class is annotated, auto-create an instance // if the class is annotated, auto-create an instance
if (clazz.getAnnotation(Autocreate.class) != null) { if (clazz.getAnnotation(Autocreate.class) != null) {
autocreate.add(clazz); autoCreate.add(clazz);
} }
} }
} else { } else {
Log.debug("configuring managed instance", "instance", classOrInstance); Object instance = classOrInstance;
addInjectionProvider(clazz, classOrInstance); Log.debug("configuring provided instance", "instance", instance);
managedInstances.add(classOrInstance); addProvider(clazz, instance);
providedInstances.add(instance);
} }
} }


for (Class<?> clazz : autocreate) { for (Class<?> clazz : autoCreate) {
singleton(clazz); singleton(clazz);
} }
} }


private void addInjectionProvider(Class<?> type, Object provider) { private void addProvider(Class<?> type, Object provider) {
meta(type).injectors.add(provider); meta(type).providers.add(provider);
} }


public synchronized <T> T singleton(Class<T> type) { public synchronized <T> T singleton(Class<T> type) {
Expand Down Expand Up @@ -159,11 +161,11 @@ private <T> T provideIoCInstanceOf(Object target, Class<T> type, String name,
} }


if (instance == null) { if (instance == null) {
instance = provideIoCInstanceByType(type, properties); instance = provideInstanceByType(type, properties);
} }


if (instance == null && canInjectNew(type)) { if (instance == null && Cls.isBeanType(type)) {
instance = provideNewIoCInstanceOf(type, properties); instance = provideNewInstanceOf(type, properties);
} }


if (!optional) { if (!optional) {
Expand All @@ -179,62 +181,47 @@ private <T> T provideIoCInstanceOf(Object target, Class<T> type, String name,
return instance != null ? ioc(instance, properties) : null; return instance != null ? ioc(instance, properties) : null;
} }


private boolean canInjectNew(Class<?> type) {
return !type.isAnnotation() && !type.isEnum() && !type.isInterface() && !type.isPrimitive()
&& !type.equals(String.class) && !type.equals(Object.class) && !type.equals(Boolean.class)
&& !Number.class.isAssignableFrom(type);
}

@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T provideNewIoCInstanceOf(Class<T> type, Map<String, Object> properties) { private <T> T provideNewInstanceOf(Class<T> type, Map<String, Object> properties) {
// instantiation if it's real class // instantiation if it's real class
if (!type.isInterface() && !type.isEnum() && !type.isAnnotation()) { if (!type.isInterface() && !type.isEnum() && !type.isAnnotation()) {
T instance = (T) singletons.get(type); return ioc(Cls.newInstance(type, properties), properties);

if (instance == null) {
instance = ioc(Cls.newInstance(type, properties), properties);
}

return instance;
} else { } else {
return null; return null;
} }
} }


private <T> T provideIoCInstanceByType(Class<T> type, Map<String, Object> properties) { private <T> T provideInstanceByType(Class<T> type, Map<String, Object> properties) {
Set<Object> providers = meta(type).injectors;


if (providers != null && !providers.isEmpty()) { Set<Object> providers = meta(type).providers;
Object provider = null;


Object provider = null; for (Object candidate : providers) {

if (provider == null) {
for (Object pr : providers) { provider = candidate;
if (provider == null) { } else {
provider = pr; if (isClass(provider) && !isClass(candidate)) {
} else { provider = candidate;
if (isClass(provider) && !isClass(pr)) { } else if (isClass(provider) || !isClass(candidate)) {
provider = pr; throw U.rte("Found more than 1 candidates for type '%s': %s", type, providers);
} else if (isClass(provider) || !isClass(pr)) {
throw U.rte("Found more than 1 injection candidates for type '%s': %s", type, providers);
}
} }
} }
}


if (provider != null) { if (provider != null) {
return provideFrom(provider, properties); return provideFrom(provider, properties);
}
} }


return null; return null;
} }


@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private <T> T provideFrom(Object classOrInstance, Map<String, Object> properties) { private <T> T provideFrom(Object provider, Map<String, Object> properties) {
T instance; T instance;
if (isClass(classOrInstance)) { if (isClass(provider)) {
instance = provideNewIoCInstanceOf((Class<T>) classOrInstance, properties); instance = provideNewInstanceOf((Class<T>) provider, properties);
} else { } else {
instance = (T) classOrInstance; instance = (T) provider;
} }
return instance; return instance;
} }
Expand Down Expand Up @@ -328,8 +315,8 @@ private <T> void invokePostConstruct(T target) {
} }


private <T> T ioc(T target, Map<String, Object> properties) { private <T> T ioc(T target, Map<String, Object> properties) {
if (!isIocProcessed(target)) { if (!isProxyOrHasProxy(target)) {
iocInstances.put(target, null); proxies.put(target, null);


manage(target); manage(target);


Expand All @@ -339,7 +326,7 @@ private <T> T ioc(T target, Map<String, Object> properties) {


T proxy = proxyWrap(target); T proxy = proxyWrap(target);


iocInstances.put(target, proxy); proxies.put(target, proxy);


manage(proxy); manage(proxy);


Expand All @@ -349,8 +336,8 @@ private <T> T ioc(T target, Map<String, Object> properties) {
return target; return target;
} }


private boolean isIocProcessed(Object target) { private boolean isProxyOrHasProxy(Object target) {
for (Map.Entry<Object, Object> e : iocInstances.entrySet()) { for (Map.Entry<Object, Object> e : proxies.entrySet()) {
if (e.getKey() == target || e.getValue() == target) { if (e.getKey() == target || e.getValue() == target) {
return true; return true;
} }
Expand Down Expand Up @@ -398,4 +385,35 @@ public V map(K src) throws Exception {
}); });
} }


public synchronized Object findInstanceOf(String className) {
for (Object instance : providedInstances) {
if (instance.getClass().getName().equals(className)) {
return instance;
}
}
return null;
}

@Override
public synchronized String toString() {
return UTILS.classNames(providedInstances);
}

public synchronized boolean remove(Object bean) {
boolean removed = providedInstances.remove(bean);
removed |= (proxies.remove(bean) != null);

if (removed) {
Class<?> clazz = bean.getClass();
providedClasses.remove(clazz);
metadata.remove(clazz);
}

return removed;
}

public synchronized void reload(ClassLoader classLoader) {
// FIXME implement
}

} }
11 changes: 11 additions & 0 deletions rapidoid-commons/src/main/java/org/rapidoid/util/UTILS.java
Expand Up @@ -849,4 +849,15 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
return ((T) Proxy.newProxyInstance(targetInterface.getClassLoader(), new Class[]{targetInterface}, handler)); return ((T) Proxy.newProxyInstance(targetInterface.getClassLoader(), new Class[]{targetInterface}, handler));
} }


public static String classNames(Collection<?> classesOrInstances) {
List<Object> names = U.list();

for (Object o : classesOrInstances) {
Class<?> clazz = (o instanceof Class<?>) ? ((Class) o) : o.getClass();
names.add(clazz.getSimpleName());
}

return "[" + U.join(", ", names) + "]";
}

} }
Expand Up @@ -23,8 +23,8 @@
import org.junit.Test; import org.junit.Test;
import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since; import org.rapidoid.annotation.Since;
import org.rapidoid.test.AbstractCommonsTest;
import org.rapidoid.ioc.IoC; import org.rapidoid.ioc.IoC;
import org.rapidoid.test.AbstractCommonsTest;


@Authors("Nikolche Mihajlovski") @Authors("Nikolche Mihajlovski")
@Since("2.0.0") @Since("2.0.0")
Expand Down
Expand Up @@ -34,8 +34,8 @@ public class Database {
@Inject @Inject
Transactor transactor; Transactor transactor;


final Map<String, Table> tables = IoC.getDefault().autoExpandingInjectingMap(Table.class); final Map<String, Table> tables = IoC.defaultContext().autoExpandingInjectingMap(Table.class);


final Map<String, Relat> relations = IoC.getDefault().autoExpandingInjectingMap(Relat.class); final Map<String, Relat> relations = IoC.defaultContext().autoExpandingInjectingMap(Relat.class);


} }
Expand Up @@ -48,7 +48,6 @@
import org.rapidoid.u.U; import org.rapidoid.u.U;
import org.rapidoid.util.Constants; import org.rapidoid.util.Constants;
import org.rapidoid.util.UTILS; import org.rapidoid.util.UTILS;
import org.rapidoid.ioc.IoC;
import org.rapidoid.wrap.BoolWrap; import org.rapidoid.wrap.BoolWrap;


import java.io.Serializable; import java.io.Serializable;
Expand Down Expand Up @@ -84,7 +83,7 @@ public class FastHttp implements Protocol, HttpMetadata {


private static final byte[] DATE_IS = "Date: ".getBytes(); private static final byte[] DATE_IS = "Date: ".getBytes();


private static final HttpParser HTTP_PARSER = IoC.singleton(HttpParser.class); private static final HttpParser HTTP_PARSER = new HttpParser();


private static final byte[] _POST = Constants.POST.getBytes(); private static final byte[] _POST = Constants.POST.getBytes();
private static final byte[] _PUT = Constants.PUT.getBytes(); private static final byte[] _PUT = Constants.PUT.getBytes();
Expand Down

0 comments on commit bb03af1

Please sign in to comment.