Port champ-microservice project restructure
[aai/champ.git] / champ-service / src / main / java / org / onap / champ / service / ChampDataService.java
1 package org.onap.champ.service;
2
3 import org.onap.aai.champcore.ChampGraph;
4 import org.onap.aai.champcore.ChampTransaction;
5 import org.onap.aai.champcore.exceptions.ChampMarshallingException;
6 import org.onap.aai.champcore.exceptions.ChampObjectNotExistsException;
7 import org.onap.aai.champcore.exceptions.ChampRelationshipNotExistsException;
8 import org.onap.aai.champcore.exceptions.ChampSchemaViolationException;
9 import org.onap.aai.champcore.exceptions.ChampTransactionException;
10 import org.onap.aai.champcore.exceptions.ChampUnmarshallingException;
11 import org.onap.aai.champcore.model.ChampElement;
12 import org.onap.aai.champcore.model.ChampObject;
13 import org.onap.aai.champcore.model.ChampRelationship;
14 import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
15 import org.onap.aai.cl.api.Logger;
16 import org.onap.aai.cl.eelf.LoggerFactory;
17 import org.onap.champ.exception.ChampServiceException;
18 import org.onap.champ.service.logging.ChampMsgs;
19 import org.onap.champ.util.ChampProperties;
20 import org.onap.champ.util.ChampServiceConstants;
21
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29 import javax.ws.rs.core.Response.Status;
30
31 public class ChampDataService {
32   private ChampUUIDService champUUIDService;
33
34   private ChampGraph graphImpl;
35   private ChampTransactionCache cache;
36   private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME);
37   private static final String SOT_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_SOT_NAME);
38   private static final String CREATED_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_CREATED_TS_NAME);
39   private static final String LAST_MOD_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_LAST_MOD_TS_NAME);
40   private Logger logger = LoggerFactory.getInstance().getLogger(ChampDataService.class);
41
42
43   public ChampDataService(ChampUUIDService champUUIDService, ChampGraph graphImpl, ChampTransactionCache cache) {
44
45     this.champUUIDService = champUUIDService;
46     this.graphImpl = graphImpl;
47     this.cache = cache;
48   }
49
50   public ChampObject getObject(String id, Optional<ChampTransaction> transaction) throws ChampServiceException {
51
52     Optional<ChampObject> retrieved = Optional.empty();
53     try {
54       retrieved = champUUIDService.getObjectbyUUID(id, transaction.orElse(null));
55     } catch (ChampUnmarshallingException | ChampTransactionException e) {
56       throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR);
57     }
58     if (retrieved.isPresent()) {
59       return (ChampObject) champUUIDService.populateUUIDKey(retrieved.get());
60     } else {
61       return null;
62     }
63   }
64
65   public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction)
66       throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException,
67       ChampTransactionException, ChampServiceException {
68
69     if (object.getProperty(KEY_NAME).isPresent() || object.getKey().isPresent()) {
70       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
71     }
72
73     champUUIDService.populateUUIDProperty(object, java.util.UUID.randomUUID().toString());
74     addTimestamps(object, null);
75     ChampObject created = graphImpl.storeObject(object, transaction);
76     return (ChampObject) champUUIDService.populateUUIDKey(created);
77   }
78
79   public ChampObject replaceObject(ChampObject object, String objectId, Optional<ChampTransaction> transaction)
80       throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException,
81       ChampSchemaViolationException, ChampObjectNotExistsException {
82     if (object.getKey().isPresent() && (!object.getKeyValue().equals(objectId))) {
83       throw new ChampServiceException("Object Id in the URI doesn't match the body.", Status.BAD_REQUEST);
84     }
85
86     if (object.getProperty(KEY_NAME).isPresent() && !object.getProperty(KEY_NAME).get().toString().equals(objectId)) {
87       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
88     }
89
90     Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
91     if (!retrieved.isPresent()) {
92       throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
93     }
94     ObjectBuildOrPropertiesStep payloadBuilder = ChampObject.create().from(object).withKey(retrieved.get().getKey().get())
95         .withProperty(KEY_NAME, objectId);
96     if (retrieved.get().getProperty(SOT_NAME).isPresent()){
97       payloadBuilder = payloadBuilder.withProperty(SOT_NAME, retrieved.get().getProperty(SOT_NAME).get());
98     }
99
100     if (object.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) {
101       // the timestamps in object are parsed as strings regardless of how the input json is. Convert retrieved to string for easy comparison
102       if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(object.getProperty(CREATED_TS_NAME).get())) {
103         throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST);
104       }
105     }
106
107     if (object.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) {
108       if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(object.getProperty(LAST_MOD_TS_NAME).get())) {
109         throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST);
110       }
111     }
112
113     ChampObject payload = payloadBuilder.build();
114     addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null));
115     ChampObject updated = graphImpl.replaceObject(payload, transaction);
116     return (ChampObject) champUUIDService.populateUUIDKey(updated);
117   }
118
119   public void deleteObject(String objectId, Optional<ChampTransaction> transaction) throws ChampServiceException,
120       ChampObjectNotExistsException, ChampTransactionException, ChampUnmarshallingException {
121     Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
122     if (!retrieved.isPresent()) {
123       throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
124     }
125     Stream<ChampRelationship> relationships = graphImpl.retrieveRelationships(retrieved.get(), transaction);
126
127     if (relationships.count() > 0) {
128       throw new ChampServiceException("Attempt to delete vertex with id " + objectId + " which has incident edges.",
129           Status.BAD_REQUEST);
130     }
131     graphImpl.deleteObject(retrieved.get().getKey().get(), transaction);
132
133   }
134
135   public ChampRelationship storeRelationship(ChampRelationship r, Optional<ChampTransaction> transaction)
136       throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException,
137       ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException,
138       ChampServiceException {
139
140     if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null
141         || !r.getTarget().getKey().isPresent()) {
142       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target Object key must be provided");
143       throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST);
144     }
145
146     if (r.getProperty(KEY_NAME).isPresent() || r.getKey().isPresent()) {
147       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "key or " + KEY_NAME + " not allowed while creating new Objects");
148       throw new ChampServiceException("key or " + KEY_NAME + " not allowed while creating new Objects", Status.BAD_REQUEST);
149
150     }
151
152     Optional<ChampObject> source = champUUIDService.getObjectbyUUID(r.getSource().getKey().get().toString(),
153         transaction.orElse(null));
154     Optional<ChampObject> target = champUUIDService.getObjectbyUUID(r.getTarget().getKey().get().toString(),
155         transaction.orElse(null));
156
157     if (!source.isPresent() || !target.isPresent()) {
158       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target object not found");
159       throw new ChampServiceException("Source/Target object not found", Status.BAD_REQUEST);
160     }
161
162     champUUIDService.populateUUIDProperty(r, java.util.UUID.randomUUID().toString());
163
164     ChampRelationship payload = new ChampRelationship.Builder(source.get(), target.get(), r.getType())
165         .properties(r.getProperties()).build();
166     addTimestamps(payload, null);
167     ChampRelationship created = graphImpl.storeRelationship(payload, transaction);
168     return (ChampRelationship) champUUIDService.populateUUIDKey(created);
169   }
170
171   public ChampRelationship updateRelationship(ChampRelationship r, String rId, Optional<ChampTransaction> transaction)
172       throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException,
173       ChampSchemaViolationException, ChampRelationshipNotExistsException {
174     if (r.getKey().isPresent() && (!r.getKeyValue().equals(rId))) {
175
176       throw new ChampServiceException("Relationship Id in the URI \"" + rId + "\" doesn't match the URI in the body"
177           + " \"" + r.getKeyValue() + "\"", Status.BAD_REQUEST);
178
179     }
180
181     if (r.getProperty(KEY_NAME).isPresent() && !r.getProperty(KEY_NAME).get().toString().equals(rId)) {
182       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
183     }
184
185     Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(rId, transaction.orElse(null));
186     if (!retrieved.isPresent()) {
187       throw new ChampServiceException(rId + " not found", Status.NOT_FOUND);
188     }
189     // check if key is present or if it equals the key that is in the URI
190     if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null
191         || !r.getTarget().getKey().isPresent()) {
192       throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST);
193     }
194     ChampObject source = retrieved.get().getSource();
195     ChampObject target = retrieved.get().getTarget();
196
197     if (!source.getProperty(KEY_NAME).get().toString().equals(r.getSource().getKey().get().toString())
198         || !target.getProperty(KEY_NAME).get().toString().equals(r.getTarget().getKey().get().toString())) {
199       throw new ChampServiceException("Source/Target cannot be updated", Status.BAD_REQUEST);
200     }
201
202     if (r.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) {
203       if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(r.getProperty(CREATED_TS_NAME).get())) {
204         throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST);
205       }
206     }
207
208     if (r.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) {
209       if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(r.getProperty(LAST_MOD_TS_NAME).get())) {
210         throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST);
211       }
212     }
213
214     ChampRelationship payload = new ChampRelationship.Builder(source, target, r.getType())
215         .key(retrieved.get().getKey().get()).properties(r.getProperties()).property(KEY_NAME, rId).build();
216     addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null));
217     ChampRelationship updated = graphImpl.replaceRelationship(payload, transaction);
218     return (ChampRelationship) champUUIDService.populateUUIDKey(updated);
219   }
220
221   public void deleteRelationship(String relationshipId, Optional<ChampTransaction> transaction)
222       throws ChampServiceException, ChampRelationshipNotExistsException, ChampTransactionException,
223       ChampUnmarshallingException {
224     Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(relationshipId,
225         transaction.orElse(null));
226     if (!retrieved.isPresent()) {
227       throw new ChampServiceException(relationshipId + " not found", Status.NOT_FOUND);
228     }
229
230     graphImpl.deleteRelationship(retrieved.get(), transaction);
231
232   }
233
234
235   public List<ChampRelationship> getRelationshipsByObject(String objectId, Optional<ChampTransaction> transaction)
236       throws ChampServiceException {
237     try {
238       Optional<ChampObject> retrievedObject = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
239       if (!retrievedObject.isPresent()) {
240         throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
241       }
242       List<ChampRelationship> relations = new ArrayList<ChampRelationship>();
243
244       Stream<ChampRelationship> retrieved = graphImpl.retrieveRelationships(retrievedObject.get(), transaction);
245       relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
246       return relations;
247     } catch (ChampObjectNotExistsException e) {
248       throw new ChampServiceException(" obj not found", Status.NOT_FOUND);
249     } catch (ChampUnmarshallingException | ChampTransactionException e) {
250       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
251     }
252
253   }
254
255   /**
256    * Gets the ChampObjects that pass filter
257    * @param filter key/value pairs that must be present in the returned objects
258    * @param properties properties that will show up in the object
259    * @return
260    * @throws ChampServiceException
261    */
262   public List<ChampObject> queryObjects(Map<String, Object> filter, HashSet<String> properties) throws ChampServiceException {
263     try {
264
265       Stream<ChampObject> retrieved = graphImpl.queryObjects(filter);
266       List<ChampObject> objects = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
267
268       if (!properties.contains("all")) {
269         for (ChampObject champObject : objects) {
270           champObject.dropProperties(properties);
271         }
272       }
273
274       return objects;
275     } catch (ChampTransactionException e) {
276       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
277     }
278   }
279
280   public List<ChampRelationship> queryRelationships(Map<String, Object> filter) throws ChampServiceException {
281     try {
282       List<ChampRelationship> relations = new ArrayList<ChampRelationship>();
283       Stream<ChampRelationship> retrieved;
284
285       retrieved = graphImpl.queryRelationships(filter);
286
287       relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
288       return relations;
289     } catch (ChampTransactionException e) {
290       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
291     }
292   }
293
294   public ChampRelationship getRelationship(String id, Optional<ChampTransaction> transaction)
295       throws ChampServiceException {
296
297     Optional<ChampRelationship> retrieved = Optional.empty();
298     try {
299       retrieved = champUUIDService.getRelationshipbyUUID(id, transaction.orElse(null));
300     } catch (ChampUnmarshallingException | ChampTransactionException e) {
301       throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR);
302     }
303     if (retrieved.isPresent()) {
304       return (ChampRelationship) champUUIDService.populateUUIDKey(retrieved.get());
305     } else {
306       return null;
307     }
308   }
309
310   public String openTransaction() {
311     ChampTransaction transaction = graphImpl.openTransaction();
312     String transacId = transaction.id();
313     cache.put(transacId, transaction);
314     return transacId;
315
316   }
317
318   public void commitTransaction(String tId) throws ChampServiceException, ChampTransactionException {
319     ChampTransaction transaction = cache.get(tId);
320     if (transaction == null) {
321       throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND);
322     }
323     graphImpl.commitTransaction(transaction);
324     cache.invalidate(tId);
325     cache.invalidate(transaction.id());
326
327   }
328
329   public void rollbackTransaction(String tId) throws ChampServiceException, ChampTransactionException {
330     ChampTransaction transaction = cache.get(tId);
331     if (transaction == null) {
332       throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND);
333     }
334     graphImpl.rollbackTransaction(transaction);
335     cache.invalidate(tId);
336     cache.invalidate(transaction.id());
337
338   }
339
340   public ChampTransaction getTransaction(String id) {
341     return cache.get(id);
342   }
343
344   private void addTimestamps(ChampElement e, Long oldCreated) {
345     Long timestamp = System.currentTimeMillis();
346
347     if (oldCreated == null) {
348       e.getProperties().put(CREATED_TS_NAME, timestamp);
349     } else {
350       e.getProperties().put(CREATED_TS_NAME, oldCreated);
351     }
352
353     e.getProperties().put(LAST_MOD_TS_NAME, timestamp);
354   }
355 }