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.events;
21  
22  import com.tinkerpop.blueprints.Direction;
23  import com.tinkerpop.blueprints.Vertex;
24  import com.tinkerpop.frames.Adjacency;
25  import com.tinkerpop.frames.Property;
26  import com.tinkerpop.frames.modules.javahandler.JavaHandler;
27  import com.tinkerpop.frames.modules.javahandler.JavaHandlerContext;
28  import com.tinkerpop.gremlin.java.GremlinPipeline;
29  import eu.ehri.project.definitions.Entities;
30  import eu.ehri.project.definitions.EventTypes;
31  import eu.ehri.project.definitions.Ontology;
32  import eu.ehri.project.models.EntityClass;
33  import eu.ehri.project.models.annotations.EntityType;
34  import eu.ehri.project.models.annotations.Fetch;
35  import eu.ehri.project.models.annotations.Mandatory;
36  import eu.ehri.project.models.annotations.Meta;
37  import eu.ehri.project.models.base.Accessible;
38  import eu.ehri.project.models.base.Actioner;
39  import eu.ehri.project.models.base.Entity;
40  import eu.ehri.project.models.base.ItemHolder;
41  import eu.ehri.project.models.utils.JavaHandlerUtils;
42  
43  /**
44   * Frame class representing an event that happened in the
45   * graph.
46   */
47  @EntityType(EntityClass.SYSTEM_EVENT)
48  public interface SystemEvent extends Accessible {
49  
50      @Meta(ItemHolder.CHILD_COUNT)
51      @JavaHandler
52      int subjectCount();
53  
54      /**
55       * Fetch the time stamp of this event.
56       *
57       * @return a UTF timestamp string
58       */
59      @Mandatory
60      @Property(Ontology.EVENT_TIMESTAMP)
61      String getTimestamp();
62  
63      /**
64       * Fetch the event type of this event.
65       *
66       * @return an {@link EventTypes} value
67       */
68      @Mandatory
69      @Property(Ontology.EVENT_TYPE)
70      EventTypes getEventType();
71  
72      /**
73       * Fetch the log message associated with this event.
74       *
75       * @return A string
76       */
77      @Property(Ontology.EVENT_LOG_MESSAGE)
78      String getLogMessage();
79  
80      /**
81       * Fetch the actioner who triggered this event.
82       *
83       * @return A user profile instance
84       */
85      @Fetch(value = Ontology.EVENT_HAS_ACTIONER, numLevels = 0)
86      @JavaHandler
87      Actioner getActioner();
88  
89      /**
90       * Fetch the subject items to whom this event pertains.
91       *
92       * @return an iterable of frame items
93       */
94      @JavaHandler
95      Iterable<Accessible> getSubjects();
96  
97      /**
98       * If new versions have been created, fetch the prior versions
99       * of the subjects that were affected by this event.
100      *
101      * @return an iterable of version nodes
102      */
103     @Fetch(value = Ontology.VERSION_HAS_EVENT, ifLevel = 0)
104     @Adjacency(label = Ontology.VERSION_HAS_EVENT, direction = Direction.IN)
105     Iterable<Version> getPriorVersions();
106 
107     /**
108      * Fetch the first subject of this event. This is a shortcut
109      * method to avoid having to fetch many items.
110      *
111      * @return an item frame
112      */
113     @Fetch(value = Ontology.EVENT_HAS_FIRST_SUBJECT, ifLevel = 0)
114     @JavaHandler
115     Accessible getFirstSubject();
116 
117     /**
118      * Fetch the event chronologically prior to this one.
119      *
120      * @return an event item
121      */
122     @Adjacency(label = Ontology.ACTIONER_HAS_LIFECYCLE_ACTION)
123     SystemEvent getPriorEvent();
124 
125     /**
126      * Fetch the "scope" of this event, or the context in which a
127      * given creation/modification/deletion event is happening.
128      *
129      * @return the event scope
130      */
131     @Fetch(value = Ontology.EVENT_HAS_SCOPE, ifLevel = 0)
132     @Adjacency(label = Ontology.EVENT_HAS_SCOPE, direction = Direction.OUT)
133     Entity getEventScope();
134 
135     /**
136      * Set the scope of this event.
137      *
138      * @param frame a scope item
139      */
140     @Adjacency(label = Ontology.EVENT_HAS_SCOPE, direction = Direction.OUT)
141     void setEventScope(Entity frame);
142 
143     /**
144      * Implementation of complex methods.
145      */
146     abstract class Impl implements JavaHandlerContext<Vertex>, SystemEvent {
147 
148         @Override
149         public int subjectCount() {
150             return Math.toIntExact(gremlin().inE(Ontology.ENTITY_HAS_EVENT).count());
151         }
152 
153         @Override
154         public Iterable<Accessible> getSubjects() {
155             return frameVertices(gremlin().in(Ontology.ENTITY_HAS_EVENT)
156                     .as("n").in(Ontology.ENTITY_HAS_LIFECYCLE_EVENT)
157                     .loop("n", JavaHandlerUtils.noopLoopFunc,
158                             vertexLoopBundle -> isValidEndpoint(vertexLoopBundle.getObject(),
159                             Ontology.ENTITY_HAS_LIFECYCLE_EVENT)));
160         }
161 
162         @Override
163         public Accessible getFirstSubject() {
164             // Ugh: horrible code duplication is horrible - unfortunately
165             // just calling getSubjects() fails for an obscure reason to do
166             // with Frames not being thinking it has an iterable???
167             GremlinPipeline<Vertex, Vertex> subjects = gremlin().in(Ontology.ENTITY_HAS_EVENT)
168                     .as("n").in(Ontology.ENTITY_HAS_LIFECYCLE_EVENT)
169                     .loop("n", JavaHandlerUtils.noopLoopFunc,
170                             vertexLoopBundle -> isValidEndpoint(vertexLoopBundle.getObject(),
171                             Ontology.ENTITY_HAS_LIFECYCLE_EVENT));
172             return (Accessible) (subjects.iterator().hasNext()
173                     ? frame(subjects.iterator().next())
174                     : null);
175         }
176 
177         @Override
178         public Actioner getActioner() {
179             GremlinPipeline<Vertex, Vertex> actioners = gremlin().in(Ontology.ACTION_HAS_EVENT)
180                     .as("n").in(Ontology.ACTIONER_HAS_LIFECYCLE_ACTION)
181                     .loop("n", JavaHandlerUtils.noopLoopFunc,
182                             vertexLoopBundle -> isValidEndpoint(vertexLoopBundle.getObject(),
183                             Ontology.ACTIONER_HAS_LIFECYCLE_ACTION));
184             return (Actioner) (actioners.iterator().hasNext()
185                     ? frame(actioners.iterator().next())
186                     : null);
187         }
188 
189         private boolean isValidEndpoint(Vertex vertex, String linkRel) {
190             // A node at the end of an event link chain will have
191             //  - a) no in-coming event link relations
192             //  - b) be of a different type than an event link
193             if (vertex.getEdges(Direction.IN, linkRel).iterator().hasNext()) {
194                 return false;
195             } else {
196                 String type = vertex.getProperty(EntityType.TYPE_KEY);
197                 return type != null && !type.equals(Entities.EVENT_LINK);
198             }
199         }
200     }
201 }