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 com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
25 import org.apache.commons.lang.StringUtils;
26 import org.openecomp.aai.exceptions.AAIException;
27 import org.openecomp.aai.logging.LoggingContext.StatusCode;
28 import org.openecomp.aai.util.AAIConstants;
29 import org.openecomp.aai.util.MapperUtil;
32 import javax.ws.rs.core.MediaType;
33 import javax.xml.bind.JAXBContext;
34 import javax.xml.bind.Marshaller;
35 import java.io.FileInputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.StringWriter;
40 import java.util.Map.Entry;
44 * This classes loads the application error properties file
45 * and provides a method that returns an ErrorObject
49 public class ErrorLogHelper {
51 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class);
52 private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject> ();
57 } catch (IOException e) {
58 throw new RuntimeException("Failed to load error.properties file", e);
59 } catch (ErrorObjectFormatException e) {
60 throw new RuntimeException("Failed to parse error.properties file", e);
66 * @throws ErrorObjectFormatException
67 * @throws Exception the exception
69 public static void loadProperties() throws IOException, ErrorObjectFormatException {
70 final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties";
71 final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
72 final Properties properties = new Properties();
77 try (final FileInputStream fis = new FileInputStream(filePath)) {
82 for (Entry<Object, Object> entry : properties.entrySet()) {
83 final String key = (String) entry.getKey();
84 final String value = (String) entry.getValue();
85 final String[] errorProperties = value.split(":");
87 if (errorProperties.length != 7) throw new ErrorObjectFormatException();
89 final ErrorObject errorObject = new ErrorObject();
91 errorObject.setDisposition(errorProperties[0].trim());
92 errorObject.setCategory(errorProperties[1].trim());
93 errorObject.setSeverity(errorProperties[2].trim());
94 errorObject.setErrorCode(errorProperties[3].trim());
95 errorObject.setHTTPResponseCode(errorProperties[4].trim());
96 errorObject.setRESTErrorCode(errorProperties[5].trim());
97 errorObject.setErrorText(errorProperties[6].trim());
99 ERROR_OBJECTS.put(key, errorObject);
104 * Logs a known A&AI exception (i.e. one that can be found in error.properties)
106 * @param key The key for the error in the error.properties file
107 * @throws IOException
108 * @throws ErrorObjectNotFoundException
109 * @throws ErrorObjectFormatException
111 public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException {
113 if (code == null) throw new IllegalArgumentException("Key cannot be null");
115 final ErrorObject errorObject = ERROR_OBJECTS.get(code);
117 if (errorObject == null) {
118 LOGGER.warn("Unknown AAIException with code=" + code + ". Using default AAIException");
119 return ERROR_OBJECTS.get(AAIException.DEFAULT_EXCEPTION_CODE);
126 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
127 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
128 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
129 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
130 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
131 * @param variables optional list of variables to flesh out text in error string
132 * @return appropriately formatted JSON response per the REST API spec.
133 * @throws ErrorObjectFormatException
134 * @throws ErrorObjectNotFoundException
135 * @throws IOException
138 public static String getRESTAPIErrorResponse(AAIException are, ArrayList<String> variables) {
139 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
140 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
142 return getRESTAPIErrorResponse(acceptHeaders, are, variables);
146 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
147 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
148 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
149 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
151 * @param acceptHeadersOrig the accept headers orig
152 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
153 * @param variables optional list of variables to flesh out text in error string
154 * @return appropriately formatted JSON response per the REST API spec.
155 * @throws ErrorObjectFormatException
156 * @throws ErrorObjectNotFoundException
157 * @throws IOException
159 public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
162 StringBuilder text = new StringBuilder();
163 String response = null;
165 List<MediaType> acceptHeaders = new ArrayList<MediaType>();
166 // we might have an exception but no accept header, so we'll set default to JSON
167 boolean foundValidAcceptHeader = false;
168 for (MediaType mt : acceptHeadersOrig) {
169 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt) ||
170 MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) {
171 acceptHeaders.add(mt);
172 foundValidAcceptHeader = true;
175 if (foundValidAcceptHeader == false) {
176 // override the exception, client needs to set an appropriate Accept header
177 are = new AAIException("AAI_4014");
178 acceptHeaders.add(MediaType.APPLICATION_JSON_TYPE);
181 final ErrorObject eo = are.getErrorObject();
183 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
185 ErrorObject restErrorObject;
188 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
189 } catch (ErrorObjectNotFoundException e) {
190 LOGGER.warn("Failed to find related error object AAI_" + restErrorCode + " for error object " + eo.getErrorCode() + "; using AAI_" + restErrorCode);
191 restErrorObject = eo;
194 text.append(restErrorObject.getErrorText());
196 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
197 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
198 // error, are ordered based on the error string.
199 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
200 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
202 if (variables == null)
204 variables = new ArrayList<String>();
207 if (variables.size() < localDataIndex) {
208 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
209 while (variables.size() < localDataIndex) {
210 variables.add("null");
214 // This will put the error code and error text into the right positions
215 if (are.getMessage() == null || are.getMessage().length() == 0) {
216 variables.add(localDataIndex++, eo.getErrorText());
219 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
221 variables.add(localDataIndex, eo.getErrorCodeString());
223 for (MediaType mediaType : acceptHeaders) {
224 if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
225 JAXBContext context = null;
227 if(eo.getCategory().equals("1")) {
229 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
230 Marshaller m = context.createMarshaller();
231 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
232 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
234 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
235 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
236 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
237 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
238 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
240 policyException.setMessageId("POL" + eo.getRESTErrorCode());
241 policyException.setText(text.toString());
242 for (int i=0;i<variables.size();i++)
244 polvariables.getVariable().add(variables.get(i));
246 policyException.setVariables(polvariables);
247 requestError.setPolicyException(policyException);
248 fault.setRequestError(requestError);
250 StringWriter sw = new StringWriter();
251 m.marshal(fault, sw);
253 response = sw.toString();
257 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
258 Marshaller m = context.createMarshaller();
259 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
260 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
262 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
263 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
264 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
265 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
266 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
267 serviceException.setMessageId("SVC" + eo.getRESTErrorCode());
268 serviceException.setText(text.toString());
269 for (int i=0;i<variables.size();i++)
271 svcvariables.getVariable().add(variables.get(i));
273 serviceException.setVariables(svcvariables);
274 requestError.setServiceException(serviceException);
275 fault.setRequestError(requestError);
277 StringWriter sw = new StringWriter();
278 m.marshal(fault, sw);
280 response = sw.toString();
283 } catch (Exception ex) {
284 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
289 if(eo.getCategory().equals("1")) {
290 org.openecomp.aai.domain.restPolicyException.RESTResponse restresp = new org.openecomp.aai.domain.restPolicyException.RESTResponse();
291 org.openecomp.aai.domain.restPolicyException.RequestError reqerr = new org.openecomp.aai.domain.restPolicyException.RequestError();
292 org.openecomp.aai.domain.restPolicyException.PolicyException polexc = new org.openecomp.aai.domain.restPolicyException.PolicyException();
293 polexc.setMessageId("POL" + eo.getRESTErrorCode());
294 polexc.setText(text.toString());
295 polexc.setVariables(variables);
296 reqerr.setPolicyException(polexc);
297 restresp.setRequestError(reqerr);
298 response = (MapperUtil.writeAsJSONString((Object) restresp));
301 org.openecomp.aai.domain.restServiceException.RESTResponse restresp = new org.openecomp.aai.domain.restServiceException.RESTResponse();
302 org.openecomp.aai.domain.restServiceException.RequestError reqerr = new org.openecomp.aai.domain.restServiceException.RequestError();
303 org.openecomp.aai.domain.restServiceException.ServiceException svcexc = new org.openecomp.aai.domain.restServiceException.ServiceException();
304 svcexc.setMessageId("SVC" + eo.getRESTErrorCode());
305 svcexc.setText(text.toString());
306 svcexc.setVariables(variables);
307 reqerr.setServiceException(svcexc);
308 restresp.setRequestError(reqerr);
309 response = (MapperUtil.writeAsJSONString((Object) restresp));
311 } catch (AAIException ex) {
312 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
322 * Gets the RESTAPI error response with logging.
324 * @param acceptHeadersOrig the accept headers orig
326 * @param variables the variables
327 * @param logline the logline
328 * @return the RESTAPI error response with logging
329 * @throws ErrorObjectFormatException
330 * @throws ErrorObjectNotFoundException
331 * @throws IOException
333 public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) {
334 String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables);
336 LOGGER.error(are.getMessage(), are);
342 * Gets the RESTAPI info response.
344 * @param acceptHeaders the accept headers
345 * @param areList the are list
346 * @return the RESTAPI info response
347 * @throws ErrorObjectFormatException
348 * @throws ErrorObjectNotFoundException
349 * @throws IOException
351 public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException,ArrayList<String>> areList) {
353 Object respObj = null;
355 org.openecomp.aai.domain.restResponseInfo.ObjectFactory factory = new org.openecomp.aai.domain.restResponseInfo.ObjectFactory();
356 org.openecomp.aai.domain.restResponseInfo.Info info = factory.createInfo();
357 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages responseMessages = factory.createInfoResponseMessages();
358 Iterator<Entry<AAIException, ArrayList<String>>> it = areList.entrySet().iterator();
360 while (it.hasNext()) {
361 Entry<AAIException,ArrayList<String>> pair = (Entry<AAIException, ArrayList<String>>)it.next();
362 AAIException are = pair.getKey();
363 ArrayList<String> variables = pair.getValue();
365 StringBuilder text = new StringBuilder();
367 ErrorObject eo = are.getErrorObject();
369 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
370 ErrorObject restErrorObject;
372 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+String.format("%04d", restErrorCode));
373 } catch (ErrorObjectNotFoundException e) {
374 restErrorObject = eo;
376 text.append(restErrorObject.getErrorText());
378 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
379 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
380 // error, are ordered based on the error string.
381 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
382 text.append(" (msg=%").append(localDataIndex+1).append(") (rc=%").append(localDataIndex+2).append(")");
384 if (variables == null)
386 variables = new ArrayList<String>();
389 if (variables.size() < localDataIndex) {
390 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
391 while (variables.size() < localDataIndex) {
392 variables.add("null");
396 // This will put the error code and error text into the right positions
397 if (are.getMessage() == null) {
398 variables.add(localDataIndex++, eo.getErrorText());
401 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
403 variables.add(localDataIndex, eo.getErrorCodeString());
406 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage responseMessage = factory.createInfoResponseMessagesResponseMessage();
407 org.openecomp.aai.domain.restResponseInfo.Info.ResponseMessages.ResponseMessage.Variables infovariables = factory.createInfoResponseMessagesResponseMessageVariables();
409 responseMessage.setMessageId("INF" + eo.getRESTErrorCode());
410 responseMessage.setText(text.toString());
411 for (int i=0;i<variables.size();i++)
413 infovariables.getVariable().add(variables.get(i));
416 responseMessage.setVariables(infovariables);
417 responseMessages.getResponseMessage().add(responseMessage);
419 } catch (Exception ex) {
420 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
424 info.setResponseMessages(responseMessages);
425 respObj = (Object) info;
432 * Determines whether category is policy or not. If policy (1), this is a POL error, else it's a SVC error.
433 * The AAIRESTException may contain a different ErrorObject than that created with the REST error key.
434 * This allows lower level exception detail to be returned to the client to help troubleshoot the problem.
435 * If no error object is embedded in the AAIException, one will be created using the error object from the AAIException.
436 * @param are must have a restError value whose numeric value must match what should be returned in the REST API
437 * @param variables optional list of variables to flesh out text in error string
438 * @return appropriately formatted JSON response per the REST API spec.
439 * @throws ErrorObjectFormatException
440 * @throws ErrorObjectNotFoundException
441 * @throws IOException
443 public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) {
445 StringBuilder text = new StringBuilder();
446 String response = null;
447 JAXBContext context = null;
449 ErrorObject eo = are.getErrorObject();
451 int restErrorCode = Integer.parseInt(eo.getRESTErrorCode());
452 ErrorObject restErrorObject;
454 restErrorObject = ErrorLogHelper.getErrorObject("AAI_"+restErrorCode);
455 } catch (ErrorObjectNotFoundException e) {
456 restErrorObject = eo;
459 text.append(restErrorObject.getErrorText());
461 // We want to always append the (msg=%n) (ec=%n+1) to the text, but have to find value of n
462 // This assumes that the variables in the ArrayList, which might be more than are needed to flesh out the
463 // error, are ordered based on the error string.
464 int localDataIndex = StringUtils.countMatches(restErrorObject.getErrorText(), "%");
465 text.append(" (msg=%").append(localDataIndex+1).append(") (ec=%").append(localDataIndex+2).append(")");
467 if (variables == null)
469 variables = new ArrayList<String>();
472 if (variables.size() < localDataIndex) {
473 ErrorLogHelper.logError("AAI_4011", "data missing for rest error");
474 while (variables.size() < localDataIndex) {
475 variables.add("null");
479 // This will put the error code and error text into the right positions
480 if (are.getMessage() == null) {
481 variables.add(localDataIndex++, eo.getErrorText());
484 variables.add(localDataIndex++, eo.getErrorText() + ":" + are.getMessage());
486 variables.add(localDataIndex, eo.getErrorCodeString());
489 if(eo.getCategory().equals("1")) {
491 context = JAXBContext.newInstance(org.openecomp.aai.domain.restPolicyException.Fault.class);
492 Marshaller m = context.createMarshaller();
493 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
494 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
496 org.openecomp.aai.domain.restPolicyException.ObjectFactory factory = new org.openecomp.aai.domain.restPolicyException.ObjectFactory();
497 org.openecomp.aai.domain.restPolicyException.Fault fault = factory.createFault();
498 org.openecomp.aai.domain.restPolicyException.Fault.RequestError requestError = factory.createFaultRequestError();
499 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException policyException = factory.createFaultRequestErrorPolicyException();
500 org.openecomp.aai.domain.restPolicyException.Fault.RequestError.PolicyException.Variables polvariables = factory.createFaultRequestErrorPolicyExceptionVariables();
502 policyException.setMessageId("POL" + eo.getRESTErrorCode());
503 policyException.setText(text.toString());
504 for (int i=0;i<variables.size();i++)
506 polvariables.getVariable().add(variables.get(i));
508 policyException.setVariables(polvariables);
509 requestError.setPolicyException(policyException);
510 fault.setRequestError(requestError);
512 StringWriter sw = new StringWriter();
513 m.marshal(fault, sw);
515 response = sw.toString();
519 context = JAXBContext.newInstance(org.openecomp.aai.domain.restServiceException.Fault.class);
520 Marshaller m = context.createMarshaller();
521 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
522 m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
524 org.openecomp.aai.domain.restServiceException.ObjectFactory factory = new org.openecomp.aai.domain.restServiceException.ObjectFactory();
525 org.openecomp.aai.domain.restServiceException.Fault fault = factory.createFault();
526 org.openecomp.aai.domain.restServiceException.Fault.RequestError requestError = factory.createFaultRequestError();
527 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException serviceException = factory.createFaultRequestErrorServiceException();
528 org.openecomp.aai.domain.restServiceException.Fault.RequestError.ServiceException.Variables svcvariables = factory.createFaultRequestErrorServiceExceptionVariables();
529 serviceException.setMessageId("POL" + eo.getRESTErrorCode());
530 serviceException.setText(text.toString());
531 for (int i=0;i<variables.size();i++)
533 svcvariables.getVariable().add(variables.get(i));
535 serviceException.setVariables(svcvariables);
536 requestError.setServiceException(serviceException);
537 fault.setRequestError(requestError);
539 StringWriter sw = new StringWriter();
540 m.marshal(fault, sw);
542 response = sw.toString();
545 } catch (Exception ex) {
546 LOGGER.error("We were unable to create a rest exception to return on an API because of a parsing error", ex);
551 public static void logException(AAIException e) {
552 final ErrorObject errorObject = e.getErrorObject();
554 MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity)
556 final String errorMessage = new StringBuilder()
557 .append(errorObject.getErrorText())
559 .append(errorObject.getRESTErrorCode())
561 .append(errorObject.getHTTPResponseCode())
563 .append(e.getMessage())
566 LoggingContext.responseCode(errorObject.getErrorCodeString());
567 LoggingContext.responseDescription(errorMessage);
568 LoggingContext.statusCode(StatusCode.ERROR);
570 if (errorObject.getSeverity().equalsIgnoreCase("WARN"))
571 LOGGER.warn(errorMessage, e);
572 else if (errorObject.getSeverity().equalsIgnoreCase("ERROR"))
573 LOGGER.error(errorMessage, e);
574 else if (errorObject.getSeverity().equalsIgnoreCase("FATAL"))
575 LOGGER.error(errorMessage, e);
576 else if (errorObject.getSeverity().equals("INFO"))
577 LOGGER.info(errorMessage + ", " + e.getMessage());
580 public static void logError(String code) {
584 public static void logError(String code, String message) {
585 logException(new AAIException(code, message));