cleaned up clds service code
[clamp.git] / src / main / java / org / onap / clamp / clds / service / CldsService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
6  *                             reserved.
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  * Modifications copyright (c) 2018 Nokia
21  * ===================================================================
22  * 
23  */
24
25 package org.onap.clamp.clds.service;
26
27 import com.att.eelf.configuration.EELFLogger;
28 import com.att.eelf.configuration.EELFManager;
29 import com.fasterxml.jackson.databind.JsonNode;
30 import com.fasterxml.jackson.databind.ObjectMapper;
31 import com.fasterxml.jackson.databind.node.ObjectNode;
32
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.security.GeneralSecurityException;
36 import java.util.Arrays;
37 import java.util.Date;
38 import java.util.List;
39 import java.util.Properties;
40 import java.util.UUID;
41
42 import javax.annotation.PostConstruct;
43 import javax.ws.rs.BadRequestException;
44 import javax.ws.rs.Consumes;
45 import javax.ws.rs.DefaultValue;
46 import javax.ws.rs.GET;
47 import javax.ws.rs.NotAuthorizedException;
48 import javax.ws.rs.POST;
49 import javax.ws.rs.PUT;
50 import javax.ws.rs.Path;
51 import javax.ws.rs.PathParam;
52 import javax.ws.rs.Produces;
53 import javax.ws.rs.QueryParam;
54 import javax.ws.rs.core.MediaType;
55 import javax.ws.rs.core.Response;
56 import javax.xml.transform.TransformerException;
57
58 import org.apache.camel.Produce;
59 import org.apache.commons.codec.DecoderException;
60 import org.apache.commons.lang3.StringUtils;
61 import org.json.simple.parser.ParseException;
62 import org.onap.clamp.clds.camel.CamelProxy;
63 import org.onap.clamp.clds.client.DcaeDispatcherServices;
64 import org.onap.clamp.clds.client.DcaeInventoryServices;
65 import org.onap.clamp.clds.client.req.sdc.SdcCatalogServices;
66 import org.onap.clamp.clds.config.ClampProperties;
67 import org.onap.clamp.clds.dao.CldsDao;
68 import org.onap.clamp.clds.exception.CldsConfigException;
69 import org.onap.clamp.clds.exception.policy.PolicyClientException;
70 import org.onap.clamp.clds.exception.sdc.SdcCommunicationException;
71 import org.onap.clamp.clds.model.CldsDbServiceCache;
72 import org.onap.clamp.clds.model.CldsEvent;
73 import org.onap.clamp.clds.model.CldsHealthCheck;
74 import org.onap.clamp.clds.model.CldsInfo;
75 import org.onap.clamp.clds.model.CldsModel;
76 import org.onap.clamp.clds.model.CldsModelProp;
77 import org.onap.clamp.clds.model.CldsMonitoringDetails;
78 import org.onap.clamp.clds.model.CldsServiceData;
79 import org.onap.clamp.clds.model.CldsTemplate;
80 import org.onap.clamp.clds.model.DcaeEvent;
81 import org.onap.clamp.clds.model.ValueItem;
82 import org.onap.clamp.clds.model.properties.AbstractModelElement;
83 import org.onap.clamp.clds.model.properties.ModelProperties;
84 import org.onap.clamp.clds.model.sdc.SdcResource;
85 import org.onap.clamp.clds.model.sdc.SdcServiceDetail;
86 import org.onap.clamp.clds.model.sdc.SdcServiceInfo;
87 import org.onap.clamp.clds.sdc.controller.installer.CsarInstallerImpl;
88 import org.onap.clamp.clds.transform.XslTransformer;
89 import org.onap.clamp.clds.util.JacksonUtils;
90 import org.onap.clamp.clds.util.LoggingUtils;
91 import org.onap.clamp.clds.util.ResourceFileUtil;
92 import org.springframework.beans.factory.annotation.Autowired;
93 import org.springframework.beans.factory.annotation.Value;
94 import org.springframework.http.HttpStatus;
95 import org.springframework.stereotype.Component;
96 import org.springframework.web.client.HttpClientErrorException;
97
98 /**
99  * Service to save and retrieve the CLDS model attributes.
100  */
101 @Component
102 @Path("/clds")
103 public class CldsService extends SecureServiceBase {
104
105     @Produce(uri = "direct:processSubmit")
106     private CamelProxy camelProxy;
107     protected static final EELFLogger securityLogger = EELFManager.getInstance()
108         .getSecurityLogger();
109     static final String RESOURCE_NAME = "clds-version.properties";
110     public static final String GLOBAL_PROPERTIES_KEY = "files.globalProperties";
111     private final String cldsPersmissionTypeCl;
112     private final String cldsPermissionTypeClManage;
113     private final String cldsPermissionTypeClEvent;
114     private final String cldsPermissionTypeFilterVf;
115     private final String cldsPermissionTypeTemplate;
116     private final String cldsPermissionInstance;
117     final SecureServicePermission permissionReadCl;
118     final SecureServicePermission permissionUpdateCl;
119     final SecureServicePermission permissionReadTemplate;
120     final SecureServicePermission permissionUpdateTemplate;
121
122     private final CldsDao cldsDao;
123     private final XslTransformer cldsBpmnTransformer;
124     private final ClampProperties refProp;
125     private final SdcCatalogServices sdcCatalogServices;
126     private final DcaeDispatcherServices dcaeDispatcherServices;
127     private final DcaeInventoryServices dcaeInventoryServices;
128
129     @Autowired
130     public CldsService(CldsDao cldsDao, XslTransformer cldsBpmnTransformer, ClampProperties refProp,
131         SdcCatalogServices sdcCatalogServices, DcaeDispatcherServices dcaeDispatcherServices,
132         DcaeInventoryServices dcaeInventoryServices,
133         @Value("${clamp.config.security.permission.type.cl:permission-type-cl}") String cldsPersmissionTypeCl,
134         @Value("${clamp.config.security.permission.type.cl.manage:permission-type-cl-manage}") String cldsPermissionTypeClManage,
135         @Value("${clamp.config.security.permission.type.cl.event:permission-type-cl-event}") String cldsPermissionTypeClEvent,
136         @Value("${clamp.config.security.permission.type.filter.vf:permission-type-filter-vf}") String cldsPermissionTypeFilterVf,
137         @Value("${clamp.config.security.permission.type.template:permission-type-template}") String cldsPermissionTypeTemplate,
138         @Value("${clamp.config.security.permission.instance:dev}") String cldsPermissionInstance
139     ) {
140         this.cldsDao = cldsDao;
141         this.cldsBpmnTransformer = cldsBpmnTransformer;
142         this.refProp = refProp;
143         this.sdcCatalogServices = sdcCatalogServices;
144         this.dcaeDispatcherServices = dcaeDispatcherServices;
145         this.dcaeInventoryServices = dcaeInventoryServices;
146         this.cldsPersmissionTypeCl = cldsPersmissionTypeCl;
147         this.cldsPermissionTypeClManage = cldsPermissionTypeClManage;
148         this.cldsPermissionTypeClEvent = cldsPermissionTypeClEvent;
149         this.cldsPermissionTypeFilterVf = cldsPermissionTypeFilterVf;
150         this.cldsPermissionTypeTemplate = cldsPermissionTypeTemplate;
151         this.cldsPermissionInstance = cldsPermissionInstance;
152         permissionReadCl = SecureServicePermission.create(cldsPersmissionTypeCl, cldsPermissionInstance, "read");
153         permissionUpdateCl = SecureServicePermission.create(cldsPersmissionTypeCl, cldsPermissionInstance, "update");
154         permissionReadTemplate = SecureServicePermission.create(cldsPermissionTypeTemplate, cldsPermissionInstance, "read");
155         permissionUpdateTemplate = SecureServicePermission.create(cldsPermissionTypeTemplate, cldsPermissionInstance, "update");
156     }
157
158     /*
159      * @return list of CLDS-Monitoring-Details: CLOSELOOP_NAME | Close loop name
160      * used in the CLDS application (prefix: ClosedLoop- + unique ClosedLoop ID)
161      * MODEL_NAME | Model Name in CLDS application SERVICE_TYPE_ID | TypeId
162      * returned from the DCAE application when the ClosedLoop is submitted
163      * (DCAEServiceTypeRequest generated in DCAE application). DEPLOYMENT_ID |
164      * Id generated when the ClosedLoop is deployed in DCAE. TEMPLATE_NAME |
165      * Template used to generate the ClosedLoop model. ACTION_CD | Current state
166      * of the ClosedLoop in CLDS application.
167      */
168     @GET
169     @Path("/cldsDetails")
170     @Produces(MediaType.APPLICATION_JSON)
171     public List<CldsMonitoringDetails> getCLDSDetails() {
172         Date startTime = new Date();
173         LoggingUtils.setRequestContext("CldsService: GET model details", getPrincipalName());
174         List<CldsMonitoringDetails> cldsMonitoringDetailsList = cldsDao.getCLDSMonitoringDetails();
175         // audit log
176         LoggingUtils.setTimeContext(startTime, new Date());
177         LoggingUtils.setResponseContext("0", "Get cldsDetails success", this.getClass().getName());
178         auditLogger.info("GET cldsDetails completed");
179         return cldsMonitoringDetailsList;
180     }
181
182     /*
183      * CLDS IFO service will return 3 things 1. User Name 2. CLDS code version
184      * that is currently installed from pom.xml file 3. User permissions
185      */
186     @GET
187     @Path("/cldsInfo")
188     @Produces(MediaType.APPLICATION_JSON)
189     public CldsInfo getCldsInfo() {
190         Date startTime = new Date();
191         LoggingUtils.setRequestContext("CldsService: GET cldsInfo", getPrincipalName());
192         LoggingUtils.setTimeContext(startTime, new Date());
193
194         CldsInfoProvider cldsInfoProvider = new CldsInfoProvider(this);
195         CldsInfo cldsInfo = cldsInfoProvider.getCldsInfo();
196
197         // audit log
198         LoggingUtils.setTimeContext(startTime, new Date());
199         LoggingUtils.setResponseContext("0", "Get cldsInfo success", this.getClass().getName());
200         securityLogger.info("GET cldsInfo completed");
201         return cldsInfo;
202     }
203
204     /**
205      * REST service that retrieves clds healthcheck information.
206      *
207      * @return CldsHealthCheck class containing healthcheck info
208      */
209     @GET
210     @Path("/healthcheck")
211     @Produces(MediaType.APPLICATION_JSON)
212     public Response gethealthcheck() {
213         CldsHealthCheck cldsHealthCheck = new CldsHealthCheck();
214         Date startTime = new Date();
215         LoggingUtils.setRequestContext("CldsService: GET healthcheck", "Clamp-Health-Check");
216         LoggingUtils.setTimeContext(startTime, new Date());
217         boolean healthcheckFailed = false;
218         try {
219             cldsDao.doHealthCheck();
220             cldsHealthCheck.setHealthCheckComponent("CLDS-APP");
221             cldsHealthCheck.setHealthCheckStatus("UP");
222             cldsHealthCheck.setDescription("OK");
223             LoggingUtils
224                 .setResponseContext("0", "Get healthcheck success", this.getClass().getName());
225         } catch (Exception e) {
226             healthcheckFailed = true;
227             logger.error("CLAMP application DB Error", e);
228             LoggingUtils
229                 .setResponseContext("999", "Get healthcheck failed", this.getClass().getName());
230             cldsHealthCheck.setHealthCheckComponent("CLDS-APP");
231             cldsHealthCheck.setHealthCheckStatus("DOWN");
232             cldsHealthCheck.setDescription("NOT-OK");
233         }
234         // audit log
235         LoggingUtils.setTimeContext(startTime, new Date());
236         logger.info("GET healthcheck completed");
237         if (healthcheckFailed) {
238             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(cldsHealthCheck)
239                 .build();
240         } else {
241             return Response.status(Response.Status.OK).entity(cldsHealthCheck).build();
242         }
243     }
244
245     /**
246      * REST service that retrieves BPMN for a CLDS model name from the database.
247      * This is subset of the json getModel. This is only expected to be used for
248      * testing purposes, not by the UI.
249      *
250      * @param modelName
251      * @return bpmn xml text - content of bpmn given name
252      */
253     @GET
254     @Path("/model/bpmn/{modelName}")
255     @Produces(MediaType.TEXT_XML)
256     public String getBpmnXml(@PathParam("modelName") String modelName) {
257         Date startTime = new Date();
258         LoggingUtils.setRequestContext("CldsService: GET model bpmn", getPrincipalName());
259         isAuthorized(permissionReadCl);
260         logger.info("GET bpmnText for modelName={}", modelName);
261         CldsModel model = CldsModel.retrieve(cldsDao, modelName, false);
262         // audit log
263         LoggingUtils.setTimeContext(startTime, new Date());
264         LoggingUtils.setResponseContext("0", "Get model bpmn success", this.getClass().getName());
265         auditLogger.info("GET model bpmn completed");
266         return model.getBpmnText();
267     }
268
269     /**
270      * REST service that retrieves image for a CLDS model name from the
271      * database. This is subset of the json getModel. This is only expected to
272      * be used for testing purposes, not by the UI.
273      *
274      * @param modelName
275      * @return image xml text - content of image given name
276      */
277     @GET
278     @Path("/model/image/{modelName}")
279     @Produces(MediaType.TEXT_XML)
280     public String getImageXml(@PathParam("modelName") String modelName) {
281         Date startTime = new Date();
282         LoggingUtils.setRequestContext("CldsService: GET model image", getPrincipalName());
283         isAuthorized(permissionReadCl);
284         logger.info("GET imageText for modelName={}", modelName);
285         CldsModel model = CldsModel.retrieve(cldsDao, modelName, false);
286         // audit log
287         LoggingUtils.setTimeContext(startTime, new Date());
288         LoggingUtils.setResponseContext("0", "Get model image success", this.getClass().getName());
289         auditLogger.info("GET model image completed");
290         return model.getImageText();
291     }
292
293     /**
294      * REST service that retrieves a CLDS model by name from the database.
295      *
296      * @param modelName
297      * @return clds model - clds model for the given model name
298      */
299     @GET
300     @Path("/model/{modelName}")
301     @Produces(MediaType.APPLICATION_JSON)
302     public CldsModel getModel(@PathParam("modelName") String modelName) {
303         Date startTime = new Date();
304         LoggingUtils.setRequestContext("CldsService: GET model", getPrincipalName());
305         isAuthorized(permissionReadCl);
306         logger.debug("GET model for  modelName={}", modelName);
307         CldsModel cldsModel = CldsModel.retrieve(cldsDao, modelName, false);
308         isAuthorizedForVf(cldsModel);
309         // Checking condition whether our CLDS model can call Inventory Method
310         if (cldsModel.canInventoryCall()) {
311             try {
312                 // Method to call dcae inventory and invoke insert event method
313                 dcaeInventoryServices.setEventInventory(cldsModel, getUserId());
314             } catch (Exception e) {
315                 LoggingUtils.setErrorContext("900", "Set event inventory error");
316                 logger.error("getModel set event Inventory error:" + e);
317             }
318         }
319         // audit log
320         LoggingUtils.setTimeContext(startTime, new Date());
321         LoggingUtils.setResponseContext("0", "Get model success", this.getClass().getName());
322         auditLogger.info("GET model completed");
323         return cldsModel;
324     }
325
326     /**
327      * REST service that saves a CLDS model by name in the database.
328      *
329      * @param modelName
330      */
331     @PUT
332     @Path("/model/{modelName}")
333     @Consumes(MediaType.APPLICATION_JSON)
334     @Produces(MediaType.APPLICATION_JSON)
335     public CldsModel putModel(@PathParam("modelName") String modelName, CldsModel cldsModel) {
336         Date startTime = new Date();
337         LoggingUtils.setRequestContext("CldsService: PUT model", getPrincipalName());
338         isAuthorized(permissionUpdateCl);
339         isAuthorizedForVf(cldsModel);
340         logger.info("PUT model for  modelName={}", modelName);
341         logger.info("PUT bpmnText={}", cldsModel.getBpmnText());
342         logger.info("PUT propText={}", cldsModel.getPropText());
343         logger.info("PUT imageText={}", cldsModel.getImageText());
344         cldsModel.setName(modelName);
345         fillInCldsModel(cldsModel);
346         updateAndInsertNewEvent(cldsModel.getName(), cldsModel.getControlNamePrefix(),
347             cldsModel.getEvent(),
348             CldsEvent.ACTION_MODIFY);
349         cldsModel.save(cldsDao, getUserId());
350         // audit log
351         LoggingUtils.setTimeContext(startTime, new Date());
352         LoggingUtils.setResponseContext("0", "Put model success", this.getClass().getName());
353         auditLogger.info("PUT model completed");
354         return cldsModel;
355     }
356
357     /**
358      * REST service that retrieves a list of CLDS model names.
359      *
360      * @return model names in JSON
361      */
362     @GET
363     @Path("/model-names")
364     @Produces(MediaType.APPLICATION_JSON)
365     public List<ValueItem> getModelNames() {
366         Date startTime = new Date();
367         LoggingUtils.setRequestContext("CldsService: GET model names", getPrincipalName());
368         isAuthorized(permissionReadCl);
369         logger.info("GET list of model names");
370         List<ValueItem> names = cldsDao.getBpmnNames();
371         // audit log
372         LoggingUtils.setTimeContext(startTime, new Date());
373         LoggingUtils.setResponseContext("0", "Get model names success", this.getClass().getName());
374         auditLogger.info("GET model names completed");
375         return names;
376     }
377
378     private void fillInCldsModel(CldsModel model) {
379         if (model.getTemplateName() != null) {
380             CldsTemplate template = cldsDao.getTemplate(model.getTemplateName());
381             if (template != null) {
382                 model.setTemplateId(template.getId());
383                 model.setDocText(template.getPropText());
384                 // This is to provide the Bpmn XML when Template part in UI
385                 // is
386                 // disabled
387                 model.setBpmnText(template.getBpmnText());
388             }
389         }
390     }
391
392     /**
393      * REST service that saves and processes an action for a CLDS model by name.
394      *
395      * @param action
396      * @param modelName
397      * @param test
398      * @param model
399      * @return
400      * @throws TransformerException
401      *             In case of issues when doing the XSLT of the BPMN flow
402      * @throws ParseException
403      *             In case of issues when parsing the JSON
404      * @throws GeneralSecurityException
405      *             In case of issues when decrypting the password
406      * @throws DecoderException
407      *             In case of issues with the Hex String decoding
408      */
409     @PUT
410     @Path("/action/{action}/{modelName}")
411     @Consumes(MediaType.APPLICATION_JSON)
412     @Produces(MediaType.APPLICATION_JSON)
413     public Response putModelAndProcessAction(@PathParam("action") String action,
414         @PathParam("modelName") String modelName, @QueryParam("test") String test, CldsModel model)
415         throws TransformerException, ParseException {
416         Date startTime = new Date();
417         CldsModel retrievedModel = null;
418         Boolean errorCase = false;
419         try {
420             LoggingUtils.setRequestContext("CldsService: Process model action", getPrincipalName());
421             String actionCd = action.toUpperCase();
422             SecureServicePermission permisionManage = SecureServicePermission
423                 .create(cldsPermissionTypeClManage, cldsPermissionInstance, actionCd);
424             isAuthorized(permisionManage);
425             isAuthorizedForVf(model);
426             String userId = getUserId();
427             logger.info("PUT actionCd={}", actionCd);
428             logger.info("PUT modelName={}", modelName);
429             logger.info("PUT test={}", test);
430             logger.info("PUT bpmnText={}", model.getBpmnText());
431             logger.info("PUT propText={}", model.getPropText());
432             logger.info("PUT userId={}", userId);
433             logger.info("PUT getTypeId={}", model.getTypeId());
434             logger.info("PUT deploymentId={}", model.getDeploymentId());
435             this.fillInCldsModel(model);
436             // save model to db
437             model.setName(modelName);
438             updateAndInsertNewEvent(modelName, model.getControlNamePrefix(), model.getEvent(),
439                 CldsEvent.ACTION_MODIFY);
440             model.save(cldsDao, getUserId());
441             // get vars and format if necessary
442             String prop = model.getPropText();
443             String bpmn = model.getBpmnText();
444             String docText = model.getDocText();
445             String controlName = model.getControlName();
446             String bpmnJson = cldsBpmnTransformer.doXslTransformToString(bpmn);
447             logger.info("PUT bpmnJson={}", bpmnJson);
448             // Flag indicates whether it is triggered by Validation Test button
449             // from
450             // UI
451             boolean isTest = Boolean.getBoolean(test);
452             if (!isTest) {
453                 String actionTestOverride = refProp.getStringValue("action.test.override");
454                 if (Boolean.getBoolean(actionTestOverride)) {
455                     logger.info("PUT actionTestOverride={}", actionTestOverride);
456                     logger.info("PUT override test indicator and setting it to true");
457                     isTest = true;
458                 }
459             }
460             logger.info("PUT isTest={}", isTest);
461             String insertTestEvent = refProp.getStringValue("action.insert.test.event");
462             boolean isInsertTestEvent = Boolean.getBoolean(insertTestEvent);
463
464             logger.info("PUT isInsertTestEvent={}", isInsertTestEvent);
465             // determine if requested action is permitted
466             model.validateAction(actionCd);
467             logger.info("modelProp - " + prop);
468             logger.info("docText - " + docText);
469             try {
470                 String result = camelProxy
471                     .submit(actionCd, prop, bpmnJson, modelName, controlName, docText, isTest,
472                         userId, isInsertTestEvent, model.getEvent().getActionCd());
473                 logger.info("Starting Camel flow on request, result is: ", result);
474             } catch (SdcCommunicationException | PolicyClientException | BadRequestException e) {
475                 errorCase = true;
476                 logger.error("Exception occured during invoking Camel process", e);
477             }
478             if (!actionCd.equalsIgnoreCase(CldsEvent.ACTION_DELETE)) {
479                 // refresh model info from db (get fresh event info)
480                 retrievedModel = CldsModel.retrieve(cldsDao, modelName, false);
481             }
482             if (!isTest && (actionCd.equalsIgnoreCase(CldsEvent.ACTION_SUBMIT)
483                     || actionCd.equalsIgnoreCase(CldsEvent.ACTION_RESUBMIT)
484                     || actionCd.equalsIgnoreCase(CldsEvent.ACTION_SUBMITDCAE))) {
485                 if (retrievedModel.getTemplateName().startsWith(CsarInstallerImpl.TEMPLATE_NAME_PREFIX)) {
486                     // SDC artifact case
487                     logger.info("Skipping DCAE inventory call as closed loop has been created from SDC notification");
488                     DcaeEvent dcaeEvent = new DcaeEvent();
489                     dcaeEvent.setArtifactName(retrievedModel.getControlName() + ".yml");
490                     dcaeEvent.setEvent(DcaeEvent.EVENT_DISTRIBUTION);
491                     CldsEvent.insEvent(cldsDao, dcaeEvent.getControlName(), userId, dcaeEvent.getCldsActionCd(),
492                             CldsEvent.ACTION_STATE_RECEIVED, null);
493                 } else {
494                     // This should be done only when the call to DCAE
495                     // has not yet been done. When CL comes from SDC
496                     // this is not required as the DCAE inventory call is done
497                     // during the CL deployment.
498                     dcaeInventoryServices.setEventInventory(retrievedModel, getUserId());
499                 }
500                 retrievedModel.save(cldsDao, getUserId());
501             }
502             // audit log
503             LoggingUtils.setTimeContext(startTime, new Date());
504             LoggingUtils.setResponseContext("0", "Process model action success", this.getClass().getName());
505             auditLogger.info("Process model action completed");
506         } catch (Exception e) {
507             errorCase = true;
508             logger.error("Exception occured during putModelAndProcessAction", e);
509         }
510         if (errorCase) {
511             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(retrievedModel).build();
512         }
513         return Response.status(Response.Status.OK).entity(retrievedModel).build();
514     }
515
516     /**
517      * REST service that accepts events for a model.
518      *
519      * @param test
520      * @param dcaeEvent
521      */
522     @POST
523     @Path("/dcae/event")
524     @Consumes(MediaType.APPLICATION_JSON)
525     @Produces(MediaType.APPLICATION_JSON)
526     public String postDcaeEvent(@QueryParam("test") String test, DcaeEvent dcaeEvent) {
527         Date startTime = new Date();
528         LoggingUtils.setRequestContext("CldsService: Post dcae event", getPrincipalName());
529         String userid = null;
530         // TODO: allow auth checking to be turned off by removing the permission
531         // type property
532         if (cldsPermissionTypeClEvent != null && cldsPermissionTypeClEvent.length() > 0) {
533             SecureServicePermission permissionEvent = SecureServicePermission.create(cldsPermissionTypeClEvent,
534                     cldsPermissionInstance, dcaeEvent.getEvent());
535             isAuthorized(permissionEvent);
536             userid = getUserId();
537         }
538         // Flag indicates whether it is triggered by Validation Test button from
539         // UI
540         boolean isTest = Boolean.valueOf(test);
541         int instanceCount = 0;
542         if (dcaeEvent.getInstances() != null) {
543             instanceCount = dcaeEvent.getInstances().size();
544         }
545         String msgInfo = "event=" + dcaeEvent.getEvent() + " serviceUUID=" + dcaeEvent.getServiceUUID()
546                 + " resourceUUID=" + dcaeEvent.getResourceUUID() + " artifactName=" + dcaeEvent.getArtifactName()
547                 + " instance count=" + instanceCount + " isTest=" + isTest;
548         logger.info("POST dcae event {}", msgInfo);
549         if (isTest) {
550             logger.warn("Ignorning test event from DCAE");
551         } else {
552             if (DcaeEvent.EVENT_DEPLOYMENT.equalsIgnoreCase(dcaeEvent.getEvent())) {
553                 CldsModel.insertModelInstance(cldsDao, dcaeEvent, userid);
554             } else {
555                 CldsEvent.insEvent(cldsDao, dcaeEvent.getControlName(), userid, dcaeEvent.getCldsActionCd(),
556                         CldsEvent.ACTION_STATE_RECEIVED, null);
557             }
558         }
559         // audit log
560         LoggingUtils.setTimeContext(startTime, new Date());
561         LoggingUtils.setResponseContext("0", "Post dcae event success", this.getClass().getName());
562         auditLogger.info("Post dcae event completed");
563         return msgInfo;
564     }
565
566     /**
567      * REST service that retrieves sdc services
568      *
569      * @throws GeneralSecurityException
570      *             In case of issue when decryting the SDC password
571      * @throws DecoderException
572      *             In case of issues with the decoding of the Hex String
573      */
574     @GET
575     @Path("/sdc/services")
576     @Produces(MediaType.APPLICATION_JSON)
577     public String getSdcServices() throws GeneralSecurityException, DecoderException {
578         Date startTime = new Date();
579         LoggingUtils.setRequestContext("CldsService: GET sdc services", getPrincipalName());
580         String retStr;
581         try {
582             retStr = createUiServiceFormatJson(sdcCatalogServices.getSdcServicesInformation(null));
583         } catch (IOException e) {
584             logger.error("IOException during SDC communication", e);
585             throw new SdcCommunicationException("IOException during SDC communication", e);
586         }
587         logger.info("value of sdcServices : {}", retStr);
588         // audit log
589         LoggingUtils.setTimeContext(startTime, new Date());
590         LoggingUtils.setResponseContext("0", "Get sdc services success", this.getClass().getName());
591         auditLogger.info("GET sdc services completed");
592         return retStr;
593     }
594
595     /**
596      * REST service that retrieves total properties required by UI
597      *
598      * @throws IOException
599      *             In case of issues
600      */
601     @GET
602     @Path("/properties")
603     @Produces(MediaType.APPLICATION_JSON)
604     public String getSdcProperties() throws IOException {
605         return createPropertiesObjectByUUID("{}");
606     }
607
608     /**
609      * REST service that retrieves total properties by using invariantUUID based
610      * on refresh and non refresh
611      *
612      * @throws GeneralSecurityException
613      *             In case of issues with the decryting the encrypted password
614      * @throws DecoderException
615      *             In case of issues with the decoding of the Hex String
616      * @throws IOException
617      *             In case of issue to convert CldsServiceCache to InputStream
618      */
619     @GET
620     @Path("/properties/{serviceInvariantUUID}")
621     @Produces(MediaType.APPLICATION_JSON)
622     public String getSdcPropertiesByServiceUUIDForRefresh(
623             @PathParam("serviceInvariantUUID") String serviceInvariantUUID,
624             @DefaultValue("false") @QueryParam("refresh") boolean refresh)
625             throws GeneralSecurityException, DecoderException, IOException {
626         Date startTime = new Date();
627         LoggingUtils.setRequestContext("CldsService: GET sdc properties by uuid", getPrincipalName());
628         CldsServiceData cldsServiceData = new CldsServiceData();
629         cldsServiceData.setServiceInvariantUUID(serviceInvariantUUID);
630         if (!refresh) {
631             cldsServiceData = cldsDao.getCldsServiceCache(serviceInvariantUUID);
632         }
633         if (sdcCatalogServices.isCldsSdcCacheDataExpired(cldsServiceData)) {
634             cldsServiceData = sdcCatalogServices.getCldsServiceDataWithAlarmConditions(serviceInvariantUUID);
635             cldsDao.setCldsServiceCache(new CldsDbServiceCache(cldsServiceData));
636         }
637         // filter out VFs the user is not authorized for
638         cldsServiceData.filterVfs(this);
639         // format retrieved data into properties json
640         String sdcProperties = sdcCatalogServices.createPropertiesObjectByUUID(cldsServiceData);
641         // audit log
642         LoggingUtils.setTimeContext(startTime, new Date());
643         LoggingUtils.setResponseContext("0", "Get sdc properties by uuid success", this.getClass().getName());
644         auditLogger.info("GET sdc properties by uuid completed");
645         return sdcProperties;
646     }
647
648     /**
649      * Determine if the user is authorized for a particular VF by its invariant
650      * UUID.
651      *
652      * @param vfInvariantUuid
653      * @throws NotAuthorizedException
654      * @return
655      */
656     public boolean isAuthorizedForVf(String vfInvariantUuid) {
657         if (cldsPermissionTypeFilterVf != null && !cldsPermissionTypeFilterVf.isEmpty()) {
658             SecureServicePermission permission = SecureServicePermission.create(cldsPermissionTypeFilterVf,
659                     cldsPermissionInstance, vfInvariantUuid);
660             return isAuthorized(permission);
661         } else {
662             // if CLDS_PERMISSION_TYPE_FILTER_VF property is not provided, then
663             // VF filtering is turned off
664             logger.warn("VF filtering turned off");
665             return true;
666         }
667     }
668
669     /**
670      * Determine if the user is authorized for a particular VF by its invariant
671      * UUID. If not authorized, then NotAuthorizedException is thrown.
672      *
673      * @param model
674      * @return
675      */
676     private boolean isAuthorizedForVf(CldsModel model) {
677         String vf = ModelProperties.getVf(model);
678         if (vf == null || vf.length() == 0) {
679             logger.info("VF not found in model");
680             return true;
681         } else {
682             return isAuthorizedForVf(vf);
683         }
684     }
685
686     private String createUiServiceFormatJson(String responseStr) throws IOException {
687         if (StringUtils.isBlank(responseStr)) {
688             return "";
689         }
690         ObjectMapper objectMapper = JacksonUtils.getObjectMapperInstance();
691         List<SdcServiceInfo> rawList = objectMapper.readValue(responseStr,
692                 objectMapper.getTypeFactory().constructCollectionType(List.class, SdcServiceInfo.class));
693         ObjectNode invariantIdServiceNode = objectMapper.createObjectNode();
694         ObjectNode serviceNode = objectMapper.createObjectNode();
695         logger.info("value of cldsserviceiNfolist: {}", rawList);
696         if (rawList != null && !rawList.isEmpty()) {
697             List<SdcServiceInfo> cldsSdcServiceInfoList = sdcCatalogServices.removeDuplicateServices(rawList);
698             for (SdcServiceInfo currCldsSdcServiceInfo : cldsSdcServiceInfoList) {
699                 if (currCldsSdcServiceInfo != null) {
700                     invariantIdServiceNode.put(currCldsSdcServiceInfo.getInvariantUUID(),
701                             currCldsSdcServiceInfo.getName());
702                 }
703             }
704             serviceNode.putPOJO("service", invariantIdServiceNode);
705         }
706         return serviceNode.toString();
707     }
708
709     private String createPropertiesObjectByUUID(String cldsResponseStr) throws IOException {
710         ObjectMapper mapper = JacksonUtils.getObjectMapperInstance();
711         SdcServiceDetail cldsSdcServiceDetail = mapper.readValue(cldsResponseStr, SdcServiceDetail.class);
712         ObjectNode globalPropsJson = (ObjectNode) refProp.getJsonTemplate(GLOBAL_PROPERTIES_KEY);
713         if (cldsSdcServiceDetail != null && cldsSdcServiceDetail.getUuid() != null) {
714             /**
715              * to create json with vf, alarm and locations
716              */
717             ObjectNode serviceObjectNode = createEmptyVfAlarmObject();
718             ObjectNode vfObjectNode = mapper.createObjectNode();
719             /**
720              * to create json with vf and vfresourceId
721              */
722             createVfObjectNode(vfObjectNode, cldsSdcServiceDetail.getResources());
723             serviceObjectNode.putPOJO(cldsSdcServiceDetail.getInvariantUUID(), vfObjectNode);
724             ObjectNode byServiceBasicObjetNode = mapper.createObjectNode();
725             byServiceBasicObjetNode.putPOJO("byService", serviceObjectNode);
726             /**
727              * to create json with VFC Node
728              */
729             ObjectNode emptyvfcobjectNode = createByVFCObjectNode(cldsSdcServiceDetail.getResources());
730             byServiceBasicObjetNode.putPOJO("byVf", emptyvfcobjectNode);
731             globalPropsJson.putPOJO("shared", byServiceBasicObjetNode);
732             logger.info("valuie of objNode: {}", globalPropsJson);
733         }
734         return globalPropsJson.toString();
735     }
736
737     private ObjectNode createEmptyVfAlarmObject() {
738         ObjectMapper mapper = JacksonUtils.getObjectMapperInstance();
739         ObjectNode emptyObjectNode = mapper.createObjectNode();
740         emptyObjectNode.put("", "");
741         ObjectNode vfObjectNode = mapper.createObjectNode();
742         vfObjectNode.putPOJO("vf", emptyObjectNode);
743         vfObjectNode.putPOJO("location", emptyObjectNode);
744         vfObjectNode.putPOJO("alarmCondition", emptyObjectNode);
745         ObjectNode emptyServiceObjectNode = mapper.createObjectNode();
746         emptyServiceObjectNode.putPOJO("", vfObjectNode);
747         return emptyServiceObjectNode;
748     }
749
750     private void createVfObjectNode(ObjectNode vfObjectNode2,
751         List<SdcResource> rawCldsSdcResourceList) {
752         ObjectMapper mapper = JacksonUtils.getObjectMapperInstance();
753         ObjectNode vfNode = mapper.createObjectNode();
754         vfNode.put("", "");
755         // To remove repeated resource instance name from
756         // resourceInstanceList
757         List<SdcResource> cldsSdcResourceList = sdcCatalogServices
758             .removeDuplicateSdcResourceInstances(rawCldsSdcResourceList);
759         /**
760          * Creating vf resource node using cldsSdcResource Object
761          */
762         if (cldsSdcResourceList != null && !cldsSdcResourceList.isEmpty()) {
763             for (SdcResource cldsSdcResource : cldsSdcResourceList) {
764                 if (cldsSdcResource != null && "VF".equalsIgnoreCase(cldsSdcResource.getResoucreType())) {
765                     vfNode.put(cldsSdcResource.getResourceUUID(), cldsSdcResource.getResourceName());
766                 }
767             }
768         }
769         vfObjectNode2.putPOJO("vf", vfNode);
770         /**
771          * creating location json object using properties file value
772          */
773         ObjectNode locationJsonNode;
774         try {
775             locationJsonNode = (ObjectNode) mapper
776                 .readValue(refProp.getStringValue("ui.location.default"),
777                     JsonNode.class);
778         } catch (IOException e) {
779             logger.error(
780                 "Unable to load ui.location.default JSON in clds-references.properties properly", e);
781             throw new CldsConfigException(
782                 "Unable to load ui.location.default JSON in clds-references.properties properly", e);
783         }
784         vfObjectNode2.putPOJO("location", locationJsonNode);
785         /**
786          * creating alarm json object using properties file value
787          */
788         String alarmStringValue = refProp.getStringValue("ui.alarm.default");
789         logger.info("value of alarm: {}", alarmStringValue);
790         ObjectNode alarmStringJsonNode;
791         try {
792             alarmStringJsonNode = (ObjectNode) mapper.readValue(alarmStringValue, JsonNode.class);
793         } catch (IOException e) {
794             logger
795                 .error("Unable to ui.alarm.default JSON in clds-references.properties properly", e);
796             throw new CldsConfigException(
797                 "Unable to load ui.alarm.default JSON in clds-references.properties properly", e);
798         }
799         vfObjectNode2.putPOJO("alarmCondition", alarmStringJsonNode);
800     }
801
802     private ObjectNode createByVFCObjectNode(List<SdcResource> cldsSdcResourceList) {
803         ObjectMapper mapper = JacksonUtils.getObjectMapperInstance();
804         ObjectNode emptyObjectNode = mapper.createObjectNode();
805         ObjectNode emptyvfcobjectNode = mapper.createObjectNode();
806         ObjectNode vfCObjectNode = mapper.createObjectNode();
807         vfCObjectNode.putPOJO("vfC", emptyObjectNode);
808         ObjectNode subVfCObjectNode = mapper.createObjectNode();
809         subVfCObjectNode.putPOJO("vfc", emptyObjectNode);
810         if (cldsSdcResourceList != null && !cldsSdcResourceList.isEmpty()) {
811             for (SdcResource cldsSdcResource : cldsSdcResourceList) {
812                 if (cldsSdcResource != null && "VF".equalsIgnoreCase(cldsSdcResource.getResoucreType())) {
813                     vfCObjectNode.putPOJO(cldsSdcResource.getResourceUUID(), subVfCObjectNode);
814                 }
815             }
816         }
817         emptyvfcobjectNode.putPOJO("", vfCObjectNode);
818         return emptyvfcobjectNode;
819     }
820
821     @PUT
822     @Path("/deploy/{modelName}")
823     @Consumes(MediaType.APPLICATION_JSON)
824     @Produces(MediaType.APPLICATION_JSON)
825     public Response deployModel(@PathParam("modelName") String modelName, CldsModel model) {
826         Date startTime = new Date();
827         LoggingUtils.setRequestContext("CldsService: Deploy model", getPrincipalName());
828         Boolean errorCase = false;
829         try {
830             fillInCldsModel(model);
831             String bpmnJson = cldsBpmnTransformer.doXslTransformToString(model.getBpmnText());
832             logger.info("PUT bpmnJson={}", bpmnJson);
833             SecureServicePermission permisionManage = SecureServicePermission
834                 .create(cldsPermissionTypeClManage,
835                     cldsPermissionInstance, CldsEvent.ACTION_DEPLOY);
836             isAuthorized(permisionManage);
837             isAuthorizedForVf(model);
838             ModelProperties modelProp = new ModelProperties(modelName, model.getControlName(),
839                 CldsEvent.ACTION_DEPLOY,
840                 false, bpmnJson, model.getPropText());
841             checkForDuplicateServiceVf(modelName, model.getPropText());
842             String deploymentId = "";
843             // If model is already deployed then pass same deployment id
844             if (model.getDeploymentId() != null && !model.getDeploymentId().isEmpty()) {
845                 deploymentId = model.getDeploymentId();
846             } else {
847                 deploymentId = "closedLoop_" + UUID.randomUUID() + "_deploymentId";
848             }
849             String createNewDeploymentStatusUrl = dcaeDispatcherServices
850                 .createNewDeployment(deploymentId,
851                     model.getTypeId(), modelProp.getGlobal().getDeployParameters());
852             String operationStatus = dcaeDispatcherServices
853                 .getOperationStatusWithRetry(createNewDeploymentStatusUrl);
854             if ("succeeded".equalsIgnoreCase(operationStatus)) {
855                 String artifactName = model.getControlName();
856                 if (artifactName != null) {
857                     artifactName = artifactName + ".yml";
858                 }
859                 DcaeEvent dcaeEvent = new DcaeEvent();
860                 /* set dcae events */
861                 dcaeEvent.setArtifactName(artifactName);
862                 dcaeEvent.setEvent(DcaeEvent.EVENT_DEPLOYMENT);
863                 CldsEvent.insEvent(cldsDao, dcaeEvent.getControlName(), getUserId(),
864                     dcaeEvent.getCldsActionCd(),
865                     CldsEvent.ACTION_STATE_RECEIVED, null);
866                 model.setDeploymentId(deploymentId);
867                 model.save(cldsDao, getUserId());
868             } else {
869                 logger.info("Deploy model (" + modelName + ") failed...Operation Status is - "
870                     + operationStatus);
871                 throw new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR,
872                     "Deploy model (" + modelName + ") failed...Operation Status is - "
873                         + operationStatus);
874             }
875             logger.info(
876                 "Deploy model (" + modelName + ") succeeded...Deployment Id is - " + deploymentId);
877             // audit log
878             LoggingUtils.setTimeContext(startTime, new Date());
879             LoggingUtils.setResponseContext("0", "Deploy model success", this.getClass().getName());
880             auditLogger.info("Deploy model completed");
881         } catch (Exception e) {
882             errorCase = true;
883             logger.error("Exception occured during deployModel", e);
884         }
885         if (errorCase) {
886             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(model).build();
887         }
888         return Response.status(Response.Status.OK).entity(model).build();
889     }
890
891     @PUT
892     @Path("/undeploy/{modelName}")
893     @Consumes(MediaType.APPLICATION_JSON)
894     @Produces(MediaType.APPLICATION_JSON)
895     public Response unDeployModel(@PathParam("modelName") String modelName, CldsModel model) {
896         Date startTime = new Date();
897         LoggingUtils.setRequestContext("CldsService: Undeploy model", getPrincipalName());
898         Boolean errorCase = false;
899         try {
900             SecureServicePermission permisionManage = SecureServicePermission
901                 .create(cldsPermissionTypeClManage,
902                     cldsPermissionInstance, CldsEvent.ACTION_UNDEPLOY);
903             isAuthorized(permisionManage);
904             isAuthorizedForVf(model);
905             String operationStatusUndeployUrl = dcaeDispatcherServices
906                 .deleteExistingDeployment(model.getDeploymentId(),
907                     model.getTypeId());
908             String operationStatus = dcaeDispatcherServices
909                 .getOperationStatusWithRetry(operationStatusUndeployUrl);
910             if ("succeeded".equalsIgnoreCase(operationStatus)) {
911                 String artifactName = model.getControlName();
912                 if (artifactName != null) {
913                     artifactName = artifactName + ".yml";
914                 }
915                 DcaeEvent dcaeEvent = new DcaeEvent();
916                 // set dcae events
917                 dcaeEvent.setArtifactName(artifactName);
918                 dcaeEvent.setEvent(DcaeEvent.EVENT_UNDEPLOYMENT);
919                 CldsEvent.insEvent(cldsDao, model.getControlName(), getUserId(),
920                     dcaeEvent.getCldsActionCd(),
921                     CldsEvent.ACTION_STATE_RECEIVED, null);
922                 model.setDeploymentId(null);
923                 model.save(cldsDao, getUserId());
924             } else {
925                 logger.info("Undeploy model (" + modelName + ") failed...Operation Status is - "
926                     + operationStatus);
927                 throw new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR,
928                     "Undeploy model (" + modelName + ") failed...Operation Status is - "
929                         + operationStatus);
930             }
931             logger.info("Undeploy model (" + modelName + ") succeeded.");
932             // audit log
933             LoggingUtils.setTimeContext(startTime, new Date());
934             LoggingUtils
935                 .setResponseContext("0", "Undeploy model success", this.getClass().getName());
936             auditLogger.info("Undeploy model completed");
937         } catch (Exception e) {
938             errorCase = true;
939             logger.error("Exception occured during unDeployModel", e);
940         }
941         if (errorCase) {
942             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(model).build();
943         }
944         return Response.status(Response.Status.OK).entity(model).build();
945     }
946
947     private void checkForDuplicateServiceVf(String modelName, String modelPropText)
948         throws IOException {
949         JsonNode globalNode = JacksonUtils.getObjectMapperInstance().readTree(modelPropText)
950             .get("global");
951         String service = AbstractModelElement.getValueByName(globalNode, "service");
952         List<String> resourceVf = AbstractModelElement.getValuesByName(globalNode, "vf");
953         if (service != null && resourceVf != null && !resourceVf.isEmpty()) {
954             List<CldsModelProp> cldsModelPropList = cldsDao.getDeployedModelProperties();
955             for (CldsModelProp cldsModelProp : cldsModelPropList) {
956                 JsonNode currentNode = JacksonUtils.getObjectMapperInstance()
957                     .readTree(cldsModelProp.getPropText())
958                     .get("global");
959                 String currentService = AbstractModelElement.getValueByName(currentNode, "service");
960                 List<String> currentVf = AbstractModelElement.getValuesByName(currentNode, "vf");
961                 if (currentVf != null && !currentVf.isEmpty()) {
962                     if (!modelName.equalsIgnoreCase(cldsModelProp.getName()) && service
963                         .equalsIgnoreCase(currentService)
964                         && resourceVf.get(0).equalsIgnoreCase(currentVf.get(0))) {
965                         throw new BadRequestException(
966                             "Same Service/VF already exists in " + cldsModelProp.getName()
967                                 + " model, please select different Service/VF.");
968                     }
969                 }
970             }
971         }
972     }
973
974     private void updateAndInsertNewEvent(String cldsModelName, String cldsControlNamePrfx,
975         CldsEvent event,
976         String newAction) {
977         // If model action is in submit/resubmit/distributed and user try
978         // to save then we are changing action back to create.
979         if (event != null && (CldsEvent.ACTION_SUBMIT.equalsIgnoreCase(event.getActionCd())
980             || CldsEvent.ACTION_RESUBMIT.equalsIgnoreCase(event.getActionCd())
981             || CldsEvent.ACTION_DISTRIBUTE.equalsIgnoreCase(event.getActionCd()))) {
982             CldsEvent newEvent = new CldsEvent();
983             newEvent.setUserid(getUserId());
984             newEvent.setActionCd(newAction);
985             newEvent.setActionStateCd(CldsEvent.ACTION_STATE_COMPLETED);
986             cldsDao.insEvent(cldsModelName, cldsControlNamePrfx, null, newEvent);
987         }
988     }
989 }