Create vertex and edge indicies on startup
[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.ChampField;
33 import org.onap.aai.champcore.model.ChampObject;
34 import org.onap.aai.champcore.model.ChampObjectIndex;
35 import org.onap.aai.champcore.model.ChampRelationship;
36 import org.onap.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
37 import org.onap.aai.cl.api.Logger;
38 import org.onap.aai.cl.eelf.LoggerFactory;
39 import org.onap.champ.entity.ChampBulkEdgeResponse;
40 import org.onap.champ.entity.ChampBulkOp;
41 import org.onap.champ.entity.ChampBulkPayload;
42 import org.onap.champ.entity.ChampBulkResponse;
43 import org.onap.champ.entity.ChampBulkVertexResponse;
44 import org.onap.champ.exception.ChampServiceException;
45 import org.onap.champ.service.logging.ChampMsgs;
46 import org.onap.champ.util.ChampProperties;
47 import org.onap.champ.util.ChampServiceConstants;
48
49 import java.io.PrintWriter;
50 import java.io.StringWriter;
51 import java.util.ArrayList;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Optional;
57 import java.util.stream.Collectors;
58 import java.util.stream.Stream;
59 import javax.ws.rs.core.Response.Status;
60
61 public class ChampDataService {
62   private ChampUUIDService champUUIDService;
63
64   private ChampGraph graphImpl;
65   private ChampTransactionCache cache;
66   private boolean graphInitialized = false;
67   private static final String KEY_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_KEY_NAME);
68   private static final String SOT_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_SOT_NAME);
69   private static final String CREATED_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_CREATED_TS_NAME);
70   private static final String LAST_MOD_TS_NAME = ChampProperties.get(ChampServiceConstants.CHAMP_LAST_MOD_TS_NAME);
71   private Logger logger = LoggerFactory.getInstance().getLogger(ChampDataService.class);
72
73
74   public ChampDataService(ChampUUIDService champUUIDService, ChampGraph graphImpl, ChampTransactionCache cache) {
75
76     this.champUUIDService = champUUIDService;
77     this.graphImpl = graphImpl;
78     this.cache = cache;
79     
80     try {
81       initializeGraph();
82     }
83     catch (Exception ex) {
84       // Swallow exception to prevent application from crashing.  Connection will be retried when
85       // champ processes a new request.
86       StringWriter writer = new StringWriter();
87       PrintWriter printWriter = new PrintWriter(writer);
88       ex.printStackTrace(printWriter);
89       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Unable to initialize graph: " + ex.getLocalizedMessage());
90       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, writer.toString());
91     }
92   }
93
94   public ChampObject getObject(String id, Optional<ChampTransaction> transaction) throws ChampServiceException {
95     if (!graphInitialized) {
96       initializeGraph();
97     }
98       
99     Optional<ChampObject> retrieved = Optional.empty();
100     try {
101       retrieved = champUUIDService.getObjectbyUUID(id, transaction.orElse(null));
102     } catch (ChampUnmarshallingException | ChampTransactionException e) {
103       throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR);
104     }
105     if (retrieved.isPresent()) {
106       return (ChampObject) champUUIDService.populateUUIDKey(retrieved.get());
107     } else {
108       return null;
109     }
110   }
111
112   public ChampObject storeObject(ChampObject object, Optional<ChampTransaction> transaction)
113           throws ChampMarshallingException, ChampSchemaViolationException, ChampObjectNotExistsException,
114           ChampTransactionException, ChampServiceException {
115     if (!graphInitialized) {
116       initializeGraph();
117     }
118       
119     if (object.getProperty(KEY_NAME).isPresent() || object.getKey().isPresent()) {
120       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
121     }
122
123     champUUIDService.populateUUIDProperty(object, java.util.UUID.randomUUID().toString());
124     addTimestamps(object, null);
125     ChampObject created = graphImpl.storeObject(object, transaction);
126     return (ChampObject) champUUIDService.populateUUIDKey(created);
127   }
128
129   public ChampObject replaceObject(ChampObject object, String objectId, Optional<ChampTransaction> transaction)
130           throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException,
131           ChampSchemaViolationException, ChampObjectNotExistsException {
132     if (!graphInitialized) {
133       initializeGraph();
134     }
135       
136     if (object.getKey().isPresent() && (!object.getKeyValue().equals(objectId))) {
137       throw new ChampServiceException("Object Id in the URI doesn't match the body.", Status.BAD_REQUEST);
138     }
139
140     if (object.getProperty(KEY_NAME).isPresent() && !object.getProperty(KEY_NAME).get().toString().equals(objectId)) {
141       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
142     }
143
144     Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
145     if (!retrieved.isPresent()) {
146       throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
147     }
148     ObjectBuildOrPropertiesStep payloadBuilder = ChampObject.create().from(object).withKey(retrieved.get().getKey().get())
149             .withProperty(KEY_NAME, objectId);
150     if (retrieved.get().getProperty(SOT_NAME).isPresent()){
151       payloadBuilder = payloadBuilder.withProperty(SOT_NAME, retrieved.get().getProperty(SOT_NAME).get());
152     }
153
154     if (object.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) {
155       // the timestamps in object are parsed as strings regardless of how the input json is. Convert retrieved to string for easy comparison
156       if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(object.getProperty(CREATED_TS_NAME).get())) {
157         throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST);
158       }
159     }
160
161     if (object.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) {
162       if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(object.getProperty(LAST_MOD_TS_NAME).get())) {
163         throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST);
164       }
165     }
166
167     ChampObject payload = payloadBuilder.build();
168     addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null));
169     ChampObject updated = graphImpl.replaceObject(payload, transaction);
170     return (ChampObject) champUUIDService.populateUUIDKey(updated);
171   }
172
173   public void deleteObject(String objectId, Optional<ChampTransaction> transaction) throws ChampServiceException,
174           ChampObjectNotExistsException, ChampTransactionException, ChampUnmarshallingException {
175     if (!graphInitialized) {
176       initializeGraph();
177     } 
178     
179     Optional<ChampObject> retrieved = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
180     if (!retrieved.isPresent()) {
181       throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
182     }
183     Stream<ChampRelationship> relationships = graphImpl.retrieveRelationships(retrieved.get(), transaction);
184
185     if (relationships.count() > 0) {
186       throw new ChampServiceException("Attempt to delete vertex with id " + objectId + " which has incident edges.",
187               Status.BAD_REQUEST);
188     }
189     graphImpl.deleteObject(retrieved.get().getKey().get(), transaction);
190
191   }
192
193   public ChampRelationship storeRelationship(ChampRelationship r, Optional<ChampTransaction> transaction)
194           throws ChampMarshallingException, ChampObjectNotExistsException, ChampSchemaViolationException,
195           ChampRelationshipNotExistsException, ChampUnmarshallingException, ChampTransactionException,
196           ChampServiceException {
197     if (!graphInitialized) {
198       initializeGraph();
199     } 
200       
201     if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null
202             || !r.getTarget().getKey().isPresent()) {
203       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target Object key must be provided");
204       throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST);
205     }
206
207     if (r.getProperty(KEY_NAME).isPresent() || r.getKey().isPresent()) {
208       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "key or " + KEY_NAME + " not allowed while creating new Objects");
209       throw new ChampServiceException("key or " + KEY_NAME + " not allowed while creating new Objects", Status.BAD_REQUEST);
210
211     }
212
213     Optional<ChampObject> source = champUUIDService.getObjectbyUUID(r.getSource().getKey().get().toString(),
214             transaction.orElse(null));
215     Optional<ChampObject> target = champUUIDService.getObjectbyUUID(r.getTarget().getKey().get().toString(),
216             transaction.orElse(null));
217
218     if (!source.isPresent() || !target.isPresent()) {
219       logger.error(ChampMsgs.CHAMP_DATA_SERVICE_ERROR, "Source/Target object not found");
220       throw new ChampServiceException("Source/Target object not found", Status.BAD_REQUEST);
221     }
222
223     champUUIDService.populateUUIDProperty(r, java.util.UUID.randomUUID().toString());
224
225     ChampRelationship payload = new ChampRelationship.Builder(source.get(), target.get(), r.getType())
226             .properties(r.getProperties()).build();
227     addTimestamps(payload, null);
228     ChampRelationship created = graphImpl.storeRelationship(payload, transaction);
229     return (ChampRelationship) champUUIDService.populateUUIDKey(created);
230   }
231
232   public ChampRelationship updateRelationship(ChampRelationship r, String rId, Optional<ChampTransaction> transaction)
233           throws ChampServiceException, ChampUnmarshallingException, ChampTransactionException, ChampMarshallingException,
234           ChampSchemaViolationException, ChampRelationshipNotExistsException {
235     if (!graphInitialized) {
236       initializeGraph();
237     }      
238       
239     if (r.getKey().isPresent() && (!r.getKeyValue().equals(rId))) {
240
241       throw new ChampServiceException("Relationship Id in the URI \"" + rId + "\" doesn't match the URI in the body"
242               + " \"" + r.getKeyValue() + "\"", Status.BAD_REQUEST);
243
244     }
245
246     if (r.getProperty(KEY_NAME).isPresent() && !r.getProperty(KEY_NAME).get().toString().equals(rId)) {
247       throw new ChampServiceException(KEY_NAME + " can't be updated", Status.BAD_REQUEST);
248     }
249
250     Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(rId, transaction.orElse(null));
251     if (!retrieved.isPresent()) {
252       throw new ChampServiceException(rId + " not found", Status.NOT_FOUND);
253     }
254     // check if key is present or if it equals the key that is in the URI
255     if (r.getSource() == null || !r.getSource().getKey().isPresent() || r.getTarget() == null
256             || !r.getTarget().getKey().isPresent()) {
257       throw new ChampServiceException("Source/Target Object key must be provided", Status.BAD_REQUEST);
258     }
259     ChampObject source = retrieved.get().getSource();
260     ChampObject target = retrieved.get().getTarget();
261
262     if (!source.getProperty(KEY_NAME).get().toString().equals(r.getSource().getKey().get().toString())
263             || !target.getProperty(KEY_NAME).get().toString().equals(r.getTarget().getKey().get().toString())) {
264       throw new ChampServiceException("Source/Target cannot be updated", Status.BAD_REQUEST);
265     }
266
267     if (r.getProperty(CREATED_TS_NAME).isPresent() && retrieved.get().getProperty(CREATED_TS_NAME).isPresent()) {
268       if (!retrieved.get().getProperty(CREATED_TS_NAME).get().toString().equals(r.getProperty(CREATED_TS_NAME).get())) {
269         throw new ChampServiceException(CREATED_TS_NAME + " can't be updated", Status.BAD_REQUEST);
270       }
271     }
272
273     if (r.getProperty(LAST_MOD_TS_NAME).isPresent() && retrieved.get().getProperty(LAST_MOD_TS_NAME).isPresent()) {
274       if (!retrieved.get().getProperty(LAST_MOD_TS_NAME).get().toString().equals(r.getProperty(LAST_MOD_TS_NAME).get())) {
275         throw new ChampServiceException(LAST_MOD_TS_NAME + " can't be updated", Status.BAD_REQUEST);
276       }
277     }
278
279     ChampRelationship payload = new ChampRelationship.Builder(source, target, r.getType())
280             .key(retrieved.get().getKey().get()).properties(r.getProperties()).property(KEY_NAME, rId).build();
281     addTimestamps(payload, (Long)retrieved.get().getProperty(CREATED_TS_NAME).orElse(null));
282     ChampRelationship updated = graphImpl.replaceRelationship(payload, transaction);
283     return (ChampRelationship) champUUIDService.populateUUIDKey(updated);
284   }
285
286   public void deleteRelationship(String relationshipId, Optional<ChampTransaction> transaction)
287           throws ChampServiceException, ChampRelationshipNotExistsException, ChampTransactionException,
288           ChampUnmarshallingException {
289     if (!graphInitialized) {
290       initializeGraph();
291     }
292       
293     Optional<ChampRelationship> retrieved = champUUIDService.getRelationshipbyUUID(relationshipId,
294             transaction.orElse(null));
295     if (!retrieved.isPresent()) {
296       throw new ChampServiceException(relationshipId + " not found", Status.NOT_FOUND);
297     }
298
299     graphImpl.deleteRelationship(retrieved.get(), transaction);
300
301   }
302
303
304   public List<ChampRelationship> getRelationshipsByObject(String objectId, Optional<ChampTransaction> transaction)
305           throws ChampServiceException {
306     if (!graphInitialized) {
307       initializeGraph();
308     }
309       
310     try {
311       Optional<ChampObject> retrievedObject = champUUIDService.getObjectbyUUID(objectId, transaction.orElse(null));
312       if (!retrievedObject.isPresent()) {
313         throw new ChampServiceException(objectId + " not found", Status.NOT_FOUND);
314       }
315       List<ChampRelationship> relations = new ArrayList<ChampRelationship>();
316
317       Stream<ChampRelationship> retrieved = graphImpl.retrieveRelationships(retrievedObject.get(), transaction);
318       relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
319       return relations;
320     } catch (ChampObjectNotExistsException e) {
321       throw new ChampServiceException(" obj not found", Status.NOT_FOUND);
322     } catch (ChampUnmarshallingException | ChampTransactionException e) {
323       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
324     }
325
326   }
327
328   /**
329    * Gets the ChampObjects that pass filter
330    * @param filter key/value pairs that must be present in the returned objects
331    * @param properties properties that will show up in the object
332    * @return
333    * @throws ChampServiceException
334    */
335   public List<ChampObject> queryObjects(Map<String, Object> filter, HashSet<String> properties) throws ChampServiceException {
336     if (!graphInitialized) {
337       initializeGraph();
338     }
339       
340     try {
341       Stream<ChampObject> retrieved = graphImpl.queryObjects(filter);
342       List<ChampObject> objects = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
343
344       if (!properties.contains("all")) {
345         for (ChampObject champObject : objects) {
346           champObject.dropProperties(properties);
347         }
348       }
349
350       return objects;
351     } catch (ChampTransactionException e) {
352       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
353     }
354   }
355
356   public List<ChampRelationship> queryRelationships(Map<String, Object> filter) throws ChampServiceException {
357     if (!graphInitialized) {
358       initializeGraph();
359     }
360       
361     try {
362       List<ChampRelationship> relations = new ArrayList<ChampRelationship>();
363       Stream<ChampRelationship> retrieved;
364
365       retrieved = graphImpl.queryRelationships(filter);
366
367       relations = champUUIDService.populateUUIDKey(retrieved.collect(Collectors.toList()));
368       return relations;
369     } catch (ChampTransactionException e) {
370       throw new ChampServiceException("Internal Error", Status.INTERNAL_SERVER_ERROR);
371     }
372   }
373
374   public ChampRelationship getRelationship(String id, Optional<ChampTransaction> transaction)
375           throws ChampServiceException {
376     if (!graphInitialized) {
377       initializeGraph();
378     }
379       
380     Optional<ChampRelationship> retrieved = Optional.empty();
381     try {
382       retrieved = champUUIDService.getRelationshipbyUUID(id, transaction.orElse(null));
383     } catch (ChampUnmarshallingException | ChampTransactionException e) {
384       throw new ChampServiceException("Error: " + e.getMessage(), Status.INTERNAL_SERVER_ERROR);
385     }
386     if (retrieved.isPresent()) {
387       return (ChampRelationship) champUUIDService.populateUUIDKey(retrieved.get());
388     } else {
389       return null;
390     }
391   }
392
393   public String openTransaction() {
394     if (!graphInitialized) {
395       initializeGraph();
396     }
397     
398     ChampTransaction transaction = graphImpl.openTransaction();
399     String transacId = transaction.id();
400     cache.put(transacId, transaction);
401     return transacId;
402
403   }
404
405   public void commitTransaction(String tId) throws ChampServiceException, ChampTransactionException {
406     if (!graphInitialized) {
407       initializeGraph();
408     }      
409       
410     ChampTransaction transaction = cache.get(tId);
411     if (transaction == null) {
412       throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND);
413     }
414     graphImpl.commitTransaction(transaction);
415     cache.invalidate(tId);
416     cache.invalidate(transaction.id());
417
418   }
419
420   public void rollbackTransaction(String tId) throws ChampServiceException, ChampTransactionException {
421     if (!graphInitialized) {
422       initializeGraph();
423     }
424       
425     ChampTransaction transaction = cache.get(tId);
426     if (transaction == null) {
427       throw new ChampServiceException("Transaction Not found: " + tId, Status.NOT_FOUND);
428     }
429     graphImpl.rollbackTransaction(transaction);
430     cache.invalidate(tId);
431     cache.invalidate(transaction.id());
432
433   }
434
435   public ChampTransaction getTransaction(String id) {
436     return cache.get(id);
437   }
438
439   public ChampBulkResponse processBulkRequest(ChampBulkPayload bulkPayload) throws ChampServiceException, ChampRelationshipNotExistsException, ChampTransactionException, ChampUnmarshallingException, ChampObjectNotExistsException, ChampMarshallingException, ChampSchemaViolationException {
440     if (!graphInitialized) {
441       initializeGraph();
442     }
443       
444     // Open a transaction.  If any operations fail, we want to rollback
445     ChampTransaction transaction = graphImpl.openTransaction();
446     if (transaction == null) {
447       throw new ChampServiceException("Unable to open transaction", Status.INTERNAL_SERVER_ERROR);
448     }
449
450     ChampBulkResponse responsePayload = new ChampBulkResponse();
451     Map<String,ChampObject> addedObjects = new HashMap<String,ChampObject>();
452     List<ChampBulkVertexResponse> addedObjectsResp = new ArrayList<ChampBulkVertexResponse>();
453     List<ChampBulkEdgeResponse> addedEdgesResp = new ArrayList<ChampBulkEdgeResponse>();
454
455     try {
456       // 1. Process edge deletes
457       for (ChampBulkOp op : bulkPayload.getEdgeDeleteOps()) {
458         deleteRelationship(op.getId(), Optional.ofNullable(transaction));
459       }
460
461       // 2. Process vertex deletes
462       for (ChampBulkOp op : bulkPayload.getVertexDeleteOps()) {
463         deleteObject(op.getId(), Optional.ofNullable(transaction));
464       }
465
466       // 3. Add/modify vertexes
467       for (ChampBulkOp op : bulkPayload.getVertexAddModifyOps()) {
468         if (op.getOperation().equals(ChampBulkPayload.ADD_OP)) {
469           ChampObject addedObj = storeObject(op.toChampObject(), Optional.ofNullable(transaction));
470           addedObjects.put(op.getLabel(), addedObj);
471           addedObjectsResp.add(new ChampBulkVertexResponse(op.getLabel(), addedObj));
472         }
473         else {
474           ChampObject addedObj = replaceObject(op.toChampObject(), op.getId(), Optional.ofNullable(transaction));
475           addedObjects.put(op.getLabel(), addedObj);
476           addedObjectsResp.add(new ChampBulkVertexResponse(op.getLabel(), addedObj));
477         }
478       }
479
480       // 4. Add/modify edges
481       for (ChampBulkOp op : bulkPayload.getEdgeAddModifyOps()) {
482         // If the edge references a newly added vertex, we need to replace the reference with the real ID
483         op.setSource(resolveVertex(op.getSource(), addedObjects));
484         op.setTarget(resolveVertex(op.getTarget(), addedObjects));
485
486         if (op.getOperation().equals(ChampBulkPayload.ADD_OP)) {
487           ChampRelationship addedRel = storeRelationship(op.toChampRelationship(), Optional.ofNullable(transaction));
488           addedEdgesResp.add(new ChampBulkEdgeResponse(op.getLabel(), addedRel));
489         }
490         else {
491           ChampRelationship addedRel = updateRelationship(op.toChampRelationship(), op.getId(), Optional.ofNullable(transaction));
492           addedEdgesResp.add(new ChampBulkEdgeResponse(op.getLabel(), addedRel));
493         }
494       }
495     }
496     catch (Exception ex) {
497       // Rollback the transaction
498       graphImpl.rollbackTransaction(transaction);
499       throw ex;
500     }
501
502     // Commit transaction
503     graphImpl.commitTransaction(transaction);
504
505     responsePayload.setObjects(addedObjectsResp);
506     responsePayload.setRelationships(addedEdgesResp);
507     return responsePayload;
508   }
509
510
511   private String resolveVertex(String vertexId, Map<String, ChampObject> addedObjects) throws ChampServiceException {
512     if (vertexId.startsWith("$")) {
513       String key = vertexId.substring(1);
514       if (addedObjects.get(key) != null) {
515         return addedObjects.get(key).getKey().get().toString();
516       }
517
518       throw new ChampServiceException("Unable to resolve vertex " + key, Status.BAD_REQUEST);
519     }
520
521     return vertexId;
522   }
523
524   private void addTimestamps(ChampElement e, Long oldCreated) {
525     Long timestamp = System.currentTimeMillis();
526
527     if (oldCreated == null) {
528       e.getProperties().put(CREATED_TS_NAME, timestamp);
529     } else {
530       e.getProperties().put(CREATED_TS_NAME, oldCreated);
531     }
532
533     e.getProperties().put(LAST_MOD_TS_NAME, timestamp);
534   }
535   
536   private synchronized void initializeGraph() {
537     if (graphInitialized) {
538       return;
539     }
540     
541     graphImpl.createDefaultIndexes();
542         
543     graphInitialized = true;
544   }
545 }