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