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.models;
21  
22  import com.tinkerpop.blueprints.Direction;
23  import com.tinkerpop.blueprints.Vertex;
24  import com.tinkerpop.frames.Adjacency;
25  import com.tinkerpop.frames.modules.javahandler.JavaHandler;
26  import com.tinkerpop.frames.modules.javahandler.JavaHandlerContext;
27  import com.tinkerpop.gremlin.java.GremlinPipeline;
28  import com.tinkerpop.pipes.util.Pipeline;
29  import eu.ehri.project.definitions.Ontology;
30  import eu.ehri.project.models.annotations.EntityType;
31  import eu.ehri.project.models.annotations.Fetch;
32  import eu.ehri.project.models.annotations.Meta;
33  import eu.ehri.project.models.base.AbstractUnit;
34  import eu.ehri.project.models.utils.JavaHandlerUtils;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * A frame class for graph nodes representing documentary
40   * unit items.
41   */
42  @EntityType(EntityClass.DOCUMENTARY_UNIT)
43  public interface DocumentaryUnit extends AbstractUnit {
44  
45      Logger logger = LoggerFactory.getLogger(DocumentaryUnit.class);
46  
47      /**
48       * Get the repository that holds this documentary unit.
49       *
50       * @return the repository that holds this DocumentaryUnit
51       */
52      @Fetch(Ontology.DOC_HELD_BY_REPOSITORY)
53      @JavaHandler
54      Repository getRepository();
55  
56      /**
57       * Get the repository if this item is at the top of its hierarchy.
58       * Otherwise, return null.
59       *
60       * @return the repository, or null.
61       */
62      @Adjacency(label = Ontology.DOC_HELD_BY_REPOSITORY, direction = Direction.OUT)
63      Repository getRepositoryIfTopLevel();
64  
65      /**
66       * Set the repository that holds this documentary unit.
67       *
68       * @param repository a repository instance
69       */
70      @JavaHandler
71      void setRepository(Repository repository);
72  
73      /**
74       * Get parent documentary unit, if any
75       *
76       * @return a DocumentaryUnit that is this DocumentaryUnit's parent or null
77       */
78      @Fetch(Ontology.DOC_IS_CHILD_OF)
79      @Adjacency(label = Ontology.DOC_IS_CHILD_OF)
80      DocumentaryUnit getParent();
81  
82      /**
83       * Add a child document to this one.
84       *
85       * @param child a documentary unit instance
86       */
87      @JavaHandler
88      void addChild(DocumentaryUnit child);
89  
90      /**
91       * Fetches a list of all ancestors (parent -> parent -> parent)
92       *
93       * @return an Iterable of DocumentaryUnits that are ancestors
94       */
95      @JavaHandler
96      Iterable<DocumentaryUnit> getAncestors();
97  
98      /**
99       * Get an iterable of ancestors, prefixed by this item.
100      *
101      * @return an iterable of DocumentaryUnit items including
102      * the current item
103      */
104     @JavaHandler
105     Iterable<DocumentaryUnit> getAncestorsAndSelf();
106 
107     /**
108      * Get virtual collections to which this documentary unit belongs.
109      *
110      * @return an iterable of virtual unit objects at the top level
111      */
112     @JavaHandler
113     Iterable<VirtualUnit> getVirtualCollections();
114 
115     /**
116      * Count the number of child units at the immediate lower
117      * level (not counting grand-children and lower ancestors.)
118      *
119      * @return the number of immediate child items
120      */
121     @Meta(CHILD_COUNT)
122     @JavaHandler
123     int getChildCount();
124 
125     /**
126      * Get child documentary units
127      *
128      * @return an Iterable of DocumentaryUnits that are children
129      */
130     @JavaHandler
131     Iterable<DocumentaryUnit> getChildren();
132 
133     /**
134      * Fetch <b>all</b> ancestor items, including children of
135      * children to all depths.
136      *
137      * @return child items at all lower levels
138      */
139     @JavaHandler
140     Iterable<DocumentaryUnit> getAllChildren();
141 
142     /**
143      * Get the description items for this documentary unit.
144      *
145      * @return a iterable of document descriptions
146      */
147     @Adjacency(label = Ontology.DESCRIPTION_FOR_ENTITY, direction = Direction.IN)
148     Iterable<DocumentaryUnitDescription> getDocumentDescriptions();
149 
150     /**
151      * Implementation of complex methods.
152      */
153     abstract class Impl implements JavaHandlerContext<Vertex>, DocumentaryUnit {
154 
155         public int getChildCount() {
156             return Math.toIntExact(gremlin().inE(Ontology.DOC_IS_CHILD_OF).count());
157         }
158 
159         public Iterable<DocumentaryUnit> getChildren() {
160             return frameVertices(gremlin().in(Ontology.DOC_IS_CHILD_OF));
161         }
162 
163         public void addChild(DocumentaryUnit child) {
164             JavaHandlerUtils
165                     .addSingleRelationship(child.asVertex(), it(), Ontology.DOC_IS_CHILD_OF);
166         }
167 
168         public Iterable<DocumentaryUnit> getAllChildren() {
169             Pipeline<Vertex, Vertex> otherPipe = gremlin().as("n").in(Ontology.DOC_IS_CHILD_OF)
170                     .loop("n", JavaHandlerUtils.noopLoopFunc, JavaHandlerUtils.noopLoopFunc);
171 
172             return frameVertices(gremlin().in(Ontology.DOC_IS_CHILD_OF).cast(Vertex.class).copySplit(gremlin(), otherPipe)
173                     .fairMerge().cast(Vertex.class));
174         }
175 
176 
177         public void setRepository(Repository repository) {
178             // NB: Convenience methods that proxies addTopLevelDocumentaryUnit (which
179             // in turn maintains the child item cache.)
180             repository.addTopLevelDocumentaryUnit(frame(it(), DocumentaryUnit.class));
181         }
182 
183         public Repository getRepository() {
184             Pipeline<Vertex, Vertex> otherPipe = gremlin().as("n").out(Ontology.DOC_IS_CHILD_OF)
185                     .loop("n", JavaHandlerUtils.defaultMaxLoops,
186                             vertexLoopBundle -> !vertexLoopBundle.getObject().getVertices(Direction.OUT,
187                                     Ontology.DOC_IS_CHILD_OF).iterator().hasNext());
188 
189             GremlinPipeline<Vertex, Vertex> out = gremlin().cast(Vertex.class).copySplit(gremlin(), otherPipe)
190                     .exhaustMerge().out(Ontology.DOC_HELD_BY_REPOSITORY);
191 
192             return (Repository) (out.hasNext() ? frame(out.next()) : null);
193         }
194 
195         public Iterable<DocumentaryUnit> getAncestors() {
196             return frameVertices(gremlin().as("n")
197                     .out(Ontology.DOC_IS_CHILD_OF)
198                     .loop("n", JavaHandlerUtils.defaultMaxLoops, JavaHandlerUtils.noopLoopFunc));
199         }
200 
201         public Iterable<DocumentaryUnit> getAncestorsAndSelf() {
202             GremlinPipeline<Vertex, Vertex> ancestors = gremlin()
203                     .as("n")
204                     .out(Ontology.DOC_IS_CHILD_OF)
205                     .loop("n", JavaHandlerUtils.defaultMaxLoops, JavaHandlerUtils.noopLoopFunc);
206 
207             GremlinPipeline<Vertex, Vertex> all = gremlin().cast(Vertex.class)
208                     .copySplit(gremlin(), ancestors).exhaustMerge().cast(Vertex.class);
209 
210             return frameVertices(all);
211         }
212 
213         public Iterable<VirtualUnit> getVirtualCollections() {
214             GremlinPipeline<Vertex, ?> ancestors = gremlin()
215                     .as("n")
216                     .out(Ontology.DOC_IS_CHILD_OF)
217                     .loop("n", JavaHandlerUtils.defaultMaxLoops, JavaHandlerUtils.noopLoopFunc);
218 
219             GremlinPipeline<Vertex, ?> ancestorsAndSelf = gremlin()
220                     .cast(Vertex.class)
221                     .copySplit(gremlin(), ancestors)
222                     .exhaustMerge();
223 
224 
225             Pipeline<Vertex, Vertex> all = ancestorsAndSelf
226                     .in(Ontology.VC_INCLUDES_UNIT)
227                     .as("n").out(Ontology.VC_IS_PART_OF)
228                     .loop("n", JavaHandlerUtils.defaultMaxLoops, vertexLoopBundle ->
229                             (!vertexLoopBundle.getObject()
230                                     .getEdges(Direction.OUT, Ontology.VC_IS_PART_OF)
231                                     .iterator().hasNext())
232                                     && EntityClass.VIRTUAL_UNIT
233                                     .getName()
234                                     .equals(vertexLoopBundle.getObject()
235                                             .getProperty(EntityType.TYPE_KEY)))
236                     .cast(Vertex.class);
237 
238             return frameVertices(all);
239         }
240     }
241 }