Tue, 06 Mar 2012 16:09:35 -0800
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 | } |