Package info.archinnov.achilles.internal.persistence.operations

Source Code of info.archinnov.achilles.internal.persistence.operations.EntityProxifier

/*
* Copyright (C) 2012-2014 DuyHai DOAN
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package info.archinnov.achilles.internal.persistence.operations;

import info.archinnov.achilles.internal.context.facade.EntityOperations;
import info.archinnov.achilles.internal.metadata.holder.EntityMeta;
import info.archinnov.achilles.internal.metadata.holder.PropertyMeta;
import info.archinnov.achilles.internal.proxy.ProxyClassFactory;
import info.archinnov.achilles.internal.proxy.ProxyInterceptor;
import info.archinnov.achilles.internal.proxy.ProxyInterceptorBuilder;
import info.archinnov.achilles.internal.reflection.ObjectInstantiator;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.NoOp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class EntityProxifier {

    private static final Logger log = LoggerFactory.getLogger(EntityProxifier.class);

    private ObjectInstantiator instantiator = ObjectInstantiator.Singleton.INSTANCE.get();
    private ProxyClassFactory factory = ProxyClassFactory.Singleton.INSTANCE.get();

    @SuppressWarnings("unchecked")
    public <T> Class<T> deriveBaseClass(Object entity) {
        log.debug("Deriving base class for entity {} ", entity);

        Class<T> baseClass = (Class<T>) entity.getClass();
        if (isProxy(entity)) {
            ProxyInterceptor<?> interceptor = getInterceptor(entity);
            baseClass = (Class<T>) interceptor.getTarget().getClass();
        }

        return baseClass;
    }

    public <T> T buildProxyWithAllFieldsLoadedExceptCounters(T entity, EntityOperations context) {
        return buildProxy(entity, context, context.getAllGettersExceptCounters());
    }

    public <T> T buildProxyWithNoFieldLoaded(T entity, EntityOperations context) {
        return buildProxy(entity, context, new HashSet<Method>());
    }

    public <T> T buildProxy(T entity, EntityOperations context, Set<Method> alreadyLoaded) {

        if (entity == null) {
            return null;
        }

        log.debug("Build Cglib proxy for entity {} ", entity);

        Class<?> proxyClass = factory.createProxyClass(entity.getClass(), context.getConfigContext());

        @SuppressWarnings("unchecked")
        T instance = (T) instantiator.instantiate(proxyClass);

        EntityMeta meta = context.getEntityMeta();
        for (PropertyMeta pm : meta.getAllMetasExceptCounters()) {
            Object value = pm.forValues().getValueFromField(entity);
            pm.forValues().setValueToField(instance, value);
        }

        for (PropertyMeta pm : meta.getAllCounterMetas()) {
            pm.forValues().setValueToField(entity,null);
        }

        ((Factory) instance).setCallbacks(new Callback[] {
                buildInterceptor(context, entity, alreadyLoaded),
                NoOp.INSTANCE
        });
        return instance;
    }

    @SuppressWarnings("unchecked")
    public <T> T getRealObject(T proxy) {
        log.debug("Get real entity from proxy {} ", proxy);

        if (isProxy(proxy)) {
            Factory factory = (Factory) proxy;
            ProxyInterceptor<T> interceptor = (ProxyInterceptor<T>) factory.getCallback(0);
            return (T) interceptor.getTarget();
        } else {
            return proxy;
        }

    }

    public boolean isProxy(Object entity) {
        return Factory.class.isAssignableFrom(entity.getClass());
    }

    public <T> ProxyInterceptor<T> getInterceptor(T proxy) {
        log.debug("Get interceptor from proxy {} ", proxy);

        Factory factory = (Factory) proxy;

        @SuppressWarnings("unchecked")
        ProxyInterceptor<T> interceptor = (ProxyInterceptor<T>) factory.getCallback(0);
        return interceptor;
    }

    public void ensureProxy(Object proxy) {
        if (!isProxy(proxy)) {
            throw new IllegalStateException("The entity '" + proxy + "' is not in 'managed' state.");
        }
    }

    public void ensureNotProxy(Object rawEntity) {
        if (isProxy(rawEntity)) {
            throw new IllegalStateException("The entity is already in 'managed' state.");
        }
    }

    public <T> T removeProxy(T proxy) {
        log.debug("Unwrapping object {} ", proxy);

        if (proxy != null) {

            if (isProxy(proxy)) {
                return getRealObject(proxy);
            } else {
                return proxy;
            }
        } else {
            return null;
        }
    }

    public <K, V> Map.Entry<K, V> removeProxy(Map.Entry<K, V> entry) {
        V value = entry.getValue();
        if (isProxy(value)) {
            value = getRealObject(value);
            entry.setValue(value);
        }
        return entry;
    }

    public <T> Collection<T> removeProxy(Collection<T> proxies) {
        Collection<T> result = new ArrayList<>();
        for (T proxy : proxies) {
            result.add(removeProxy(proxy));
        }
        return result;
    }

    public <T> List<T> removeProxy(List<T> proxies) {
        List<T> result = new ArrayList<>();
        for (T proxy : proxies) {
            result.add(this.removeProxy(proxy));
        }

        return result;
    }

    public <T> Set<T> removeProxy(Set<T> proxies) {
        Set<T> result = new HashSet<>();
        for (T proxy : proxies) {
            result.add(this.removeProxy(proxy));
        }

        return result;
    }

    public <T> ProxyInterceptor<T> buildInterceptor(EntityOperations context, T entity, Set<Method> alreadyLoaded) {
        return new ProxyInterceptorBuilder<>(context, entity).alreadyLoaded(alreadyLoaded).build();
    }

    public static enum Singleton {
        INSTANCE;

        private final EntityProxifier instance = new EntityProxifier();

        public EntityProxifier get() {
            return instance;
        }
    }
}
TOP

Related Classes of info.archinnov.achilles.internal.persistence.operations.EntityProxifier

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.