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.AAIConfig;
45 import org.openecomp.aai.util.AAIConstants;
46 import org.openecomp.aai.util.MapperUtil;
48 import com.att.eelf.configuration.EELFLogger;
49 import com.att.eelf.configuration.EELFManager;
53 * This classes loads the application error properties file
54 * and provides a method that returns an ErrorObject
58 public class ErrorLogHelper {
60 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class);
61 private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject> ();
66 } catch (IOException e) {
67 throw new RuntimeException("Failed to load error.properties file", e);
68 } catch (ErrorObjectFormatException e) {
69 throw new RuntimeException("Failed to parse error.properties file", e);
75 * @throws ErrorObjectFormatException
76 * @throws Exception the exception
78 public static void loadProperties() throws IOException, ErrorObjectFormatException {
79 final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties";
80 final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
81 final Properties properties = new Properties();
86 try (final FileInputStream fis = new FileInputStream(filePath)) {
91 for (Entry<Object, Object> entry : properties.entrySet()) {
92 final String key = (String) entry.getKey();
93 final String value = (String) entry.getValue();
94 final String[] errorProperties = value.split(":");
96 if (errorProperties.length != 7) throw new ErrorObjectFormatException();
98 final ErrorObject errorObject = new ErrorObject();
100 errorObject.setDisposition(errorProperties[0].trim());
101 errorObject.setCategory(errorProperties[1].trim());
102 errorObject.setSeverity(errorProperties[2].trim());
103 errorObject.setErrorCode(errorProperties[3].trim());
104 errorObject.setHTTPResponseCode(errorProperties[4].trim());
105 errorObject.setRESTErrorCode(errorProperties[5].trim());
106 errorObject.setErrorText(errorProperties[6].trim());
108 ERROR_OBJECTS.put(key, errorObject);
113 * Logs a known A&AI exception (i.e. one that can be found in error.properties)
115 * @param key The key for the error in the error.properties file
116 * @throws IOException
117 * @throws ErrorObjectNotFoundException
118 * @throws ErrorObjectFormatException
120 public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException {
122 if (code == null) throw new IllegalArgumentException("Key cannot be null");
124 final ErrorObject errorObject = ERROR_OBJECTS.get(code);
126 if (errorObject == null) {
127 LOGGER.warn("Unknown AAIException with code=" + code + ". Using default AAIException");
128 return ERROR_OBJECTS.get(AAIException.DEFAULT_EXCEPTION_CODE);
135 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
136 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
137 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
138 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
139 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
140 * @param variables optional list of variables to flesh out text in error string
141 * @return appropriately formatted JSON response per the REST API spec.
142 * @throws ErrorObjectFormatException
143 * @throws ErrorObjectNotFoundException
144 * @throws IOException
147 public static String getRESTAPIErrorResponse(AAIException are, ArrayList<String> variables) {
148 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
149 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
151 return getRESTAPIErrorResponse(acceptHeaders, are, variables);
155 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
156 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
157 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
158 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
160 * @param acceptHeadersOrig the accept headers orig
161 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
162 * @param variables optional list of variables to flesh out text in error string
163 * @return appropriately formatted JSON response per the REST API spec.
164 * @throws ErrorObjectFormatException
165 * @throws ErrorObjectNotFoundException
166 * @throws IOException
168 public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
171 StringBuilder text = new StringBuilder();
172 String response = null;
174 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
175 // we might have an exception but no accept header, so we'll set default to JSON
176 boolean foundValidAcceptHeader = false;
177 for (MediaType mt : acceptHeadersOrig) {
178 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt) ||
179 MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) {
180 acceptHeaders.add(mt);
181 foundValidAcceptHeader = true;
184 if (foundValidAcceptHeader == false) {
185 // override the exception, client needs to set an appropriate Accept header
186 are = new AAIException("AAI_4014");
187 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
190 final ErrorObject eo = are.getErrorObject();
192 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
194 ErrorObject restErrorObject;
197 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
198 } catch (ErrorObjectNotFoundException e) {
199 LOGGER.warn("Failed to find related error object AAI_" + restErrorCode + " for error object " + eo.getErrorCode() + "; using AAI_" + restErrorCode);
200 restErrorObject = eo;
203 text.append(restErrorObject.getErrorText());
205 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
206 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
207 // error, are ordered based on the error string.
208 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
209 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
211 if (variables == null)
213 variables = new ArrayList<String>();
216 if (variables.size() < localDataIndex) {
217 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
218 while (variables.size() < localDataIndex) {
219 variables.add("null");
223 // This will put the error code and error text into the right positions
224 if (are.getMessage() == null || are.getMessage().length() == 0) {
225 variables.add(localDataIndex++, eo.getErrorText());
228 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
230 variables.add(localDataIndex, eo.getErrorCodeString());
232 for (MediaType mediaType : acceptHeaders) {
233 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
234 JAXBContext context = null;
236 if(eo.getCategory().equals("1")) {
238 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
239 Marshaller m = context.createMarshaller();
240 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
241 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
243 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
244 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
245 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
246 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
247 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
249 policyException.setMessageId("POL" + eo.getRESTErrorCode());
250 policyException.setText(text.toString());
251 for (int i=0;i<variables.size();i++)
253 polvariables.getVariable().add(variables.get(i));
255 policyException.setVariables(polvariables);
256 requestError.setPolicyException(policyException);
257 fault.setRequestError(requestError);
259 StringWriter sw = new StringWriter();
260 m.marshal(fault, sw);
262 response = sw.toString();
266 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
267 Marshaller m = context.createMarshaller();
268 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
269 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
271 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
272 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
273 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
274 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
275 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
276 serviceException.setMessageId("SVC" + eo.getRESTErrorCode());
277 serviceException.setText(text.toString());
278 for (int i=0;i<variables.size();i++)
280 svcvariables.getVariable().add(variables.get(i));
282 serviceException.setVariables(svcvariables);
283 requestError.setServiceException(serviceException);
284 fault.setRequestError(requestError);
286 StringWriter sw = new StringWriter();
287 m.marshal(fault, sw);
289 response = sw.toString();
292 } catch (Exception ex) {
293 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
298 if(eo.getCategory().equals("1")) {
299 org.openecomp.aai.domain.restPolicyException.RESTResponse restresp = new org.openecomp.aai.domain.restPolicyException.RESTResponse();
300 org.openecomp.aai.domain.restPolicyException.RequestError reqerr = new org.openecomp.aai.domain.restPolicyException.RequestError();
301 org.openecomp.aai.domain.restPolicyException.PolicyException polexc = new org.openecomp.aai.domain.restPolicyException.PolicyException();
302 polexc.setMessageId("POL" + eo.getRESTErrorCode());
303 polexc.setText(text.toString());
304 polexc.setVariables(variables);
305 reqerr.setPolicyException(polexc);
306 restresp.setRequestError(reqerr);
307 response = (MapperUtil.writeAsJSONString((Object) restresp));
310 org.openecomp.aai.domain.restServiceException.RESTResponse restresp = new org.openecomp.aai.domain.restServiceException.RESTResponse();
311 org.openecomp.aai.domain.restServiceException.RequestError reqerr = new org.openecomp.aai.domain.restServiceException.RequestError();
312 org.openecomp.aai.domain.restServiceException.ServiceException svcexc = new org.openecomp.aai.domain.restServiceException.ServiceException();
313 svcexc.setMessageId("SVC" + eo.getRESTErrorCode());
314 svcexc.setText(text.toString());
315 svcexc.setVariables(variables);
316 reqerr.setServiceException(svcexc);
317 restresp.setRequestError(reqerr);
318 response = (MapperUtil.writeAsJSONString((Object) restresp));
320 } catch (AAIException ex) {
321 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
331 * Gets the RESTAPI error response with logging.
333 * @param acceptHeadersOrig the accept headers orig
335 * @param variables the variables
336 * @param logline the logline
337 * @return the RESTAPI error response with logging
338 * @throws ErrorObjectFormatException
339 * @throws ErrorObjectNotFoundException
340 * @throws IOException
342 public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
343 String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables);
345 LOGGER.error(are.getMessage(), are);
351 * Gets the RESTAPI info response.
353 * @param acceptHeaders the accept headers
354 * @param areList the are list
355 * @return the RESTAPI info response
356 * @throws ErrorObjectFormatException
357 * @throws ErrorObjectNotFoundException
358 * @throws IOException
360 public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException,ArrayList<String>> areList) {
362 Object respObj = null;
364 org.openecomp.aai.domain.restResponseInfo.ObjectFactory factory = new org.openecomp.aai.domain.restResponseInfo.ObjectFactory();
365 org.openecomp.aai.domain.restResponseInfo.Info info = factory.createInfo();
366 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages responseMessages = factory.createInfoResponseMessages();
367 Iterator<Map.Entry<AAIException, ArrayList<String>>> it = areList.entrySet().iterator();
369 while (it.hasNext()) {
370 Map.Entry<AAIException,ArrayList<String>> pair = (Map.Entry<AAIException, ArrayList<String>>)it.next();
371 AAIException are = pair.getKey();
372 ArrayList<String> variables = pair.getValue();
374 StringBuilder text = new StringBuilder();
376 ErrorObject eo = are.getErrorObject();
378 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
379 ErrorObject restErrorObject;
381 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+String.format("%04d", restErrorCode));
382 } catch (ErrorObjectNotFoundException e) {
383 restErrorObject = eo;
385 text.append(restErrorObject.getErrorText());
387 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
388 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
389 // error, are ordered based on the error string.
390 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
391 text.append(" (msg=%").append(localDataIndex+1).append(") (rc=%").append(localDataIndex+2).append(")");
393 if (variables == null)
395 variables = new ArrayList<String>();
398 if (variables.size() < localDataIndex) {
399 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
400 while (variables.size() < localDataIndex) {
401 variables.add("null");
405 // This will put the error code and error text into the right positions
406 if (are.getMessage() == null) {
407 variables.add(localDataIndex++, eo.getErrorText());
410 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
412 variables.add(localDataIndex, eo.getErrorCodeString());
415 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage responseMessage = factory.createInfoResponseMessagesResponseMessage();
416 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage.Variables infovariables = factory.createInfoResponseMessagesResponseMessageVariables();
418 responseMessage.setMessageId("INF" + eo.getRESTErrorCode());
419 responseMessage.setText(text.toString());
420 for (int i=0;i<variables.size();i++)
422 infovariables.getVariable().add(variables.get(i));
425 responseMessage.setVariables(infovariables);
426 responseMessages.getResponseMessage().add(responseMessage);
428 } catch (Exception ex) {
429 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
433 info.setResponseMessages(responseMessages);
434 respObj = (Object) info;
441 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
442 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
443 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
444 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
445 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
446 * @param variables optional list of variables to flesh out text in error string
447 * @return appropriately formatted JSON response per the REST API spec.
448 * @throws ErrorObjectFormatException
449 * @throws ErrorObjectNotFoundException
450 * @throws IOException
452 public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) {
454 StringBuilder text = new StringBuilder();
455 String response = null;
456 JAXBContext context = null;
458 ErrorObject eo = are.getErrorObject();
460 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
461 ErrorObject restErrorObject;
463 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
464 } catch (ErrorObjectNotFoundException e) {
465 restErrorObject = eo;
468 text.append(restErrorObject.getErrorText());
470 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
471 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
472 // error, are ordered based on the error string.
473 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
474 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
476 if (variables == null)
478 variables = new ArrayList<String>();
481 if (variables.size() < localDataIndex) {
482 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
483 while (variables.size() < localDataIndex) {
484 variables.add("null");
488 // This will put the error code and error text into the right positions
489 if (are.getMessage() == null) {
490 variables.add(localDataIndex++, eo.getErrorText());
493 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
495 variables.add(localDataIndex, eo.getErrorCodeString());
498 if(eo.getCategory().equals("1")) {
500 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
501 Marshaller m = context.createMarshaller();
502 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
503 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
505 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
506 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
507 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
508 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
509 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
511 policyException.setMessageId("POL" + eo.getRESTErrorCode());
512 policyException.setText(text.toString());
513 for (int i=0;i<variables.size();i++)
515 polvariables.getVariable().add(variables.get(i));
517 policyException.setVariables(polvariables);
518 requestError.setPolicyException(policyException);
519 fault.setRequestError(requestError);
521 StringWriter sw = new StringWriter();
522 m.marshal(fault, sw);
524 response = sw.toString();
528 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
529 Marshaller m = context.createMarshaller();
530 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
531 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
533 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
534 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
535 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
536 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
537 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
538 serviceException.setMessageId("POL" + eo.getRESTErrorCode());
539 serviceException.setText(text.toString());
540 for (int i=0;i<variables.size();i++)
542 svcvariables.getVariable().add(variables.get(i));
544 serviceException.setVariables(svcvariables);
545 requestError.setServiceException(serviceException);
546 fault.setRequestError(requestError);
548 StringWriter sw = new StringWriter();
549 m.marshal(fault, sw);
551 response = sw.toString();
554 } catch (Exception ex) {
555 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
560 public static void logException(AAIException e) {
561 final ErrorObject errorObject = e.getErrorObject();
563 // MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity)
564 String severityCode = errorObject.getSeverityCode(errorObject.getSeverity());
566 if (!AAIConfig.isEmpty(severityCode)) {
567 int sevCode = Integer.parseInt(severityCode);
568 if (sevCode > 0 && sevCode <= 3 )
570 LoggingContext.severity(sevCode);
574 final String errorMessage = new StringBuilder()
575 .append(errorObject.getErrorText())
577 .append(errorObject.getRESTErrorCode())
579 .append(errorObject.getHTTPResponseCode())
581 .append(e.getMessage())
584 LoggingContext.responseCode(Integer.toString(errorObject.getHTTPResponseCode().getStatusCode()));
585 LoggingContext.responseDescription(errorMessage);
586 LoggingContext.statusCode(StatusCode.ERROR);
588 if (errorObject.getSeverity().equalsIgnoreCase("WARN"))
589 LOGGER.warn(errorMessage, e);
590 else if (errorObject.getSeverity().equalsIgnoreCase("ERROR"))
591 LOGGER.error(errorMessage, e);
592 else if (errorObject.getSeverity().equalsIgnoreCase("FATAL"))
593 LOGGER.error(errorMessage, e);
594 else if (errorObject.getSeverity().equals("INFO"))
595 LOGGER.info(errorMessage + ", " + e.getMessage());
598 public static void logError(String code) {
602 public static void logError(String code, String message) {
603 logException(new AAIException(code, message));