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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

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

mercurial