/**
* 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.work;
import java.util.Optional;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.dswarm.graph.DMPGraphException;
import org.dswarm.graph.GraphProcessingStatics;
import org.dswarm.graph.NodeType;
import org.dswarm.graph.delta.DeltaStatics;
import org.dswarm.graph.delta.util.GraphDBPrintUtil;
import org.dswarm.graph.delta.util.GraphDBUtil;
import org.dswarm.graph.index.NamespaceIndex;
import org.dswarm.graph.model.GraphStatics;
import org.dswarm.graph.read.NodeHandler;
import org.dswarm.graph.utils.GraphUtils;
/**
* @author tgaengler
*/
public class PropertyEnrichGDMWorker implements GDMWorker {
private static final Logger LOG = LoggerFactory.getLogger(PropertyEnrichGDMWorker.class);
private final HierarchyLevelNodeHandler nodeHandler;
private final NodeHandler startNodeHandler;
private final HierarchyLevelRelationshipHandler relationshipHandler;
private final String prefixedResourceUri;
private final long resourceHash;
private final GraphDatabaseService database;
private final NamespaceIndex namespaceIndex;
private final RelationshipType prefixedRDFType;
private final Label prefixedRDFSClass;
public PropertyEnrichGDMWorker(final String prefixedResourceUriArg, final long resourceHashArg, final GraphDatabaseService databaseArg, final
NamespaceIndex namespaceIndexArg) throws DMPGraphException {
prefixedResourceUri = prefixedResourceUriArg;
resourceHash = resourceHashArg;
database = databaseArg;
namespaceIndex = namespaceIndexArg;
nodeHandler = new CBDNodeHandler();
startNodeHandler = new CBDStartNodeHandler();
relationshipHandler = new CBDRelationshipHandler();
final String prefixedRDFTypeURI = namespaceIndex.createPrefixedURI(RDF.type.getURI());
final String prefixedRDFSClassURI = namespaceIndex.createPrefixedURI(RDFS.Class.getURI());
prefixedRDFType = DynamicRelationshipType.withName(prefixedRDFTypeURI);
prefixedRDFSClass = DynamicLabel.label(prefixedRDFSClassURI);
}
@Override
public void work() throws DMPGraphException {
try (final Transaction tx = database.beginTx()) {
PropertyEnrichGDMWorker.LOG.debug("start enrich GDM TX");
final Node recordNode = GraphDBUtil.getResourceNode(database, prefixedResourceUri);
if (recordNode == null) {
PropertyEnrichGDMWorker.LOG.debug("couldn't find record for resource '{}'", prefixedResourceUri);
tx.success();
PropertyEnrichGDMWorker.LOG.debug("finished enrich GDM TX successfully");
return;
}
startNodeHandler.handleNode(recordNode);
tx.success();
PropertyEnrichGDMWorker.LOG.debug("finished enrich GDM TX successfully");
} catch (final Exception e) {
final String message = "couldn't finished enrich GDM TX successfully";
PropertyEnrichGDMWorker.LOG.error(message, e);
throw new DMPGraphException(message);
}
}
private class CBDNodeHandler implements HierarchyLevelNodeHandler {
@Override
public void handleNode(final Node node, final int hierarchyLevel) throws DMPGraphException {
if (node.hasProperty(GraphStatics.RESOURCE_PROPERTY) && node.getProperty(GraphStatics.RESOURCE_PROPERTY).equals(resourceHash)) {
final Iterable<Relationship> relationships = node.getRelationships(Direction.OUTGOING);
for (final Relationship relationship : relationships) {
relationshipHandler.handleRelationship(relationship, hierarchyLevel);
}
}
}
}
private class CBDStartNodeHandler implements NodeHandler {
@Override
public void handleNode(final Node node) throws DMPGraphException {
if (node.hasProperty(GraphStatics.URI_PROPERTY)) {
final Iterable<Relationship> relationships = node.getRelationships(Direction.OUTGOING);
for (final Relationship relationship : relationships) {
relationshipHandler.handleRelationship(relationship, 0);
}
}
}
}
private class CBDRelationshipHandler implements HierarchyLevelRelationshipHandler {
@Override
public void handleRelationship(final Relationship rel, final int hierarchyLevel) throws DMPGraphException {
// subject
final Node subjectNode = rel.getStartNode();
subjectNode.setProperty(DeltaStatics.HIERARCHY_LEVEL_PROPERTY, hierarchyLevel);
// predicate
rel.setProperty(DeltaStatics.HIERARCHY_LEVEL_PROPERTY, hierarchyLevel);
// object
final Node objectNode = rel.getEndNode();
final NodeType objectNodeType = GraphUtils.determineNodeType(objectNode);
switch (objectNodeType) {
case Literal:
case Resource:
case TypeResource:
objectNode.setProperty(DeltaStatics.HIERARCHY_LEVEL_PROPERTY, hierarchyLevel + 1);
break;
default:
// note: we need to filter out bnodes without further statements, e.g., mabxml:tfType nodes have no statements (except of the optional rdf:type statement)
if (objectNode.hasRelationship(Direction.OUTGOING)) {
// continue traversal with object node
nodeHandler.handleNode(objectNode, hierarchyLevel + 1);
} else {
// i.e. we need to set additional rdf:type statement here
final Optional<String> optionalTypeLabel = GraphDBUtil.determineTypeLabel(objectNode);
final String typeLabel = optionalTypeLabel.get();
final Node typeNode = determineNode(typeLabel);
objectNode.createRelationshipTo(typeNode, prefixedRDFType);
// objectNode.setProperty(DeltaStatics.HIERARCHY_LEVEL_PROPERTY, hierarchyLevel + 1);
// objectNode.addLabel(GraphProcessingStatics.LEAF_LABEL);
// // not really needed, or? -since label is set
// objectNode.setProperty(GraphProcessingStatics.LEAF_IDENTIFIER, true);
// continue traversal with object node
nodeHandler.handleNode(objectNode, hierarchyLevel + 1);
LOG.debug("BNODE has no outgoing rels " + GraphDBPrintUtil.printDeltaRelationship(rel));
}
break;
}
}
private Node determineNode(final String typeLabel) {
final Node typeNode = database.findNode(GraphProcessingStatics.RESOURCE_TYPE_LABEL, GraphStatics.URI_PROPERTY, typeLabel);
if (typeNode != null) {
return typeNode;
}
final Node newTypeNode = database.createNode(GraphProcessingStatics.RESOURCE_LABEL, GraphProcessingStatics.RESOURCE_TYPE_LABEL, prefixedRDFSClass);
newTypeNode.setProperty(GraphStatics.URI_PROPERTY, typeLabel);
return newTypeNode;
}
}
}