Initial OpenECOMP MSO commit
[so.git] / mso-api-handlers / mso-api-handler-infra / src / main / java / org / openecomp / mso / apihandlerinfra / NetworkMsoInfraRequest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * OPENECOMP - MSO
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.mso.apihandlerinfra;
22
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.sql.Timestamp;
26 import java.text.SimpleDateFormat;
27 import java.util.Calendar;
28 import java.util.Date;
29
30 import javax.ws.rs.core.Response;
31 import javax.xml.bind.JAXBContext;
32 import javax.xml.bind.JAXBException;
33 import javax.xml.bind.Marshaller;
34 import javax.xml.bind.Unmarshaller;
35 import javax.xml.transform.OutputKeys;
36 import javax.xml.transform.Transformer;
37 import javax.xml.transform.TransformerFactory;
38 import javax.xml.transform.dom.DOMSource;
39 import javax.xml.transform.sax.SAXSource;
40 import javax.xml.transform.stream.StreamResult;
41
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;
48
49 import org.openecomp.mso.apihandler.common.ErrorNumbers;
50 import org.openecomp.mso.apihandler.common.ValidationException;
51 import org.openecomp.mso.apihandlerinfra.networkbeans.ActionType;
52 import org.openecomp.mso.apihandlerinfra.networkbeans.NetworkInputs;
53 import org.openecomp.mso.apihandlerinfra.networkbeans.NetworkRequest;
54 import org.openecomp.mso.apihandlerinfra.networkbeans.ObjectFactory;
55 import org.openecomp.mso.apihandlerinfra.networkbeans.RequestInfo;
56 import org.openecomp.mso.apihandlerinfra.networkbeans.RequestStatusType;
57 import org.openecomp.mso.logger.MessageEnum;
58 import org.openecomp.mso.logger.MsoLogger;
59 import org.openecomp.mso.properties.MsoJavaProperties;
60 import org.openecomp.mso.requestsdb.HibernateUtil;
61 import org.openecomp.mso.requestsdb.InfraActiveRequests;
62 import org.openecomp.mso.requestsdb.RequestsDatabase;
63
64 public class NetworkMsoInfraRequest {
65
66     private String requestId;
67     private String requestXML;
68     private String requestUri;
69     private RequestInfo rinfo;
70     private NetworkInputs networkInputs;
71     private String networkParams;
72     private ActionType action;
73     private String errorMessage;
74     private String httpResponse;
75     private String responseBody;
76     private RequestStatusType status;
77     private long startTime;
78     private long progress = Constants.PROGRESS_REQUEST_RECEIVED;
79
80     private static MsoLogger msoLogger = MsoLogger.getMsoLogger (MsoLogger.Catalog.APIH);
81     private static final String NOT_PROVIDED = "not provided";
82
83     NetworkMsoInfraRequest (String requestId) {
84         this.requestId = requestId;
85         Calendar startTimeCalendar = Calendar.getInstance ();
86         this.startTime = startTimeCalendar.getTimeInMillis ();
87         MsoLogger.setLogContext (requestId, null);
88
89     }
90
91     // Parse request XML
92     void parse (String reqXML, String version, MsoJavaProperties props) throws ValidationException {
93
94         msoLogger.debug ("Validating the request");
95
96         this.requestXML = reqXML;
97
98         NetworkRequest networkReq = null;
99         boolean isWrongRootElement = false;
100
101         try {
102             JAXBContext jaxbContext = JAXBContext.newInstance (NetworkRequest.class);
103             Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller ();
104
105             InputSource inputSource = new InputSource (new StringReader (reqXML));
106             SAXSource source = new SAXSource (inputSource);
107
108             if (reqXML.contains ("network-request") && !reqXML.contains ("vnf-request")) {
109                 networkReq = jaxbUnmarshaller.unmarshal (source, NetworkRequest.class).getValue ();
110             } else {
111                 isWrongRootElement = true;
112             }
113
114         } catch (Exception e) {
115                  msoLogger.error (MessageEnum.APIH_VNFREQUEST_VALIDATION_ERROR, "", "", MsoLogger.ErrorCode.DataError, "Exception when parsing reqXML", e);
116             throw new ValidationException ("format for network request");
117         }
118
119         if (isWrongRootElement) {
120                 msoLogger.error (MessageEnum.APIH_REQUEST_VALIDATION_ERROR_REASON, "root element is not correct", "", "", MsoLogger.ErrorCode.DataError, "root element <network-request> expected");
121             throw new ValidationException ("root element <network-request> expected");
122         }
123
124         if (networkReq == null) {
125             throw new ValidationException ("network-request");
126         }
127
128         this.rinfo = networkReq.getRequestInfo ();
129
130         if (this.rinfo == null) {
131             throw new ValidationException ("request-info");
132         }
133         
134         action = this.rinfo.getAction ();
135         if (action == null) {
136             throw new ValidationException ("action");
137         }
138         
139         if (!InfraUtils.isActionAllowed (props, "network", version, action.value ())) {
140                 throw new ValidationException ("action allowable for version " + version + " of network request");              
141         }
142
143         this.networkInputs = networkReq.getNetworkInputs ();
144         if (this.networkInputs == null) {
145             throw new ValidationException ("network-inputs");
146         }
147         
148         // Verify that the elements correspond to the version
149         
150         if (version.equals(Constants.SCHEMA_VERSION_V1)) {
151                         if (this.networkInputs.getBackoutOnFailure() != null || this.networkInputs.getAicCloudRegion() != null ||
152                                         this.networkInputs.getServiceInstanceId() != null) {
153                                 throw new ValidationException ("format for v1 version of network request");
154                         }
155         }
156         else if (version.equals(Constants.SCHEMA_VERSION_V2)) {
157                         if (this.networkInputs.getServiceType() != null || this.networkInputs.getAicNodeClli() != null ||
158                                         this.networkInputs.getServiceInstanceId() != null) {
159                                 throw new ValidationException ("format for v2 version of network request");
160                         }
161         }
162         else if (version.equals(Constants.SCHEMA_VERSION_V3)) {
163                 if (this.networkInputs.getServiceType() != null || this.networkInputs.getAicNodeClli() != null) {
164                         throw new ValidationException ("format for v3 version of network request");
165                 }
166     }
167
168         switch (action) {            
169             case UPDATE:
170             case DELETE:
171                 if (this.networkInputs.getNetworkId () == null) {
172                     throw new ValidationException ("network-id");
173                 }
174                 break;
175             default:
176                 break;
177         }
178
179         if (ActionType.CREATE.equals (action) && this.networkInputs.getNetworkName () == null) {
180             throw new ValidationException ("network-name");
181         }
182
183         if (this.networkInputs.getNetworkType () == null) {
184             throw new ValidationException ("network-type");
185         }
186         
187         if (!version.equals(Constants.SCHEMA_VERSION_V1) && this.networkInputs.getServiceId () == null) {
188                 throw new ValidationException ("service-id ");
189         }
190         
191         if (this.networkInputs.getServiceType () != null && this.networkInputs.getServiceId () != null) {
192                 throw new ValidationException ("service-type or service-id ");
193         }
194         
195         if (version.equals(Constants.SCHEMA_VERSION_V1) && this.networkInputs.getAicNodeClli () == null) {
196                 throw new ValidationException ("aic-node-clli");
197         }
198         
199         if ((version.equals (Constants.SCHEMA_VERSION_V2) || version.equals (Constants.SCHEMA_VERSION_V3)) && (this.networkInputs.getAicCloudRegion () == null || this.networkInputs.getAicCloudRegion ().isEmpty())) {
200                 throw new ValidationException ("aic-cloud-region");
201         }
202         
203         if (version.equals(Constants.SCHEMA_VERSION_V3) && this.networkInputs.getServiceInstanceId () == null) {
204                 throw new ValidationException ("service-instance-id");
205         }
206
207         if (ActionType.CREATE.equals (action)) {
208             if (this.networkInputs.getTenantId () == null) {
209                 throw new ValidationException ("tenant-id");
210             }
211         }
212
213         
214         Object vpN = networkReq.getNetworkParams ();
215
216         if (vpN != null) {
217             Node node = (Node) vpN;
218             Document doc = node.getOwnerDocument ();
219             this.networkParams = domToStr (doc);
220         }
221
222         msoLogger.debug ("NetworkParams: " + this.networkParams);
223
224         msoLogger.debug ("Request valid");
225
226         // Rebuild the request string for BPEL to include request-id
227         rinfo.setRequestId (this.requestId);
228         networkReq.setRequestInfo (rinfo);
229
230         StringWriter stringWriter = new StringWriter ();
231         try {
232             JAXBContext jaxbContext = JAXBContext.newInstance (NetworkRequest.class);
233             Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
234
235             // output pretty printed
236             jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
237
238             jaxbMarshaller.marshal (networkReq, stringWriter);
239
240         } catch (JAXBException e) {
241             msoLogger.debug ("Exception: ", e);
242         }
243
244         this.requestXML = stringWriter.toString ().replace ("http://ecomp.att.com/mso/infra/network-request",
245                                                             "http://ecomp.att.com/mso/infra/vnf-request");
246         msoLogger.debug("REQUEST XML to BPEL: " + this.requestXML);
247
248     }
249
250     public void createRequestRecord (Status status) {
251
252         long startTime = System.currentTimeMillis ();
253
254         Session session = null;
255         try {
256
257             session = HibernateUtil.getSessionFactory ().openSession ();
258             session.beginTransaction ();
259
260             InfraActiveRequests aq = new InfraActiveRequests ();
261             aq.setRequestId (requestId);
262
263             Timestamp startTimeStamp = new Timestamp (Calendar.getInstance ().getTimeInMillis ());
264             if (rinfo != null) {
265                 if (rinfo.getAction () != null) {
266                     aq.setAction (rinfo.getAction ().value ());
267                     aq.setRequestAction (RequestActionMap.getMappedRequestAction (rinfo.getAction ().value ()));
268                 }
269                 aq.setSource (rinfo.getSource ());
270             } else {
271                 // Set up mandatory parameters
272                 aq.setAction (NOT_PROVIDED);
273                 aq.setRequestAction (NOT_PROVIDED);
274             }
275
276             aq.setRequestBody (this.requestXML);
277             aq.setRequestScope (ModelType.network.name ());
278
279             if (networkInputs != null) {
280                 if (networkInputs.getNetworkId () != null) {
281                     aq.setVnfId (networkInputs.getNetworkId ());
282                 }
283                 if (networkInputs.getNetworkName () != null) {
284                     aq.setVnfName (networkInputs.getNetworkName ());
285                 }
286                 if (networkInputs.getNetworkType () != null) {
287                     aq.setVnfType (networkInputs.getNetworkType ());
288                 }
289                 if (networkInputs.getServiceInstanceId () != null) {
290                     aq.setServiceInstanceId (networkInputs.getServiceInstanceId ());
291                 }
292                 if (networkInputs.getServiceType () != null) {
293                     aq.setServiceType (networkInputs.getServiceType ());
294                 }
295                 if (networkInputs.getServiceId () != null) {
296                     aq.setServiceType (networkInputs.getServiceId ());
297                 }
298                 if (networkInputs.getAicNodeClli () != null) {
299                     aq.setAicNodeClli (networkInputs.getAicNodeClli ());
300                 }
301                 if (networkInputs.getTenantId () != null) {
302                     aq.setTenantId (networkInputs.getTenantId ());
303                 }
304                 if (networkInputs.getProvStatus () != null) {
305                     aq.setProvStatus (networkInputs.getProvStatus ());
306                 }
307
308             }
309             aq.setStartTime (startTimeStamp);
310             aq.setRequestStatus (status.toString ());
311             aq.setLastModifiedBy (Constants.MODIFIED_BY_APIHANDLER);
312             aq.setRequestType ("NETWORK");
313
314             if (networkParams != null) {
315                 msoLogger.debug ("Storing networkParams: " + networkParams);
316                 aq.setVnfParams (this.networkParams);
317             }
318
319             if ((status == Status.FAILED) || (status == Status.COMPLETE)) {
320                 aq.setStatusMessage (this.errorMessage);
321                 aq.setResponseBody (this.responseBody);
322
323                 Calendar endTime = Calendar.getInstance ();
324                 Timestamp endTimeStamp = new Timestamp (endTime.getTimeInMillis ());
325                 aq.setEndTime (endTimeStamp);                
326             } 
327             aq.setProgress (this.progress);
328             
329
330             msoLogger.debug ("About to insert a record");
331
332             session.save (aq);
333             session.getTransaction ().commit ();
334             session.close ();
335             msoLogger.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully", "RequestDB", "saveRequest", null);
336
337         } catch (Exception e) {
338                 msoLogger.error (MessageEnum.APIH_DB_INSERT_EXC, "", "", MsoLogger.ErrorCode.SchemaError, "Exception in createRequestRecord", e);
339             msoLogger.recordMetricEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DBAccessError, e.getMessage (), "RequestDB", "saveRequest", null);
340             if (session != null) {
341                 session.close ();
342             }
343             if (!status.equals (Status.FAILED)) {
344                 throw e;
345             }
346         }
347     }
348
349     public void updateFinalStatus (Status status) {
350         try {
351             RequestsDatabase.updateInfraFinalStatus (requestId,
352                                                      status.toString (),
353                                                      this.errorMessage,
354                                                      this.progress,
355                                                      this.responseBody,
356                                                      Constants.MODIFIED_BY_APIHANDLER);
357         } catch (Exception e) {
358                 msoLogger.error (MessageEnum.APIH_DB_UPDATE_EXC, e.getMessage (), "", "", MsoLogger.ErrorCode.SchemaError, "Exception in updateFinalStatus");
359             msoLogger.debug ("Exception: ", e);
360         }
361     }
362
363     public Response buildResponse (int httpResponseCode, String errorCode, InfraActiveRequests inProgress) {
364         return buildResponseWithError (httpResponseCode, errorCode, inProgress, null);
365     }
366
367     public Response buildResponseWithError (int httpResponseCode,
368                                             String errorCode,
369                                             InfraActiveRequests inProgress,
370                                             String errorString) {
371
372         ObjectFactory beansObjectFactory = new ObjectFactory ();
373
374         NetworkRequest vr = beansObjectFactory.createNetworkRequest ();
375
376         RequestInfo ri = beansObjectFactory.createRequestInfo ();
377
378         ri.setRequestId (requestId);
379         ri.setRequestStatus (this.status);
380         ri.setAction (this.rinfo.getAction ());
381         ri.setSource (this.rinfo.getSource ());
382
383         String errorMsg = null;
384         if (errorCode != null) {
385             // If error code is actually an XML error response from BPEL, treat it specially:
386             if (!Messages.errors.containsKey (errorCode)) {
387                 if (errorCode.length () > 300) {
388                     errorMsg = errorCode.substring (0, 299);
389                 } else {
390                     errorMsg = errorCode;
391                 }
392
393             } else {
394
395                 if (inProgress == null) {
396                     if (errorCode.equals (ErrorNumbers.RECIPE_DOES_NOT_EXIST)) {
397                         errorMsg = String.format (Messages.errors.get (errorCode), "network", errorString);
398                     } else {
399                         errorMsg = String.format (Messages.errors.get (errorCode), errorString);
400                     }
401                 } else if (errorCode.equals (ErrorNumbers.LOCKED_CREATE_ON_THE_SAME_VNF_NAME_IN_PROGRESS)) {
402                     errorMsg = String.format (Messages.errors.get (errorCode),
403                                               "network",
404                                               inProgress.getVnfName (),
405                                               inProgress.getRequestStatus (),
406                                               "network");
407                 } else if (errorCode.equals (ErrorNumbers.LOCKED_SAME_ACTION_AND_VNF_ID)) {
408                     errorMsg = String.format (Messages.errors.get (errorCode),
409                                               "network",
410                                               inProgress.getVnfId (),
411                                               inProgress.getRequestStatus (),
412                                               inProgress.getAction (),
413                                               "network");
414                 }
415             }
416
417             ri.setStatusMessage (errorMsg);
418             this.errorMessage = errorMsg;
419         }
420         ri.setProgress ((int) this.progress);
421
422         Date startDate = new Date (this.startTime);
423         SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
424         String startTimeString = sdf.format (startDate);
425
426         ri.setStartTime (startTimeString);
427
428         vr.setRequestInfo (ri);
429         vr.setNetworkInputs (this.networkInputs);
430
431         StringWriter stringWriter = new StringWriter ();
432         try {
433             JAXBContext jaxbContext = JAXBContext.newInstance (NetworkRequest.class);
434             Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
435             jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
436
437             jaxbMarshaller.marshal (vr, stringWriter);
438
439         } catch (JAXBException e) {
440             msoLogger.debug ("Exception: ", e);
441         }
442
443         String response = stringWriter.toString ();
444
445         this.httpResponse = Integer.toString (httpResponseCode);
446         this.responseBody = response;
447
448         // Log the failed request into the MSO Requests database
449
450         return Response.status (httpResponseCode).entity (response).build ();
451
452     }
453
454     public Response buildResponseFailedValidation (int httpResponseCode, String exceptionMessage) {
455
456         ObjectFactory beansObjectFactory = new ObjectFactory ();
457         NetworkRequest vr = beansObjectFactory.createNetworkRequest ();
458
459         RequestInfo ri = beansObjectFactory.createRequestInfo ();
460         ri.setRequestId (requestId);
461
462         if (this.rinfo != null) {
463             if (this.rinfo.getAction () != null) {
464                 ri.setAction (this.rinfo.getAction ());
465             } else {
466                 ri.setAction (ActionType.NOT_PROVIDED);
467             }
468             if (this.rinfo.getSource () != null) {
469                 ri.setSource (this.rinfo.getSource ());
470             }
471         } else {
472             ri.setAction (ActionType.NOT_PROVIDED);
473         }
474
475         // Nothing more is expected for this request
476
477         String errorMsg = String.format (Messages.errors.get (ErrorNumbers.REQUEST_FAILED_SCHEMA_VALIDATION
478                                                               + "_service"),
479                                          exceptionMessage);
480         ri.setStatusMessage (errorMsg);
481         this.errorMessage = errorMsg;
482
483         ri.setProgress ((int) this.progress);
484         ri.setRequestStatus (RequestStatusType.FAILED);
485         Date startDate = new Date (this.startTime);
486         SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
487         String startTimeString = sdf.format (startDate);
488
489         ri.setStartTime (startTimeString);
490
491         vr.setRequestInfo (ri);
492         vr.setNetworkInputs (this.networkInputs);
493
494         StringWriter stringWriter = new StringWriter ();
495         try {
496             JAXBContext jaxbContext = JAXBContext.newInstance (NetworkRequest.class);
497             Marshaller jaxbMarshaller = jaxbContext.createMarshaller ();
498
499             // output pretty printed
500             jaxbMarshaller.setProperty (Marshaller.JAXB_FORMATTED_OUTPUT, true);
501
502             jaxbMarshaller.marshal (vr, stringWriter);
503
504         } catch (JAXBException e) {
505             msoLogger.debug ("Error marshalling", e);
506         }
507
508         String response = stringWriter.toString ();
509
510         this.httpResponse = Integer.toString (httpResponseCode);
511         this.responseBody = response;
512
513         return Response.status (httpResponseCode).entity (response).build ();
514     }
515
516     public String getRequestUri () {
517         return requestUri;
518     }
519
520     public void setRequestUri (String requestUri) {
521         this.requestUri = requestUri;
522     }
523
524     public NetworkInputs getNetworkInputs () {
525         return networkInputs;
526     }
527
528     public RequestInfo getRequestInfo () {
529         return rinfo;
530     }
531
532     public String getResponseBody () {
533         return responseBody;
534     }
535
536     public void setResponseBody (String responseBody) {
537         this.responseBody = responseBody;
538     }
539
540     public String getHttpResponse () {
541         return httpResponse;
542     }
543
544     public void setHttpResponse (String httpResponse) {
545         this.httpResponse = httpResponse;
546     }
547
548     public String getRequestId () {
549         return requestId;
550     }
551
552     public String getRequestXML () {
553         return requestXML;
554     }
555
556     public void setRequestXML (String requestXML) {
557         this.requestXML = requestXML;
558     }
559
560     public RequestStatusType getStatus () {
561         return status;
562     }
563
564     public void setStatus (RequestStatusType status) {
565         this.status = status;
566         switch (status) {
567         case FAILED:
568         case COMPLETE:
569                 this.progress = Constants.PROGRESS_REQUEST_COMPLETED;
570                 break;
571         case IN_PROGRESS:
572                 this.progress = Constants.PROGRESS_REQUEST_IN_PROGRESS;
573                 break;
574         }
575     }
576     
577     public String getServiceType () {
578         if (this.networkInputs.getServiceType () != null) 
579                 return this.networkInputs.getServiceType ();
580         if (this.networkInputs.getServiceId () != null) 
581                 return this.networkInputs.getServiceId ();
582         return null;
583     }
584
585     public static String domToStr (Document doc) {
586         if (doc == null) {
587             return null;
588         }
589
590         try {
591             StringWriter sw = new StringWriter ();
592             StreamResult sr = new StreamResult (sw);
593             TransformerFactory tf = TransformerFactory.newInstance ();
594             Transformer t = tf.newTransformer ();
595             t.setOutputProperty (OutputKeys.STANDALONE, "yes");
596             NodeList nl = doc.getDocumentElement ().getChildNodes ();
597             DOMSource source = null;
598             for (int x = 0; x < nl.getLength (); x++) {
599                 Node e = nl.item (x);
600                 if (e instanceof Element) {
601                     source = new DOMSource (e);
602                     break;
603                 }
604             }
605             if (source != null) {
606                 t.transform (source, sr);
607
608                 String s = sw.toString ();
609                 return s;
610             }
611
612             return null;
613
614         } catch (Exception e) {
615                 msoLogger.error (MessageEnum.APIH_DOM2STR_ERROR, "", "", MsoLogger.ErrorCode.DataError, "Exception in domToStr", e);
616         }
617         return null;
618     }
619 }