src/share/jaxws_classes/com/sun/xml/internal/ws/client/sei/ResponseBuilder.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2010, 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.client.sei;
ohair@286 27
ohair@286 28 import com.sun.xml.internal.ws.api.SOAPVersion;
ohair@286 29 import com.sun.xml.internal.ws.api.message.Attachment;
ohair@286 30 import com.sun.xml.internal.ws.api.message.AttachmentSet;
ohair@286 31 import com.sun.xml.internal.ws.api.message.Message;
ohair@286 32 import com.sun.xml.internal.ws.api.model.ParameterBinding;
ohair@286 33 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
ohair@286 34 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
ohair@286 35 import com.sun.xml.internal.ws.model.ParameterImpl;
ohair@286 36 import com.sun.xml.internal.ws.model.WrapperParameter;
ohair@286 37 import com.sun.xml.internal.ws.resources.ServerMessages;
ohair@286 38 import com.sun.xml.internal.ws.spi.db.XMLBridge;
ohair@286 39 import com.sun.xml.internal.ws.spi.db.DatabindingException;
ohair@286 40 import com.sun.xml.internal.ws.spi.db.PropertyAccessor;
ohair@286 41 import com.sun.xml.internal.ws.spi.db.WrapperComposite;
ohair@286 42 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
ohair@286 43 import com.sun.xml.internal.ws.encoding.StringDataContentHandler;
ohair@286 44 import com.sun.xml.internal.ws.encoding.DataHandlerDataSource;
ohair@286 45
ohair@286 46 import javax.activation.DataHandler;
ohair@286 47 import javax.imageio.ImageIO;
ohair@286 48 import javax.xml.bind.JAXBException;
ohair@286 49 import javax.xml.namespace.QName;
ohair@286 50 import javax.xml.soap.SOAPException;
ohair@286 51 import javax.xml.soap.SOAPFault;
ohair@286 52 import javax.xml.stream.XMLStreamException;
ohair@286 53 import javax.xml.stream.XMLStreamReader;
ohair@286 54 import javax.xml.stream.XMLStreamConstants;
ohair@286 55 import javax.xml.transform.Source;
ohair@286 56 import javax.xml.ws.Holder;
ohair@286 57 import javax.xml.ws.WebServiceException;
ohair@286 58 import javax.xml.ws.soap.SOAPFaultException;
ohair@286 59 import java.awt.Image;
ohair@286 60 import java.io.IOException;
ohair@286 61 import java.io.InputStream;
ohair@286 62 import java.io.UnsupportedEncodingException;
ohair@286 63 import java.lang.reflect.Type;
ohair@286 64 import java.util.ArrayList;
ohair@286 65 import java.util.Collection;
ohair@286 66 import java.util.HashMap;
ohair@286 67 import java.util.Iterator;
ohair@286 68 import java.util.List;
ohair@286 69 import java.util.Map;
ohair@286 70
ohair@286 71 /**
ohair@286 72 * Reads a response {@link Message}, disassembles it, and moves obtained Java values
ohair@286 73 * to the expected places.
ohair@286 74 *
ohair@286 75 * @author Kohsuke Kawaguchi
ohair@286 76 * @author Jitendra Kotamraju
ohair@286 77 */
ohair@286 78 public abstract class ResponseBuilder {
ohair@286 79 /**
ohair@286 80 * Reads a response {@link Message}, disassembles it, and moves obtained Java values
ohair@286 81 * to the expected places.
ohair@286 82 *
ohair@286 83 * @param reply
ohair@286 84 * The reply {@link Message} to be de-composed.
ohair@286 85 * @param args
ohair@286 86 * The Java arguments given to the SEI method invocation.
ohair@286 87 * Some parts of the reply message may be set to {@link Holder}s in the arguments.
ohair@286 88 * @return
ohair@286 89 * If a part of the reply message is returned as a return value from
ohair@286 90 * the SEI method, this method returns that value. Otherwise null.
ohair@286 91 * @throws JAXBException
ohair@286 92 * if there's an error during unmarshalling the reply message.
ohair@286 93 * @throws XMLStreamException
ohair@286 94 * if there's an error during unmarshalling the reply message.
ohair@286 95 */
ohair@286 96 public abstract Object readResponse(Message reply, Object[] args) throws JAXBException, XMLStreamException;
ohair@286 97
ohair@286 98 static final class None extends ResponseBuilder {
ohair@286 99 private None(){
ohair@286 100 }
ohair@286 101 public Object readResponse(Message msg, Object[] args) {
ohair@286 102 msg.consume();
ohair@286 103 return null;
ohair@286 104 }
ohair@286 105 }
ohair@286 106
ohair@286 107 /**
ohair@286 108 * The singleton instance that produces null return value.
ohair@286 109 * Used for operations that doesn't have any output.
ohair@286 110 */
ohair@286 111 public static ResponseBuilder NONE = new None();
ohair@286 112
ohair@286 113 /**
ohair@286 114 * Returns the 'uninitialized' value for the given type.
ohair@286 115 *
ohair@286 116 * <p>
ohair@286 117 * For primitive types, it's '0', and for reference types, it's null.
ohair@286 118 */
ohair@286 119 public static Object getVMUninitializedValue(Type type) {
ohair@286 120 // if this map returns null, that means the 'type' is a reference type,
ohair@286 121 // in which case 'null' is the correct null value, so this code is correct.
ohair@286 122 return primitiveUninitializedValues.get(type);
ohair@286 123 }
ohair@286 124
ohair@286 125 private static final Map<Class,Object> primitiveUninitializedValues = new HashMap<Class, Object>();
ohair@286 126
ohair@286 127 static {
ohair@286 128 Map<Class, Object> m = primitiveUninitializedValues;
ohair@286 129 m.put(int.class,(int)0);
ohair@286 130 m.put(char.class,(char)0);
ohair@286 131 m.put(byte.class,(byte)0);
ohair@286 132 m.put(short.class,(short)0);
ohair@286 133 m.put(long.class,(long)0);
ohair@286 134 m.put(float.class,(float)0);
ohair@286 135 m.put(double.class,(double)0);
ohair@286 136 }
ohair@286 137
ohair@286 138 /**
ohair@286 139 * {@link ResponseBuilder} that sets the VM uninitialized value to the type.
ohair@286 140 */
ohair@286 141 public static final class NullSetter extends ResponseBuilder {
ohair@286 142 private final ValueSetter setter;
ohair@286 143 private final Object nullValue;
ohair@286 144
ohair@286 145 public NullSetter(ValueSetter setter, Object nullValue){
ohair@286 146 assert setter!=null;
ohair@286 147 this.nullValue = nullValue;
ohair@286 148 this.setter = setter;
ohair@286 149 }
ohair@286 150 public Object readResponse(Message msg, Object[] args) {
ohair@286 151 return setter.put(nullValue, args);
ohair@286 152 }
ohair@286 153 }
ohair@286 154
ohair@286 155 /**
ohair@286 156 * {@link ResponseBuilder} that is a composition of multiple
ohair@286 157 * {@link ResponseBuilder}s.
ohair@286 158 *
ohair@286 159 * <p>
ohair@286 160 * Sometimes we need to look at multiple parts of the reply message
ohair@286 161 * (say, two header params, one body param, and three attachments, etc.)
ohair@286 162 * and that's when this object is used to combine multiple {@link ResponseBuilder}s
ohair@286 163 * (that each responsible for handling one part).
ohair@286 164 *
ohair@286 165 * <p>
ohair@286 166 * The model guarantees that only at most one {@link ResponseBuilder} will
ohair@286 167 * return a value as a return value (and everything else has to go to
ohair@286 168 * {@link Holder}s.)
ohair@286 169 */
ohair@286 170 public static final class Composite extends ResponseBuilder {
ohair@286 171 private final ResponseBuilder[] builders;
ohair@286 172
ohair@286 173 public Composite(ResponseBuilder... builders) {
ohair@286 174 this.builders = builders;
ohair@286 175 }
ohair@286 176
ohair@286 177 public Composite(Collection<? extends ResponseBuilder> builders) {
ohair@286 178 this(builders.toArray(new ResponseBuilder[builders.size()]));
ohair@286 179 }
ohair@286 180
ohair@286 181 public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
ohair@286 182 Object retVal = null;
ohair@286 183 for (ResponseBuilder builder : builders) {
ohair@286 184 Object r = builder.readResponse(msg,args);
ohair@286 185 // there's only at most one ResponseBuilder that returns a value.
ohair@286 186 if(r!=null) {
ohair@286 187 assert retVal==null;
ohair@286 188 retVal = r;
ohair@286 189 }
ohair@286 190 }
ohair@286 191 return retVal;
ohair@286 192 }
ohair@286 193 }
ohair@286 194
ohair@286 195 /**
ohair@286 196 * Reads an Attachment into a Java parameter.
ohair@286 197 */
ohair@286 198 public static abstract class AttachmentBuilder extends ResponseBuilder {
ohair@286 199 protected final ValueSetter setter;
ohair@286 200 protected final ParameterImpl param;
ohair@286 201 private final String pname;
ohair@286 202 private final String pname1;
ohair@286 203
ohair@286 204 AttachmentBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 205 this.setter = setter;
ohair@286 206 this.param = param;
ohair@286 207 this.pname = param.getPartName();
ohair@286 208 this.pname1 = "<"+pname;
ohair@286 209 }
ohair@286 210
ohair@286 211 /**
ohair@286 212 * Creates an AttachmentBuilder based on the parameter type
ohair@286 213 *
ohair@286 214 * @param param
ohair@286 215 * runtime Parameter that abstracts the annotated java parameter
ohair@286 216 * @param setter
ohair@286 217 * specifies how the obtained value is set into the argument. Takes
ohair@286 218 * care of Holder arguments.
ohair@286 219 */
ohair@286 220 public static ResponseBuilder createAttachmentBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 221 Class type = (Class)param.getTypeInfo().type;
ohair@286 222 if (DataHandler.class.isAssignableFrom(type)) {
ohair@286 223 return new DataHandlerBuilder(param, setter);
ohair@286 224 } else if (byte[].class==type) {
ohair@286 225 return new ByteArrayBuilder(param, setter);
ohair@286 226 } else if(Source.class.isAssignableFrom(type)) {
ohair@286 227 return new SourceBuilder(param, setter);
ohair@286 228 } else if(Image.class.isAssignableFrom(type)) {
ohair@286 229 return new ImageBuilder(param, setter);
ohair@286 230 } else if(InputStream.class==type) {
ohair@286 231 return new InputStreamBuilder(param, setter);
ohair@286 232 } else if(isXMLMimeType(param.getBinding().getMimeType())) {
ohair@286 233 return new JAXBBuilder(param, setter);
ohair@286 234 } else if(String.class.isAssignableFrom(type)) {
ohair@286 235 return new StringBuilder(param, setter);
ohair@286 236 } else {
ohair@286 237 throw new UnsupportedOperationException("Unexpected Attachment type ="+type);
ohair@286 238 }
ohair@286 239 }
ohair@286 240
ohair@286 241 public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
ohair@286 242 // TODO not to loop
ohair@286 243 for (Attachment att : msg.getAttachments()) {
ohair@286 244 String part = getWSDLPartName(att);
ohair@286 245 if (part == null) {
ohair@286 246 continue;
ohair@286 247 }
ohair@286 248 if(part.equals(pname) || part.equals(pname1)){
ohair@286 249 return mapAttachment(att, args);
ohair@286 250 }
ohair@286 251 }
ohair@286 252 return null;
ohair@286 253 }
ohair@286 254
ohair@286 255 abstract Object mapAttachment(Attachment att, Object[] args) throws JAXBException;
ohair@286 256 }
ohair@286 257
ohair@286 258 private static final class DataHandlerBuilder extends AttachmentBuilder {
ohair@286 259 DataHandlerBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 260 super(param, setter);
ohair@286 261 }
ohair@286 262
ohair@286 263 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 264 return setter.put(att.asDataHandler(), args);
ohair@286 265 }
ohair@286 266 }
ohair@286 267
ohair@286 268 private static final class StringBuilder extends AttachmentBuilder {
ohair@286 269 StringBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 270 super(param, setter);
ohair@286 271 }
ohair@286 272
ohair@286 273 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 274 att.getContentType();
ohair@286 275 StringDataContentHandler sdh = new StringDataContentHandler();
ohair@286 276 try {
ohair@286 277 String str = (String)sdh.getContent(new DataHandlerDataSource(att.asDataHandler()));
ohair@286 278 return setter.put(str, args);
ohair@286 279 } catch(Exception e) {
ohair@286 280 throw new WebServiceException(e);
ohair@286 281 }
ohair@286 282
ohair@286 283 }
ohair@286 284 }
ohair@286 285
ohair@286 286 private static final class ByteArrayBuilder extends AttachmentBuilder {
ohair@286 287 ByteArrayBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 288 super(param, setter);
ohair@286 289 }
ohair@286 290
ohair@286 291 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 292 return setter.put(att.asByteArray(), args);
ohair@286 293 }
ohair@286 294 }
ohair@286 295
ohair@286 296 private static final class SourceBuilder extends AttachmentBuilder {
ohair@286 297 SourceBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 298 super(param, setter);
ohair@286 299 }
ohair@286 300
ohair@286 301 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 302 return setter.put(att.asSource(), args);
ohair@286 303 }
ohair@286 304 }
ohair@286 305
ohair@286 306 private static final class ImageBuilder extends AttachmentBuilder {
ohair@286 307 ImageBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 308 super(param, setter);
ohair@286 309 }
ohair@286 310
ohair@286 311 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 312 Image image;
ohair@286 313 InputStream is = null;
ohair@286 314 try {
ohair@286 315 is = att.asInputStream();
ohair@286 316 image = ImageIO.read(is);
ohair@286 317 } catch(IOException ioe) {
ohair@286 318 throw new WebServiceException(ioe);
ohair@286 319 } finally {
ohair@286 320 if (is != null) {
ohair@286 321 try {
ohair@286 322 is.close();
ohair@286 323 } catch(IOException ioe) {
ohair@286 324 throw new WebServiceException(ioe);
ohair@286 325 }
ohair@286 326 }
ohair@286 327 }
ohair@286 328 return setter.put(image, args);
ohair@286 329 }
ohair@286 330 }
ohair@286 331
ohair@286 332 private static final class InputStreamBuilder extends AttachmentBuilder {
ohair@286 333 InputStreamBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 334 super(param, setter);
ohair@286 335 }
ohair@286 336
ohair@286 337 Object mapAttachment(Attachment att, Object[] args) {
ohair@286 338 return setter.put(att.asInputStream(), args);
ohair@286 339 }
ohair@286 340 }
ohair@286 341
ohair@286 342 private static final class JAXBBuilder extends AttachmentBuilder {
ohair@286 343 JAXBBuilder(ParameterImpl param, ValueSetter setter) {
ohair@286 344 super(param, setter);
ohair@286 345 }
ohair@286 346
ohair@286 347 Object mapAttachment(Attachment att, Object[] args) throws JAXBException {
ohair@286 348 Object obj = param.getXMLBridge().unmarshal(att.asInputStream());
ohair@286 349 return setter.put(obj, args);
ohair@286 350 }
ohair@286 351 }
ohair@286 352
ohair@286 353 /**
ohair@286 354 * Gets the WSDL part name of this attachment.
ohair@286 355 *
ohair@286 356 * <p>
ohair@286 357 * According to WSI AP 1.0
ohair@286 358 * <PRE>
ohair@286 359 * 3.8 Value-space of Content-Id Header
ohair@286 360 * Definition: content-id part encoding
ohair@286 361 * The "content-id part encoding" consists of the concatenation of:
ohair@286 362 * 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:
ohair@286 363 * o Each disallowed character is converted to UTF-8 as one or more bytes.
ohair@286 364 * 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).
ohair@286 365 * o The original character is replaced by the resulting character sequence.
ohair@286 366 * The character '=' (0x3D).
ohair@286 367 * A globally unique value such as a UUID.
ohair@286 368 * The character '@' (0x40).
ohair@286 369 * A valid domain name under the authority of the entity constructing the message.
ohair@286 370 * </PRE>
ohair@286 371 *
ohair@286 372 * So a wsdl:part fooPart will be encoded as:
ohair@286 373 * <fooPart=somereallybignumberlikeauuid@example.com>
ohair@286 374 *
ohair@286 375 * @return null
ohair@286 376 * if the parsing fails.
ohair@286 377 */
ohair@286 378 public static final String getWSDLPartName(com.sun.xml.internal.ws.api.message.Attachment att){
ohair@286 379 String cId = att.getContentId();
ohair@286 380
ohair@286 381 int index = cId.lastIndexOf('@', cId.length());
ohair@286 382 if(index == -1){
ohair@286 383 return null;
ohair@286 384 }
ohair@286 385 String localPart = cId.substring(0, index);
ohair@286 386 index = localPart.lastIndexOf('=', localPart.length());
ohair@286 387 if(index == -1){
ohair@286 388 return null;
ohair@286 389 }
ohair@286 390 try {
ohair@286 391 return java.net.URLDecoder.decode(localPart.substring(0, index), "UTF-8");
ohair@286 392 } catch (UnsupportedEncodingException e) {
ohair@286 393 throw new WebServiceException(e);
ohair@286 394 }
ohair@286 395 }
ohair@286 396
ohair@286 397
ohair@286 398 /**
ohair@286 399 * Reads a header into a JAXB object.
ohair@286 400 */
ohair@286 401 public static final class Header extends ResponseBuilder {
ohair@286 402 private final XMLBridge<?> bridge;
ohair@286 403 private final ValueSetter setter;
ohair@286 404 private final QName headerName;
ohair@286 405 private final SOAPVersion soapVersion;
ohair@286 406
ohair@286 407 /**
ohair@286 408 * @param soapVersion
ohair@286 409 * SOAP1.1 or 1.2
ohair@286 410 * @param name
ohair@286 411 * The name of the header element.
ohair@286 412 * @param bridge
ohair@286 413 * specifies how to unmarshal a header into a JAXB object.
ohair@286 414 * @param setter
ohair@286 415 * specifies how the obtained value is returned to the client.
ohair@286 416 */
ohair@286 417 public Header(SOAPVersion soapVersion, QName name, XMLBridge<?> bridge, ValueSetter setter) {
ohair@286 418 this.soapVersion = soapVersion;
ohair@286 419 this.headerName = name;
ohair@286 420 this.bridge = bridge;
ohair@286 421 this.setter = setter;
ohair@286 422 }
ohair@286 423
ohair@286 424 public Header(SOAPVersion soapVersion, ParameterImpl param, ValueSetter setter) {
ohair@286 425 this(soapVersion,
ohair@286 426 param.getTypeInfo().tagName,
ohair@286 427 param.getXMLBridge(),
ohair@286 428 setter);
ohair@286 429 assert param.getOutBinding()== ParameterBinding.HEADER;
ohair@286 430 }
ohair@286 431
ohair@286 432 private SOAPFaultException createDuplicateHeaderException() {
ohair@286 433 try {
ohair@286 434 SOAPFault fault = soapVersion.getSOAPFactory().createFault();
ohair@286 435 fault.setFaultCode(soapVersion.faultCodeServer);
ohair@286 436 fault.setFaultString(ServerMessages.DUPLICATE_PORT_KNOWN_HEADER(headerName));
ohair@286 437 return new SOAPFaultException(fault);
ohair@286 438 } catch(SOAPException e) {
ohair@286 439 throw new WebServiceException(e);
ohair@286 440 }
ohair@286 441 }
ohair@286 442
ohair@286 443 public Object readResponse(Message msg, Object[] args) throws JAXBException {
ohair@286 444 com.sun.xml.internal.ws.api.message.Header header = null;
ohair@286 445 Iterator<com.sun.xml.internal.ws.api.message.Header> it =
ohair@286 446 msg.getHeaders().getHeaders(headerName,true);
ohair@286 447 if (it.hasNext()) {
ohair@286 448 header = it.next();
ohair@286 449 if (it.hasNext()) {
ohair@286 450 throw createDuplicateHeaderException();
ohair@286 451 }
ohair@286 452 }
ohair@286 453
ohair@286 454 if(header!=null)
ohair@286 455 return setter.put( header.readAsJAXB(bridge), args );
ohair@286 456 else
ohair@286 457 // header not found.
ohair@286 458 return null;
ohair@286 459 }
ohair@286 460 }
ohair@286 461
ohair@286 462 /**
ohair@286 463 * Reads the whole payload into a single JAXB bean.
ohair@286 464 */
ohair@286 465 public static final class Body extends ResponseBuilder {
ohair@286 466 private final XMLBridge<?> bridge;
ohair@286 467 private final ValueSetter setter;
ohair@286 468
ohair@286 469 /**
ohair@286 470 * @param bridge
ohair@286 471 * specifies how to unmarshal the payload into a JAXB object.
ohair@286 472 * @param setter
ohair@286 473 * specifies how the obtained value is returned to the client.
ohair@286 474 */
ohair@286 475 public Body(XMLBridge<?> bridge, ValueSetter setter) {
ohair@286 476 this.bridge = bridge;
ohair@286 477 this.setter = setter;
ohair@286 478 }
ohair@286 479
ohair@286 480 public Object readResponse(Message msg, Object[] args) throws JAXBException {
ohair@286 481 return setter.put( msg.readPayloadAsJAXB(bridge), args );
ohair@286 482 }
ohair@286 483 }
ohair@286 484
ohair@286 485 /**
ohair@286 486 * Treats a payload as multiple parts wrapped into one element,
ohair@286 487 * and processes all such wrapped parts.
ohair@286 488 */
ohair@286 489 public static final class DocLit extends ResponseBuilder {
ohair@286 490 /**
ohair@286 491 * {@link PartBuilder} keyed by the element name (inside the wrapper element.)
ohair@286 492 */
ohair@286 493 private final PartBuilder[] parts;
ohair@286 494
ohair@286 495 private final XMLBridge wrapper;
ohair@286 496
ohair@286 497 private final QName wrapperName;
ohair@286 498
ohair@286 499 public DocLit(WrapperParameter wp, ValueSetterFactory setterFactory) {
ohair@286 500 wrapperName = wp.getName();
ohair@286 501 wrapper = wp.getXMLBridge();
ohair@286 502 Class wrapperType = (Class) wrapper.getTypeInfo().type;
ohair@286 503
ohair@286 504 List<PartBuilder> parts = new ArrayList<PartBuilder>();
ohair@286 505
ohair@286 506 List<ParameterImpl> children = wp.getWrapperChildren();
ohair@286 507 for (ParameterImpl p : children) {
ohair@286 508 if(p.isIN())
ohair@286 509 continue;
ohair@286 510 QName name = p.getName();
ohair@286 511 try {
ohair@286 512 parts.add( new PartBuilder(
ohair@286 513 wp.getOwner().getBindingContext().getElementPropertyAccessor(
ohair@286 514 wrapperType,
ohair@286 515 name.getNamespaceURI(),
ohair@286 516 p.getName().getLocalPart()),
ohair@286 517 setterFactory.get(p)
ohair@286 518 ));
ohair@286 519 // wrapper parameter itself always bind to body, and
ohair@286 520 // so do all its children
ohair@286 521 assert p.getBinding()== ParameterBinding.BODY;
ohair@286 522 } catch (JAXBException e) {
ohair@286 523 throw new WebServiceException( // TODO: i18n
ohair@286 524 wrapperType+" do not have a property of the name "+name,e);
ohair@286 525 }
ohair@286 526 }
ohair@286 527
ohair@286 528 this.parts = parts.toArray(new PartBuilder[parts.size()]);
ohair@286 529 }
ohair@286 530
ohair@286 531 public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
ohair@286 532 Object retVal = null;
ohair@286 533
ohair@286 534 if (parts.length>0) {
ohair@286 535 if (!msg.hasPayload()) {
ohair@286 536 throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
ohair@286 537 }
ohair@286 538 XMLStreamReader reader = msg.readPayload();
ohair@286 539 XMLStreamReaderUtil.verifyTag(reader,wrapperName);
ohair@286 540 Object wrapperBean = wrapper.unmarshal(reader, (msg.getAttachments() != null) ?
ohair@286 541 new AttachmentUnmarshallerImpl(msg.getAttachments()): null);
ohair@286 542
ohair@286 543 try {
ohair@286 544 for (PartBuilder part : parts) {
ohair@286 545 Object o = part.readResponse(args,wrapperBean);
ohair@286 546 // there's only at most one ResponseBuilder that returns a value.
ohair@286 547 // TODO: reorder parts so that the return value comes at the end.
ohair@286 548 if(o!=null) {
ohair@286 549 assert retVal==null;
ohair@286 550 retVal = o;
ohair@286 551 }
ohair@286 552 }
ohair@286 553 } catch (DatabindingException e) {
ohair@286 554 // this can happen when the set method throw a checked exception or something like that
ohair@286 555 throw new WebServiceException(e); // TODO:i18n
ohair@286 556 }
ohair@286 557
ohair@286 558 // we are done with the body
ohair@286 559 reader.close();
ohair@286 560 XMLStreamReaderFactory.recycle(reader);
ohair@286 561 } else {
ohair@286 562 msg.consume();
ohair@286 563 }
ohair@286 564
ohair@286 565 return retVal;
ohair@286 566 }
ohair@286 567
ohair@286 568 /**
ohair@286 569 * Unmarshals each wrapped part into a JAXB object and moves it
ohair@286 570 * to the expected place.
ohair@286 571 */
ohair@286 572 static final class PartBuilder {
ohair@286 573 private final PropertyAccessor accessor;
ohair@286 574 private final ValueSetter setter;
ohair@286 575
ohair@286 576 /**
ohair@286 577 * @param accessor
ohair@286 578 * specifies which portion of the wrapper bean to obtain the value from.
ohair@286 579 * @param setter
ohair@286 580 * specifies how the obtained value is returned to the client.
ohair@286 581 */
ohair@286 582 public PartBuilder(PropertyAccessor accessor, ValueSetter setter) {
ohair@286 583 this.accessor = accessor;
ohair@286 584 this.setter = setter;
ohair@286 585 assert accessor!=null && setter!=null;
ohair@286 586 }
ohair@286 587
ohair@286 588 final Object readResponse( Object[] args, Object wrapperBean ) {
ohair@286 589 Object obj = accessor.get(wrapperBean);
ohair@286 590 return setter.put(obj,args);
ohair@286 591 }
ohair@286 592
ohair@286 593
ohair@286 594 }
ohair@286 595 }
ohair@286 596
ohair@286 597 /**
ohair@286 598 * Treats a payload as multiple parts wrapped into one element,
ohair@286 599 * and processes all such wrapped parts.
ohair@286 600 */
ohair@286 601 public static final class RpcLit extends ResponseBuilder {
ohair@286 602 /**
ohair@286 603 * {@link PartBuilder} keyed by the element name (inside the wrapper element.)
ohair@286 604 */
ohair@286 605 private final Map<QName,PartBuilder> parts = new HashMap<QName,PartBuilder>();
ohair@286 606
ohair@286 607 private QName wrapperName;
ohair@286 608
ohair@286 609 public RpcLit(WrapperParameter wp, ValueSetterFactory setterFactory) {
ohair@286 610 assert wp.getTypeInfo().type== WrapperComposite.class;
ohair@286 611
ohair@286 612 wrapperName = wp.getName();
ohair@286 613 List<ParameterImpl> children = wp.getWrapperChildren();
ohair@286 614 for (ParameterImpl p : children) {
ohair@286 615 parts.put( p.getName(), new PartBuilder(
ohair@286 616 p.getXMLBridge(), setterFactory.get(p)
ohair@286 617 ));
ohair@286 618 // wrapper parameter itself always bind to body, and
ohair@286 619 // so do all its children
ohair@286 620 assert p.getBinding()== ParameterBinding.BODY;
ohair@286 621 }
ohair@286 622 }
ohair@286 623
ohair@286 624 public Object readResponse(Message msg, Object[] args) throws JAXBException, XMLStreamException {
ohair@286 625 Object retVal = null;
ohair@286 626
ohair@286 627 if (!msg.hasPayload()) {
ohair@286 628 throw new WebServiceException("No payload. Expecting payload with "+wrapperName+" element");
ohair@286 629 }
ohair@286 630 XMLStreamReader reader = msg.readPayload();
ohair@286 631 XMLStreamReaderUtil.verifyTag(reader,wrapperName);
ohair@286 632 reader.nextTag();
ohair@286 633
ohair@286 634 while(reader.getEventType()==XMLStreamReader.START_ELEMENT) {
ohair@286 635 // TODO: QName has a performance issue
ohair@286 636 PartBuilder part = parts.get(reader.getName());
ohair@286 637 if(part==null) {
ohair@286 638 // no corresponding part found. ignore
ohair@286 639 XMLStreamReaderUtil.skipElement(reader);
ohair@286 640 reader.nextTag();
ohair@286 641 } else {
ohair@286 642 Object o = part.readResponse(args,reader, msg.getAttachments());
ohair@286 643 // there's only at most one ResponseBuilder that returns a value.
ohair@286 644 if(o!=null) {
ohair@286 645 assert retVal==null;
ohair@286 646 retVal = o;
ohair@286 647 }
ohair@286 648 }
ohair@286 649 // skip any whitespace
ohair@286 650 if (reader.getEventType() != XMLStreamConstants.START_ELEMENT &&
ohair@286 651 reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
ohair@286 652 XMLStreamReaderUtil.nextElementContent(reader);
ohair@286 653 }
ohair@286 654 }
ohair@286 655
ohair@286 656 // we are done with the body
ohair@286 657 reader.close();
ohair@286 658 XMLStreamReaderFactory.recycle(reader);
ohair@286 659
ohair@286 660 return retVal;
ohair@286 661 }
ohair@286 662
ohair@286 663 /**
ohair@286 664 * Unmarshals each wrapped part into a JAXB object and moves it
ohair@286 665 * to the expected place.
ohair@286 666 */
ohair@286 667 static final class PartBuilder {
ohair@286 668 private final XMLBridge bridge;
ohair@286 669 private final ValueSetter setter;
ohair@286 670
ohair@286 671 /**
ohair@286 672 * @param bridge
ohair@286 673 * specifies how the part is unmarshalled.
ohair@286 674 * @param setter
ohair@286 675 * specifies how the obtained value is returned to the client.
ohair@286 676 */
ohair@286 677 public PartBuilder(XMLBridge bridge, ValueSetter setter) {
ohair@286 678 this.bridge = bridge;
ohair@286 679 this.setter = setter;
ohair@286 680 }
ohair@286 681
ohair@286 682 final Object readResponse(Object[] args, XMLStreamReader r, AttachmentSet att) throws JAXBException {
ohair@286 683 Object obj = bridge.unmarshal(r, (att != null)?new AttachmentUnmarshallerImpl(att):null);
ohair@286 684 return setter.put(obj,args);
ohair@286 685 }
ohair@286 686
ohair@286 687
ohair@286 688 }
ohair@286 689 }
ohair@286 690
ohair@286 691 private static boolean isXMLMimeType(String mimeType){
ohair@286 692 return mimeType.equals("text/xml") || mimeType.equals("application/xml");
ohair@286 693 }
ohair@286 694 }

mercurial