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