31bc9abf3b39b6bcb455516fd6f9cab84ca8806d
[aai/gizmo.git] / src / main / java / org / openecomp / crud / dao / champ / ChampDao.java
1 /**
2  * ============LICENSE_START=======================================================
3  * Gizmo
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property.
6  * Copyright © 2017 Amdocs
7  * All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *    http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  *
22  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23  */
24 package org.openecomp.crud.dao.champ;
25
26 import org.openecomp.aai.champcore.ChampGraph;
27 import org.openecomp.aai.champcore.exceptions.ChampMarshallingException;
28 import org.openecomp.aai.champcore.exceptions.ChampObjectNotExistsException;
29 import org.openecomp.aai.champcore.exceptions.ChampRelationshipNotExistsException;
30 import org.openecomp.aai.champcore.exceptions.ChampSchemaViolationException;
31 import org.openecomp.aai.champcore.exceptions.ChampTransactionException;
32 import org.openecomp.aai.champcore.exceptions.ChampUnmarshallingException;
33 import org.openecomp.aai.champcore.model.ChampObject;
34 import org.openecomp.aai.champcore.model.ChampRelationship;
35 import org.openecomp.aai.champcore.model.fluent.object.ObjectBuildOrPropertiesStep;
36 import org.openecomp.cl.api.Logger;
37 import org.openecomp.cl.eelf.LoggerFactory;
38 import org.openecomp.crud.dao.GraphDao;
39 import org.openecomp.crud.entity.Edge;
40 import org.openecomp.crud.entity.Vertex;
41 import org.openecomp.crud.exception.CrudException;
42 import org.openecomp.crud.logging.CrudServiceMsgs;
43
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Optional;
49 import java.util.stream.Collectors;
50 import java.util.stream.Stream;
51
52
53 /**
54  * This is the integration layer between the CRUD API service and the low level Champ library
55  * for graph database interaction.
56  */
57 public class ChampDao implements GraphDao {
58
59   public static final String CONFIG_STORAGE_BACKEND = "storage.backend";
60   public static final String CONFIG_STORAGE_BACKEND_DB = "storage.backend.db";
61   public static final String STORAGE_HBASE_DB = "hbase";
62   public static final String STORAGE_CASSANDRA_DB = "cassandra";
63   public static final String CONFIG_STORAGE_HOSTNAMES = "storage.hostnames";
64   public static final String CONFIG_STORAGE_PORT = "storage.port";
65   public static final String CONFIG_HBASE_ZNODE_PARENT = "storage.hbase.ext.zookeeper.znode.parent";
66   public static final String CONFIG_GRAPH_NAME = "graph.name";
67   public static final String GRAPH_UNQ_INSTANCE_ID_SUFFIX = "graph.unique-instance-id-suffix";
68
69   public static final String CONFIG_EVENT_STREAM_PUBLISHER = "event.stream.publisher";
70   public static final String CONFIG_EVENT_STREAM_NUM_PUBLISHERS = "event.stream.num-publishers";
71
72
73   public static final String DEFAULT_GRAPH_NAME = "default_graph";
74
75   private enum GraphType {
76     IN_MEMORY,
77     TITAN,
78     DSE
79   }
80   
81   /**
82    * Instance of the API used for interacting with the Champ library.
83    */
84   private ChampGraph champApi = null;
85
86   private Logger logger = LoggerFactory.getInstance().getLogger(ChampDao.class.getName());
87
88
89   /**
90    * Creates a new instance of the ChampDao.
91    *
92    * @param champGraph - Concrete implementation of the graph dao layer
93    */
94   public ChampDao(ChampGraph champGraph) {
95         this.champApi = champGraph;
96   }
97
98   @Override
99   public Vertex getVertex(String id) throws CrudException {
100     
101     try {
102       
103       if (logger.isDebugEnabled()) {
104         logger.debug("getVertex with id: " + id);
105       }
106       
107       long idAsLong = Long.parseLong(id);
108       
109       Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
110       
111       String nodeType = org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName();
112       if(retrievedVertex.isPresent() && 
113          retrievedVertex.get().getProperties().get(nodeType)!=null) {
114         return vertexFromChampObject(retrievedVertex.get(), 
115                                      retrievedVertex.get().getProperties().get(nodeType).toString());
116       } else {
117
118         // We didn't find a vertex with the supplied id, so just throw an
119         // exception.
120         throw new CrudException("No vertex with id " + id + " found in graph",
121                                 javax.ws.rs.core.Response.Status.NOT_FOUND);
122       }
123       
124     } catch (ChampUnmarshallingException | ChampTransactionException e) {
125
126       // Something went wrong - throw an exception.
127       throw new CrudException(e.getMessage(),
128                               javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
129     }
130   }
131   
132   @Override
133   public Vertex getVertex(String id, String type) throws CrudException {
134
135     try {
136
137       if (logger.isDebugEnabled()) {
138         logger.debug("getVertex with id: " + id);
139       }
140
141       long idAsLong = Long.parseLong(id);
142
143       // Request the vertex from the graph db.
144       Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
145
146       // Did we find it?
147       if (retrievedVertex.isPresent() && retrievedVertex.get().getProperties()
148           .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName())!=null && retrievedVertex.get().getProperties()
149           .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()
150           .equalsIgnoreCase(type)) {  
151         
152         // Yup, convert it to a Vector object and return it.
153         return vertexFromChampObject(retrievedVertex.get(),type);
154
155       } else {
156
157         // We didn't find a vertex with the supplied id, so just throw an
158         // exception.
159         throw new CrudException("No vertex with id " + id + " found in graph",
160             javax.ws.rs.core.Response.Status.NOT_FOUND);
161       }
162
163     } catch (ChampUnmarshallingException | ChampTransactionException e) {
164
165       // Something went wrong - throw an exception.
166       throw new CrudException(e.getMessage(),
167           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
168     }
169   }
170
171
172   @Override
173   public List<Edge> getVertexEdges(String id) throws CrudException {
174
175     if (logger.isDebugEnabled()) {
176       logger.debug("get Edges incident to vertex with id: " + id + " from graph");
177     }
178
179     try {
180       long idAsLong = Long.parseLong(id); // GDF - what to do about id???
181
182       // Request the vertex from the graph db.
183       Optional<ChampObject> retrievedVertex = champApi.retrieveObject(idAsLong);
184
185       // Did we find it?
186       if (retrievedVertex.isPresent()) {
187
188         // Query the Champ library for the edges which are incident to the specified
189         // vertex.
190         Stream<ChampRelationship> relationships =
191             champApi.retrieveRelationships(retrievedVertex.get());
192
193         // Build an edge list from the result stream.
194         List<Edge> edges = new ArrayList<Edge>();
195         relationships.forEach(r -> edges.add(edgeFromChampRelationship(r)));
196
197         return edges;
198
199       } else {
200
201         // We couldn't find the specified vertex, so throw an exception.
202         throw new CrudException("No vertex with id " + id + " found in graph",
203             javax.ws.rs.core.Response.Status.NOT_FOUND);
204       }
205
206     } catch (ChampUnmarshallingException e) {
207
208       // Something went wrong, so throw an exception.
209       throw new CrudException(e.getMessage(),
210           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
211
212     } catch (ChampObjectNotExistsException e) {
213
214       // We couldn't find the specified vertex, so throw an exception.
215       throw new CrudException("No vertex with id " + id + " found in graph",
216           javax.ws.rs.core.Response.Status.NOT_FOUND);
217     } catch (ChampTransactionException e) {
218       throw new CrudException("Transaction error occured",
219           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
220     }
221   }
222
223
224   @Override
225   public Vertex addVertex(String type, Map<String, Object> properties) throws CrudException {
226
227     if (logger.isDebugEnabled()) {
228       logger.debug("Add/update vertex: {label: " + type
229           + " properties:" + propertiesMapToString(properties));
230     }
231
232     //Add the aai_node_type so that AAI can read the data created by gizmo
233     properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
234
235     // Create an object to represent our vertex in the format expected by the Champ library.
236     ChampObject objectToCreate = buildChampObject(type, properties);
237
238     try {
239
240       // Ask the Champ library to store our vertex, placing the returned object into a
241       // list so that we can easily put that into our result object.
242       return vertexFromChampObject(champApi.storeObject(objectToCreate),type);
243
244     } catch (ChampMarshallingException
245         | ChampSchemaViolationException
246         | ChampObjectNotExistsException 
247         | ChampTransactionException e) {
248
249       // Something went wrong - throw an exception.
250       throw new CrudException(e.getMessage(),
251           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
252     }
253   }
254
255
256   @Override
257   public Vertex updateVertex(String id, String type, Map<String, Object> properties)
258       throws CrudException {
259
260     if (logger.isDebugEnabled()) {
261       logger.debug("Update vertex with id: " + id + " with properties: "
262           + propertiesMapToString(properties));
263     }
264     //Add the aai_node_type so that AAI can read the data created by gizmo
265     properties.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
266
267     try {
268       // Now, build the updated version of the Champ Object...
269       ChampObject updateObject = buildChampObject(id, type, properties);
270       // ...and send it to the Champ library.
271       return vertexFromChampObject(champApi.replaceObject(updateObject),type);
272
273     } catch (ChampObjectNotExistsException e) {
274       throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
275     } catch (NumberFormatException | ChampMarshallingException | ChampSchemaViolationException e) {
276       throw new CrudException(e.getMessage(),
277           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
278     } catch (ChampTransactionException e) {
279       throw new CrudException("Transaction error occured",
280           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
281     }
282
283   }
284
285
286   @Override
287   public List<Vertex> getVertices(String type, Map<String, Object> filter) throws CrudException {
288
289     if (logger.isDebugEnabled()) {
290       logger.debug("Retrieve vertices with type label: " + type + " which map query parameters: "
291           + propertiesMapToString(filter));
292     }
293
294
295     filter.put(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName(), type);
296
297
298     Stream<ChampObject> retrievedVertices;
299     try {
300       retrievedVertices = champApi.queryObjects(filter);
301       
302     } catch (ChampTransactionException e) {
303       throw new CrudException("Transaction error occured",
304           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
305     }
306
307     List<Vertex> vertices = retrievedVertices
308         .map(v -> vertexFromChampObject(v,type))
309         .collect(Collectors.toList());
310
311
312     if (logger.isDebugEnabled()) {
313       logger.debug("Resulting vertex list: " + retrievedVertices);
314     }
315
316     // ...and return it to the caller.
317     return vertices;
318   }
319
320   private Object getRelKey(String id) {
321     Object key = id;
322     // convert into Long if applicable . TODO : revisit in story NUC-304
323     try {
324       key = Long.parseLong(id);
325     } catch (NumberFormatException e) {
326       // The id isn't a Long, leave it as a string
327     }
328
329     return key;
330   }
331
332   @Override
333   public Edge getEdge(String id, String type) throws CrudException {
334
335     if (logger.isDebugEnabled()) {
336       logger.debug("Get edge with id: " + id);
337     }
338
339     try {
340
341       // Request the edge from the graph db.
342       Optional<ChampRelationship> relationship = champApi.retrieveRelationship(getRelKey(id));
343
344       // Did we find it?
345       if (relationship.isPresent() && relationship.get().getType().equals(type)) {
346
347         // Yup - return the result.
348         return edgeFromChampRelationship(relationship.get());
349
350       } else {
351
352         // We didn't find an edge with the supplied id, so throw an exception.
353         throw new CrudException("No edge with id " + id + " found in graph",
354             javax.ws.rs.core.Response.Status.NOT_FOUND);
355       }
356
357     } catch (ChampUnmarshallingException | ChampTransactionException e) {
358
359       // Something went wrong, so throw an exception.
360       throw new CrudException(e.getMessage(),
361           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
362     }
363   }
364
365   @Override
366   public Edge addEdge(String type,
367                       Vertex source,
368                       Vertex target,
369                       Map<String, Object> properties) throws CrudException {
370
371     // For now, assume source and target are straight ids...
372     try {
373
374       Optional<ChampObject> sourceObject
375           = champApi.retrieveObject(Long.parseLong(source.getId().get()));
376       if (!sourceObject.isPresent() || !sourceObject.get().getType().equals(source.getType())) {
377         throw new CrudException("Error creating edge - source vertex with id " + source
378             + " does not exist in graph data base",
379             javax.ws.rs.core.Response.Status.BAD_REQUEST);
380       }
381
382       Optional<ChampObject> targetObject
383           = champApi.retrieveObject(Long.parseLong(target.getId().get()));
384       if (!targetObject.isPresent() || !targetObject.get().getType().equals(target.getType())) {
385         throw new CrudException("Error creating edge - target vertex with id " + target
386             + " does not exist in graph data base",
387             javax.ws.rs.core.Response.Status.BAD_REQUEST);
388       }
389
390       // Now, create the ChampRelationship object for our edge and store it in
391       // the graph database.
392       return edgeFromChampRelationship(
393           champApi.storeRelationship(
394               new ChampRelationship.Builder(sourceObject.get(), targetObject.get(), type)
395                   .properties(properties)
396                   .build()));
397
398     } catch (ChampMarshallingException
399         | ChampObjectNotExistsException
400         | ChampSchemaViolationException
401         | ChampRelationshipNotExistsException
402         | ChampUnmarshallingException | NumberFormatException | ChampTransactionException e) {
403
404       throw new CrudException("Error creating edge: " + e.getMessage(),
405           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
406     }
407   }
408
409
410   @Override
411   public List<Edge> getEdges(String type, Map<String, Object> filter) throws CrudException {
412
413     filter.put(ChampRelationship.ReservedPropertyKeys.CHAMP_RELATIONSHIP_TYPE.toString(), type);
414
415     Stream<ChampRelationship> retrievedRelationships;
416     try {
417       retrievedRelationships = champApi.queryRelationships(filter);
418       
419     } catch (ChampTransactionException e) {
420       throw new CrudException("Transaction error occured",
421           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
422     }
423     
424     // Process the result stream from the Champ library into an Edge list, keeping only
425     // edges of the specified type.
426     List<Edge> edges = retrievedRelationships
427         .map(r -> edgeFromChampRelationship(r))
428         .collect(Collectors.toList());
429
430     return edges;
431   }
432
433   @Override
434   public Edge updateEdge(Edge edge) throws CrudException {
435
436     if (logger.isDebugEnabled()) {
437       logger.debug("Update edge with id: " + edge.getId() + " with properties: "
438           + propertiesMapToString(edge.getProperties()));
439     }
440
441     try {
442       // Now, build the updated version of the Champ Relationship...
443       ChampRelationship updateRelationship = new ChampRelationship.Builder(
444           buildChampObject(edge.getSource().getId().get(), edge.getSource().getType(),
445               edge.getSource().getProperties()),
446           buildChampObject(edge.getTarget().getId().get(), edge.getTarget().getType(),
447               edge.getTarget().getProperties()),
448           edge.getType()).key(getRelKey(edge.getId().get()))
449           .properties(edge.getProperties()).build();
450       // ...and send it to the Champ library.
451       return edgeFromChampRelationship(champApi.replaceRelationship(updateRelationship));
452
453
454     } catch (ChampRelationshipNotExistsException ex) {
455       throw new CrudException("Not Found", javax.ws.rs.core.Response.Status.NOT_FOUND);
456     } catch (NumberFormatException | 
457              ChampUnmarshallingException | 
458              ChampMarshallingException | 
459              ChampSchemaViolationException |
460              ChampTransactionException ex) {
461
462       throw new CrudException(ex.getMessage(),
463           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
464     } 
465   }
466
467   @Override
468   public void deleteVertex(String id, String type) throws CrudException {
469
470     try {
471
472       // First, retrieve the vertex that we intend to delete.
473       Optional<ChampObject> retrievedVertex = champApi.retrieveObject(Long.parseLong(id));
474
475       // Did we find it?
476       if (!retrievedVertex.isPresent() || !retrievedVertex.get().getType().equals(type)) {
477         throw new CrudException("Failed to delete vertex with id: "
478             + id + " - vertex does not exist.",
479             javax.ws.rs.core.Response.Status.NOT_FOUND);
480       }
481
482       // Now, verify that there are no edges incident to the vertex (they must be deleted
483       // first if so).
484       Stream<ChampRelationship> relationships =
485           champApi.retrieveRelationships(retrievedVertex.get());
486
487       if (relationships.count() > 0) {
488         throw new CrudException("Attempt to delete vertex with id "
489             + id + " which has incident edges.",
490             javax.ws.rs.core.Response.Status.BAD_REQUEST);
491       }
492
493       // Finally, we can attempt to delete our vertex.
494       champApi.deleteObject(Long.parseLong(id));
495
496
497     } catch (NumberFormatException
498            | ChampUnmarshallingException
499            | ChampObjectNotExistsException 
500            | ChampTransactionException e) {
501
502       throw new CrudException(e.getMessage(),
503           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
504     }
505   }
506
507   @Override
508   public void deleteEdge(String id, String type) throws CrudException {
509
510     try {
511
512       // First, retrieve the edge that we want to delete.
513       Optional<ChampRelationship> relationshipToDelete
514           = champApi.retrieveRelationship(getRelKey(id));
515
516
517       // Did we find it?
518       if (!relationshipToDelete.isPresent() || !relationshipToDelete.get().getType().equals(type)) {
519         throw new CrudException("Failed to delete edge with id: " + id + " - edge does not exist",
520             javax.ws.rs.core.Response.Status.NOT_FOUND);
521       }
522
523       // Now we can delete the edge.
524       champApi.deleteRelationship(relationshipToDelete.get());
525
526     } catch (ChampRelationshipNotExistsException
527         | NumberFormatException
528         | ChampUnmarshallingException 
529         | ChampTransactionException e) {
530
531       throw new CrudException(e.getMessage(),
532           javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR);
533     }
534   }
535
536
537   /**
538    * This helper method generates a string representation of a properties map for
539    * logging purposes.
540    *
541    * @param properties - The properties map to be converted.
542    * @return - The log statement friendly conversion of the properties map.
543    */
544   private String propertiesMapToString(Map<String, Object> properties) {
545
546     StringBuilder sb = new StringBuilder();
547     sb.append("{");
548
549     for (String key : properties.keySet()) {
550       sb.append("(").append(key).append(" -> ").append(properties.get(key)).append(") ");
551     }
552
553     sb.append("}");
554
555     return sb.toString();
556   }
557
558
559   /**
560    * This helper method constructs a {@link ChampObject} suitable for passing to the Champ library.
561    *
562    * @param type       - The type to assign to our ChampObject
563    * @param properties - The set of properties to assign to our ChampObject
564    * @return - A populated ChampObject
565    */
566   private ChampObject buildChampObject(String type, Map<String, Object> properties) {
567
568     ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create()
569         .ofType(type)
570         .withoutKey();
571
572     for (String key : properties.keySet()) {
573       objectInProgress.withProperty(key, properties.get(key));
574     }
575     return objectInProgress.build();
576   }
577
578
579   /**
580    * This helper method constructs a {@link ChampObject} suitable for passing to the Champ library.
581    *
582    * @param id         - Unique identifier for this object.
583    * @param type       - The type to assign to our ChampObject
584    * @param properties - The set of properties to assign to our ChampObject
585    * @return - A populated ChampObject
586    */
587   private ChampObject buildChampObject(String id, String type, Map<String, Object> properties) {
588
589     ObjectBuildOrPropertiesStep objectInProgress = ChampObject.create()
590         .ofType(type)
591         .withKey(Long.parseLong(id));
592
593     for (String key : properties.keySet()) {
594       objectInProgress.withProperty(key, properties.get(key));
595     }
596     return objectInProgress.build();
597   }
598
599
600   
601   
602   private Vertex vertexFromChampObject(ChampObject champObject, String type) {
603
604     // Get the identifier for this vertex from the Champ object.
605     Object id = champObject.getKey().orElse("");
606
607     // Start building our {@link Vertex} object.
608     Vertex.Builder vertexBuilder = new Vertex.Builder(type);
609     vertexBuilder.id(id.toString());
610
611     // Convert the properties associated with the Champ object into the form expected for
612     // a Vertex object.
613     for (String key : champObject.getProperties().keySet()) {
614       vertexBuilder.property(key, champObject.getProperties().get(key));
615     }
616
617     // ...and return it.
618     return vertexBuilder.build();
619   }
620
621
622   /**
623    * This helper method converts a {@link ChampRelationship} from the Champ library into an
624    * equivalent {@link Edge} object that is understood by the CRUD Service.
625    *
626    * @param relationship - The ChampRelationship object to be converted.
627    * @return - An Edge object corresponding to the supplied ChampRelationship
628    */
629   private Edge edgeFromChampRelationship(ChampRelationship relationship) {
630
631     // Populate the edge's id, if available.
632     Object relationshipId = relationship.getKey().orElse("");
633
634     Edge.Builder edgeBuilder = new Edge.Builder(relationship.getType())
635         .id(relationshipId.toString());
636     edgeBuilder.source(vertexFromChampObject(relationship.getSource(),
637         relationship.getSource().getProperties()
638             .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
639                 ? relationship.getSource().getType()
640                 : relationship.getSource().getProperties()
641                     .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
642     edgeBuilder.target(vertexFromChampObject(relationship.getTarget(),
643         relationship.getTarget().getProperties()
644             .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()) == null
645                 ? relationship.getTarget().getType()
646                 : relationship.getTarget().getProperties()
647                     .get(org.openecomp.schema.OxmModelValidator.Metadata.NODE_TYPE.propertyName()).toString()));
648
649     for (String key : relationship.getProperties().keySet()) {
650       edgeBuilder.property(key, relationship.getProperties().get(key).toString());
651     }
652
653     return edgeBuilder.build();
654   }
655
656   /**
657    * Performs any necessary shut down operations when the DAO is no longer needed.
658    */
659   public void close() {
660
661     if (champApi != null) {
662
663       logger.info(CrudServiceMsgs.STOPPING_CHAMP_DAO);
664
665       champApi.shutdown();
666     }
667   }
668 }