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.aai.logging;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringWriter;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
32 import java.util.Map.Entry;
33 import java.util.Properties;
35 import javax.ws.rs.core.MediaType;
36 import javax.xml.bind.JAXBContext;
37 import javax.xml.bind.Marshaller;
39 import org.apache.commons.lang.StringUtils;
42 import org.openecomp.aai.exceptions.AAIException;
43 import org.openecomp.aai.logging.LoggingContext.StatusCode;
44 import org.openecomp.aai.util.AAIConstants;
45 import org.openecomp.aai.util.MapperUtil;
46 import com.att.eelf.configuration.EELFLogger;
47 import com.att.eelf.configuration.EELFManager;
51 * This classes loads the application error properties file
52 * and provides a method that returns an ErrorObject
56 public class ErrorLogHelper {
58 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class);
59 private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject> ();
64 } catch (IOException e) {
65 throw new RuntimeException("Failed to load error.properties file", e);
66 } catch (ErrorObjectFormatException e) {
67 throw new RuntimeException("Failed to parse error.properties file", e);
73 * @throws ErrorObjectFormatException
74 * @throws Exception the exception
76 public static void loadProperties() throws IOException, ErrorObjectFormatException {
77 final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties";
78 final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
79 final Properties properties = new Properties();
84 try (final FileInputStream fis = new FileInputStream(filePath)) {
89 for (Entry<Object, Object> entry : properties.entrySet()) {
90 final String key = (String) entry.getKey();
91 final String value = (String) entry.getValue();
92 final String[] errorProperties = value.split(":");
94 if (errorProperties.length != 7) throw new ErrorObjectFormatException();
96 final ErrorObject errorObject = new ErrorObject();
98 errorObject.setDisposition(errorProperties[0].trim());
99 errorObject.setCategory(errorProperties[1].trim());
100 errorObject.setSeverity(errorProperties[2].trim());
101 errorObject.setErrorCode(errorProperties[3].trim());
102 errorObject.setHTTPResponseCode(errorProperties[4].trim());
103 errorObject.setRESTErrorCode(errorProperties[5].trim());
104 errorObject.setErrorText(errorProperties[6].trim());
106 ERROR_OBJECTS.put(key, errorObject);
111 * Logs a known A&AI exception (i.e. one that can be found in error.properties)
113 * @param key The key for the error in the error.properties file
114 * @throws IOException
115 * @throws ErrorObjectNotFoundException
116 * @throws ErrorObjectFormatException
118 public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException {
120 if (code == null) throw new IllegalArgumentException("Key cannot be null");
122 final ErrorObject errorObject = ERROR_OBJECTS.get(code);
124 if (errorObject == null) {
125 LOGGER.warn("Unknown AAIException with code=" + code + ". Using default AAIException");
126 return ERROR_OBJECTS.get(AAIException.DEFAULT_EXCEPTION_CODE);
133 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
134 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
135 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
136 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
137 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
138 * @param variables optional list of variables to flesh out text in error string
139 * @return appropriately formatted JSON response per the REST API spec.
140 * @throws ErrorObjectFormatException
141 * @throws ErrorObjectNotFoundException
142 * @throws IOException
145 public static String getRESTAPIErrorResponse(AAIException are, ArrayList<String> variables) {
146 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
147 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
149 return getRESTAPIErrorResponse(acceptHeaders, are, variables);
153 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
154 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
155 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
156 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
158 * @param acceptHeadersOrig the accept headers orig
159 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
160 * @param variables optional list of variables to flesh out text in error string
161 * @return appropriately formatted JSON response per the REST API spec.
162 * @throws ErrorObjectFormatException
163 * @throws ErrorObjectNotFoundException
164 * @throws IOException
166 public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
169 StringBuilder text = new StringBuilder();
170 String response = null;
172 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
173 // we might have an exception but no accept header, so we'll set default to JSON
174 boolean foundValidAcceptHeader = false;
175 for (MediaType mt : acceptHeadersOrig) {
176 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt) ||
177 MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) {
178 acceptHeaders.add(mt);
179 foundValidAcceptHeader = true;
182 if (foundValidAcceptHeader == false) {
183 // override the exception, client needs to set an appropriate Accept header
184 are = new AAIException("AAI_4014");
185 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
188 final ErrorObject eo = are.getErrorObject();
190 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
192 ErrorObject restErrorObject;
195 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
196 } catch (ErrorObjectNotFoundException e) {
197 LOGGER.warn("Failed to find related error object AAI_" + restErrorCode + " for error object " + eo.getErrorCode() + "; using AAI_" + restErrorCode);
198 restErrorObject = eo;
201 text.append(restErrorObject.getErrorText());
203 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
204 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
205 // error, are ordered based on the error string.
206 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
207 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
209 if (variables == null)
211 variables = new ArrayList<String>();
214 if (variables.size() < localDataIndex) {
215 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
216 while (variables.size() < localDataIndex) {
217 variables.add("null");
221 // This will put the error code and error text into the right positions
222 if (are.getMessage() == null || are.getMessage().length() == 0) {
223 variables.add(localDataIndex++, eo.getErrorText());
226 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
228 variables.add(localDataIndex, eo.getErrorCodeString());
230 for (MediaType mediaType : acceptHeaders) {
231 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
232 JAXBContext context = null;
234 if(eo.getCategory().equals("1")) {
236 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
237 Marshaller m = context.createMarshaller();
238 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
239 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
241 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
242 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
243 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
244 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
245 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
247 policyException.setMessageId("POL" + eo.getRESTErrorCode());
248 policyException.setText(text.toString());
249 for (int i=0;i<variables.size();i++)
251 polvariables.getVariable().add(variables.get(i));
253 policyException.setVariables(polvariables);
254 requestError.setPolicyException(policyException);
255 fault.setRequestError(requestError);
257 StringWriter sw = new StringWriter();
258 m.marshal(fault, sw);
260 response = sw.toString();
264 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
265 Marshaller m = context.createMarshaller();
266 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
267 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
269 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
270 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
271 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
272 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
273 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
274 serviceException.setMessageId("SVC" + eo.getRESTErrorCode());
275 serviceException.setText(text.toString());
276 for (int i=0;i<variables.size();i++)
278 svcvariables.getVariable().add(variables.get(i));
280 serviceException.setVariables(svcvariables);
281 requestError.setServiceException(serviceException);
282 fault.setRequestError(requestError);
284 StringWriter sw = new StringWriter();
285 m.marshal(fault, sw);
287 response = sw.toString();
290 } catch (Exception ex) {
291 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
296 if(eo.getCategory().equals("1")) {
297 org.openecomp.aai.domain.restPolicyException.RESTResponse restresp = new org.openecomp.aai.domain.restPolicyException.RESTResponse();
298 org.openecomp.aai.domain.restPolicyException.RequestError reqerr = new org.openecomp.aai.domain.restPolicyException.RequestError();
299 org.openecomp.aai.domain.restPolicyException.PolicyException polexc = new org.openecomp.aai.domain.restPolicyException.PolicyException();
300 polexc.setMessageId("POL" + eo.getRESTErrorCode());
301 polexc.setText(text.toString());
302 polexc.setVariables(variables);
303 reqerr.setPolicyException(polexc);
304 restresp.setRequestError(reqerr);
305 response = (MapperUtil.writeAsJSONString((Object) restresp));
308 org.openecomp.aai.domain.restServiceException.RESTResponse restresp = new org.openecomp.aai.domain.restServiceException.RESTResponse();
309 org.openecomp.aai.domain.restServiceException.RequestError reqerr = new org.openecomp.aai.domain.restServiceException.RequestError();
310 org.openecomp.aai.domain.restServiceException.ServiceException svcexc = new org.openecomp.aai.domain.restServiceException.ServiceException();
311 svcexc.setMessageId("SVC" + eo.getRESTErrorCode());
312 svcexc.setText(text.toString());
313 svcexc.setVariables(variables);
314 reqerr.setServiceException(svcexc);
315 restresp.setRequestError(reqerr);
316 response = (MapperUtil.writeAsJSONString((Object) restresp));
318 } catch (AAIException ex) {
319 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
329 * Gets the RESTAPI error response with logging.
331 * @param acceptHeadersOrig the accept headers orig
333 * @param variables the variables
334 * @param logline the logline
335 * @return the RESTAPI error response with logging
336 * @throws ErrorObjectFormatException
337 * @throws ErrorObjectNotFoundException
338 * @throws IOException
340 public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
341 String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables);
343 LOGGER.error(are.getMessage(), are);
349 * Gets the RESTAPI info response.
351 * @param acceptHeaders the accept headers
352 * @param areList the are list
353 * @return the RESTAPI info response
354 * @throws ErrorObjectFormatException
355 * @throws ErrorObjectNotFoundException
356 * @throws IOException
358 public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException,ArrayList<String>> areList) {
360 Object respObj = null;
362 org.openecomp.aai.domain.restResponseInfo.ObjectFactory factory = new org.openecomp.aai.domain.restResponseInfo.ObjectFactory();
363 org.openecomp.aai.domain.restResponseInfo.Info info = factory.createInfo();
364 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages responseMessages = factory.createInfoResponseMessages();
365 Iterator<Map.Entry<AAIException, ArrayList<String>>> it = areList.entrySet().iterator();
367 while (it.hasNext()) {
368 Map.Entry<AAIException,ArrayList<String>> pair = (Map.Entry<AAIException, ArrayList<String>>)it.next();
369 AAIException are = pair.getKey();
370 ArrayList<String> variables = pair.getValue();
372 StringBuilder text = new StringBuilder();
374 ErrorObject eo = are.getErrorObject();
376 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
377 ErrorObject restErrorObject;
379 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+String.format("%04d", restErrorCode));
380 } catch (ErrorObjectNotFoundException e) {
381 restErrorObject = eo;
383 text.append(restErrorObject.getErrorText());
385 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
386 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
387 // error, are ordered based on the error string.
388 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
389 text.append(" (msg=%").append(localDataIndex+1).append(") (rc=%").append(localDataIndex+2).append(")");
391 if (variables == null)
393 variables = new ArrayList<String>();
396 if (variables.size() < localDataIndex) {
397 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
398 while (variables.size() < localDataIndex) {
399 variables.add("null");
403 // This will put the error code and error text into the right positions
404 if (are.getMessage() == null) {
405 variables.add(localDataIndex++, eo.getErrorText());
408 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
410 variables.add(localDataIndex, eo.getErrorCodeString());
413 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage responseMessage = factory.createInfoResponseMessagesResponseMessage();
414 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage.Variables infovariables = factory.createInfoResponseMessagesResponseMessageVariables();
416 responseMessage.setMessageId("INF" + eo.getRESTErrorCode());
417 responseMessage.setText(text.toString());
418 for (int i=0;i<variables.size();i++)
420 infovariables.getVariable().add(variables.get(i));
423 responseMessage.setVariables(infovariables);
424 responseMessages.getResponseMessage().add(responseMessage);
426 } catch (Exception ex) {
427 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
431 info.setResponseMessages(responseMessages);
432 respObj = (Object) info;
439 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
440 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
441 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
442 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
443 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
444 * @param variables optional list of variables to flesh out text in error string
445 * @return appropriately formatted JSON response per the REST API spec.
446 * @throws ErrorObjectFormatException
447 * @throws ErrorObjectNotFoundException
448 * @throws IOException
450 public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) {
452 StringBuilder text = new StringBuilder();
453 String response = null;
454 JAXBContext context = null;
456 ErrorObject eo = are.getErrorObject();
458 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
459 ErrorObject restErrorObject;
461 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
462 } catch (ErrorObjectNotFoundException e) {
463 restErrorObject = eo;
466 text.append(restErrorObject.getErrorText());
468 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
469 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
470 // error, are ordered based on the error string.
471 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
472 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
474 if (variables == null)
476 variables = new ArrayList<String>();
479 if (variables.size() < localDataIndex) {
480 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
481 while (variables.size() < localDataIndex) {
482 variables.add("null");
486 // This will put the error code and error text into the right positions
487 if (are.getMessage() == null) {
488 variables.add(localDataIndex++, eo.getErrorText());
491 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
493 variables.add(localDataIndex, eo.getErrorCodeString());
496 if(eo.getCategory().equals("1")) {
498 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
499 Marshaller m = context.createMarshaller();
500 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
501 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
503 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
504 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
505 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
506 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
507 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
509 policyException.setMessageId("POL" + eo.getRESTErrorCode());
510 policyException.setText(text.toString());
511 for (int i=0;i<variables.size();i++)
513 polvariables.getVariable().add(variables.get(i));
515 policyException.setVariables(polvariables);
516 requestError.setPolicyException(policyException);
517 fault.setRequestError(requestError);
519 StringWriter sw = new StringWriter();
520 m.marshal(fault, sw);
522 response = sw.toString();
526 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
527 Marshaller m = context.createMarshaller();
528 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
529 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
531 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
532 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
533 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
534 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
535 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
536 serviceException.setMessageId("POL" + eo.getRESTErrorCode());
537 serviceException.setText(text.toString());
538 for (int i=0;i<variables.size();i++)
540 svcvariables.getVariable().add(variables.get(i));
542 serviceException.setVariables(svcvariables);
543 requestError.setServiceException(serviceException);
544 fault.setRequestError(requestError);
546 StringWriter sw = new StringWriter();
547 m.marshal(fault, sw);
549 response = sw.toString();
552 } catch (Exception ex) {
553 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
558 public static void logException(AAIException e) {
559 final ErrorObject errorObject = e.getErrorObject();
561 MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity)
563 final String errorMessage = new StringBuilder()
564 .append(errorObject.getErrorText())
566 .append(errorObject.getRESTErrorCode())
568 .append(errorObject.getHTTPResponseCode())
570 .append(e.getMessage())
573 LoggingContext.responseCode(errorObject.getErrorCodeString());
574 LoggingContext.responseDescription(errorMessage);
575 LoggingContext.statusCode(StatusCode.ERROR);
577 if (errorObject.getSeverity().equalsIgnoreCase("WARN"))
578 LOGGER.warn(errorMessage, e);
579 else if (errorObject.getSeverity().equalsIgnoreCase("ERROR"))
580 LOGGER.error(errorMessage, e);
581 else if (errorObject.getSeverity().equalsIgnoreCase("FATAL"))
582 LOGGER.error(errorMessage, e);
583 else if (errorObject.getSeverity().equals("INFO"))
584 LOGGER.info(errorMessage + ", " + e.getMessage());
587 public static void logError(String code) {
591 public static void logError(String code, String message) {
592 logException(new AAIException(code, message));