/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.webservices.interceptor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import nl.strohalm.cyclos.utils.MessageResolver; import nl.strohalm.cyclos.utils.validation.ValidationError; import nl.strohalm.cyclos.utils.validation.ValidationException; import nl.strohalm.cyclos.webservices.WebServiceContext; import nl.strohalm.cyclos.webservices.utils.WebServiceHelper; import org.apache.commons.lang.StringUtils; import org.apache.cxf.binding.soap.SoapFault; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.Phase; /** * An interceptor used to map known exceptions to fault codes * * @author luis */ public class CustomFaultInterceptor extends AbstractSoapInterceptor { private WebServiceHelper webServiceHelper; private MessageResolver messageResolver; public CustomFaultInterceptor() { super(Phase.MARSHAL); } @Override public void handleMessage(final SoapMessage message) throws Fault { final Fault fault = (Fault) message.getContent(Exception.class); // Only change the fault code if it was not generated by Cyclos if (!WebServiceHelper.isFromCyclos(fault)) { final Throwable exception = fault.getCause() == null ? fault : fault.getCause(); final SoapFault soapFault = WebServiceHelper.fault(exception); fault.setDetail(null); fault.setFaultCode(soapFault.getFaultCode()); fault.setMessage(message(exception)); } // there are cases where this interceptor is invoked but the context wasn't initialized // (e.g.: there is a unmarshalling error when CXF is trying to convert the request parameters) // if (WebServiceContext.isInitialized()) { final HttpServletRequest request = WebServiceContext.getRequest(); request.setAttribute("soapFault", fault); } webServiceHelper.error(fault); } public void setMessageResolver(final MessageResolver messageResolver) { this.messageResolver = messageResolver; } public void setWebServiceHelper(final WebServiceHelper webServiceHelper) { this.webServiceHelper = webServiceHelper; } private String message(final Throwable exception) { if (exception == null) { return "null"; } else if (exception instanceof ValidationException) { return message((ValidationException) exception); } else { return exception.getMessage(); } } private String message(final ValidationException e) { String key = "error.validation"; List<Object> args = Collections.emptyList(); if (!e.getGeneralErrors().isEmpty()) { final ValidationError error = e.getGeneralErrors().iterator().next(); key = error.getKey(); args = error.getArguments(); } else if (!e.getErrorsByProperty().isEmpty()) { final Entry<String, Collection<ValidationError>> entry = e.getErrorsByProperty().entrySet().iterator().next(); final Collection<ValidationError> errors = entry.getValue(); if (!errors.isEmpty()) { // We must show the validation error in a friendly way final String propertyName = entry.getKey(); final ValidationError error = errors.iterator().next(); key = error.getKey(); args = new ArrayList<Object>(); // First, check if there's a fixed display name for the property... String propertyLabel = e.getPropertyDisplayName(propertyName); if (StringUtils.isEmpty(propertyLabel)) { // ... it doesn't. Check if there's a message key... final String propertyKey = e.getPropertyKey(propertyName); if (StringUtils.isNotEmpty(propertyKey)) { // ... the key is set! Get the property label from the message bundle. propertyLabel = messageResolver.message(e.getPropertyKey(propertyName)); } else { // ... we're out of luck! There's no property key. Use the raw property name as label, which is ugly! propertyLabel = propertyName; } } // The first message argument is always the property label args.add(propertyLabel); if (error.getArguments() != null) { // If there are more, add them as well. args.addAll(error.getArguments()); } } } // With the key and arguments, we can show a friendly message to the user return messageResolver.message(key, args.toArray()); } }