pl.setblack.airomem.direct.impl.ClassContext.java Source code

Java tutorial

Introduction

Here is the source code for pl.setblack.airomem.direct.impl.ClassContext.java

Source

/*
 *  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()]);
        }

    }

}