fr.inria.atlanmod.neoemf.graph.blueprints.datastore.BlueprintsPersistenceBackendFactory.java Source code

Java tutorial

Introduction

Here is the source code for fr.inria.atlanmod.neoemf.graph.blueprints.datastore.BlueprintsPersistenceBackendFactory.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Atlanmod INRIA LINA Mines Nantes
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Atlanmod INRIA LINA Mines Nantes - initial API and implementation
 *******************************************************************************/
package fr.inria.atlanmod.neoemf.graph.blueprints.datastore;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;

import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.GraphFactory;
import com.tinkerpop.blueprints.KeyIndexableGraph;
import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
import com.tinkerpop.blueprints.util.GraphHelper;

import fr.inria.atlanmod.neoemf.datastore.AbstractPersistenceBackendFactory;
import fr.inria.atlanmod.neoemf.datastore.InvalidDataStoreException;
import fr.inria.atlanmod.neoemf.datastore.PersistenceBackend;
import fr.inria.atlanmod.neoemf.datastore.estores.SearcheableResourceEStore;
import fr.inria.atlanmod.neoemf.graph.blueprints.datastore.estores.impl.AutocommitBlueprintsResourceEStoreImpl;
import fr.inria.atlanmod.neoemf.graph.blueprints.datastore.estores.impl.DirectWriteBlueprintsResourceEStoreImpl;
import fr.inria.atlanmod.neoemf.graph.blueprints.resources.BlueprintsResourceOptions;
import fr.inria.atlanmod.neoemf.graph.blueprints.tg.config.AbstractBlueprintsConfig;
import fr.inria.atlanmod.neoemf.logger.NeoLogger;
import fr.inria.atlanmod.neoemf.resources.PersistentResource;
import fr.inria.atlanmod.neoemf.resources.PersistentResourceOptions;

public class BlueprintsPersistenceBackendFactory extends AbstractPersistenceBackendFactory {

    /**
     * The configuration file name. This file stores the metadata information
     * about the underlying graph, i.e., graph type and other configuration
     * options
     */
    protected static final String CONFIG_FILE = "config.properties";
    public static final String BLUEPRINTS_BACKEND = "blueprints";

    @Override
    public PersistenceBackend createTransientBackend() {
        return new BlueprintsPersistenceBackend(new TinkerGraph());
    }

    @Override
    public SearcheableResourceEStore createTransientEStore(PersistentResource resource,
            PersistenceBackend backend) {
        assert backend instanceof BlueprintsPersistenceBackend : "Trying to create a Graph-based EStore with an invalid backend";
        return new DirectWriteBlueprintsResourceEStoreImpl(resource, (BlueprintsPersistenceBackend) backend);
    }

    @Override
    public BlueprintsPersistenceBackend createPersistentBackend(File file, Map<?, ?> options)
            throws InvalidDataStoreException {
        BlueprintsPersistenceBackend graphDB = null;
        PropertiesConfiguration neoConfig = null;
        PropertiesConfiguration configuration = null;
        try {
            // Try to load previous configurations
            Path path = Paths.get(file.getAbsolutePath()).resolve(CONFIG_FILE);
            try {
                configuration = new PropertiesConfiguration(path.toFile());
            } catch (ConfigurationException e) {
                throw new InvalidDataStoreException(e);
            }
            // Initialize value if the config file has just been created
            if (!configuration.containsKey(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE)) {
                configuration.setProperty(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE,
                        BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE_DEFAULT);
            } else if (options.containsKey(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE)) {
                // The file already existed, check that the issued options
                // are not conflictive
                String savedGraphType = configuration
                        .getString(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE);
                String issuedGraphType = options.get(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE)
                        .toString();
                if (!savedGraphType.equals(issuedGraphType)) {
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR, "Unable to create graph as type " + issuedGraphType
                            + ", expected graph type was " + savedGraphType + ")");
                    throw new InvalidDataStoreException("Unable to create graph as type " + issuedGraphType
                            + ", expected graph type was " + savedGraphType + ")");
                }
            }

            // Copy the options to the configuration
            for (Entry<?, ?> e : options.entrySet()) {
                configuration.setProperty(e.getKey().toString(), e.getValue().toString());
            }

            // Check we have a valid graph type, it is needed to get the
            // graph name
            String graphType = configuration.getString(BlueprintsResourceOptions.OPTIONS_BLUEPRINTS_GRAPH_TYPE);
            if (graphType == null) {
                throw new InvalidDataStoreException("Graph type is undefined for " + file.getAbsolutePath());
            }

            String[] segments = graphType.split("\\.");
            if (segments.length >= 2) {
                String graphName = segments[segments.length - 2];
                String upperCaseGraphName = Character.toUpperCase(graphName.charAt(0)) + graphName.substring(1);
                String configClassQualifiedName = MessageFormat.format(
                        "fr.inria.atlanmod.neoemf.graph.blueprints.{0}.config.Blueprints{1}Config", graphName,
                        upperCaseGraphName);
                try {
                    ClassLoader classLoader = BlueprintsPersistenceBackendFactory.class.getClassLoader();
                    Class<?> configClass = classLoader.loadClass(configClassQualifiedName);
                    Field configClassInstanceField = configClass.getField("eINSTANCE");
                    AbstractBlueprintsConfig configClassInstance = (AbstractBlueprintsConfig) configClassInstanceField
                            .get(configClass);
                    Method configMethod = configClass.getMethod("putDefaultConfiguration", Configuration.class,
                            File.class);
                    configMethod.invoke(configClassInstance, configuration, file);
                    Method setGlobalSettingsMethod = configClass.getMethod("setGlobalSettings");
                    setGlobalSettingsMethod.invoke(configClassInstance);
                } catch (ClassNotFoundException e1) {
                    NeoLogger.log(NeoLogger.SEVERITY_WARNING,
                            "Unable to find the configuration class " + configClassQualifiedName);
                    e1.printStackTrace();
                } catch (NoSuchFieldException e2) {
                    NeoLogger.log(NeoLogger.SEVERITY_WARNING,
                            MessageFormat.format(
                                    "Unable to find the static field eINSTANCE in class Blueprints{0}Config",
                                    upperCaseGraphName));
                    e2.printStackTrace();
                } catch (NoSuchMethodException e3) {
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR,
                            MessageFormat.format(
                                    "Unable to find configuration methods in class Blueprints{0}Config",
                                    upperCaseGraphName));
                    e3.printStackTrace();
                } catch (InvocationTargetException e4) {
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR, MessageFormat.format(
                            "An error occured during the exection of a configuration method", upperCaseGraphName));
                    e4.printStackTrace();
                } catch (IllegalAccessException e5) {
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR, MessageFormat.format(
                            "An error occured during the exection of a configuration method", upperCaseGraphName));
                    e5.printStackTrace();
                }
            } else {
                NeoLogger.log(NeoLogger.SEVERITY_WARNING, "Unable to compute graph type name from " + graphType);
            }

            Graph baseGraph = null;
            try {
                baseGraph = GraphFactory.open(configuration);
            } catch (RuntimeException e) {
                throw new InvalidDataStoreException(e);
            }
            if (baseGraph instanceof KeyIndexableGraph) {
                graphDB = new BlueprintsPersistenceBackend((KeyIndexableGraph) baseGraph);
            } else {
                NeoLogger.log(NeoLogger.SEVERITY_ERROR,
                        "Graph type " + file.getAbsolutePath() + " does not support Key Indices");
                throw new InvalidDataStoreException(
                        "Graph type " + file.getAbsolutePath() + " does not support Key Indices");
            }
            // Save the neoconfig file
            Path neoConfigPath = Paths.get(file.getAbsolutePath()).resolve(NEO_CONFIG_FILE);
            try {
                neoConfig = new PropertiesConfiguration(neoConfigPath.toFile());
            } catch (ConfigurationException e) {
                throw new InvalidDataStoreException(e);
            }
            if (!neoConfig.containsKey(BACKEND_PROPERTY)) {
                neoConfig.setProperty(BACKEND_PROPERTY, BLUEPRINTS_BACKEND);
            }
        } finally {
            if (configuration != null) {
                try {
                    configuration.save();
                } catch (ConfigurationException e) {
                    // Unable to save configuration, supposedly it's a minor error,
                    // so we log it without rising an exception
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR, e);
                }
            }
            if (neoConfig != null) {
                try {
                    neoConfig.save();
                } catch (ConfigurationException e) {
                    NeoLogger.log(NeoLogger.SEVERITY_ERROR, e);
                }
            }
        }
        return graphDB;
    }

    @Override
    protected SearcheableResourceEStore internalCreatePersistentEStore(PersistentResource resource,
            PersistenceBackend backend, Map<?, ?> options) throws InvalidDataStoreException {
        assert backend instanceof BlueprintsPersistenceBackend : "Trying to create a Graph-based EStore with an invalid backend";
        @SuppressWarnings("unchecked")
        ArrayList<PersistentResourceOptions.StoreOption> storeOptions = (ArrayList<PersistentResourceOptions.StoreOption>) options
                .get(PersistentResourceOptions.STORE_OPTIONS);
        if (storeOptions == null || storeOptions.isEmpty()
                || storeOptions.contains(BlueprintsResourceOptions.EStoreGraphOption.DIRECT_WRITE)) {
            // Default store
            return new DirectWriteBlueprintsResourceEStoreImpl(resource, (BlueprintsPersistenceBackend) backend);
        } else {
            if (storeOptions.contains(BlueprintsResourceOptions.EStoreGraphOption.AUTOCOMMIT)) {
                return new AutocommitBlueprintsResourceEStoreImpl(resource, (BlueprintsPersistenceBackend) backend);
            } else {
                throw new InvalidDataStoreException();
            }
        }
    }

    @Override
    public void copyBackend(PersistenceBackend from, PersistenceBackend to) {
        assert from instanceof BlueprintsPersistenceBackend
                && to instanceof BlueprintsPersistenceBackend : "Trying to use Graph backend copy on non Graph databases";
        BlueprintsPersistenceBackend bFrom = (BlueprintsPersistenceBackend) from;
        BlueprintsPersistenceBackend bTo = (BlueprintsPersistenceBackend) to;
        GraphHelper.copyGraph(bFrom, bTo);
        bTo.initMetaClassesIndex(bFrom.getIndexedEClasses());
    }
}