View Javadoc

1   /*
2    * Copyright 2015 Data Archiving and Networked Services (an institute of
3    * Koninklijke Nederlandse Akademie van Wetenschappen), King's College London,
4    * Georg-August-Universitaet Goettingen Stiftung Oeffentlichen Rechts
5    *
6    * Licensed under the EUPL, Version 1.1 or – as soon they will be approved by
7    * the European Commission - subsequent versions of the EUPL (the "Licence");
8    * You may not use this work except in compliance with the Licence.
9    * You may obtain a copy of the Licence at:
10   *
11   * https://joinup.ec.europa.eu/software/page/eupl
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the Licence is distributed on an "AS IS" basis,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the Licence for the specific language governing
17   * permissions and limitations under the Licence.
18   */
19  
20  package eu.ehri.project.importers.ead;
21  
22  import com.google.common.collect.Lists;
23  import com.google.common.collect.Maps;
24  import com.tinkerpop.frames.FramedGraph;
25  import eu.ehri.project.definitions.Ontology;
26  import eu.ehri.project.exceptions.ItemNotFound;
27  import eu.ehri.project.exceptions.ValidationError;
28  import eu.ehri.project.importers.ImportLog;
29  import eu.ehri.project.models.DocumentaryUnit;
30  import eu.ehri.project.models.EntityClass;
31  import eu.ehri.project.models.Repository;
32  import eu.ehri.project.models.UserProfile;
33  import eu.ehri.project.models.VirtualUnit;
34  import eu.ehri.project.models.base.AbstractUnit;
35  import eu.ehri.project.models.base.Actioner;
36  import eu.ehri.project.models.base.PermissionScope;
37  import eu.ehri.project.persistence.Bundle;
38  import eu.ehri.project.persistence.BundleManager;
39  import eu.ehri.project.persistence.Mutation;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  import java.util.List;
44  import java.util.Map;
45  
46  import static eu.ehri.project.importers.util.ImportHelpers.OBJECT_IDENTIFIER;
47  
48  /**
49   * Import EAD describing a Virtual Collection. some rules governing virtual collections:
50   * <p>
51   * the archdesc should describe the purpose of this vc. it can not in itself refer to a DU.
52   * <p>
53   * every c level is either 1) a virtual level (=VirtualLevel), or 2) it points to an existing DocumentaryUnit
54   * (=VirtualReferrer) (and consequently to the entire subtree beneath it) 1) there is no repository-tag with a
55   * ehri-label
56   * <p>
57   * 2) there is exactly one repository-tag with an ehri-label &lt;repository
58   * label="ehri_repository_vc"&gt;il-002777&lt;/repository&gt; (this will not be shown in the portal) and exactly one unitid with
59   * a ehri-main-identifier label, that is identical to the existing unitid within the graph for this repository
60   * <p>
61   * all other tags will be ignored, since the DocumentsDescription of the referred DocumentaryUnit will be shown. there
62   * should not be any c-levels beneath such a c-level
63   */
64  public class VirtualEadImporter extends EadImporter {
65  
66      private static final String REPOID = "vcRepository";
67      private static final Logger logger = LoggerFactory.getLogger(VirtualEadImporter.class);
68  
69      /**
70       * Construct a VirtualEadImporter object.
71       *
72       * @param graph           the framed graph
73       * @param permissionScope the permission scope
74       * @param log             the import log
75       */
76      public VirtualEadImporter(FramedGraph<?> graph, PermissionScope permissionScope,
77              Actioner actioner, ImportLog log) {
78          super(graph, permissionScope, actioner, log);
79      }
80  
81      /**
82       * Import a single archdesc or c01-12 item, keeping a reference to the hierarchical depth. this will import the
83       * structure as VirtualUnits, which either have a DocDescription (VirtualLevel, like series) or they point to an
84       * existing DocDesc from an existing DocumentaryUnit (VirtualReferrer).
85       *
86       * @param itemData The data map
87       * @param idPath   The identifiers of parent documents, not including those of the overall permission scope
88       * @throws ValidationError when the itemData does not contain an identifier for the unit or...
89       */
90      @Override
91      public AbstractUnit importItem(Map<String, Object> itemData, List<String> idPath)
92              throws ValidationError {
93  
94          BundleManager persister = getPersister(idPath);
95  
96          Bundle unit = Bundle.of(EntityClass.VIRTUAL_UNIT, extractVirtualUnit(itemData));
97  
98          if (isVirtualLevel(itemData)) {
99              // Check for missing identifier, throw an exception when there is no ID.
100             if (unit.getDataValue(Ontology.IDENTIFIER_KEY) == null) {
101                 throw new ValidationError(unit, Ontology.IDENTIFIER_KEY,
102                         "Missing identifier " + Ontology.IDENTIFIER_KEY);
103             }
104             logger.debug("Imported item: {}", itemData.get(Ontology.NAME_KEY));
105 
106             Bundle description = getDescription(itemData);
107 
108             unit = unit.withRelation(Ontology.DESCRIPTION_FOR_ENTITY, description);
109             Mutation<VirtualUnit> mutation = persister.createOrUpdate(unit, VirtualUnit.class);
110             VirtualUnit frame = mutation.getNode();
111             // Set the repository/item relationship
112             //TODO: figure out another way to determine we're at the root, so we can get rid of the depth param
113             if (idPath.isEmpty() && mutation.created()) {
114                 EntityClass scopeType = manager.getEntityClass(permissionScope);
115                 if (scopeType.equals(EntityClass.USER_PROFILE)) {
116                     UserProfile responsibleUser = permissionScope.as(UserProfile.class);
117                     frame.setAuthor(responsibleUser);
118                     //the top Virtual Unit does not have a permissionScope. 
119                 } else if (scopeType.equals(EntityClass.VIRTUAL_UNIT)) {
120                     VirtualUnit parent = framedGraph.frame(permissionScope.asVertex(), VirtualUnit.class);
121                     parent.addChild(frame);
122                     frame.setPermissionScope(parent);
123                 } else {
124                     logger.error("Unknown scope type for virtual unit: {}", scopeType);
125                 }
126             }
127             handleCallbacks(mutation);
128             return frame;
129         } else {
130             try {
131                 //find the DocumentaryUnit using the repository_id/unit_id combo
132                 return findReferredToDocumentaryUnit(itemData);
133             } catch (ItemNotFound ex) {
134                 throw new ValidationError(unit, ex.getKey(), ex.getMessage());
135             }
136         }
137     }
138 
139     @SuppressWarnings("unchecked")
140     @Override
141     protected Iterable<Map<String, Object>> extractRelations(Map<String, Object> data) {
142         String rel = "AccessPoint";
143         List<Map<String, Object>> list = Lists.newArrayList();
144         for (String key : data.keySet()) {
145             if (key.endsWith(rel)) {
146                 logger.debug("{} found in data", key);
147                 //type, targetUrl, targetName, notes
148                 for (Map<String, Object> origRelation : (List<Map<String, Object>>) data.get(key)) {
149                     Map<String, Object> relationNode = Maps.newHashMap();
150                     for (String eventkey : origRelation.keySet()) {
151                         logger.debug(eventkey);
152                         if (eventkey.endsWith(rel)) {
153                             relationNode.put(Ontology.ACCESS_POINT_TYPE, eventkey);
154                             relationNode.put(Ontology.NAME_KEY, origRelation.get(eventkey));
155                         } else {
156                             relationNode.put(eventkey, origRelation.get(eventkey));
157                         }
158                     }
159                     if (!relationNode.containsKey(Ontology.ACCESS_POINT_TYPE)) {
160                         relationNode.put(Ontology.ACCESS_POINT_TYPE, "corporateBodyAccessPoint");
161                     }
162                     list.add(relationNode);
163                 }
164             }
165         }
166         return list;
167     }
168 
169     /**
170      * Creates a Map containing properties of a Virtual Unit.
171      * <p>
172      * These properties are the unit's identifiers.
173      *
174      * @param itemData Map of all extracted information
175      * @return a Map representing a Documentary Unit node
176      */
177     private Map<String, Object> extractVirtualUnit(Map<String, Object> itemData) throws ValidationError {
178         Map<String, Object> unit = Maps.newHashMap();
179         if (itemData.get(OBJECT_IDENTIFIER) != null) {
180             unit.put(Ontology.IDENTIFIER_KEY, itemData.get(OBJECT_IDENTIFIER));
181         }
182         if (itemData.get(Ontology.OTHER_IDENTIFIERS) != null) {
183             logger.debug("otherIdentifiers is not null");
184             unit.put(Ontology.OTHER_IDENTIFIERS, itemData.get(Ontology.OTHER_IDENTIFIERS));
185         }
186         return unit;
187     }
188 
189     @Override
190     public AbstractUnit importItem(Map<String, Object> itemData) throws ValidationError {
191         throw new UnsupportedOperationException("Not supported yet.");
192     }
193 
194     private boolean isVirtualLevel(Map<String, Object> itemData) {
195         return !(itemData.containsKey(REPOID) && itemData.containsKey(OBJECT_IDENTIFIER));
196     }
197 
198     private DocumentaryUnit findReferredToDocumentaryUnit(Map<String, Object> itemData) throws ItemNotFound {
199         if (itemData.containsKey(REPOID) && itemData.containsKey(OBJECT_IDENTIFIER)) {
200             String repositoryId = itemData.get(REPOID).toString();
201             String unitId = itemData.get(OBJECT_IDENTIFIER).toString();
202             Repository repository = manager.getEntity(repositoryId, Repository.class);
203             for (DocumentaryUnit unit : repository.getAllDocumentaryUnits()) {
204                 logger.debug("{} / {} / {}", unit.getIdentifier(), unit.getId(), unitId);
205                 if (unit.getIdentifier().equals(unitId)) {
206                     return unit;
207                 }
208             }
209             throw new ItemNotFound(String.format("No item %s found in repo %s", unitId, repositoryId));
210         }
211         throw new ItemNotFound("Apparently no repositoryid/unitid combo given");
212     }
213 }