org.seedstack.seed.core.internal.data.DataPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.seedstack.seed.core.internal.data.DataPlugin.java

Source

/**
 * Copyright (c) 2013-2015 by The SeedStack authors. All rights reserved.
 *
 * This file is part of SeedStack, An enterprise-oriented full development stack.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.seedstack.seed.core.internal.data;

import org.seedstack.seed.core.api.DataManager;
import org.seedstack.seed.core.api.SeedException;
import org.seedstack.seed.core.spi.data.DataExporter;
import org.seedstack.seed.core.spi.data.DataImporter;
import org.seedstack.seed.core.spi.data.DataSet;
import io.nuun.kernel.api.Plugin;
import io.nuun.kernel.api.plugin.InitState;
import io.nuun.kernel.api.plugin.context.Context;
import io.nuun.kernel.api.plugin.context.InitContext;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
import io.nuun.kernel.core.AbstractPlugin;
import org.apache.commons.configuration.Configuration;
import org.kametic.specifications.Specification;
import org.seedstack.seed.core.internal.CorePlugin;
import org.seedstack.seed.core.internal.application.ApplicationPlugin;
import org.seedstack.seed.core.utils.SeedReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * This plugin provides data import and export facilities.
 *
 * @author pierre.thirouin@ext.mpsa.com
 */
public class DataPlugin extends AbstractPlugin {
    private static final Logger LOGGER = LoggerFactory.getLogger(DataPlugin.class);

    private final Specification<Class<?>> dataExporterSpecification = and(classImplements(DataExporter.class),
            classAnnotatedWith(DataSet.class));
    private final Specification<Class<?>> dataImporterSpecification = and(classImplements(DataImporter.class),
            classAnnotatedWith(DataSet.class));

    private final Map<String, Map<String, DataExporterDefinition<Object>>> allDataExporters = new HashMap<String, Map<String, DataExporterDefinition<Object>>>();
    private final Map<String, Map<String, DataImporterDefinition<Object>>> allDataImporters = new HashMap<String, Map<String, DataImporterDefinition<Object>>>();

    private boolean loadInitializationData;
    private boolean forceInitializationData;

    @Inject
    private DataManager dataManager;

    @Override
    public String name() {
        return "seed-data-plugin";
    }

    @Override
    public Collection<ClasspathScanRequest> classpathScanRequests() {
        return classpathScanRequestBuilder().specification(dataExporterSpecification)
                .specification(dataImporterSpecification).build();
    }

    @SuppressWarnings("unchecked")
    @Override
    public InitState init(InitContext initContext) {
        ApplicationPlugin applicationPlugin = (ApplicationPlugin) initContext.pluginsRequired().iterator().next();
        Configuration configuration = applicationPlugin.getApplication().getConfiguration()
                .subset(CorePlugin.CORE_PLUGIN_PREFIX);

        String dataInitializationMode = configuration.getString("data-initialization", "auto");
        if ("auto".equals(dataInitializationMode)) {
            loadInitializationData = true;
        } else if ("force".equals(dataInitializationMode)) {
            loadInitializationData = true;
            forceInitializationData = true;
        }

        Collection<Class<?>> scannedDataExporterClasses = initContext.scannedTypesBySpecification()
                .get(dataExporterSpecification);
        for (Class<?> scannedDataExporterClass : scannedDataExporterClasses) {
            if (DataExporter.class.isAssignableFrom(scannedDataExporterClass)) {
                DataSet dataSet = scannedDataExporterClass.getAnnotation(DataSet.class);
                Map<String, DataExporterDefinition<Object>> nameDataExporterDefinitionMap = allDataExporters
                        .get(dataSet.group());
                if (nameDataExporterDefinitionMap == null) {
                    nameDataExporterDefinitionMap = new HashMap<String, DataExporterDefinition<Object>>();
                }

                Class exportedClass = getTypeParameter(scannedDataExporterClass, DataExporter.class);
                if (exportedClass == null) {
                    throw SeedException.createNew(DataErrorCode.MISSING_TYPE_PARAMETER).put("class",
                            scannedDataExporterClass);
                }

                DataExporterDefinition dataExporterDefinition = new DataExporterDefinition(dataSet.name(),
                        dataSet.group(), exportedClass, scannedDataExporterClass);
                nameDataExporterDefinitionMap.put(dataSet.name(), dataExporterDefinition);
                allDataExporters.put(dataSet.group(), nameDataExporterDefinitionMap);
            }
        }

        Collection<Class<?>> scannedDataImporterClasses = initContext.scannedTypesBySpecification()
                .get(dataImporterSpecification);
        for (Class<?> scannedDataImporterClass : scannedDataImporterClasses) {
            if (DataImporter.class.isAssignableFrom(scannedDataImporterClass)) {
                DataSet dataSet = scannedDataImporterClass.getAnnotation(DataSet.class);
                Map<String, DataImporterDefinition<Object>> nameDataImporterDefinitionMap = allDataImporters
                        .get(dataSet.group());
                if (nameDataImporterDefinitionMap == null) {
                    nameDataImporterDefinitionMap = new HashMap<String, DataImporterDefinition<Object>>();
                }

                Class actualType = getTypeParameter(scannedDataImporterClass, DataImporter.class);
                if (actualType == null) {
                    throw SeedException.createNew(DataErrorCode.MISSING_TYPE_PARAMETER).put("class",
                            scannedDataImporterClass);
                }

                DataImporterDefinition dataImporterDefinition = new DataImporterDefinition(dataSet.name(),
                        dataSet.group(), actualType, scannedDataImporterClass);
                nameDataImporterDefinitionMap.put(dataSet.name(), dataImporterDefinition);
                allDataImporters.put(dataSet.group(), nameDataImporterDefinitionMap);
            }
        }

        return InitState.INITIALIZED;
    }

    @Override
    public void start(Context context) {
        ClassLoader classLoader = SeedReflectionUtils.findMostCompleteClassLoader(DataPlugin.class);

        if (loadInitializationData) {
            for (Map<String, DataImporterDefinition<Object>> dataImporterDefinitionMap : allDataImporters
                    .values()) {
                for (DataImporterDefinition<Object> dataImporterDefinition : dataImporterDefinitionMap.values()) {
                    String dataPath = String.format("META-INF/data/%s/%s.json", dataImporterDefinition.getGroup(),
                            dataImporterDefinition.getName());
                    InputStream dataStream = classLoader.getResourceAsStream(dataPath);

                    if (dataStream != null) {
                        if (!dataManager.isInitialized(dataImporterDefinition.getGroup(),
                                dataImporterDefinition.getName()) || forceInitializationData) {
                            LOGGER.info("Importing initialization data for {}.{}",
                                    dataImporterDefinition.getGroup(), dataImporterDefinition.getName());
                            dataManager.importData(dataStream, dataImporterDefinition.getGroup(),
                                    dataImporterDefinition.getName(), true);
                        }

                        try {
                            dataStream.close();
                        } catch (IOException e) {
                            LOGGER.warn("Unable to close data resource " + dataPath, e);
                        }
                    }
                }
            }
        }
    }

    private Class getTypeParameter(Class<?> scannedDataImporterClass, Class<?> genericInterface) {
        Class actualType = null;
        // Get all generic interfaces implemented by the scanned class
        Type[] genericInterfaces = scannedDataImporterClass.getGenericInterfaces();
        for (Type type : genericInterfaces) {
            if (type instanceof ParameterizedType) {
                Class anInterface = (Class) ((ParameterizedType) type).getRawType();
                // If the interface is DataImporter get its type parameter
                if (genericInterface.isAssignableFrom(anInterface)) {
                    actualType = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
                }
            }
        }
        return actualType;
    }

    @Override
    public Collection<Class<? extends Plugin>> requiredPlugins() {
        Collection<Class<? extends Plugin>> plugins = new ArrayList<Class<? extends Plugin>>();
        plugins.add(ApplicationPlugin.class);
        return plugins;
    }

    @Override
    public Object nativeUnitModule() {
        return new DataModule(allDataExporters, allDataImporters);
    }
}