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