/* Copyright 2008-2010 Gephi Authors : Martin Škurla Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.neo4j.plugin.impl; import java.util.Collection; import java.util.Collections; import org.gephi.neo4j.plugin.api.FilterDescription; import org.gephi.neo4j.plugin.api.Neo4jImporter; import org.gephi.neo4j.plugin.api.RelationshipDescription; import org.gephi.neo4j.plugin.api.TraversalOrder; import org.gephi.project.api.ProjectController; import org.gephi.utils.longtask.spi.LongTask; import org.gephi.utils.progress.Progress; import org.gephi.utils.progress.ProgressTicket; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.traversal.PruneEvaluator; import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.graphdb.traversal.Traverser; import org.neo4j.kernel.Traversal; import org.neo4j.remote.RemoteGraphDatabase; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; /** * * @author Martin Škurla */ @ServiceProvider(service = Neo4jImporter.class) public final class Neo4jImporterImpl implements Neo4jImporter, LongTask { // when we want to iterate through whole graph private static final int NO_START_NODE = -1; private ProgressTicket progressTicket; private boolean cancelImport; @Override public boolean cancel() { cancelImport = true; return true; } @Override public void setProgressTicket(ProgressTicket progressTicket) { cancelImport = false; this.progressTicket = progressTicket; } @Override public void importDatabase(GraphDatabaseService graphDB) { importDatabase(graphDB, NO_START_NODE, TraversalOrder.DEPTH_FIRST, Integer.MAX_VALUE); } @Override public void importDatabase(GraphDatabaseService graphDB, Collection<FilterDescription> filterDescriptions, boolean restrictMode, boolean matchCase) { importDatabase(graphDB, NO_START_NODE, TraversalOrder.DEPTH_FIRST, Integer.MAX_VALUE, Collections.<RelationshipDescription>emptyList(), filterDescriptions, restrictMode, matchCase); } @Override public void importDatabase(GraphDatabaseService graphDB, long startNodeId, TraversalOrder order, int maxDepth) { importDatabase(graphDB, startNodeId, order, maxDepth, Collections.<RelationshipDescription>emptyList()); } @Override public void importDatabase(GraphDatabaseService graphDB, long startNodeId, TraversalOrder order, int maxDepth, Collection<RelationshipDescription> relationshipDescriptions) { // last 2 boolean parameters are not important, because if we pass empty collection of filter descriptions, they // are not needed importDatabase(graphDB, startNodeId, order, maxDepth, relationshipDescriptions, Collections.<FilterDescription>emptyList(), false, false); } @Override public void importDatabase(GraphDatabaseService graphDB, long startNodeId, TraversalOrder order, int maxDepth, Collection<RelationshipDescription> relationshipDescriptions, Collection<FilterDescription> filterDescriptions, boolean restrictMode, boolean matchCase) { String longTaskMessage = (graphDB instanceof RemoteGraphDatabase) ? NbBundle.getMessage(Neo4jImporterImpl.class, "CTL_Neo4j_RemoteImportMessage") : NbBundle.getMessage(Neo4jImporterImpl.class, "CTL_Neo4j_LocalImportMessage"); Progress.setDisplayName(progressTicket, longTaskMessage); Progress.start(progressTicket); Traverser traverser; NodeReturnFilter nodeReturnFilter = null; if (startNodeId != NO_START_NODE) { TraversalDescription traversalDescription = Traversal.description(); PruneEvaluator pruneEvaluator = Traversal.pruneAfterDepth(maxDepth); traversalDescription = order.update(traversalDescription); for (RelationshipDescription relationshipDescription : relationshipDescriptions) { traversalDescription = traversalDescription.relationships(relationshipDescription.getRelationshipType(), relationshipDescription.getDirection()); } if (!filterDescriptions.isEmpty()) { traversalDescription = traversalDescription.filter(new NodeReturnFilter(filterDescriptions, restrictMode, matchCase)); } traverser = traversalDescription.prune(pruneEvaluator).traverse(graphDB.getNodeById(startNodeId)); } else if (startNodeId == NO_START_NODE && filterDescriptions.size() > 0) { nodeReturnFilter = new NodeReturnFilter(filterDescriptions, restrictMode, matchCase); traverser = null; } else { traverser = null; } doImport(graphDB, traverser, nodeReturnFilter); } private void doImport(GraphDatabaseService graphDB, Traverser traverser, NodeReturnFilter nodeReturnFilter) { Transaction transaction = graphDB.beginTx(); try { importGraph(graphDB, traverser, nodeReturnFilter); transaction.success(); } finally { transaction.finish(); } Progress.finish(progressTicket); } private void importGraph(GraphDatabaseService graphDB, Traverser traverser, NodeReturnFilter nodeReturnFilter) { initProject(); GraphModelImportConverter graphModelImportConverter = GraphModelImportConverter.getInstance(graphDB); graphModelImportConverter.createNeo4jRelationshipTypeGephiColumn(); if (traverser == null) { importNodes(graphModelImportConverter, graphDB.getAllNodes(), nodeReturnFilter); for (org.neo4j.graphdb.Node node : graphDB.getAllNodes()) { importRelationships(graphModelImportConverter, node.getRelationships(Direction.INCOMING)); } } else { importNodes(graphModelImportConverter, traverser.nodes(), nodeReturnFilter); importRelationships(graphModelImportConverter, traverser.relationships()); } } private void importNodes(GraphModelImportConverter graphModelImportConverter, Iterable<org.neo4j.graphdb.Node> nodes, NodeReturnFilter nodeReturnFilter) { for (org.neo4j.graphdb.Node node : nodes) { if (cancelImport) { return; } if (nodeReturnFilter != null) { if (nodeReturnFilter.accept(node)) { processNode(graphModelImportConverter, node); } } else { processNode(graphModelImportConverter, node); } } } private void processNode(GraphModelImportConverter graphModelImportConverter, org.neo4j.graphdb.Node node) { graphModelImportConverter.createGephiNodeFromNeoNode(node); } private void importRelationships(GraphModelImportConverter graphModelImportConverter, Iterable<Relationship> relationships) { for (Relationship relationship : relationships) { if (cancelImport) { return; } processRelationship(graphModelImportConverter, relationship); } } private void processRelationship(GraphModelImportConverter graphModelImportConverter, Relationship neoRelationship) { graphModelImportConverter.createGephiEdge(neoRelationship); } private void initProject() { ProjectController pc = Lookup.getDefault().lookup(ProjectController.class); if (pc.getCurrentProject() == null) { pc.newProject(); } } }