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