Java tutorial
/* * Copyright (c) Jarek Ratajski, Licensed under the Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 */ package pl.setblack.airomem.direct.impl; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.interceptor.InvocationContext; import javax.naming.InitialContext; import org.apache.commons.lang.ClassUtils; import pl.setblack.airomem.core.ContextCommand; import pl.setblack.airomem.core.PrevalanceContext; import pl.setblack.airomem.core.SimpleController; import pl.setblack.airomem.direct.OperationType; import pl.setblack.airomem.direct.PersistenceInterceptor; import pl.setblack.airomem.direct.PersistentObject; import pl.setblack.badass.Politician; /** * * @author jratajsk */ public class ClassContext { private final Class targetClass; private ElemHandler elem; ClassContext(final Class target) { this.targetClass = target; scan(); } private void scan() { List<ElemHandler> allAnootatedFields = scanFields(targetClass); if (allAnootatedFields.size() == 1) { prepare(allAnootatedFields.get(0)); } else { throw new IllegalStateException("must have exactly one PersistentObject"); } } private List<ElemHandler> scanFields(Class<? extends Object> aClass) { Field[] fields = aClass.getDeclaredFields(); final ArrayList<ElemHandler> result = new ArrayList<>(2); for (Field f : fields) { final PersistentObject po = f.getAnnotation(PersistentObject.class); if (po != null) { result.add(new FieldHandler(f)); } } if (aClass.getSuperclass() != null) { result.addAll(scanFields(aClass.getSuperclass())); } return result; } private void prepare(ElemHandler elem) { this.elem = elem; } private Class calcTargetClass(Object obj) { return obj.getClass().getSuperclass(); } Object performTransaction(final Object target, Method method, final Object[] args) { final SimpleController controller = PrevaylerRegister.getInstance().getController(elem.getTargetType(), elem.getName()); final WraperTransaction transaction = new WraperTransaction(calcTargetClass(target).getCanonicalName(), method, args); return controller.executeAndQuery(transaction); } private void inject(Object target, Object system) { this.elem.storeValue(target, system); } private void clean(Object target) { this.elem.cleanValue(target); } private static BeanManager getBeanManager() { return Politician.beatAroundTheBush(() -> (BeanManager) InitialContext.doLookup("java:comp/BeanManager")); } private static Object instantiateBean(final Class cls) throws IllegalStateException { final BeanManager beanManager = getBeanManager(); for (Bean<?> bean : beanManager.getBeans(cls)) { final CreationalContext context = beanManager.createCreationalContext(bean); return beanManager.getReference(bean, cls, context); } throw new IllegalStateException("no bean of class" + cls); } private static ClassContextRegistry findRegistry() { return (ClassContextRegistry) instantiateBean(ClassContextRegistry.class); } public Object performTransaction(InvocationContext ctx) { final Method method = ctx.getMethod(); final OperationType opType = findRegistry().sayTypeOfMethod(method); if (opType == OperationType.WRITE) { return this.performTransaction(ctx.getTarget(), method, ctx.getParameters()); } else { try { final SimpleController controller = PrevaylerRegister.getInstance() .getController(elem.getTargetType(), elem.getName()); inject(ctx.getTarget(), controller.query(immutable -> immutable)); return Politician.beatAroundTheBush(() -> ctx.proceed()); } finally { clean(ctx.getTarget()); } } } private static class WraperTransaction implements ContextCommand<Object, Object>, Serializable { private static final long serialVersionUID = 1l; private static final ThreadLocal<Boolean> MARKER = new ThreadLocal<>(); private final String targetClass; private final String methodName; private String[] paramClasses; private final Object[] arguments; public WraperTransaction(String targetClass, final Method method, final Object[] args) { this.targetClass = targetClass; this.methodName = method.getName(); this.arguments = args; storeParams(method); } private Object instantiateTarget() throws ClassNotFoundException { final Class cls = Class.forName(this.targetClass); return instantiateBean(cls); } private Class[] getParams() { final Class[] result = new Class[this.paramClasses.length]; for (int i = 0; i < result.length; i++) { final String className = this.paramClasses[i]; result[i] = Politician.beatAroundTheBush(() -> ClassUtils.getClass(className)); } return result; } @Override public Object execute(Object system, PrevalanceContext context) { PersistenceInterceptor.setMarker(); final Object target = Politician.beatAroundTheBush(() -> instantiateTarget()); final ClassContext ctx = findRegistry().getContext(target); ctx.inject(target, system); try { return Politician.beatAroundTheBush(() -> { final Method method = target.getClass().getMethod(methodName, getParams()); return method.invoke(target, this.arguments); }); } finally { ctx.clean(target); } } private void storeParams(Method method) { final List<String> params = new ArrayList<>(method.getParameterCount()); for (final Class cls : method.getParameterTypes()) { params.add(cls.getCanonicalName()); } this.paramClasses = params.toArray(new String[params.size()]); } } }