com.mmnaseri.dragonfly.runtime.session.ApplicationSessionPreparator.java Source code

Java tutorial

Introduction

Here is the source code for com.mmnaseri.dragonfly.runtime.session.ApplicationSessionPreparator.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Milad Naseri.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.mmnaseri.dragonfly.runtime.session;

import com.mmnaseri.couteau.basics.api.Transformer;
import com.mmnaseri.couteau.basics.api.impl.CastingTransformer;
import com.mmnaseri.couteau.reflection.util.ClassUtils;
import com.mmnaseri.dragonfly.annotations.Extension;
import com.mmnaseri.dragonfly.data.DataAccessSession;
import com.mmnaseri.dragonfly.dialect.DatabaseDialect;
import com.mmnaseri.dragonfly.entity.EntityDefinition;
import com.mmnaseri.dragonfly.entity.EntityDefinitionContext;
import com.mmnaseri.dragonfly.entity.ModifiableEntityContext;
import com.mmnaseri.dragonfly.entity.impl.DefaultEntityDefinitionContext;
import com.mmnaseri.dragonfly.entity.impl.ImmutableEntityDefinition;
import com.mmnaseri.dragonfly.ext.ExtensionManager;
import com.mmnaseri.dragonfly.ext.impl.AnnotationExtensionMetadataResolver;
import com.mmnaseri.dragonfly.ext.impl.DefaultExtensionManager;
import com.mmnaseri.dragonfly.metadata.MetadataResolveStrategy;
import com.mmnaseri.dragonfly.metadata.TableMetadataInterceptor;
import com.mmnaseri.dragonfly.metadata.TableMetadataRegistry;
import com.mmnaseri.dragonfly.metadata.TableMetadataResolverContext;
import com.mmnaseri.dragonfly.metadata.impl.AnnotationTableMetadataResolver;
import com.mmnaseri.dragonfly.metadata.impl.DefaultTableMetadataResolverContext;
import com.mmnaseri.dragonfly.statement.StatementRegistry;
import com.mmnaseri.dragonfly.statement.impl.StatementRegistryPreparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import javax.persistence.Entity;
import java.util.*;

import static com.mmnaseri.couteau.basics.collections.CollectionWrapper.with;

/**
 * @author Milad Naseri (mmnaseri@programmer.net)
 * @since 1.0 (2013/9/18, 17:56)
 */
@Deprecated
public class ApplicationSessionPreparator implements BeanFactoryPostProcessor {

    private final static Log log = LogFactory.getLog(ApplicationSessionPreparator.class);

    private final ExtensionManager extensionManager;
    private final TableMetadataResolverContext resolverContext;
    private final EntityDefinitionContext definitionContext;
    private final String[] basePackages;
    private final DatabaseDialect databaseDialect;
    private TableMetadataRegistry tableMetadataRegistry;
    private StatementRegistry statementRegistry;
    private ClassLoader parentClassLoader;
    private AnnotationTableMetadataResolver metadataResolver;
    private final boolean initializeSession;

    public ApplicationSessionPreparator(String basePackages, DatabaseDialect databaseDialect,
            boolean initializeSession) {
        this(basePackages.split(","), databaseDialect, initializeSession);
    }

    public ApplicationSessionPreparator(Properties basePackages, DatabaseDialect databaseDialect,
            boolean initializeSession) {
        this(with(basePackages.keySet()).transform(new CastingTransformer<Object, String>(String.class)).list(),
                databaseDialect, initializeSession);
    }

    public ApplicationSessionPreparator(Collection<String> basePackages, DatabaseDialect databaseDialect,
            boolean initializeSession) {
        this(basePackages.toArray(new String[basePackages.size()]), databaseDialect, initializeSession);
    }

    public ApplicationSessionPreparator(String[] basePackages, DatabaseDialect databaseDialect,
            boolean initializeSession) {
        this.basePackages = basePackages;
        this.databaseDialect = databaseDialect;
        this.initializeSession = initializeSession;
        extensionManager = new DefaultExtensionManager();
        resolverContext = new DefaultTableMetadataResolverContext(MetadataResolveStrategy.UNAMBIGUOUS,
                Arrays.<TableMetadataInterceptor>asList(extensionManager));
        definitionContext = new DefaultEntityDefinitionContext();
        definitionContext.addInterceptor(extensionManager);
        metadataResolver = new AnnotationTableMetadataResolver(databaseDialect);
        resolverContext.addMetadataResolver(metadataResolver);
        parentClassLoader = null;
    }

    public void setParentClassLoader(ClassLoader parentClassLoader) {
        this.parentClassLoader = parentClassLoader;
    }

    public ExtensionManager getExtensionManager() {
        return extensionManager;
    }

    public TableMetadataResolverContext getResolverContext() {
        return resolverContext;
    }

    public EntityDefinitionContext getDefinitionContext() {
        return definitionContext;
    }

    public String[] getBasePackages() {
        return basePackages;
    }

    public TableMetadataRegistry getTableMetadataRegistry() {
        return tableMetadataRegistry;
    }

    public StatementRegistry getStatementRegistry() {
        return statementRegistry;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory context) throws BeansException {
        showDeprecationWarning();
        long time = System.nanoTime();
        log.warn(
                "Preparing the session at runtime can be harmful to your performance. You should consider switching to "
                        + "the Maven plugin.");
        log.debug("Looking up the necessary components ...");
        tableMetadataRegistry = context.getBean(TableMetadataRegistry.class);
        statementRegistry = context.getBean(StatementRegistry.class);
        final ModifiableEntityContext entityContext = context.getBean(ModifiableEntityContext.class);
        final ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
                false);
        log.info("Finding entity classes ...");
        log.debug("Looking for classes with @Entity");
        componentProvider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
        if (parentClassLoader == null) {
            log.debug("Falling back to the application context class loader");
            parentClassLoader = context.getBeanClassLoader();
        }
        for (String basePackage : basePackages) {
            final Set<BeanDefinition> beanDefinitions = componentProvider.findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : beanDefinitions) {
                try {
                    log.debug("Registering entity " + beanDefinition.getBeanClassName());
                    //noinspection unchecked
                    definitionContext.addDefinition(new ImmutableEntityDefinition<Object>(
                            ClassUtils.forName(beanDefinition.getBeanClassName(), parentClassLoader),
                            Collections.<Class<?>, Class<?>>emptyMap()));
                } catch (ClassNotFoundException e) {
                    throw new FatalBeanException("Failed to retrieve class: " + beanDefinition.getBeanClassName(),
                            e);
                }
            }
        }
        componentProvider.resetFilters(false);
        log.info("Finding extensions to the data access ...");
        log.debug("Looking for classes with @Extension");
        componentProvider.addIncludeFilter(new AnnotationTypeFilter(Extension.class));
        final AnnotationExtensionMetadataResolver extensionMetadataResolver = new AnnotationExtensionMetadataResolver(
                metadataResolver);
        for (String basePackage : basePackages) {
            final Set<BeanDefinition> beanDefinitions = componentProvider.findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : beanDefinitions) {
                try {
                    log.debug("Registering extension " + beanDefinition.getBeanClassName());
                    extensionManager.addExtension(extensionMetadataResolver
                            .resolve(ClassUtils.forName(beanDefinition.getBeanClassName(), parentClassLoader)));
                } catch (ClassNotFoundException e) {
                    throw new FatalBeanException("Failed to retrieve class: " + beanDefinition.getBeanClassName(),
                            e);
                }
            }
        }
        log.info("Preparing entity statements for later use");
        final StatementRegistryPreparator preparator = new StatementRegistryPreparator(databaseDialect,
                resolverContext, tableMetadataRegistry);
        for (Class<?> entity : definitionContext.getEntities()) {
            preparator.addEntity(entity);
        }
        preparator.prepare(statementRegistry);
        log.info("Registering interfaces with the context");
        entityContext.setInterfaces(
                with(definitionContext.getEntities()).map(new Transformer<Class<?>, Map<Class<?>, Class<?>>>() {
                    @Override
                    public Map<Class<?>, Class<?>> map(Class<?> input) {
                        //noinspection unchecked
                        final EntityDefinition<Object> definition = extensionManager
                                .intercept(new ImmutableEntityDefinition<Object>((Class<Object>) input,
                                        Collections.<Class<?>, Class<?>>emptyMap()));
                        return definition.getInterfaces();
                    }
                }));
        if (initializeSession) {
            final DataAccessSession session = context.getBean(DataAccessSession.class);
            session.initialize();
            session.markInitialized();
        }
        log.info("Setting the class loader for the entity context");
        entityContext.setDefaultClassLoader(context.getBeanClassLoader());
        time = System.nanoTime() - time;
        log.info("Session preparation took " + Math.round((double) time / 1000000d) / 1000d + " second(s)");
    }

    private void showDeprecationWarning() {
        System.out.flush();
        System.err.println("\n\n\n\n");
        System.err.println("DEPRECATED METHOD IN USE");
        System.err.println("------------------------");
        System.err
                .println("Please note that you are initializing the persistence unit via a deprecated method and\n"
                        + "as such your setup is not guaranteed to work as you expect. In this mode, you should also deactivate\n"
                        + "scanning for @Configuration classes via the XML based configuration for Spring as it might lead to multiple\n"
                        + "instances of session-related metadata collectors to be created.");
        System.err.println("");
        for (int i = 5; i >= 0; i--) {
            try {
                System.err.print("This notice will go away in " + i + " more second(s) ...\r");
                System.err.flush();
                Thread.sleep(1000);
            } catch (InterruptedException ignored) {
            }
        }
        System.err.print("\t\t\t\t\t\t\t\t\t\t\t\r");
        System.err.println("");
    }

}