<commit_before>/* Copyright (c) 2013 OpenPlans. All rights reserved.
 * This code is licensed under the BSD New License, available at the root
 * application directory.
 */
package org.geogit.storage;

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.geogit.api.ObjectId;
import org.geogit.api.Platform;
import org.geogit.api.plumbing.ResolveGeogitDir;
import org.neo4j.graphalgo.GraphAlgoFactory;
import org.neo4j.graphalgo.PathFinder;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.Evaluation;
import org.neo4j.graphdb.traversal.Evaluator;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.kernel.Traversal;

import com.google.common.base.Optional;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.inject.Inject;

public class Neo4JGraphDatabase extends AbstractGraphDatabase {

    protected GraphDatabaseService graphDB = null;

    protected String dbPath;

    protected static Map<String, GraphDatabaseService> databaseServices = new ConcurrentHashMap<String, GraphDatabaseService>();

    private final Platform platform;

    private enum CommitRelationshipTypes implements RelationshipType {
        TOROOT, PARENT, MAPPED_TO
    }

    /**
     * Constructs a new {@code Neo4JGraphDatabase} using the given platform.
     * 
     * @param platform the platform to use.
     */
    @Inject
    public Neo4JGraphDatabase(final Platform platform) {
        this.platform = platform;
        registerShutdownHook();
    }

    @Override
    public void open() {
        if (isOpen()) {
            return;
        }
        URL envHome = new ResolveGeogitDir(platform).call();
        if (envHome == null) {
            throw new IllegalStateException("Not inside a geogit directory");
        }
        if (!"file".equals(envHome.getProtocol())) {
            throw new UnsupportedOperationException(
                    "This Graph Database works only against file system repositories. "
                            + "Repository location: " + envHome.toExternalForm());
        }
        File repoDir;
        try {
            repoDir = new File(envHome.toURI());
        } catch (URISyntaxException e) {
            throw Throwables.propagate(e);
        }
        File graph = new File(repoDir, "graph");
        if (!graph.exists() && !graph.mkdir()) {
            throw new IllegalStateException("Cannot create graph directory '"
                    + graph.getAbsolutePath() + "'");
        }

        dbPath = graph.getAbsolutePath() + "/graphDB.db";

        if (databaseServices.containsKey(dbPath)) {
            graphDB = databaseServices.get(dbPath);
        } else {
            graphDB = getGraphDatabase(dbPath);
        }

    }

    protected GraphDatabaseService getGraphDatabase(String dbPath) {
        GraphDatabaseService dbService = new GraphDatabaseFactory().newEmbeddedDatabase(dbPath);
        databaseServices.put(dbPath, dbService);
        return dbService;
    }

    private static void registerShutdownHook() {
        // Registers a shutdown hook for the Neo4j instance so that it
        // shuts down nicely when the VM exits (even if you "Ctrl-C" the
        // running example before it's completed)
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Entry<String, GraphDatabaseService> entry : databaseServices.entrySet()) {
                    File graphPath = new File(entry.getKey());
                    if (graphPath.exists()) {
                        entry.getValue().shutdown();
                    }
                }
                databaseServices.clear();
            }
        });
    }

    @Override
    public boolean isOpen() {
        return graphDB != null;
    }

    @Override
    public void close() {
        if (isOpen()) {
            File graphPath = new File(dbPath);
            if (graphPath.exists()) {
                graphDB.shutdown();
            }
            databaseServices.remove(dbPath);
            graphDB = null;
        }

    }

    @Override
    public boolean exists(ObjectId commitId) {
        Index<Node> idIndex = graphDB.index().forNodes("identifiers");
        Node node = idIndex.get("id", commitId.toString()).getSingle();<commit_msg>Register Neo4JGraphDatabase cleanup thread once<commit_after>/* Copyright (c) 2013 OpenPlans. All rights reserved.
 * This code is licensed under the BSD New License, available at the root
 * application directory.
 */
package org.geogit.storage;

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.geogit.api.ObjectId;
import org.geogit.api.Platform;
import org.geogit.api.plumbing.ResolveGeogitDir;
import org.neo4j.graphalgo.GraphAlgoFactory;
import org.neo4j.graphalgo.PathFinder;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.Evaluation;
import org.neo4j.graphdb.traversal.Evaluator;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.Traverser;
import org.neo4j.kernel.Traversal;

import com.google.common.base.Optional;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.inject.Inject;

public class Neo4JGraphDatabase extends AbstractGraphDatabase {

    protected GraphDatabaseService graphDB = null;

    protected String dbPath;

    protected static Map<String, GraphDatabaseService> databaseServices = new ConcurrentHashMap<String, GraphDatabaseService>();

    private final Platform platform;

    private enum CommitRelationshipTypes implements RelationshipType {
        TOROOT, PARENT, MAPPED_TO
    }

    static {
        // Registers a shutdown hook for the Neo4j instance so that it
        // shuts down nicely when the VM exits (even if you "Ctrl-C" the
        // running example before it's completed)
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Entry<String, GraphDatabaseService> entry : databaseServices.entrySet()) {
                    File graphPath = new File(entry.getKey());
                    if (graphPath.exists()) {
                        entry.getValue().shutdown();
                    }
                }
                databaseServices.clear();
            }
        });
    }

    /**
     * Constructs a new {@code Neo4JGraphDatabase} using the given platform.
     * 
     * @param platform the platform to use.
     */
    @Inject
    public Neo4JGraphDatabase(final Platform platform) {
        this.platform = platform;
    }

    @Override
    public void open() {
        if (isOpen()) {
            return;
        }
        URL envHome = new ResolveGeogitDir(platform).call();
        if (envHome == null) {
            throw new IllegalStateException("Not inside a geogit directory");
        }
        if (!"file".equals(envHome.getProtocol())) {
            throw new UnsupportedOperationException(
                    "This Graph Database works only against file system repositories. "
                            + "Repository location: " + envHome.toExternalForm());
        }
        File repoDir;
        try {
            repoDir = new File(envHome.toURI());
        } catch (URISyntaxException e) {
            throw Throwables.propagate(e);
        }
        File graph = new File(repoDir, "graph");
        if (!graph.exists() && !graph.mkdir()) {
            throw new IllegalStateException("Cannot create graph directory '"
                    + graph.getAbsolutePath() + "'");
        }

        dbPath = graph.getAbsolutePath() + "/graphDB.db";

        if (databaseServices.containsKey(dbPath)) {
            graphDB = databaseServices.get(dbPath);
        } else {
            graphDB = getGraphDatabase(dbPath);
        }

    }

    protected GraphDatabaseService getGraphDatabase(String dbPath) {
        GraphDatabaseService dbService = new GraphDatabaseFactory().newEmbeddedDatabase(dbPath);
        databaseServices.put(dbPath, dbService);
        return dbService;
    }

    @Override
    public boolean isOpen() {
        return graphDB != null;
    }

    @Override
    public void close() {
        if (isOpen()) {
            File graphPath = new File(dbPath);
            if (graphPath.exists()) {
                graphDB.shutdown();
            }
            databaseServices.remove(dbPath);
            graphDB = null;
        }

    }

    @Override
    public boolean exists(ObjectId commitId) {
        Index<Node> idIndex = graphDB.index().forNodes("identifiers");
        Node node = idIndex.get("id", commitId.toString()).getSingle();
{'fraction_non_alphanumeric': 0.09920398009950249, 'fraction_numerical': 0.004875621890547264, 'mean_word_length': 2.6193734245588765, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2892299', 'n_tokens_mistral': 2842, 'n_tokens_neox': 2744, 'n_words': 647}