src/share/jaxws_classes/com/sun/xml/internal/ws/fault/SOAPFaultBuilder.java

Fri, 14 Feb 2014 11:13:45 +0100

author
mkos
date
Fri, 14 Feb 2014 11:13:45 +0100
changeset 515
6cd506508147
parent 450
b0c2840e2513
child 637
9c07ef4934dd
permissions
-rw-r--r--

8026188: Enhance envelope factory
Summary: Avoiding caching data initialized via TCCL in static context; fix also reviewed by Alexander Fomin
Reviewed-by: ahgross, mgrebac, skoivu

ohair@286 1 /*
mkos@450 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.ws.fault;
ohair@286 27
ohair@286 28 import com.sun.istack.internal.NotNull;
ohair@286 29 import com.sun.istack.internal.Nullable;
ohair@286 30 import com.sun.xml.internal.ws.api.SOAPVersion;
ohair@286 31 import com.sun.xml.internal.ws.api.message.Message;
ohair@286 32 import com.sun.xml.internal.ws.api.model.ExceptionType;
ohair@286 33 import com.sun.xml.internal.ws.encoding.soap.SOAP12Constants;
ohair@286 34 import com.sun.xml.internal.ws.encoding.soap.SOAPConstants;
ohair@286 35 import com.sun.xml.internal.ws.encoding.soap.SerializationException;
ohair@286 36 import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
ohair@286 37 import com.sun.xml.internal.ws.message.FaultMessage;
ohair@286 38 import com.sun.xml.internal.ws.model.CheckedExceptionImpl;
ohair@286 39 import com.sun.xml.internal.ws.model.JavaMethodImpl;
ohair@286 40 import com.sun.xml.internal.ws.spi.db.XMLBridge;
ohair@286 41 import com.sun.xml.internal.ws.util.DOMUtil;
ohair@286 42 import com.sun.xml.internal.ws.util.StringUtils;
ohair@286 43 import org.w3c.dom.Document;
ohair@286 44 import org.w3c.dom.Element;
ohair@286 45 import org.w3c.dom.Node;
ohair@286 46
ohair@286 47 import javax.xml.bind.JAXBContext;
ohair@286 48 import javax.xml.bind.JAXBException;
ohair@286 49 import javax.xml.bind.annotation.XmlTransient;
ohair@286 50 import javax.xml.namespace.QName;
ohair@286 51 import javax.xml.soap.SOAPFault;
ohair@286 52 import javax.xml.soap.Detail;
ohair@286 53 import javax.xml.soap.DetailEntry;
ohair@286 54 import javax.xml.transform.dom.DOMResult;
ohair@286 55 import javax.xml.ws.ProtocolException;
ohair@286 56 import javax.xml.ws.WebServiceException;
ohair@286 57 import javax.xml.ws.soap.SOAPFaultException;
ohair@286 58 import java.lang.reflect.Constructor;
ohair@286 59 import java.lang.reflect.Field;
ohair@286 60 import java.lang.reflect.Method;
mkos@450 61 import java.lang.reflect.ReflectPermission;
mkos@450 62 import java.security.AccessControlContext;
mkos@450 63 import java.security.AccessController;
mkos@450 64 import java.security.Permissions;
mkos@450 65 import java.security.PrivilegedAction;
mkos@450 66 import java.security.ProtectionDomain;
ohair@286 67 import java.util.Iterator;
ohair@286 68 import java.util.Map;
ohair@286 69 import java.util.logging.Level;
ohair@286 70 import java.util.logging.Logger;
ohair@286 71
ohair@286 72 /**
ohair@286 73 * Base class that represents SOAP 1.1 or SOAP 1.2 fault. This class can be used by the invocation handlers to create
ohair@286 74 * an Exception from a received messge.
ohair@286 75 *
ohair@286 76 * @author Vivek Pandey
ohair@286 77 */
ohair@286 78 public abstract class SOAPFaultBuilder {
ohair@286 79
ohair@286 80 /**
ohair@286 81 * Gives the {@link DetailType} for a Soap 1.1 or Soap 1.2 message that can be used to create either a checked exception or
ohair@286 82 * a protocol specific exception
ohair@286 83 */
ohair@286 84 abstract DetailType getDetail();
ohair@286 85
ohair@286 86 abstract void setDetail(DetailType detailType);
ohair@286 87
ohair@286 88 public @XmlTransient @Nullable QName getFirstDetailEntryName() {
ohair@286 89 DetailType dt = getDetail();
ohair@286 90 if (dt != null) {
ohair@286 91 Node entry = dt.getDetail(0);
ohair@286 92 if (entry != null) {
ohair@286 93 return new QName(entry.getNamespaceURI(), entry.getLocalName());
ohair@286 94 }
ohair@286 95 }
ohair@286 96 return null;
ohair@286 97 }
ohair@286 98
ohair@286 99 /**
ohair@286 100 * gives the fault string that can be used to create an {@link Exception}
ohair@286 101 */
ohair@286 102 abstract String getFaultString();
ohair@286 103
ohair@286 104 /**
ohair@286 105 * This should be called from the client side to throw an {@link Exception} for a given soap mesage
ohair@286 106 */
ohair@286 107 public Throwable createException(Map<QName, CheckedExceptionImpl> exceptions) throws JAXBException {
ohair@286 108 DetailType dt = getDetail();
ohair@286 109 Node detail = null;
ohair@286 110 if(dt != null) detail = dt.getDetail(0);
ohair@286 111
ohair@286 112 //return ProtocolException if the detail is not present or there is no checked exception
ohair@286 113 if(detail == null || exceptions == null){
ohair@286 114 // No soap detail, doesnt look like its a checked exception
ohair@286 115 // throw a protocol exception
ohair@286 116 return attachServerException(getProtocolException());
ohair@286 117 }
ohair@286 118
ohair@286 119 //check if the detail is a checked exception, if not throw a ProtocolException
ohair@286 120 QName detailName = new QName(detail.getNamespaceURI(), detail.getLocalName());
ohair@286 121 CheckedExceptionImpl ce = exceptions.get(detailName);
ohair@286 122 if (ce == null) {
ohair@286 123 //No Checked exception for the received detail QName, throw a SOAPFault exception
ohair@286 124 return attachServerException(getProtocolException());
ohair@286 125
ohair@286 126 }
ohair@286 127
ohair@286 128 if (ce.getExceptionType().equals(ExceptionType.UserDefined)) {
ohair@286 129 return attachServerException(createUserDefinedException(ce));
ohair@286 130
ohair@286 131 }
ohair@286 132 Class exceptionClass = ce.getExceptionClass();
ohair@286 133 try {
ohair@286 134 Constructor constructor = exceptionClass.getConstructor(String.class, (Class) ce.getDetailType().type);
ohair@286 135 Exception exception = (Exception) constructor.newInstance(getFaultString(), getJAXBObject(detail, ce));
ohair@286 136 return attachServerException(exception);
ohair@286 137 } catch (Exception e) {
ohair@286 138 throw new WebServiceException(e);
ohair@286 139 }
ohair@286 140 }
ohair@286 141
ohair@286 142 /**
ohair@286 143 * To be called to convert a {@link ProtocolException} and faultcode for a given {@link SOAPVersion} in to a {@link Message}.
ohair@286 144 *
ohair@286 145 * @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
ohair@286 146 * @param ex a ProtocolException
ohair@286 147 * @param faultcode soap faultcode. Its ignored if the {@link ProtocolException} instance is {@link SOAPFaultException} and it has a
ohair@286 148 * faultcode present in the underlying {@link SOAPFault}.
ohair@286 149 * @return {@link Message} representing SOAP fault
ohair@286 150 */
ohair@286 151 public static @NotNull Message createSOAPFaultMessage(@NotNull SOAPVersion soapVersion, @NotNull ProtocolException ex, @Nullable QName faultcode){
ohair@286 152 Object detail = getFaultDetail(null, ex);
ohair@286 153 if(soapVersion == SOAPVersion.SOAP_12)
ohair@286 154 return createSOAP12Fault(soapVersion, ex, detail, null, faultcode);
ohair@286 155 return createSOAP11Fault(soapVersion, ex, detail, null, faultcode);
ohair@286 156 }
ohair@286 157
ohair@286 158 /**
ohair@286 159 * To be called by the server runtime in the situations when there is an Exception that needs to be transformed in
ohair@286 160 * to a soapenv:Fault payload.
ohair@286 161 *
ohair@286 162 * @param ceModel {@link CheckedExceptionImpl} model that provides useful informations such as the detail tagname
ohair@286 163 * and the Exception associated with it. Caller of this constructor should get the CheckedException
ohair@286 164 * model by calling {@link JavaMethodImpl#getCheckedException(Class)}, where
ohair@286 165 * Class is t.getClass().
ohair@286 166 * <p>
ohair@286 167 * If its null then this is not a checked exception and in that case the soap fault will be
ohair@286 168 * serialized only from the exception as described below.
ohair@286 169 * @param ex Exception that needs to be translated into soapenv:Fault, always non-null.
ohair@286 170 * <ul>
ohair@286 171 * <li>If t is instance of {@link SOAPFaultException} then its serilaized as protocol exception.
ohair@286 172 * <li>If t.getCause() is instance of {@link SOAPFaultException} and t is a checked exception then
ohair@286 173 * the soap fault detail is serilaized from t and the fault actor/string/role is taken from t.getCause().
ohair@286 174 * </ul>
ohair@286 175 * @param soapVersion non-null
ohair@286 176 */
ohair@286 177 public static Message createSOAPFaultMessage(SOAPVersion soapVersion, CheckedExceptionImpl ceModel, Throwable ex) {
alanb@368 178 // Sometimes InvocationTargetException.getCause() is null
alanb@368 179 // but InvocationTargetException.getTargetException() contains the real exception
alanb@368 180 // even though they are supposed to be equivalent.
alanb@368 181 // If we only look at .getCause this results in the real exception being lost.
alanb@368 182 // Looks like a JDK bug.
alanb@368 183 final Throwable t =
alanb@368 184 ex instanceof java.lang.reflect.InvocationTargetException
alanb@368 185 ?
alanb@368 186 ((java.lang.reflect.InvocationTargetException)ex).getTargetException()
alanb@368 187 :
alanb@368 188 ex;
alanb@368 189 return createSOAPFaultMessage(soapVersion, ceModel, t, null);
ohair@286 190 }
ohair@286 191
ohair@286 192 /**
ohair@286 193 * Create the Message with the specified faultCode
ohair@286 194 *
ohair@286 195 * @see #createSOAPFaultMessage(SOAPVersion, CheckedExceptionImpl, Throwable)
ohair@286 196 */
ohair@286 197 public static Message createSOAPFaultMessage(SOAPVersion soapVersion, CheckedExceptionImpl ceModel, Throwable ex, QName faultCode) {
ohair@286 198 Object detail = getFaultDetail(ceModel, ex);
ohair@286 199 if(soapVersion == SOAPVersion.SOAP_12)
ohair@286 200 return createSOAP12Fault(soapVersion, ex, detail, ceModel, faultCode);
ohair@286 201 return createSOAP11Fault(soapVersion, ex, detail, ceModel, faultCode);
ohair@286 202 }
ohair@286 203
ohair@286 204 /**
ohair@286 205 * Server runtime will call this when there is some internal error not resulting from an exception.
ohair@286 206 *
ohair@286 207 * @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
ohair@286 208 * @param faultString must be non-null
ohair@286 209 * @param faultCode For SOAP 1.1, it must be one of
ohair@286 210 * <ul>
ohair@286 211 * <li>{@link SOAPVersion#faultCodeClient}
ohair@286 212 * <li>{@link SOAPVersion#faultCodeServer}
ohair@286 213 * <li>{@link SOAPConstants#FAULT_CODE_MUST_UNDERSTAND}
ohair@286 214 * <li>{@link SOAPConstants#FAULT_CODE_VERSION_MISMATCH}
ohair@286 215 * </ul>
ohair@286 216 *
ohair@286 217 * For SOAP 1.2
ohair@286 218 * <ul>
ohair@286 219 * <li>{@link SOAPVersion#faultCodeClient}
ohair@286 220 * <li>{@link SOAPVersion#faultCodeServer}
ohair@286 221 * <li>{@link SOAP12Constants#FAULT_CODE_MUST_UNDERSTAND}
ohair@286 222 * <li>{@link SOAP12Constants#FAULT_CODE_VERSION_MISMATCH}
ohair@286 223 * <li>{@link SOAP12Constants#FAULT_CODE_DATA_ENCODING_UNKNOWN}
ohair@286 224 * </ul>
ohair@286 225 * @return non-null {@link Message}
ohair@286 226 */
ohair@286 227 public static Message createSOAPFaultMessage(SOAPVersion soapVersion, String faultString, QName faultCode) {
ohair@286 228 if (faultCode == null)
ohair@286 229 faultCode = getDefaultFaultCode(soapVersion);
ohair@286 230 return createSOAPFaultMessage(soapVersion, faultString, faultCode, null);
ohair@286 231 }
ohair@286 232
ohair@286 233 public static Message createSOAPFaultMessage(SOAPVersion soapVersion, SOAPFault fault) {
ohair@286 234 switch (soapVersion) {
ohair@286 235 case SOAP_11:
ohair@286 236 return JAXBMessage.create(JAXB_CONTEXT, new SOAP11Fault(fault), soapVersion);
ohair@286 237 case SOAP_12:
ohair@286 238 return JAXBMessage.create(JAXB_CONTEXT, new SOAP12Fault(fault), soapVersion);
ohair@286 239 default:
ohair@286 240 throw new AssertionError();
ohair@286 241 }
ohair@286 242 }
ohair@286 243
ohair@286 244 private static Message createSOAPFaultMessage(SOAPVersion soapVersion, String faultString, QName faultCode, Element detail) {
ohair@286 245 switch (soapVersion) {
ohair@286 246 case SOAP_11:
ohair@286 247 return JAXBMessage.create(JAXB_CONTEXT, new SOAP11Fault(faultCode, faultString, null, detail), soapVersion);
ohair@286 248 case SOAP_12:
ohair@286 249 return JAXBMessage.create(JAXB_CONTEXT, new SOAP12Fault(faultCode, faultString, detail), soapVersion);
ohair@286 250 default:
ohair@286 251 throw new AssertionError();
ohair@286 252 }
ohair@286 253 }
ohair@286 254
ohair@286 255 /**
ohair@286 256 * Creates a DOM node that represents the complete stack trace of the exception,
ohair@286 257 * and attach that to {@link DetailType}.
ohair@286 258 */
ohair@286 259 final void captureStackTrace(@Nullable Throwable t) {
ohair@286 260 if(t==null) return;
ohair@286 261 if(!captureStackTrace) return; // feature disabled
ohair@286 262
ohair@286 263 try {
ohair@286 264 Document d = DOMUtil.createDom();
ohair@286 265 ExceptionBean.marshal(t,d);
ohair@286 266
ohair@286 267 DetailType detail = getDetail();
ohair@286 268 if(detail==null)
ohair@286 269 setDetail(detail=new DetailType());
ohair@286 270
ohair@286 271 detail.getDetails().add(d.getDocumentElement());
ohair@286 272 } catch (JAXBException e) {
ohair@286 273 // this should never happen
ohair@286 274 logger.log(Level.WARNING, "Unable to capture the stack trace into XML",e);
ohair@286 275 }
ohair@286 276 }
ohair@286 277
ohair@286 278 /**
ohair@286 279 * Initialize the cause of this exception by attaching the server side exception.
ohair@286 280 */
ohair@286 281 private <T extends Throwable> T attachServerException(T t) {
ohair@286 282 DetailType detail = getDetail();
ohair@286 283 if(detail==null) return t; // no details
ohair@286 284
ohair@286 285 for (Element n : detail.getDetails()) {
ohair@286 286 if(ExceptionBean.isStackTraceXml(n)) {
ohair@286 287 try {
ohair@286 288 t.initCause(ExceptionBean.unmarshal(n));
ohair@286 289 } catch (JAXBException e) {
ohair@286 290 // perhaps incorrectly formatted XML.
ohair@286 291 logger.log(Level.WARNING, "Unable to read the capture stack trace in the fault",e);
ohair@286 292 }
ohair@286 293 return t;
ohair@286 294 }
ohair@286 295 }
ohair@286 296
ohair@286 297 return t;
ohair@286 298 }
ohair@286 299
ohair@286 300 abstract protected Throwable getProtocolException();
ohair@286 301
ohair@286 302 private Object getJAXBObject(Node jaxbBean, CheckedExceptionImpl ce) throws JAXBException {
ohair@286 303 XMLBridge bridge = ce.getBond();
ohair@286 304 return bridge.unmarshal(jaxbBean,null);
ohair@286 305 }
ohair@286 306
ohair@286 307 private Exception createUserDefinedException(CheckedExceptionImpl ce) {
ohair@286 308 Class exceptionClass = ce.getExceptionClass();
ohair@286 309 Class detailBean = ce.getDetailBean();
ohair@286 310 try{
ohair@286 311 Node detailNode = getDetail().getDetails().get(0);
ohair@286 312 Object jaxbDetail = getJAXBObject(detailNode, ce);
ohair@286 313 Constructor exConstructor;
ohair@286 314 try{
ohair@286 315 exConstructor = exceptionClass.getConstructor(String.class, detailBean);
ohair@286 316 return (Exception) exConstructor.newInstance(getFaultString(), jaxbDetail);
ohair@286 317 }catch(NoSuchMethodException e){
ohair@286 318 exConstructor = exceptionClass.getConstructor(String.class);
ohair@286 319 return (Exception) exConstructor.newInstance(getFaultString());
ohair@286 320 }
ohair@286 321 } catch (Exception e) {
ohair@286 322 throw new WebServiceException(e);
ohair@286 323 }
ohair@286 324 }
ohair@286 325
ohair@286 326 private static String getWriteMethod(Field f) {
ohair@286 327 return "set" + StringUtils.capitalize(f.getName());
ohair@286 328 }
ohair@286 329
ohair@286 330 private static Object getFaultDetail(CheckedExceptionImpl ce, Throwable exception) {
ohair@286 331 if (ce == null)
ohair@286 332 return null;
ohair@286 333 if (ce.getExceptionType().equals(ExceptionType.UserDefined)) {
ohair@286 334 return createDetailFromUserDefinedException(ce, exception);
ohair@286 335 }
ohair@286 336 try {
ohair@286 337 Method m = exception.getClass().getMethod("getFaultInfo");
ohair@286 338 return m.invoke(exception);
ohair@286 339 } catch (Exception e) {
ohair@286 340 throw new SerializationException(e);
ohair@286 341 }
ohair@286 342 }
ohair@286 343
ohair@286 344 private static Object createDetailFromUserDefinedException(CheckedExceptionImpl ce, Object exception) {
ohair@286 345 Class detailBean = ce.getDetailBean();
ohair@286 346 Field[] fields = detailBean.getDeclaredFields();
ohair@286 347 try {
ohair@286 348 Object detail = detailBean.newInstance();
ohair@286 349 for (Field f : fields) {
ohair@286 350 Method em = exception.getClass().getMethod(getReadMethod(f));
ohair@286 351 try {
ohair@286 352 Method sm = detailBean.getMethod(getWriteMethod(f), em.getReturnType());
ohair@286 353 sm.invoke(detail, em.invoke(exception));
ohair@286 354 } catch(NoSuchMethodException ne) {
ohair@286 355 // Try to use exception bean's public field to populate the value.
ohair@286 356 Field sf = detailBean.getField(f.getName());
ohair@286 357 sf.set(detail, em.invoke(exception));
ohair@286 358 }
ohair@286 359 }
ohair@286 360 return detail;
ohair@286 361 } catch (Exception e) {
ohair@286 362 throw new SerializationException(e);
ohair@286 363 }
ohair@286 364 }
ohair@286 365
ohair@286 366 private static String getReadMethod(Field f) {
ohair@286 367 if (f.getType().isAssignableFrom(boolean.class))
ohair@286 368 return "is" + StringUtils.capitalize(f.getName());
ohair@286 369 return "get" + StringUtils.capitalize(f.getName());
ohair@286 370 }
ohair@286 371
ohair@286 372 private static Message createSOAP11Fault(SOAPVersion soapVersion, Throwable e, Object detail, CheckedExceptionImpl ce, QName faultCode) {
ohair@286 373 SOAPFaultException soapFaultException = null;
ohair@286 374 String faultString = null;
ohair@286 375 String faultActor = null;
ohair@286 376 Throwable cause = e.getCause();
ohair@286 377 if (e instanceof SOAPFaultException) {
ohair@286 378 soapFaultException = (SOAPFaultException) e;
ohair@286 379 } else if (cause != null && cause instanceof SOAPFaultException) {
ohair@286 380 soapFaultException = (SOAPFaultException) e.getCause();
ohair@286 381 }
ohair@286 382 if (soapFaultException != null) {
ohair@286 383 QName soapFaultCode = soapFaultException.getFault().getFaultCodeAsQName();
ohair@286 384 if(soapFaultCode != null)
ohair@286 385 faultCode = soapFaultCode;
ohair@286 386
ohair@286 387 faultString = soapFaultException.getFault().getFaultString();
ohair@286 388 faultActor = soapFaultException.getFault().getFaultActor();
ohair@286 389 }
ohair@286 390
ohair@286 391 if (faultCode == null) {
ohair@286 392 faultCode = getDefaultFaultCode(soapVersion);
ohair@286 393 }
ohair@286 394
ohair@286 395 if (faultString == null) {
ohair@286 396 faultString = e.getMessage();
ohair@286 397 if (faultString == null) {
ohair@286 398 faultString = e.toString();
ohair@286 399 }
ohair@286 400 }
ohair@286 401 Element detailNode = null;
ohair@286 402 QName firstEntry = null;
ohair@286 403 if (detail == null && soapFaultException != null) {
ohair@286 404 detailNode = soapFaultException.getFault().getDetail();
ohair@286 405 firstEntry = getFirstDetailEntryName((Detail)detailNode);
ohair@286 406 } else if(ce != null){
ohair@286 407 try {
ohair@286 408 DOMResult dr = new DOMResult();
ohair@286 409 ce.getBond().marshal(detail,dr);
ohair@286 410 detailNode = (Element)dr.getNode().getFirstChild();
ohair@286 411 firstEntry = getFirstDetailEntryName(detailNode);
ohair@286 412 } catch (JAXBException e1) {
ohair@286 413 //Should we throw Internal Server Error???
ohair@286 414 faultString = e.getMessage();
ohair@286 415 faultCode = getDefaultFaultCode(soapVersion);
ohair@286 416 }
ohair@286 417 }
ohair@286 418 SOAP11Fault soap11Fault = new SOAP11Fault(faultCode, faultString, faultActor, detailNode);
ohair@286 419
ohair@286 420 //Don't fill the stacktrace for Service specific exceptions.
ohair@286 421 if(ce == null) {
ohair@286 422 soap11Fault.captureStackTrace(e);
ohair@286 423 }
ohair@286 424 Message msg = JAXBMessage.create(JAXB_CONTEXT, soap11Fault, soapVersion);
ohair@286 425 return new FaultMessage(msg, firstEntry);
ohair@286 426 }
ohair@286 427
ohair@286 428 private static @Nullable QName getFirstDetailEntryName(@Nullable Detail detail) {
ohair@286 429 if (detail != null) {
ohair@286 430 Iterator<DetailEntry> it = detail.getDetailEntries();
ohair@286 431 if (it.hasNext()) {
ohair@286 432 DetailEntry entry = it.next();
ohair@286 433 return getFirstDetailEntryName(entry);
ohair@286 434 }
ohair@286 435 }
ohair@286 436 return null;
ohair@286 437 }
ohair@286 438
ohair@286 439 private static @NotNull QName getFirstDetailEntryName(@NotNull Element entry) {
ohair@286 440 return new QName(entry.getNamespaceURI(), entry.getLocalName());
ohair@286 441 }
ohair@286 442
ohair@286 443 private static Message createSOAP12Fault(SOAPVersion soapVersion, Throwable e, Object detail, CheckedExceptionImpl ce, QName faultCode) {
ohair@286 444 SOAPFaultException soapFaultException = null;
ohair@286 445 CodeType code = null;
ohair@286 446 String faultString = null;
ohair@286 447 String faultRole = null;
ohair@286 448 String faultNode = null;
ohair@286 449 Throwable cause = e.getCause();
ohair@286 450 if (e instanceof SOAPFaultException) {
ohair@286 451 soapFaultException = (SOAPFaultException) e;
ohair@286 452 } else if (cause != null && cause instanceof SOAPFaultException) {
ohair@286 453 soapFaultException = (SOAPFaultException) e.getCause();
ohair@286 454 }
ohair@286 455 if (soapFaultException != null) {
ohair@286 456 SOAPFault fault = soapFaultException.getFault();
ohair@286 457 QName soapFaultCode = fault.getFaultCodeAsQName();
ohair@286 458 if(soapFaultCode != null){
ohair@286 459 faultCode = soapFaultCode;
ohair@286 460 code = new CodeType(faultCode);
ohair@286 461 Iterator iter = fault.getFaultSubcodes();
ohair@286 462 boolean first = true;
ohair@286 463 SubcodeType subcode = null;
ohair@286 464 while(iter.hasNext()){
ohair@286 465 QName value = (QName)iter.next();
ohair@286 466 if(first){
ohair@286 467 SubcodeType sct = new SubcodeType(value);
ohair@286 468 code.setSubcode(sct);
ohair@286 469 subcode = sct;
ohair@286 470 first = false;
ohair@286 471 continue;
ohair@286 472 }
ohair@286 473 subcode = fillSubcodes(subcode, value);
ohair@286 474 }
ohair@286 475 }
ohair@286 476 faultString = soapFaultException.getFault().getFaultString();
ohair@286 477 faultRole = soapFaultException.getFault().getFaultActor();
ohair@286 478 faultNode = soapFaultException.getFault().getFaultNode();
ohair@286 479 }
ohair@286 480
ohair@286 481 if (faultCode == null) {
ohair@286 482 faultCode = getDefaultFaultCode(soapVersion);
ohair@286 483 code = new CodeType(faultCode);
ohair@286 484 }else if(code == null){
ohair@286 485 code = new CodeType(faultCode);
ohair@286 486 }
ohair@286 487
ohair@286 488 if (faultString == null) {
ohair@286 489 faultString = e.getMessage();
ohair@286 490 if (faultString == null) {
ohair@286 491 faultString = e.toString();
ohair@286 492 }
ohair@286 493 }
ohair@286 494
ohair@286 495 ReasonType reason = new ReasonType(faultString);
ohair@286 496 Element detailNode = null;
ohair@286 497 QName firstEntry = null;
ohair@286 498 if (detail == null && soapFaultException != null) {
ohair@286 499 detailNode = soapFaultException.getFault().getDetail();
ohair@286 500 firstEntry = getFirstDetailEntryName((Detail)detailNode);
ohair@286 501 } else if(detail != null){
ohair@286 502 try {
ohair@286 503 DOMResult dr = new DOMResult();
ohair@286 504 ce.getBond().marshal(detail, dr);
ohair@286 505 detailNode = (Element)dr.getNode().getFirstChild();
ohair@286 506 firstEntry = getFirstDetailEntryName(detailNode);
ohair@286 507 } catch (JAXBException e1) {
ohair@286 508 //Should we throw Internal Server Error???
ohair@286 509 faultString = e.getMessage();
ohair@286 510 }
ohair@286 511 }
ohair@286 512
ohair@286 513 SOAP12Fault soap12Fault = new SOAP12Fault(code, reason, faultNode, faultRole, detailNode);
ohair@286 514
ohair@286 515 //Don't fill the stacktrace for Service specific exceptions.
ohair@286 516 if(ce == null) {
ohair@286 517 soap12Fault.captureStackTrace(e);
ohair@286 518 }
ohair@286 519 Message msg = JAXBMessage.create(JAXB_CONTEXT, soap12Fault, soapVersion);
ohair@286 520 return new FaultMessage(msg, firstEntry);
ohair@286 521 }
ohair@286 522
ohair@286 523 private static SubcodeType fillSubcodes(SubcodeType parent, QName value){
ohair@286 524 SubcodeType newCode = new SubcodeType(value);
ohair@286 525 parent.setSubcode(newCode);
ohair@286 526 return newCode;
ohair@286 527 }
ohair@286 528
ohair@286 529 private static QName getDefaultFaultCode(SOAPVersion soapVersion) {
ohair@286 530 return soapVersion.faultCodeServer;
ohair@286 531 }
ohair@286 532
ohair@286 533 /**
ohair@286 534 * Parses a fault {@link Message} and returns it as a {@link SOAPFaultBuilder}.
ohair@286 535 *
ohair@286 536 * @return always non-null valid object.
ohair@286 537 * @throws JAXBException if the parsing fails.
ohair@286 538 */
ohair@286 539 public static SOAPFaultBuilder create(Message msg) throws JAXBException {
ohair@286 540 return msg.readPayloadAsJAXB(JAXB_CONTEXT.createUnmarshaller());
ohair@286 541 }
ohair@286 542
ohair@286 543 /**
ohair@286 544 * This {@link JAXBContext} can handle SOAP 1.1/1.2 faults.
ohair@286 545 */
ohair@286 546 private static final JAXBContext JAXB_CONTEXT;
ohair@286 547
ohair@286 548 private static final Logger logger = Logger.getLogger(SOAPFaultBuilder.class.getName());
ohair@286 549
ohair@286 550 /**
ohair@286 551 * Set to false if you don't want the generated faults to have stack trace in it.
ohair@286 552 */
alanb@368 553 public static final boolean captureStackTrace;
ohair@286 554
ohair@286 555 /*package*/ static final String CAPTURE_STACK_TRACE_PROPERTY = SOAPFaultBuilder.class.getName()+".captureStackTrace";
ohair@286 556
ohair@286 557 static {
alanb@368 558 boolean tmpVal = false;
ohair@286 559 try {
alanb@368 560 tmpVal = Boolean.getBoolean(CAPTURE_STACK_TRACE_PROPERTY);
ohair@286 561 } catch (SecurityException e) {
ohair@286 562 // ignore
ohair@286 563 }
alanb@368 564 captureStackTrace = tmpVal;
mkos@450 565 JAXB_CONTEXT = createJAXBContext();
mkos@450 566 }
ohair@286 567
mkos@450 568 private static JAXBContext createJAXBContext() {
mkos@450 569
mkos@450 570 // in jdk runtime doPrivileged is necessary since JAX-WS internal classes are in restricted packages
mkos@450 571 if (isJDKRuntime()) {
mkos@450 572 Permissions permissions = new Permissions();
mkos@450 573 permissions.add(new RuntimePermission("accessClassInPackage.com.sun." + "xml.internal.ws.fault"));
mkos@450 574 permissions.add(new ReflectPermission("suppressAccessChecks"));
mkos@450 575 return AccessController.doPrivileged(
mkos@450 576 new PrivilegedAction<JAXBContext>() {
mkos@450 577 @Override
mkos@450 578 public JAXBContext run() {
mkos@450 579 try {
mkos@450 580 return JAXBContext.newInstance(SOAP11Fault.class, SOAP12Fault.class);
mkos@450 581 } catch (JAXBException e) {
mkos@450 582 throw new Error(e);
mkos@450 583 }
mkos@450 584 }
mkos@450 585 },
mkos@450 586 new AccessControlContext(new ProtectionDomain[]{new ProtectionDomain(null, permissions)})
mkos@450 587 );
mkos@450 588
mkos@450 589 } else {
mkos@450 590 try {
mkos@450 591 return JAXBContext.newInstance(SOAP11Fault.class, SOAP12Fault.class);
mkos@450 592 } catch (JAXBException e) {
mkos@450 593 throw new Error(e);
mkos@450 594 }
ohair@286 595 }
ohair@286 596 }
mkos@450 597
mkos@450 598 private static boolean isJDKRuntime() {
mkos@450 599 return SOAPFaultBuilder.class.getName().contains("internal");
mkos@450 600 }
ohair@286 601 }

mercurial