001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 * Contributors: 020 * Florent Guillaume 021 */ 022package org.nuxeo.ecm.core.opencmis.bindings; 023 024import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; 025import static javax.servlet.http.HttpServletResponse.SC_CONFLICT; 026import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; 027import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 028import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED; 029import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; 030 031import java.io.IOException; 032 033import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException; 034import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException; 035import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException; 036import org.apache.chemistry.opencmis.commons.exceptions.CmisFilterNotValidException; 037import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException; 038import org.apache.chemistry.opencmis.commons.exceptions.CmisNameConstraintViolationException; 039import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException; 040import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException; 041import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException; 042import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException; 043import org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException; 044import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException; 045import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException; 046import org.apache.chemistry.opencmis.commons.exceptions.CmisVersioningException; 047import org.apache.commons.lang.math.NumberUtils; 048import org.nuxeo.ecm.core.api.RecoverableClientException; 049import org.nuxeo.ecm.core.opencmis.bindings.NuxeoCmisErrorHelper.ErrorExtractor; 050import org.nuxeo.ecm.core.opencmis.bindings.NuxeoCmisErrorHelper.ErrorInfo; 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053 054/** 055 * Helper to deal with HTTP errors. 056 * 057 * @since 7.1 058 */ 059public class DefaultErrorExtractor implements ErrorExtractor { 060 061 private static final Logger LOG = LoggerFactory.getLogger(DefaultErrorExtractor.class); 062 063 // see CmisAtomPubServlet.printError 064 // see CmisBrowserBindingServlet.ErrorServiceCall.printError 065 @Override 066 public ErrorInfo extractError(Exception ex) { 067 int statusCode = SC_INTERNAL_SERVER_ERROR; // 500 068 String exceptionName = "runtime"; 069 070 if (ex instanceof CmisRuntimeException) { 071 Throwable cause = ex.getCause(); 072 if (cause instanceof RecoverableClientException) { 073 // don't log something harsh in that case 074 statusCode = getHttpStatus((RecoverableClientException) cause); 075 } else { 076 LOG.error(ex.getMessage(), ex); 077 } 078 } else if (ex instanceof CmisStorageException) { 079 LOG.error(ex.getMessage(), ex); 080 statusCode = getErrorCode((CmisStorageException) ex); 081 exceptionName = ((CmisStorageException) ex).getExceptionName(); 082 } else if (ex instanceof CmisBaseException) { 083 statusCode = getErrorCode((CmisBaseException) ex); 084 exceptionName = ((CmisBaseException) ex).getExceptionName(); 085 } else if (ex instanceof IOException) { 086 LOG.warn(ex.getMessage(), ex); 087 } else { 088 LOG.error(ex.getMessage(), ex); 089 } 090 091 String message = ex.getMessage(); 092 if (!(ex instanceof CmisBaseException)) { 093 message = "An error occurred!"; 094 } 095 096 return new ErrorInfo(statusCode, exceptionName, message); 097 } 098 099 /* 100 * A bit of a hack, we need a way to find the HTTP status from the exception. We use the last parameter of the 101 * localized message for that. 102 */ 103 public int getHttpStatus(RecoverableClientException ex) { 104 String[] params = ex.geLocalizedMessageParams(); // urgh, typo 105 int len = params == null ? 0 : params.length; 106 String lastParam; 107 if (len > 0 && NumberUtils.isDigits(lastParam = params[len - 1])) { 108 try { 109 return Integer.parseInt(lastParam); 110 } catch (NumberFormatException e) { 111 // fall through 112 } 113 } 114 return SC_INTERNAL_SERVER_ERROR; // 500 115 } 116 117 // see CmisAtomPubServlet.getErrorCode 118 // see CmisBrowserBindingServlet.ErrorServiceCall.getErrorCode 119 public int getErrorCode(CmisBaseException ex) { 120 if (ex instanceof CmisConstraintException) { 121 return SC_CONFLICT; // 409 122 } else if (ex instanceof CmisContentAlreadyExistsException) { 123 return SC_CONFLICT; // 409 124 } else if (ex instanceof CmisFilterNotValidException) { 125 return SC_BAD_REQUEST; // 400 126 } else if (ex instanceof CmisInvalidArgumentException) { 127 return SC_BAD_REQUEST; // 400 128 } else if (ex instanceof CmisNameConstraintViolationException) { 129 return SC_CONFLICT; // 409 130 } else if (ex instanceof CmisNotSupportedException) { 131 return SC_METHOD_NOT_ALLOWED; // 405 132 } else if (ex instanceof CmisObjectNotFoundException) { 133 return SC_NOT_FOUND; // 404 134 } else if (ex instanceof CmisPermissionDeniedException) { 135 return SC_FORBIDDEN; // 403 136 } else if (ex instanceof CmisStorageException) { 137 return SC_INTERNAL_SERVER_ERROR; // 500 138 } else if (ex instanceof CmisStreamNotSupportedException) { 139 return SC_FORBIDDEN; // 403 140 } else if (ex instanceof CmisUpdateConflictException) { 141 return SC_CONFLICT; // 409 142 } else if (ex instanceof CmisVersioningException) { 143 return SC_CONFLICT; // 409 144 } 145 return SC_INTERNAL_SERVER_ERROR; // 500 146 } 147 148}