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.commands;
21  
22  import com.google.common.collect.Iterables;
23  import com.google.common.collect.Lists;
24  import com.tinkerpop.blueprints.CloseableIterable;
25  import com.tinkerpop.frames.FramedGraph;
26  import eu.ehri.project.acl.ContentTypes;
27  import eu.ehri.project.acl.PermissionType;
28  import eu.ehri.project.core.GraphManager;
29  import eu.ehri.project.core.GraphManagerFactory;
30  import eu.ehri.project.exceptions.ItemNotFound;
31  import eu.ehri.project.models.ContentType;
32  import eu.ehri.project.models.DocumentaryUnit;
33  import eu.ehri.project.models.EntityClass;
34  import eu.ehri.project.models.Group;
35  import eu.ehri.project.models.Permission;
36  import eu.ehri.project.models.PermissionGrant;
37  import eu.ehri.project.models.Repository;
38  import eu.ehri.project.models.base.Accessible;
39  import eu.ehri.project.models.base.Entity;
40  import eu.ehri.project.models.base.Identifiable;
41  import eu.ehri.project.models.base.PermissionScope;
42  import eu.ehri.project.models.cvoc.Concept;
43  import eu.ehri.project.models.events.SystemEventQueue;
44  import eu.ehri.project.models.idgen.IdGeneratorUtils;
45  import org.apache.commons.cli.CommandLine;
46  import org.apache.commons.cli.Option;
47  import org.apache.commons.cli.Options;
48  
49  import java.util.List;
50  
51  import static eu.ehri.project.models.EntityClass.CVOC_CONCEPT;
52  import static eu.ehri.project.models.EntityClass.DOCUMENTARY_UNIT;
53  import static eu.ehri.project.models.EntityClass.HISTORICAL_AGENT;
54  import static eu.ehri.project.models.EntityClass.REPOSITORY;
55  import static eu.ehri.project.persistence.ActionManager.GLOBAL_EVENT_ROOT;
56  
57  /**
58   * Sanity check various parts of the graph.
59   */
60  public class Check extends BaseCommand {
61  
62      final static String NAME = "check";
63      private static final String QUICK = "quick";
64  
65      @Override
66      public String getHelp() {
67          return "Perform various checks on the graph structure";
68      }
69  
70      @Override
71      public String getUsage() {
72          return NAME + " [OPTIONS]";
73      }
74  
75      @Override
76      protected void setCustomOptions(Options options) {
77          options.addOption(Option.builder()
78                  .longOpt(QUICK)
79                  .desc("Run fast, basic sanity checks only")
80                  .build());
81      }
82  
83      @Override
84      public int execWithOptions(FramedGraph<?> graph,
85              CommandLine cmdLine) throws Exception {
86  
87          GraphManager manager = GraphManagerFactory.getInstance(graph);
88          checkInitialization(graph, manager);
89          if (!cmdLine.hasOption(QUICK)) {
90              checkPermissionScopes(graph, manager);
91              checkOwnerPermGrantsHaveNoScope(manager);
92          }
93  
94          return 0;
95      }
96  
97      private void checkInitialization(FramedGraph<?> graph, GraphManager manager) {
98          if (graph.getBaseGraph().getVertices().iterator().hasNext()) {
99              try {
100                 SystemEventQueue queue =
101                         manager.getEntity(GLOBAL_EVENT_ROOT, EntityClass.SYSTEM, SystemEventQueue.class);
102                 if (!queue.getSystemEvents().iterator().hasNext()) {
103                     System.err.println("Global event iterator is empty!");
104                 }
105             } catch (ItemNotFound itemNotFound) {
106                 System.err.println("Unable to read event root in graph!");
107             }
108 
109             try {
110                 manager.getEntity(Group.ADMIN_GROUP_IDENTIFIER, Group.class);
111 
112                 for (PermissionType pt : PermissionType.values()) {
113                     manager.getEntity(pt.getName(), Permission.class);
114                 }
115                 for (ContentTypes ct : ContentTypes.values()) {
116                     manager.getEntity(ct.getName(), ContentType.class);
117                 }
118             } catch (ItemNotFound itemNotFound) {
119                 System.err.println("Unable to find item in graph with id: " + itemNotFound.getValue());
120             }
121         } else {
122             System.err.println("Graph contains no vertices (has it been initialized?)");
123         }
124     }
125 
126     /**
127      * The following types of item should ALL have a permission scope.
128      * <p>
129      * Doc unit - either a repository or another doc unit
130      * Concept - a vocabulary
131      * Repository - a country
132      * Hist agent - an auth set
133      *
134      * @param graph   The graph
135      * @param manager The graph manager
136      */
137     private void checkPermissionScopes(FramedGraph<?> graph,
138             GraphManager manager) {
139 
140         List<EntityClass> types = Lists.newArrayList(DOCUMENTARY_UNIT, REPOSITORY, CVOC_CONCEPT, HISTORICAL_AGENT);
141 
142         for (EntityClass entityClass : types) {
143             try (CloseableIterable<? extends Entity> items = manager.getEntities(entityClass, entityClass.getJavaClass())) {
144                 for (Entity item : items) {
145                     Accessible entity = item.as(Accessible.class);
146                     PermissionScope scope = entity.getPermissionScope();
147                     if (scope == null) {
148                         System.err.println("Missing scope: " + entity.getId() + " (" + entity.asVertex().getId() + ")");
149                     } else {
150                         switch (manager.getEntityClass(item)) {
151                             case DOCUMENTARY_UNIT:
152                                 checkIdGeneration(graph.frame(item.asVertex(), DocumentaryUnit.class), scope);
153                                 break;
154                             case REPOSITORY:
155                                 checkIdGeneration(graph.frame(item.asVertex(), Repository.class), scope);
156                                 break;
157                             case CVOC_CONCEPT:
158                                 checkIdGeneration(graph.frame(item.asVertex(), Concept.class), scope);
159                             case HISTORICAL_AGENT:
160                                 checkIdGeneration(graph.frame(item.asVertex(), Concept.class), scope);
161                             default:
162                         }
163                     }
164                 }
165             }
166         }
167     }
168 
169     private void checkIdGeneration(Identifiable doc, PermissionScope scope) {
170         if (scope != null) {
171             String ident = doc.getIdentifier();
172             List<String> path = Lists.newArrayList(Iterables.concat(scope.idPath(), Lists.newArrayList(ident)));
173             String finalId = IdGeneratorUtils.joinPath(path);
174             if (!finalId.equals(doc.getId())) {
175                 System.err.println(String.format("Generated ID does not match scopes: '%s' -> %s + %s",
176                         doc.getId(), path, ident));
177             }
178         }
179     }
180 
181     private void checkOwnerPermGrantsHaveNoScope(GraphManager manager) {
182         try (CloseableIterable<PermissionGrant> items = manager
183                 .getEntities(EntityClass.PERMISSION_GRANT, PermissionGrant.class)) {
184             for (PermissionGrant grant : items) {
185                 Entity scope = grant.getScope();
186                 Entity perm = grant.getPermission();
187                 if (scope != null && perm != null && perm.getId().equals(PermissionType.OWNER.getName())) {
188                     System.err.println(
189                             String.format("Owner permission grant with scope: %s", grant.asVertex().getId()));
190                 }
191             }
192         }
193 
194     }
195 }