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

mercurial