2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.mso.apihandlerinfra;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.sql.Timestamp;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
29 import javax.ws.rs.core.Response;
30 import javax.xml.bind.JAXBContext;
31 import javax.xml.bind.JAXBException;
32 import javax.xml.bind.Marshaller;
33 import javax.xml.bind.Unmarshaller;
34 import javax.xml.transform.OutputKeys;
35 import javax.xml.transform.Transformer;
36 import javax.xml.transform.TransformerFactory;
37 import javax.xml.transform.dom.DOMSource;
38 import javax.xml.transform.sax.SAXSource;
39 import javax.xml.transform.stream.StreamResult;
41 import org.hibernate.Query;
42 import org.hibernate.Session;
43 import org.w3c.dom.Document;
44 import org.w3c.dom.Element;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.NodeList;
47 import org.xml.sax.InputSource;
49 import org.openecomp.mso.apihandler.common.ErrorNumbers;
50 import org.openecomp.mso.apihandler.common.ValidationException;
51 import org.openecomp.mso.apihandlerinfra.volumebeans.ActionType;
52 import org.openecomp.mso.apihandlerinfra.volumebeans.VolumeInputs;
53 import org.openecomp.mso.apihandlerinfra.volumebeans.ObjectFactory;
54 import org.openecomp.mso.apihandlerinfra.volumebeans.RequestInfo;
55 import org.openecomp.mso.apihandlerinfra.volumebeans.RequestStatusType;
56 import org.openecomp.mso.apihandlerinfra.volumebeans.VolumeRequest;
57 import org.openecomp.mso.db.HibernateUtils;
58 import org.openecomp.mso.logger.MsoLogger;
59 import org.openecomp.mso.logger.MessageEnum;
60 import org.openecomp.mso.properties.MsoJavaProperties;
61 import org.openecomp.mso.requestsdb.HibernateUtilsRequestsDb;
62 import org.openecomp.mso.requestsdb.InfraActiveRequests;
63 import org.openecomp.mso.requestsdb.RequestsDatabase;
65 public class VolumeMsoInfraRequest {
67 private String requestId;
68 private String requestXML;
69 private String requestUri;
70 private RequestInfo rinfo;
71 private VolumeInputs volumeInputs;
72 private String volumeParams;
73 private ActionType action;
74 private String errorMessage;
75 private String httpResponse;
76 private String responseBody;
77 private RequestStatusType status;
78 private long startTime;
79 private long progress = Constants.PROGRESS_REQUEST_RECEIVED;
81 protected HibernateUtils hibernateUtils = new HibernateUtilsRequestsDb ();
83 private static MsoLogger msoLogger = MsoLogger.getMsoLogger (MsoLogger.Catalog.APIH);
84 private static final String NOT_PROVIDED = "not provided";
86 VolumeMsoInfraRequest (String requestId) {
87 this.requestId = requestId;
88 this.startTime = System.currentTimeMillis();
89 MsoLogger.setLogContext (requestId, null);
94 void parse (String reqXML, String version, MsoJavaProperties props) throws ValidationException {
96 msoLogger.debug ("Validating the request");
98 this.requestXML = reqXML;
100 VolumeRequest volumeReq = null;
101 boolean isWrongRootElement = false;
104 JAXBContext jaxbContext = JAXBContext.newInstance (VolumeRequest.class);
105 Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller ();
107 InputSource inputSource = new InputSource (new StringReader (reqXML));
108 SAXSource source = new SAXSource (inputSource);
110 if (reqXML.contains ("volume-request") && !reqXML.contains("vnf-request")) {
111 volumeReq = jaxbUnmarshaller.unmarshal (source, VolumeRequest.class).getValue ();
113 isWrongRootElement = true;
116 } catch (Exception e) {
117 msoLogger.error (MessageEnum.APIH_VNFREQUEST_VALIDATION_ERROR, "", "", MsoLogger.ErrorCode.DataError, "Exception when parsing reqXML", e);
118 throw new ValidationException ("format for volume request");
121 if (isWrongRootElement) {
122 msoLogger.error (MessageEnum.APIH_REQUEST_VALIDATION_ERROR_REASON, "root element is not correct", "", "", MsoLogger.ErrorCode.SchemaError, "root element <volume-request> expected");
123 throw new ValidationException ("root element <volume-request> expected");
126 if (volumeReq == null) {
127 throw new ValidationException ("volume-request");
130 this.rinfo = volumeReq.getRequestInfo ();
132 if (this.rinfo == null) {
133 throw new ValidationException ("request-info");
136 action = this.rinfo.getAction ();
137 if (action == null) {
138 throw new ValidationException ("action");
140 this.volumeInputs = volumeReq.getVolumeInputs ();
141 if (this.volumeInputs == null) {
142 throw new ValidationException ("volume-inputs");
145 // Verify that the elements correspond to the version
147 if (version.equals(Constants.SCHEMA_VERSION_V1)) {
148 if (this.volumeInputs.getBackoutOnFailure() != null || this.volumeInputs.getAicCloudRegion() != null ||
149 this.volumeInputs.getVfModuleModelName () != null || this.volumeInputs.getAsdcServiceModelVersion () != null ||
150 this.volumeInputs.getServiceInstanceId () != null || this.volumeInputs.getVnfId () != null) {
151 throw new ValidationException ("format for v1 version of volume request");
154 else if (version.equals(Constants.SCHEMA_VERSION_V2)) {
155 if (this.volumeInputs.getServiceType() != null || this.volumeInputs.getAicNodeClli() != null ||
156 this.volumeInputs.getServiceInstanceId () != null || this.volumeInputs.getVnfId () != null) {
157 throw new ValidationException ("format for v2 version of volume request");
160 else if (version.equals(Constants.SCHEMA_VERSION_V3)) {
161 if (this.volumeInputs.getServiceType() != null || this.volumeInputs.getAicNodeClli() != null) {
162 throw new ValidationException ("format for v3 version of volume request");
167 if (!InfraUtils.isActionAllowed (props, "volume", version, action.value ())) {
168 throw new ValidationException ("action allowable for version " + version + " of volume request");
174 case UPDATE_VF_MODULE_VOL:
175 case DELETE_VF_MODULE_VOL:
176 if (this.volumeInputs.getVolumeGroupId () == null) {
177 throw new ValidationException ("volume-group-id");
184 if (ActionType.CREATE.equals (action) || ActionType.CREATE_VF_MODULE_VOL.equals(action)) {
185 if (this.volumeInputs.getVolumeGroupName () == null) {
186 throw new ValidationException ("volume-group-name");
188 if (!InfraUtils.isValidHeatName(this.volumeInputs.getVolumeGroupName ())) {
189 throw new ValidationException ("volume-group-name: no value meeting heat stack name syntax requirements");
194 if (this.volumeInputs.getVnfType () == null) {
195 throw new ValidationException ("vnf-type");
200 case CREATE_VF_MODULE_VOL:
201 case UPDATE_VF_MODULE_VOL:
202 case DELETE_VF_MODULE_VOL:
203 if (this.volumeInputs.getVfModuleModelName () == null) {
204 throw new ValidationException ("vf-module-model-name");
211 if (!version.equals(Constants.SCHEMA_VERSION_V1) && this.volumeInputs.getServiceId () == null) {
212 throw new ValidationException ("service-id ");
215 if (version.equals(Constants.SCHEMA_VERSION_V1) && this.volumeInputs.getServiceType () != null && this.volumeInputs.getServiceId () != null) {
216 throw new ValidationException ("service-type or service-id ");
219 if (version.equals(Constants.SCHEMA_VERSION_V1) && this.volumeInputs.getAicNodeClli () == null) {
220 throw new ValidationException ("aic-node-clli");
223 if ((version.equals(Constants.SCHEMA_VERSION_V2) || version.equals(Constants.SCHEMA_VERSION_V3)) && (this.volumeInputs.getAicCloudRegion () == null || this.volumeInputs.getAicCloudRegion ().isEmpty())) {
224 throw new ValidationException ("aic-cloud-region");
227 if (version.equals(Constants.SCHEMA_VERSION_V3) && this.volumeInputs.getServiceInstanceId () == null) {
228 throw new ValidationException ("service-instance-id");
231 if (version.equals(Constants.SCHEMA_VERSION_V3) && this.volumeInputs.getVnfId () == null && ActionType.CREATE_VF_MODULE_VOL.equals(action)) {
232 throw new ValidationException ("vnf-id");
235 if (ActionType.CREATE.equals (action) || ActionType.CREATE_VF_MODULE_VOL.equals(action)) {
236 if (this.volumeInputs.getTenantId () == null) {
237 throw new ValidationException ("tenant-id");
242 Object vpN = volumeReq.getVolumeParams ();
245 Node node = (Node) vpN;
246 Document doc = node.getOwnerDocument ();
247 this.volumeParams = domToStr (doc);
250 msoLogger.debug ("VolumeParams: " + this.volumeParams);
253 msoLogger.debug ("Request valid");
255 // Rebuild the request string for BPEL to include request-id
256 rinfo.setRequestId (this.requestId);
257 volumeReq.setRequestInfo (rinfo);
259 StringWriter stringWriter = new StringWriter ();
261 JAXBContext jaxbContext = JAXBContext.newInstance (VolumeRequest.class);
262 Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
264 // output pretty printed
265 jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
267 jaxbMarshaller.marshal (volumeReq, stringWriter);
269 } catch (JAXBException e) {
270 msoLogger.debug ("Exception: ", e);
273 this.requestXML = stringWriter.toString ().replace("http://org.openecomp/mso/infra/volume-request",
274 "http://org.openecomp/mso/infra/vnf-request");
276 msoLogger.debug("REQUEST XML to BPEL: " + this.requestXML);
280 public void createRequestRecord (Status status) {
282 Session session = null;
285 session = hibernateUtils.getSessionFactory ().openSession ();
286 session.beginTransaction ();
288 InfraActiveRequests aq = new InfraActiveRequests ();
289 aq.setRequestId (requestId);
291 Timestamp startTimeStamp = new Timestamp (System.currentTimeMillis());
293 if (rinfo.getAction () != null) {
294 aq.setAction (rinfo.getAction ().value ());
295 aq.setRequestAction (RequestActionMap.getMappedRequestAction (rinfo.getAction ().value ()));
297 aq.setSource (rinfo.getSource ());
299 // Set up mandatory parameters
300 aq.setAction (NOT_PROVIDED);
301 aq.setRequestAction (NOT_PROVIDED);
304 aq.setRequestBody (this.requestXML);
305 aq.setRequestScope (ModelType.volumeGroup.name ());
307 if (volumeInputs != null) {
308 if (volumeInputs.getVolumeGroupId () != null) {
309 aq.setVolumeGroupId (volumeInputs.getVolumeGroupId ());
311 if (volumeInputs.getVolumeGroupName () != null) {
312 aq.setVolumeGroupName (volumeInputs.getVolumeGroupName ());
314 if (volumeInputs.getVnfType () != null) {
315 aq.setVnfType (volumeInputs.getVnfType ());
317 if (volumeInputs.getVnfId () != null) {
318 aq.setVnfId (volumeInputs.getVnfId ());
320 if (volumeInputs.getServiceInstanceId () != null) {
321 aq.setServiceInstanceId (volumeInputs.getServiceInstanceId ());
323 if (volumeInputs.getServiceType () != null) {
324 aq.setServiceType (volumeInputs.getServiceType ());
326 if (volumeInputs.getServiceId () != null) {
327 aq.setAaiServiceId (volumeInputs.getServiceId ());
329 if (volumeInputs.getAicNodeClli () != null) {
330 aq.setAicNodeClli (volumeInputs.getAicNodeClli ());
332 if (volumeInputs.getAicCloudRegion () != null) {
333 aq.setAicCloudRegion (volumeInputs.getAicCloudRegion ());
335 if (volumeInputs.getTenantId () != null) {
336 aq.setTenantId (volumeInputs.getTenantId ());
340 aq.setStartTime (startTimeStamp);
341 aq.setRequestStatus (status.toString ());
342 aq.setLastModifiedBy (Constants.MODIFIED_BY_APIHANDLER);
343 aq.setRequestType ("VOLUME");
345 if (volumeParams != null) {
346 msoLogger.debug ("Storing volumeParams: " + volumeParams);
347 aq.setVnfParams (this.volumeParams);
350 if ((status == Status.FAILED) || (status == Status.COMPLETE)) {
351 aq.setStatusMessage (this.errorMessage);
352 aq.setResponseBody (this.responseBody);
354 Timestamp endTimeStamp = new Timestamp (System.currentTimeMillis());
355 aq.setEndTime (endTimeStamp);
357 aq.setProgress (this.progress);
360 msoLogger.debug ("About to insert a record");
363 session.getTransaction ().commit ();
365 } catch (Exception e) {
366 msoLogger.error (MessageEnum.APIH_DB_INSERT_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in createRequestRecord", e);
367 if (session != null) {
370 if (!status.equals (Status.FAILED)) {
376 public void updateFinalStatus (Status status) {
379 result = RequestsDatabase.updateInfraFinalStatus(requestId, status.toString (),
380 this.errorMessage, this.progress, this.responseBody, Constants.MODIFIED_BY_APIHANDLER);
381 } catch (Exception e) {
382 msoLogger.error(MessageEnum.APIH_DB_UPDATE_EXC, e.getMessage(), "", "", MsoLogger.ErrorCode.DataError, "Exception in updateFinalStatus");
383 msoLogger.debug("Exception: ", e);
387 public Response buildResponse (int httpResponseCode, String errorCode, InfraActiveRequests inProgress) {
388 return buildResponseWithError (httpResponseCode, errorCode, inProgress, null);
391 public Response buildResponseWithError (int httpResponseCode,
393 InfraActiveRequests inProgress,
394 String errorString) {
396 ObjectFactory beansObjectFactory = new ObjectFactory ();
398 VolumeRequest vr = beansObjectFactory.createVolumeRequest ();
400 RequestInfo ri = beansObjectFactory.createRequestInfo ();
402 ri.setRequestId (requestId);
403 ri.setRequestStatus (this.status);
404 ri.setAction (this.rinfo.getAction ());
405 ri.setSource (this.rinfo.getSource ());
407 String errorMsg = null;
408 if (errorCode != null) {
409 // If error code is actually an XML error response from BPEL, treat it specially:
410 if (!Messages.errors.containsKey (errorCode)) {
411 if (errorCode.length () > 300) {
412 errorMsg = errorCode.substring (0, 299);
414 errorMsg = errorCode;
419 if (inProgress == null) {
420 if (errorCode.equals(ErrorNumbers.RECIPE_DOES_NOT_EXIST)) {
421 errorMsg = String.format (Messages.errors.get (errorCode), "volume", errorString);
424 errorMsg = String.format (Messages.errors.get (errorCode), errorString);
426 } else if (errorCode.equals (ErrorNumbers.LOCKED_CREATE_ON_THE_SAME_VNF_NAME_IN_PROGRESS)) {
427 errorMsg = String.format (Messages.errors.get (errorCode),
429 inProgress.getVnfName (),
430 inProgress.getRequestStatus (),
432 } else if (errorCode.equals (ErrorNumbers.LOCKED_SAME_ACTION_AND_VNF_ID)) {
433 errorMsg = String.format (Messages.errors.get (errorCode),
435 inProgress.getVnfId (),
436 inProgress.getRequestStatus (),
437 inProgress.getAction (),
442 ri.setStatusMessage (errorMsg);
443 this.errorMessage = errorMsg;
445 ri.setProgress ((int) this.progress);
447 Date startDate = new Date (this.startTime);
448 SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
449 String startTimeString = sdf.format (startDate);
451 ri.setStartTime (startTimeString);
453 vr.setRequestInfo (ri);
454 vr.setVolumeInputs (this.volumeInputs);
456 StringWriter stringWriter = new StringWriter ();
458 JAXBContext jaxbContext = JAXBContext.newInstance (VolumeRequest.class);
459 Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
460 jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
462 jaxbMarshaller.marshal (vr, stringWriter);
464 } catch (JAXBException e) {
465 msoLogger.debug ("Exception: ", e);
468 String response = stringWriter.toString ();
470 this.httpResponse = Integer.toString (httpResponseCode);
471 this.responseBody = response;
473 // Log the failed request into the MSO Requests database
475 return Response.status (httpResponseCode).entity (response).build ();
479 public Response buildResponseFailedValidation (int httpResponseCode, String exceptionMessage) {
481 ObjectFactory beansObjectFactory = new ObjectFactory ();
482 VolumeRequest vr = beansObjectFactory.createVolumeRequest ();
484 RequestInfo ri = beansObjectFactory.createRequestInfo ();
485 ri.setRequestId (requestId);
487 if (this.rinfo != null) {
488 if (this.rinfo.getAction () != null) {
489 ri.setAction (this.rinfo.getAction ());
491 ri.setAction (ActionType.NOT_PROVIDED);
493 if (this.rinfo.getSource () != null) {
494 ri.setSource (this.rinfo.getSource ());
497 ri.setAction (ActionType.NOT_PROVIDED);
500 // Nothing more is expected for this request
502 String errorMsg = String.format (Messages.errors.get (ErrorNumbers.REQUEST_FAILED_SCHEMA_VALIDATION
505 ri.setStatusMessage (errorMsg);
506 this.errorMessage = errorMsg;
508 ri.setProgress ((int) this.progress);
509 ri.setRequestStatus (RequestStatusType.FAILED);
510 Date startDate = new Date (this.startTime);
511 SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
512 String startTimeString = sdf.format (startDate);
514 ri.setStartTime (startTimeString);
516 vr.setRequestInfo (ri);
517 vr.setVolumeInputs (this.volumeInputs);
519 StringWriter stringWriter = new StringWriter ();
521 JAXBContext jaxbContext = JAXBContext.newInstance (VolumeRequest.class);
522 Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
524 // output pretty printed
525 jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
527 jaxbMarshaller.marshal (vr, stringWriter);
529 } catch (JAXBException e) {
530 msoLogger.debug ("Error marshalling", e);
533 String response = stringWriter.toString ();
535 this.httpResponse = Integer.toString (httpResponseCode);
536 this.responseBody = response;
538 return Response.status (httpResponseCode).entity (response).build ();
541 public String getRequestUri () {
545 public void setRequestUri (String requestUri) {
546 this.requestUri = requestUri;
549 public VolumeInputs getVolumeInputs () {
553 public RequestInfo getRequestInfo () {
557 public String getResponseBody () {
561 public void setResponseBody (String responseBody) {
562 this.responseBody = responseBody;
565 public String getHttpResponse () {
569 public void setHttpResponse (String httpResponse) {
570 this.httpResponse = httpResponse;
573 public String getRequestId () {
577 public String getRequestXML () {
581 public void setRequestXML (String requestXML) {
582 this.requestXML = requestXML;
585 public RequestStatusType getStatus () {
589 public void setStatus (RequestStatusType status) {
590 this.status = status;
594 this.progress = Constants.PROGRESS_REQUEST_COMPLETED;
597 this.progress = Constants.PROGRESS_REQUEST_IN_PROGRESS;
602 public String getServiceType () {
603 if (this.volumeInputs.getServiceType () != null)
604 return this.volumeInputs.getServiceType ();
605 if (this.volumeInputs.getServiceId () != null)
606 return this.volumeInputs.getServiceId ();
610 public static String domToStr (Document doc) {
616 StringWriter sw = new StringWriter ();
617 StreamResult sr = new StreamResult (sw);
618 TransformerFactory tf = TransformerFactory.newInstance ();
619 Transformer t = tf.newTransformer ();
620 t.setOutputProperty (OutputKeys.STANDALONE, "yes");
621 NodeList nl = doc.getDocumentElement ().getChildNodes ();
622 DOMSource source = null;
623 for (int x = 0; x < nl.getLength (); x++) {
624 Node e = nl.item (x);
625 if (e instanceof Element) {
626 source = new DOMSource (e);
630 if (source != null) {
631 t.transform (source, sr);
633 String s = sw.toString ();
639 } catch (Exception e) {
640 msoLogger.error (MessageEnum.APIH_DOM2STR_ERROR, "", "", MsoLogger.ErrorCode.AvailabilityError, "Exception in domToStr", e);