1 package eu.ehri.project.importers.links;
2
3 import com.tinkerpop.frames.FramedGraph;
4 import eu.ehri.project.core.GraphManager;
5 import eu.ehri.project.core.GraphManagerFactory;
6 import eu.ehri.project.definitions.EventTypes;
7 import eu.ehri.project.definitions.Ontology;
8 import eu.ehri.project.exceptions.DeserializationError;
9 import eu.ehri.project.exceptions.ItemNotFound;
10 import eu.ehri.project.exceptions.ValidationError;
11 import eu.ehri.project.importers.ImportLog;
12 import eu.ehri.project.models.EntityClass;
13 import eu.ehri.project.models.Link;
14 import eu.ehri.project.models.base.Accessor;
15 import eu.ehri.project.models.base.Actioner;
16 import eu.ehri.project.models.base.Linkable;
17 import eu.ehri.project.persistence.ActionManager;
18 import eu.ehri.project.persistence.Bundle;
19 import eu.ehri.project.persistence.BundleManager;
20 import eu.ehri.project.utils.Table;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import java.util.List;
25 import java.util.Optional;
26
27 public class LinkImporter {
28
29 private static final Logger logger = LoggerFactory.getLogger(LinkImporter.class);
30
31 private final FramedGraph<?> framedGraph;
32 private final GraphManager manager;
33 private final Actioner actioner;
34 private final ActionManager actionManager;
35 private final BundleManager bundleManager;
36 private final boolean tolerant;
37
38 public LinkImporter(FramedGraph<?> framedGraph, Actioner actioner, boolean tolerant) {
39 this.framedGraph = framedGraph;
40 this.manager = GraphManagerFactory.getInstance(framedGraph);
41 this.actioner = actioner;
42 this.actionManager = new ActionManager(framedGraph);
43 this.bundleManager = new BundleManager(framedGraph);
44 this.tolerant = tolerant;
45 }
46
47 public ImportLog importLinks(Table table, String logMessage) throws DeserializationError {
48
49 if (!table.rows().isEmpty() && table.rows().get(0).size() != 5) {
50 throw new DeserializationError("Input CSV must have 5 columns: " +
51 "source, target, type, field, description. Leave columns blank where " +
52 "not applicable.");
53 }
54
55 ImportLog log = new ImportLog(logMessage);
56 ActionManager.EventContext eventContext = actionManager.newEventContext(
57 actioner,
58 EventTypes.ingest,
59 Optional.ofNullable(logMessage));
60
61 for (int i = 0; i < table.rows().size(); i++) {
62 List<String> row = table.rows().get(i);
63 String from = row.get(0);
64 String to = row.get(1);
65 String type = row.get(2);
66 String field = row.get(3);
67 String desc = row.get(4);
68 Bundle.Builder builder = Bundle.Builder.withClass(EntityClass.LINK)
69 .addDataValue(Ontology.LINK_HAS_TYPE, type);
70 if (!field.trim().isEmpty()) {
71 builder.addDataValue(Ontology.LINK_HAS_FIELD, field);
72 }
73 if (!desc.trim().isEmpty()) {
74 builder.addDataValue(Ontology.LINK_HAS_DESCRIPTION, desc);
75 }
76 Bundle bundle = builder.build();
77
78 try {
79 Linkable t1 = manager.getEntity(from, Linkable.class);
80 Linkable t2 = manager.getEntity(to, Linkable.class);
81
82 Link link = bundleManager.create(bundle, Link.class);
83 link.addLinkTarget(t1);
84 link.addLinkTarget(t2);
85 link.setLinker(actioner.as(Accessor.class));
86 eventContext.addSubjects(link);
87 log.addCreated();
88 } catch (ItemNotFound e) {
89 logger.error("Item not found at row {}: {}", i, e.getValue());
90 log.addError(e.getValue(), e.getMessage());
91 if (!tolerant) {
92 throw new DeserializationError(
93 String.format("Item ID '%s' not found at row: %d", e.getValue(), i));
94 }
95 } catch (ValidationError e) {
96 log.addError(from, e.getMessage());
97 logger.error("Deserialization error at row {}: {}", i, e.getMessage());
98 if (!tolerant) {
99 throw new DeserializationError(
100 String.format("Error validating link at row %d: %s", i,
101 e.getMessage()));
102 }
103 }
104 }
105 if (log.hasDoneWork()) {
106 eventContext.commit();
107 }
108
109 return log;
110 }
111 }