/** * This file is part of d:swarm graph extension. * * d:swarm graph extension is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * d:swarm graph extension 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with d:swarm graph extension. If not, see <http://www.gnu.org/licenses/>. */ package org.dswarm.graph.gdm.parse; import java.util.Map; import java.util.Optional; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.dswarm.graph.DMPGraphException; import org.dswarm.graph.NodeType; import org.dswarm.graph.TransactionalNeo4jProcessor; import org.dswarm.graph.gdm.GDMNeo4jProcessor; import org.dswarm.graph.gdm.read.PropertyGraphGDMReaderHelper; import org.dswarm.graph.gdm.utils.NodeTypeUtils; import org.dswarm.graph.index.NamespaceIndex; import org.dswarm.graph.json.ResourceNode; import org.dswarm.graph.json.Statement; import org.dswarm.graph.model.GraphStatics; import org.dswarm.graph.model.StatementBuilder; import org.dswarm.graph.parse.BaseNeo4jHandler; import org.dswarm.graph.parse.Neo4jHandler; import org.dswarm.graph.parse.TransactionalNeo4jHandler; /** * @author tgaengler */ public abstract class GDMNeo4jHandler implements GDMHandler, GDMUpdateHandler { private static final Logger LOG = LoggerFactory.getLogger(GDMNeo4jHandler.class); protected final BaseNeo4jHandler handler; protected final GDMNeo4jProcessor processor; protected final PropertyGraphGDMReaderHelper propertyGraphGDMReaderHelper; public GDMNeo4jHandler(final BaseNeo4jHandler handlerArg, final GDMNeo4jProcessor processorArg) throws DMPGraphException { handler = handlerArg; processor = processorArg; propertyGraphGDMReaderHelper = new PropertyGraphGDMReaderHelper(processor.getProcessor().getNamespaceIndex()); } @Override public Neo4jHandler getHandler() { return handler; } @Override public GraphDatabaseService getDatabase() { return ((TransactionalNeo4jHandler) handler).getDatabase(); } @Override public void handleStatement(final Statement st, final long resourceHash, final long index) throws DMPGraphException { final StatementBuilder sb = new StatementBuilder(); final org.dswarm.graph.json.Node subject = st.getSubject(); final Optional<NodeType> optionalSubjectNodeType = NodeTypeUtils.getNodeType(Optional.of(subject)); sb.setOptionalSubjectNodeType(optionalSubjectNodeType); processor.determineNode(subject, sb, true); final org.dswarm.graph.json.Predicate predicate = st.getPredicate(); final String predicateName = predicate.getUri(); sb.setOptionalPredicateURI(Optional.ofNullable(predicateName)); final org.dswarm.graph.json.Node object = st.getObject(); final Optional<NodeType> optionalObjectNodeType = NodeTypeUtils.getNodeType(Optional.of(object)); sb.setOptionalObjectNodeType(optionalObjectNodeType); processor.determineNode(object, sb, false); final Optional<String> optionalStatementUUID = Optional.ofNullable(st.getUUID()); sb.setOptionalStatementUUID(optionalStatementUUID); sb.setOptionalResourceHash(Optional.of(resourceHash)); final Map<String, Object> qualifiedAttributes = processor.getQualifiedAttributes(st); qualifiedAttributes.put(GraphStatics.INDEX_PROPERTY, index); sb.setOptionalQualifiedAttributes(Optional.of(qualifiedAttributes)); final org.dswarm.graph.model.Statement statement = sb.build(); handler.handleStatement(statement); } @Override public long getCountedStatements() { return handler.getCountedStatements(); } @Override public int getRelationshipsAdded() { return handler.getRelationshipsAdded(); } @Override public int getNodesAdded() { return handler.getNodesAdded(); } @Override public int getCountedLiterals() { return handler.getCountedLiterals(); } @Override public NamespaceIndex getNamespaceIndex() { return processor.getProcessor().getNamespaceIndex(); } /** * TODO: refactor this to BaseNeo4jHandler * * @param stmtUUID * @param resourceHash * @param index * @param order * @throws DMPGraphException */ @Override public void handleStatement(final Long stmtUUID, final long resourceHash, final long index, final long order) throws DMPGraphException { ((TransactionalNeo4jProcessor) handler.getProcessor()).ensureRunningTx(); try { final Optional<Relationship> optionalRel = ((TransactionalNeo4jProcessor) handler.getProcessor()).getRelationshipFromStatementIndex( stmtUUID); if (!optionalRel.isPresent()) { GDMNeo4jHandler.LOG.error("couldn't find statement with the uuid '{}' in the database", stmtUUID); } final Relationship rel = optionalRel.get(); final Node subject = rel.getStartNode(); final Node object = rel.getEndNode(); final Statement stmt = propertyGraphGDMReaderHelper.readStatement(rel); addBNode(stmt.getSubject(), subject); addBNode(stmt.getObject(), object); // reset stmt uuid, so that a new stmt uuid will be assigned when relationship will be added stmt.setUUID(null); // set actual order of the stmt stmt.setOrder(order); final String predicate = stmt.getPredicate().getUri(); // TODO: shall we include some more qualified attributes into hash generation, e.g., index, valid from, or will the // index // be update with the new stmt (?) final long hash = processor.generateStatementHash(subject, predicate, object, stmt.getSubject().getType(), stmt.getObject().getType()); final Optional<NodeType> optionalSubjectNodeType = NodeTypeUtils.getNodeType(Optional.ofNullable(stmt.getSubject())); final Optional<Long> optionalSubjectHash; if (stmt.getSubject().getType().equals(org.dswarm.graph.json.NodeType.Resource)) { final ResourceNode subjectNode = (ResourceNode) stmt.getSubject(); final String subjectURI = processor.getProcessor().createPrefixedURI(subjectNode.getUri()); final String dataModelURI = processor.getProcessor().createPrefixedURI(subjectNode.getDataModel()); final long resourceUriDataModelUriHash = processor.getProcessor().generateResourceHash(subjectURI, Optional.ofNullable(dataModelURI)); optionalSubjectHash = Optional.of(resourceUriDataModelUriHash); } else { optionalSubjectHash = Optional.empty(); } final Optional<Long> optionalResourceHash = processor.determineResourceHash(stmt.getSubject(), resourceHash); final Map<String, Object> qualifiedAttributes = processor.getQualifiedAttributes(stmt); qualifiedAttributes.put(GraphStatics.INDEX_PROPERTY, index); qualifiedAttributes.put(GraphStatics.ORDER_PROPERTY, order); final Optional<Map<String, Object>> optionalQualifiedAttributes = Optional.of(qualifiedAttributes); handler.addRelationship(subject, predicate, object, optionalSubjectNodeType, optionalSubjectHash, Optional.empty(), optionalResourceHash, optionalQualifiedAttributes, hash); } catch (final DMPGraphException e) { throw e; } catch (final Exception e) { final String message = "couldn't handle statement successfully"; ((TransactionalNeo4jProcessor) handler.getProcessor()).failTx(); GDMNeo4jHandler.LOG.error(message, e); GDMNeo4jHandler.LOG.debug("couldn't finish write TX successfully"); throw new DMPGraphException(message); } } @Override public org.dswarm.graph.json.Node deprecateStatement(final Long uuid) throws DMPGraphException { ((TransactionalNeo4jProcessor) handler.getProcessor()).ensureRunningTx(); try { final Relationship rel = handler.deprecateStatement(uuid); final org.dswarm.graph.json.Node subjectGDMNode = propertyGraphGDMReaderHelper.readObject(rel.getStartNode()); final org.dswarm.graph.json.Node objectGDMNode = propertyGraphGDMReaderHelper.readObject(rel.getEndNode()); addBNode(subjectGDMNode, rel.getStartNode()); addBNode(objectGDMNode, rel.getEndNode()); return subjectGDMNode; } catch (final DMPGraphException e) { throw e; } catch (final Exception e) { final String message = "couldn't deprecate statement successfully"; ((TransactionalNeo4jProcessor) handler.getProcessor()).failTx(); GDMNeo4jHandler.LOG.error(message, e); GDMNeo4jHandler.LOG.debug("couldn't finish write TX successfully"); throw new DMPGraphException(message); } } private void addBNode(final org.dswarm.graph.json.Node gdmNode, final Node node) throws DMPGraphException { final Optional<NodeType> optionalNodeType = NodeTypeUtils.getNodeType(Optional.of(gdmNode)); final Optional<String> optionalNodeId; if (gdmNode.getId() != null) { optionalNodeId = Optional.of("" + gdmNode.getId()); } else { optionalNodeId = Optional.empty(); } handler.addBNode(optionalNodeId, optionalNodeType, node); } }