1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/ResponseBuilder.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,721 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.ws.client.sei; 1.30 + 1.31 +import com.sun.xml.internal.ws.api.SOAPVersion; 1.32 +import com.sun.xml.internal.ws.api.message.Attachment; 1.33 +import com.sun.xml.internal.ws.api.message.AttachmentSet; 1.34 +import com.sun.xml.internal.ws.api.message.Message; 1.35 +import com.sun.xml.internal.ws.api.model.ParameterBinding; 1.36 +import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; 1.37 +import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl; 1.38 +import com.sun.xml.internal.ws.model.ParameterImpl; 1.39 +import com.sun.xml.internal.ws.model.WrapperParameter; 1.40 +import com.sun.xml.internal.ws.resources.ServerMessages; 1.41 +import com.sun.xml.internal.ws.spi.db.RepeatedElementBridge; 1.42 +import com.sun.xml.internal.ws.spi.db.XMLBridge; 1.43 +import com.sun.xml.internal.ws.spi.db.DatabindingException; 1.44 +import com.sun.xml.internal.ws.spi.db.PropertyAccessor; 1.45 +import com.sun.xml.internal.ws.spi.db.WrapperComposite; 1.46 +import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; 1.47 +import com.sun.xml.internal.ws.encoding.StringDataContentHandler; 1.48 +import com.sun.xml.internal.ws.encoding.DataHandlerDataSource; 1.49 + 1.50 +import javax.activation.DataHandler; 1.51 +import javax.imageio.ImageIO; 1.52 +import javax.xml.bind.JAXBException; 1.53 +import javax.xml.namespace.QName; 1.54 +import javax.xml.soap.SOAPException; 1.55 +import javax.xml.soap.SOAPFault; 1.56 +import javax.xml.stream.XMLStreamException; 1.57 +import javax.xml.stream.XMLStreamReader; 1.58 +import javax.xml.stream.XMLStreamConstants; 1.59 +import javax.xml.transform.Source; 1.60 +import javax.xml.ws.Holder; 1.61 +import javax.xml.ws.WebServiceException; 1.62 +import javax.xml.ws.soap.SOAPFaultException; 1.63 +import java.awt.Image; 1.64 +import java.io.IOException; 1.65 +import java.io.InputStream; 1.66 +import java.io.UnsupportedEncodingException; 1.67 +import java.lang.reflect.Type; 1.68 +import java.util.ArrayList; 1.69 +import java.util.Collection; 1.70 +import java.util.HashMap; 1.71 +import java.util.Iterator; 1.72 +import java.util.List; 1.73 +import java.util.Map; 1.74 + 1.75 +/** 1.76 + * Reads a response {@link Message}, disassembles it, and moves obtained Java values 1.77 + * to the expected places. 1.78 + * 1.79 + * @author Kohsuke Kawaguchi 1.80 + * @author Jitendra Kotamraju 1.81 + */ 1.82 +public abstract class ResponseBuilder { 1.83 + /** 1.84 + * Reads a response {@link Message}, disassembles it, and moves obtained Java values 1.85 + * to the expected places. 1.86 + * 1.87 + * @param reply 1.88 + * The reply {@link Message} to be de-composed. 1.89 + * @param args 1.90 + * The Java arguments given to the SEI method invocation. 1.91 + * Some parts of the reply message may be set to {@link Holder}s in the arguments. 1.92 + * @return 1.93 + * If a part of the reply message is returned as a return value from 1.94 + * the SEI method, this method returns that value. Otherwise null. 1.95 + * @throws JAXBException 1.96 + * if there's an error during unmarshalling the reply message. 1.97 + * @throws XMLStreamException 1.98 + * if there's an error during unmarshalling the reply message. 1.99 + */ 1.100 + public abstract Object readResponse(Message reply, Object[] args) throws JAXBException, XMLStreamException; 1.101 + 1.102 + static final class WrappedPartBuilder { 1.103 + private final XMLBridge bridge; 1.104 + private final ValueSetter setter; 1.105 + public WrappedPartBuilder(XMLBridge bridge, ValueSetter setter) { 1.106 + this.bridge = bridge; 1.107 + this.setter = setter; 1.108 + } 1.109 + final Object readResponse(Object[] args, XMLStreamReader r, AttachmentSet att) throws JAXBException { 1.110 + Object obj; 1.111 + AttachmentUnmarshallerImpl au = (att != null)?new AttachmentUnmarshallerImpl(att):null; 1.112 + if (bridge instanceof RepeatedElementBridge) { 1.113 + RepeatedElementBridge rbridge = (RepeatedElementBridge)bridge; 1.114 + ArrayList list = new ArrayList(); 1.115 + QName name = r.getName(); 1.116 + while (r.getEventType()==XMLStreamReader.START_ELEMENT && name.equals(r.getName())) { 1.117 + list.add(rbridge.unmarshal(r, au)); 1.118 + XMLStreamReaderUtil.toNextTag(r, name); 1.119 + } 1.120 + obj = rbridge.collectionHandler().convert(list); 1.121 + } else { 1.122 + obj = bridge.unmarshal(r, au); 1.123 + } 1.124 + return setter.put(obj,args); 1.125 + } 1.126 + } 1.127 + /** 1.128 + * {@link ResponseBuilder.PartBuilder} keyed by the element name (inside the wrapper element.) 1.129 + */ 1.130 + protected Map<QName,WrappedPartBuilder> wrappedParts = null; 1.131 + protected QName wrapperName; 1.132 + 1.133 + protected Object readWrappedResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException { 1.134 + Object retVal = null; 1.135 + 1.136 + if (!msg.hasPayload()) { 1.137 + throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element"); 1.138 + } 1.139 + XMLStreamReader reader = msg.readPayload(); 1.140 + XMLStreamReaderUtil.verifyTag(reader,wrapperName); 1.141 + reader.nextTag(); 1.142 + 1.143 + while(reader.getEventType()==XMLStreamReader.START_ELEMENT) { 1.144 + // TODO: QName has a performance issue 1.145 + WrappedPartBuilder part = wrappedParts.get(reader.getName()); 1.146 + if(part==null) { 1.147 + // no corresponding part found. ignore 1.148 + XMLStreamReaderUtil.skipElement(reader); 1.149 + reader.nextTag(); 1.150 + } else { 1.151 + Object o = part.readResponse(args,reader, msg.getAttachments()); 1.152 + // there's only at most one ResponseBuilder that returns a value. 1.153 + if(o!=null) { 1.154 + assert retVal==null; 1.155 + retVal = o; 1.156 + } 1.157 + } 1.158 + // skip any whitespace 1.159 + if (reader.getEventType() != XMLStreamConstants.START_ELEMENT && 1.160 + reader.getEventType() != XMLStreamConstants.END_ELEMENT) { 1.161 + XMLStreamReaderUtil.nextElementContent(reader); 1.162 + } 1.163 + } 1.164 + 1.165 + // we are done with the body 1.166 + reader.close(); 1.167 + XMLStreamReaderFactory.recycle(reader); 1.168 + 1.169 + return retVal; 1.170 + } 1.171 + 1.172 + static final class None extends ResponseBuilder { 1.173 + private None(){ 1.174 + } 1.175 + @Override 1.176 + public Object readResponse(Message msg, Object[] args) { 1.177 + msg.consume(); 1.178 + return null; 1.179 + } 1.180 + } 1.181 + 1.182 + /** 1.183 + * The singleton instance that produces null return value. 1.184 + * Used for operations that doesn't have any output. 1.185 + */ 1.186 + public final static ResponseBuilder NONE = new None(); 1.187 + 1.188 + /** 1.189 + * Returns the 'uninitialized' value for the given type. 1.190 + * 1.191 + * <p> 1.192 + * For primitive types, it's '0', and for reference types, it's null. 1.193 + */ 1.194 + @SuppressWarnings("element-type-mismatch") 1.195 + public static Object getVMUninitializedValue(Type type) { 1.196 + // if this map returns null, that means the 'type' is a reference type, 1.197 + // in which case 'null' is the correct null value, so this code is correct. 1.198 + return primitiveUninitializedValues.get(type); 1.199 + } 1.200 + 1.201 + private static final Map<Class,Object> primitiveUninitializedValues = new HashMap<Class, Object>(); 1.202 + 1.203 + static { 1.204 + Map<Class, Object> m = primitiveUninitializedValues; 1.205 + m.put(int.class,(int)0); 1.206 + m.put(char.class,(char)0); 1.207 + m.put(byte.class,(byte)0); 1.208 + m.put(short.class,(short)0); 1.209 + m.put(long.class,(long)0); 1.210 + m.put(float.class,(float)0); 1.211 + m.put(double.class,(double)0); 1.212 + } 1.213 + 1.214 + /** 1.215 + * {@link ResponseBuilder} that sets the VM uninitialized value to the type. 1.216 + */ 1.217 + public static final class NullSetter extends ResponseBuilder { 1.218 + private final ValueSetter setter; 1.219 + private final Object nullValue; 1.220 + 1.221 + public NullSetter(ValueSetter setter, Object nullValue){ 1.222 + assert setter!=null; 1.223 + this.nullValue = nullValue; 1.224 + this.setter = setter; 1.225 + } 1.226 + @Override 1.227 + public Object readResponse(Message msg, Object[] args) { 1.228 + return setter.put(nullValue, args); 1.229 + } 1.230 + } 1.231 + 1.232 + /** 1.233 + * {@link ResponseBuilder} that is a composition of multiple 1.234 + * {@link ResponseBuilder}s. 1.235 + * 1.236 + * <p> 1.237 + * Sometimes we need to look at multiple parts of the reply message 1.238 + * (say, two header params, one body param, and three attachments, etc.) 1.239 + * and that's when this object is used to combine multiple {@link ResponseBuilder}s 1.240 + * (that each responsible for handling one part). 1.241 + * 1.242 + * <p> 1.243 + * The model guarantees that only at most one {@link ResponseBuilder} will 1.244 + * return a value as a return value (and everything else has to go to 1.245 + * {@link Holder}s.) 1.246 + */ 1.247 + public static final class Composite extends ResponseBuilder { 1.248 + private final ResponseBuilder[] builders; 1.249 + 1.250 + public Composite(ResponseBuilder... builders) { 1.251 + this.builders = builders; 1.252 + } 1.253 + 1.254 + public Composite(Collection<? extends ResponseBuilder> builders) { 1.255 + this(builders.toArray(new ResponseBuilder[builders.size()])); 1.256 + } 1.257 + 1.258 + @Override 1.259 + public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException { 1.260 + Object retVal = null; 1.261 + for (ResponseBuilder builder : builders) { 1.262 + Object r = builder.readResponse(msg,args); 1.263 + // there's only at most one ResponseBuilder that returns a value. 1.264 + if(r!=null) { 1.265 + assert retVal==null; 1.266 + retVal = r; 1.267 + } 1.268 + } 1.269 + return retVal; 1.270 + } 1.271 + } 1.272 + 1.273 + /** 1.274 + * Reads an Attachment into a Java parameter. 1.275 + */ 1.276 + public static abstract class AttachmentBuilder extends ResponseBuilder { 1.277 + protected final ValueSetter setter; 1.278 + protected final ParameterImpl param; 1.279 + private final String pname; 1.280 + private final String pname1; 1.281 + 1.282 + AttachmentBuilder(ParameterImpl param, ValueSetter setter) { 1.283 + this.setter = setter; 1.284 + this.param = param; 1.285 + this.pname = param.getPartName(); 1.286 + this.pname1 = "<"+pname; 1.287 + } 1.288 + 1.289 + /** 1.290 + * Creates an AttachmentBuilder based on the parameter type 1.291 + * 1.292 + * @param param 1.293 + * runtime Parameter that abstracts the annotated java parameter 1.294 + * @param setter 1.295 + * specifies how the obtained value is set into the argument. Takes 1.296 + * care of Holder arguments. 1.297 + */ 1.298 + public static ResponseBuilder createAttachmentBuilder(ParameterImpl param, ValueSetter setter) { 1.299 + Class type = (Class)param.getTypeInfo().type; 1.300 + if (DataHandler.class.isAssignableFrom(type)) { 1.301 + return new DataHandlerBuilder(param, setter); 1.302 + } else if (byte[].class==type) { 1.303 + return new ByteArrayBuilder(param, setter); 1.304 + } else if(Source.class.isAssignableFrom(type)) { 1.305 + return new SourceBuilder(param, setter); 1.306 + } else if(Image.class.isAssignableFrom(type)) { 1.307 + return new ImageBuilder(param, setter); 1.308 + } else if(InputStream.class==type) { 1.309 + return new InputStreamBuilder(param, setter); 1.310 + } else if(isXMLMimeType(param.getBinding().getMimeType())) { 1.311 + return new JAXBBuilder(param, setter); 1.312 + } else if(String.class.isAssignableFrom(type)) { 1.313 + return new StringBuilder(param, setter); 1.314 + } else { 1.315 + throw new UnsupportedOperationException("Unexpected Attachment type ="+type); 1.316 + } 1.317 + } 1.318 + 1.319 + @Override 1.320 + public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException { 1.321 + // TODO not to loop 1.322 + for (Attachment att : msg.getAttachments()) { 1.323 + String part = getWSDLPartName(att); 1.324 + if (part == null) { 1.325 + continue; 1.326 + } 1.327 + if(part.equals(pname) || part.equals(pname1)){ 1.328 + return mapAttachment(att, args); 1.329 + } 1.330 + } 1.331 + return null; 1.332 + } 1.333 + 1.334 + abstract Object mapAttachment(Attachment att, Object[] args) throws JAXBException; 1.335 + } 1.336 + 1.337 + private static final class DataHandlerBuilder extends AttachmentBuilder { 1.338 + DataHandlerBuilder(ParameterImpl param, ValueSetter setter) { 1.339 + super(param, setter); 1.340 + } 1.341 + 1.342 + @Override 1.343 + Object mapAttachment(Attachment att, Object[] args) { 1.344 + return setter.put(att.asDataHandler(), args); 1.345 + } 1.346 + } 1.347 + 1.348 + private static final class StringBuilder extends AttachmentBuilder { 1.349 + StringBuilder(ParameterImpl param, ValueSetter setter) { 1.350 + super(param, setter); 1.351 + } 1.352 + 1.353 + @Override 1.354 + Object mapAttachment(Attachment att, Object[] args) { 1.355 + att.getContentType(); 1.356 + StringDataContentHandler sdh = new StringDataContentHandler(); 1.357 + try { 1.358 + String str = (String)sdh.getContent(new DataHandlerDataSource(att.asDataHandler())); 1.359 + return setter.put(str, args); 1.360 + } catch(Exception e) { 1.361 + throw new WebServiceException(e); 1.362 + } 1.363 + 1.364 + } 1.365 + } 1.366 + 1.367 + private static final class ByteArrayBuilder extends AttachmentBuilder { 1.368 + ByteArrayBuilder(ParameterImpl param, ValueSetter setter) { 1.369 + super(param, setter); 1.370 + } 1.371 + 1.372 + @Override 1.373 + Object mapAttachment(Attachment att, Object[] args) { 1.374 + return setter.put(att.asByteArray(), args); 1.375 + } 1.376 + } 1.377 + 1.378 + private static final class SourceBuilder extends AttachmentBuilder { 1.379 + SourceBuilder(ParameterImpl param, ValueSetter setter) { 1.380 + super(param, setter); 1.381 + } 1.382 + 1.383 + @Override 1.384 + Object mapAttachment(Attachment att, Object[] args) { 1.385 + return setter.put(att.asSource(), args); 1.386 + } 1.387 + } 1.388 + 1.389 + private static final class ImageBuilder extends AttachmentBuilder { 1.390 + ImageBuilder(ParameterImpl param, ValueSetter setter) { 1.391 + super(param, setter); 1.392 + } 1.393 + 1.394 + @Override 1.395 + Object mapAttachment(Attachment att, Object[] args) { 1.396 + Image image; 1.397 + InputStream is = null; 1.398 + try { 1.399 + is = att.asInputStream(); 1.400 + image = ImageIO.read(is); 1.401 + } catch(IOException ioe) { 1.402 + throw new WebServiceException(ioe); 1.403 + } finally { 1.404 + if (is != null) { 1.405 + try { 1.406 + is.close(); 1.407 + } catch(IOException ioe) { 1.408 + throw new WebServiceException(ioe); 1.409 + } 1.410 + } 1.411 + } 1.412 + return setter.put(image, args); 1.413 + } 1.414 + } 1.415 + 1.416 + private static final class InputStreamBuilder extends AttachmentBuilder { 1.417 + InputStreamBuilder(ParameterImpl param, ValueSetter setter) { 1.418 + super(param, setter); 1.419 + } 1.420 + 1.421 + @Override 1.422 + Object mapAttachment(Attachment att, Object[] args) { 1.423 + return setter.put(att.asInputStream(), args); 1.424 + } 1.425 + } 1.426 + 1.427 + private static final class JAXBBuilder extends AttachmentBuilder { 1.428 + JAXBBuilder(ParameterImpl param, ValueSetter setter) { 1.429 + super(param, setter); 1.430 + } 1.431 + 1.432 + @Override 1.433 + Object mapAttachment(Attachment att, Object[] args) throws JAXBException { 1.434 + Object obj = param.getXMLBridge().unmarshal(att.asInputStream()); 1.435 + return setter.put(obj, args); 1.436 + } 1.437 + } 1.438 + 1.439 + /** 1.440 + * Gets the WSDL part name of this attachment. 1.441 + * 1.442 + * <p> 1.443 + * According to WSI AP 1.0 1.444 + * <PRE> 1.445 + * 3.8 Value-space of Content-Id Header 1.446 + * Definition: content-id part encoding 1.447 + * The "content-id part encoding" consists of the concatenation of: 1.448 + * The value of the name attribute of the wsdl:part element referenced by the mime:content, in which characters disallowed in content-id headers (non-ASCII characters as represented by code points above 0x7F) are escaped as follows: 1.449 + * o Each disallowed character is converted to UTF-8 as one or more bytes. 1.450 + * o Any bytes corresponding to a disallowed character are escaped with the URI escaping mechanism (that is, converted to %HH, where HH is the hexadecimal notation of the byte value). 1.451 + * o The original character is replaced by the resulting character sequence. 1.452 + * The character '=' (0x3D). 1.453 + * A globally unique value such as a UUID. 1.454 + * The character '@' (0x40). 1.455 + * A valid domain name under the authority of the entity constructing the message. 1.456 + * </PRE> 1.457 + * 1.458 + * So a wsdl:part fooPart will be encoded as: 1.459 + * <fooPart=somereallybignumberlikeauuid@example.com> 1.460 + * 1.461 + * @return null 1.462 + * if the parsing fails. 1.463 + */ 1.464 + @SuppressWarnings("FinalStaticMethod") 1.465 + public static final String getWSDLPartName(com.sun.xml.internal.ws.api.message.Attachment att){ 1.466 + String cId = att.getContentId(); 1.467 + 1.468 + int index = cId.lastIndexOf('@', cId.length()); 1.469 + if(index == -1){ 1.470 + return null; 1.471 + } 1.472 + String localPart = cId.substring(0, index); 1.473 + index = localPart.lastIndexOf('=', localPart.length()); 1.474 + if(index == -1){ 1.475 + return null; 1.476 + } 1.477 + try { 1.478 + return java.net.URLDecoder.decode(localPart.substring(0, index), "UTF-8"); 1.479 + } catch (UnsupportedEncodingException e) { 1.480 + throw new WebServiceException(e); 1.481 + } 1.482 + } 1.483 + 1.484 + 1.485 + /** 1.486 + * Reads a header into a JAXB object. 1.487 + */ 1.488 + public static final class Header extends ResponseBuilder { 1.489 + private final XMLBridge<?> bridge; 1.490 + private final ValueSetter setter; 1.491 + private final QName headerName; 1.492 + private final SOAPVersion soapVersion; 1.493 + 1.494 + /** 1.495 + * @param soapVersion 1.496 + * SOAP1.1 or 1.2 1.497 + * @param name 1.498 + * The name of the header element. 1.499 + * @param bridge 1.500 + * specifies how to unmarshal a header into a JAXB object. 1.501 + * @param setter 1.502 + * specifies how the obtained value is returned to the client. 1.503 + */ 1.504 + public Header(SOAPVersion soapVersion, QName name, XMLBridge<?> bridge, ValueSetter setter) { 1.505 + this.soapVersion = soapVersion; 1.506 + this.headerName = name; 1.507 + this.bridge = bridge; 1.508 + this.setter = setter; 1.509 + } 1.510 + 1.511 + public Header(SOAPVersion soapVersion, ParameterImpl param, ValueSetter setter) { 1.512 + this(soapVersion, 1.513 + param.getTypeInfo().tagName, 1.514 + param.getXMLBridge(), 1.515 + setter); 1.516 + assert param.getOutBinding()== ParameterBinding.HEADER; 1.517 + } 1.518 + 1.519 + private SOAPFaultException createDuplicateHeaderException() { 1.520 + try { 1.521 + SOAPFault fault = soapVersion.getSOAPFactory().createFault(); 1.522 + fault.setFaultCode(soapVersion.faultCodeServer); 1.523 + fault.setFaultString(ServerMessages.DUPLICATE_PORT_KNOWN_HEADER(headerName)); 1.524 + return new SOAPFaultException(fault); 1.525 + } catch(SOAPException e) { 1.526 + throw new WebServiceException(e); 1.527 + } 1.528 + } 1.529 + 1.530 + @Override 1.531 + public Object readResponse(Message msg, Object[] args) throws JAXBException { 1.532 + com.sun.xml.internal.ws.api.message.Header header = null; 1.533 + Iterator<com.sun.xml.internal.ws.api.message.Header> it = 1.534 + msg.getHeaders().getHeaders(headerName,true); 1.535 + if (it.hasNext()) { 1.536 + header = it.next(); 1.537 + if (it.hasNext()) { 1.538 + throw createDuplicateHeaderException(); 1.539 + } 1.540 + } 1.541 + 1.542 + if(header!=null) 1.543 + return setter.put( header.readAsJAXB(bridge), args ); 1.544 + else 1.545 + // header not found. 1.546 + return null; 1.547 + } 1.548 + } 1.549 + 1.550 + /** 1.551 + * Reads the whole payload into a single JAXB bean. 1.552 + */ 1.553 + public static final class Body extends ResponseBuilder { 1.554 + private final XMLBridge<?> bridge; 1.555 + private final ValueSetter setter; 1.556 + 1.557 + /** 1.558 + * @param bridge 1.559 + * specifies how to unmarshal the payload into a JAXB object. 1.560 + * @param setter 1.561 + * specifies how the obtained value is returned to the client. 1.562 + */ 1.563 + public Body(XMLBridge<?> bridge, ValueSetter setter) { 1.564 + this.bridge = bridge; 1.565 + this.setter = setter; 1.566 + } 1.567 + 1.568 + @Override 1.569 + public Object readResponse(Message msg, Object[] args) throws JAXBException { 1.570 + return setter.put( msg.readPayloadAsJAXB(bridge), args ); 1.571 + } 1.572 + } 1.573 + 1.574 + /** 1.575 + * Treats a payload as multiple parts wrapped into one element, 1.576 + * and processes all such wrapped parts. 1.577 + */ 1.578 + public static final class DocLit extends ResponseBuilder { 1.579 + /** 1.580 + * {@link PartBuilder} keyed by the element name (inside the wrapper element.) 1.581 + */ 1.582 + private final PartBuilder[] parts; 1.583 + 1.584 + private final XMLBridge wrapper; 1.585 + 1.586 + private boolean dynamicWrapper; 1.587 + 1.588 + public DocLit(WrapperParameter wp, ValueSetterFactory setterFactory) { 1.589 + wrapperName = wp.getName(); 1.590 + wrapper = wp.getXMLBridge(); 1.591 + Class wrapperType = (Class) wrapper.getTypeInfo().type; 1.592 + dynamicWrapper = WrapperComposite.class.equals(wrapperType); 1.593 + 1.594 + List<PartBuilder> tempParts = new ArrayList<PartBuilder>(); 1.595 + 1.596 + List<ParameterImpl> children = wp.getWrapperChildren(); 1.597 + for (ParameterImpl p : children) { 1.598 + if(p.isIN()) 1.599 + continue; 1.600 + QName name = p.getName(); 1.601 + if (dynamicWrapper) { 1.602 + if (wrappedParts == null) wrappedParts = new HashMap<QName,WrappedPartBuilder>(); 1.603 + XMLBridge xmlBridge = p.getInlinedRepeatedElementBridge(); 1.604 + if (xmlBridge == null) xmlBridge = p.getXMLBridge(); 1.605 + wrappedParts.put( p.getName(), new WrappedPartBuilder(xmlBridge, setterFactory.get(p))); 1.606 + } else { 1.607 + try { 1.608 + tempParts.add(new PartBuilder( 1.609 + wp.getOwner().getBindingContext().getElementPropertyAccessor( 1.610 + wrapperType, 1.611 + name.getNamespaceURI(), 1.612 + p.getName().getLocalPart()), 1.613 + setterFactory.get(p) 1.614 + )); 1.615 + // wrapper parameter itself always bind to body, and 1.616 + // so do all its children 1.617 + assert p.getBinding()== ParameterBinding.BODY; 1.618 + } catch (JAXBException e) { 1.619 + throw new WebServiceException( // TODO: i18n 1.620 + wrapperType+" do not have a property of the name "+name,e); 1.621 + } 1.622 + } 1.623 + } 1.624 + this.parts = tempParts.toArray(new PartBuilder[tempParts.size()]); 1.625 + } 1.626 + 1.627 + @Override 1.628 + public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException { 1.629 + if (dynamicWrapper) return readWrappedResponse(msg, args); 1.630 + Object retVal = null; 1.631 + 1.632 + if (parts.length>0) { 1.633 + if (!msg.hasPayload()) { 1.634 + throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element"); 1.635 + } 1.636 + XMLStreamReader reader = msg.readPayload(); 1.637 + XMLStreamReaderUtil.verifyTag(reader,wrapperName); 1.638 + Object wrapperBean = wrapper.unmarshal(reader, (msg.getAttachments() != null) ? 1.639 + new AttachmentUnmarshallerImpl(msg.getAttachments()): null); 1.640 + 1.641 + try { 1.642 + for (PartBuilder part : parts) { 1.643 + Object o = part.readResponse(args,wrapperBean); 1.644 + // there's only at most one ResponseBuilder that returns a value. 1.645 + // TODO: reorder parts so that the return value comes at the end. 1.646 + if(o!=null) { 1.647 + assert retVal==null; 1.648 + retVal = o; 1.649 + } 1.650 + } 1.651 + } catch (DatabindingException e) { 1.652 + // this can happen when the set method throw a checked exception or something like that 1.653 + throw new WebServiceException(e); // TODO:i18n 1.654 + } 1.655 + 1.656 + // we are done with the body 1.657 + reader.close(); 1.658 + XMLStreamReaderFactory.recycle(reader); 1.659 + } else { 1.660 + msg.consume(); 1.661 + } 1.662 + 1.663 + return retVal; 1.664 + } 1.665 + 1.666 + /** 1.667 + * Unmarshals each wrapped part into a JAXB object and moves it 1.668 + * to the expected place. 1.669 + */ 1.670 + static final class PartBuilder { 1.671 + private final PropertyAccessor accessor; 1.672 + private final ValueSetter setter; 1.673 + 1.674 + /** 1.675 + * @param accessor 1.676 + * specifies which portion of the wrapper bean to obtain the value from. 1.677 + * @param setter 1.678 + * specifies how the obtained value is returned to the client. 1.679 + */ 1.680 + public PartBuilder(PropertyAccessor accessor, ValueSetter setter) { 1.681 + this.accessor = accessor; 1.682 + this.setter = setter; 1.683 + assert accessor!=null && setter!=null; 1.684 + } 1.685 + 1.686 + final Object readResponse( Object[] args, Object wrapperBean ) { 1.687 + Object obj = accessor.get(wrapperBean); 1.688 + return setter.put(obj,args); 1.689 + } 1.690 + 1.691 + 1.692 + } 1.693 + } 1.694 + 1.695 + /** 1.696 + * Treats a payload as multiple parts wrapped into one element, 1.697 + * and processes all such wrapped parts. 1.698 + */ 1.699 + public static final class RpcLit extends ResponseBuilder { 1.700 + public RpcLit(WrapperParameter wp, ValueSetterFactory setterFactory) { 1.701 + assert wp.getTypeInfo().type== WrapperComposite.class; 1.702 + wrapperName = wp.getName(); 1.703 + wrappedParts = new HashMap<QName,WrappedPartBuilder>(); 1.704 + List<ParameterImpl> children = wp.getWrapperChildren(); 1.705 + for (ParameterImpl p : children) { 1.706 + wrappedParts.put( p.getName(), new WrappedPartBuilder( 1.707 + p.getXMLBridge(), setterFactory.get(p) 1.708 + )); 1.709 + // wrapper parameter itself always bind to body, and 1.710 + // so do all its children 1.711 + assert p.getBinding()== ParameterBinding.BODY; 1.712 + } 1.713 + } 1.714 + 1.715 + @Override 1.716 + public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException { 1.717 + return readWrappedResponse(msg, args); 1.718 + } 1.719 + } 1.720 + 1.721 + private static boolean isXMLMimeType(String mimeType){ 1.722 + return mimeType.equals("text/xml") || mimeType.equals("application/xml"); 1.723 + } 1.724 +}