1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.builder;
21
22 import org.apache.axiom.attachments.Attachments;
23 import org.apache.axiom.attachments.lifecycle.LifecycleManager;
24 import org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl;
25 import org.apache.axiom.attachments.utils.IOUtils;
26 import org.apache.axiom.om.OMAttribute;
27 import org.apache.axiom.om.OMElement;
28 import org.apache.axiom.om.OMException;
29 import org.apache.axiom.om.OMNamespace;
30 import org.apache.axiom.om.OMText;
31 import org.apache.axiom.om.impl.MTOMConstants;
32 import org.apache.axiom.om.impl.builder.StAXBuilder;
33 import org.apache.axiom.om.impl.builder.StAXOMBuilder;
34 import org.apache.axiom.om.impl.builder.XOPAwareStAXOMBuilder;
35 import org.apache.axiom.om.util.StAXUtils;
36 import org.apache.axiom.soap.SOAP11Constants;
37 import org.apache.axiom.soap.SOAP12Constants;
38 import org.apache.axiom.soap.SOAPBody;
39 import org.apache.axiom.soap.SOAPConstants;
40 import org.apache.axiom.soap.SOAPEnvelope;
41 import org.apache.axiom.soap.SOAPFactory;
42 import org.apache.axiom.soap.SOAPProcessingException;
43 import org.apache.axiom.soap.impl.builder.MTOMStAXSOAPModelBuilder;
44 import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
45 import org.apache.axis2.AxisFault;
46 import org.apache.axis2.Constants;
47 import org.apache.axis2.context.MessageContext;
48 import org.apache.axis2.deployment.DeploymentConstants;
49 import org.apache.axis2.description.AxisMessage;
50 import org.apache.axis2.description.AxisOperation;
51 import org.apache.axis2.description.Parameter;
52 import org.apache.axis2.engine.AxisConfiguration;
53 import org.apache.axis2.java.security.AccessController;
54 import org.apache.axis2.transport.http.HTTPConstants;
55 import org.apache.axis2.util.JavaUtils;
56 import org.apache.axis2.util.MultipleEntryHashMap;
57 import org.apache.axis2.wsdl.WSDLConstants;
58 import org.apache.commons.logging.Log;
59 import org.apache.commons.logging.LogFactory;
60 import org.apache.ws.commons.schema.XmlSchemaAll;
61 import org.apache.ws.commons.schema.XmlSchemaComplexType;
62 import org.apache.ws.commons.schema.XmlSchemaElement;
63 import org.apache.ws.commons.schema.XmlSchemaGroupBase;
64 import org.apache.ws.commons.schema.XmlSchemaParticle;
65 import org.apache.ws.commons.schema.XmlSchemaSequence;
66 import org.apache.ws.commons.schema.XmlSchemaType;
67
68 import javax.activation.DataHandler;
69 import javax.xml.namespace.QName;
70 import javax.xml.parsers.FactoryConfigurationError;
71 import javax.xml.stream.XMLStreamException;
72 import javax.xml.stream.XMLStreamReader;
73 import java.io.BufferedReader;
74 import java.io.IOException;
75 import java.io.InputStream;
76 import java.io.InputStreamReader;
77 import java.io.PushbackInputStream;
78 import java.io.Reader;
79 import java.io.UnsupportedEncodingException;
80 import java.security.PrivilegedActionException;
81 import java.security.PrivilegedExceptionAction;
82 import java.util.Iterator;
83 import java.util.Map;
84
85 public class BuilderUtil {
86 private static final Log log = LogFactory.getLog(BuilderUtil.class);
87
88 public static final int BOM_SIZE = 4;
89
90 public static SOAPEnvelope buildsoapMessage(MessageContext messageContext,
91 MultipleEntryHashMap requestParameterMap,
92 SOAPFactory soapFactory) throws AxisFault {
93
94 SOAPEnvelope soapEnvelope = soapFactory.getDefaultEnvelope();
95 SOAPBody body = soapEnvelope.getBody();
96 XmlSchemaElement xmlSchemaElement;
97 AxisOperation axisOperation = messageContext.getAxisOperation();
98 if (axisOperation != null) {
99 AxisMessage axisMessage =
100 axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
101 xmlSchemaElement = axisMessage.getSchemaElement();
102
103 if (xmlSchemaElement == null) {
104 OMElement bodyFirstChild =
105 soapFactory
106 .createOMElement(messageContext.getAxisOperation().getName(), body);
107
108 // if there is no schema its piece of cake !! add these to the soap body in any order you like.
109 // Note : if there are parameters in the path of the URL, there is no way this can add them
110 // to the message.
111 createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild, requestParameterMap);
112 } else {
113
114 // first get the target namespace from the schema and the wrapping element.
115 // create an OMElement out of those information. We are going to extract parameters from
116 // url, create OMElements and add them as children to this wrapping element.
117 String targetNamespace = xmlSchemaElement.getQName().getNamespaceURI();
118 QName bodyFirstChildQName;
119 if (targetNamespace != null && !"".equals(targetNamespace)) {
120 bodyFirstChildQName = new QName(targetNamespace, xmlSchemaElement.getName());
121 } else {
122 bodyFirstChildQName = new QName(xmlSchemaElement.getName());
123 }
124 OMElement bodyFirstChild = soapFactory.createOMElement(bodyFirstChildQName, body);
125
126 // Schema should adhere to the IRI style in this. So assume IRI style and dive in to
127 // schema
128 XmlSchemaType schemaType = xmlSchemaElement.getSchemaType();
129 if (schemaType instanceof XmlSchemaComplexType) {
130 XmlSchemaComplexType complexType = ((XmlSchemaComplexType)schemaType);
131 XmlSchemaParticle particle = complexType.getParticle();
132 if (particle instanceof XmlSchemaSequence || particle instanceof XmlSchemaAll) {
133 XmlSchemaGroupBase xmlSchemaGroupBase = (XmlSchemaGroupBase)particle;
134 Iterator iterator = xmlSchemaGroupBase.getItems().getIterator();
135
136 // now we need to know some information from the binding operation.
137
138 while (iterator.hasNext()) {
139 XmlSchemaElement innerElement = (XmlSchemaElement)iterator.next();
140 QName qName = innerElement.getQName();
141 if (qName == null && innerElement.getSchemaTypeName()
142 .equals(org.apache.ws.commons.schema.constants.Constants.XSD_ANYTYPE)) {
143 createSOAPMessageWithoutSchema(soapFactory, bodyFirstChild,
144 requestParameterMap);
145 break;
146 }
147 long minOccurs = innerElement.getMinOccurs();
148 boolean nillable = innerElement.isNillable();
149 String name =
150 qName != null ? qName.getLocalPart() : innerElement.getName();
151 Object value;
152 OMNamespace ns = (qName == null ||
153 qName.getNamespaceURI() == null
154 || qName.getNamespaceURI().length() == 0) ?
155 null : soapFactory.createOMNamespace(
156 qName.getNamespaceURI(), null);
157
158 // FIXME changed
159 while ((value = requestParameterMap.get(name)) != null) {
160 addRequestParameter(soapFactory,
161 bodyFirstChild, ns, name, value);
162 minOccurs--;
163 }
164 if (minOccurs > 0) {
165 if (nillable) {
166
167 OMNamespace xsi = soapFactory.createOMNamespace(
168 Constants.URI_DEFAULT_SCHEMA_XSI,
169 Constants.NS_PREFIX_SCHEMA_XSI);
170 OMAttribute omAttribute =
171 soapFactory.createOMAttribute("nil", xsi, "true");
172 soapFactory.createOMElement(name, ns,
173 bodyFirstChild)
174 .addAttribute(omAttribute);
175
176 } else {
177 throw new AxisFault("Required element " + qName +
178 " defined in the schema can not be" +
179 " found in the request");
180 }
181 }
182 }
183 }
184 }
185 }
186 }
187 return soapEnvelope;
188 }
189
190 private static void createSOAPMessageWithoutSchema(SOAPFactory soapFactory,
191 OMElement bodyFirstChild,
192 MultipleEntryHashMap requestParameterMap) {
193
194 // first add the parameters in the URL
195 if (requestParameterMap != null) {
196 Iterator requestParamMapIter = requestParameterMap.keySet().iterator();
197 while (requestParamMapIter.hasNext()) {
198 String key = (String)requestParamMapIter.next();
199 Object value = requestParameterMap.get(key);
200 if (value != null) {
201 addRequestParameter(soapFactory, bodyFirstChild, null, key,
202 value);
203 }
204
205 }
206 }
207 }
208
209 private static void addRequestParameter(SOAPFactory soapFactory,
210 OMElement bodyFirstChild,
211 OMNamespace ns,
212 String key,
213 Object parameter) {
214 if (parameter instanceof DataHandler) {
215 DataHandler dataHandler = (DataHandler)parameter;
216 OMText dataText = bodyFirstChild.getOMFactory().createOMText(
217 dataHandler, true);
218 soapFactory.createOMElement(key, ns, bodyFirstChild).addChild(
219 dataText);
220 } else {
221 String textValue = parameter.toString();
222 soapFactory.createOMElement(key, ns, bodyFirstChild).setText(
223 textValue);
224 }
225 }
226
227 public static StAXBuilder getPOXBuilder(InputStream inStream, String charSetEnc)
228 throws XMLStreamException {
229 StAXBuilder builder;
230 XMLStreamReader xmlreader =
231 StAXUtils.createXMLStreamReader(inStream, charSetEnc);
232 builder = new StAXOMBuilder(xmlreader);
233 return builder;
234 }
235
236 /**
237 * Use the BOM Mark to identify the encoding to be used. Fall back to default encoding
238 * specified
239 *
240 * @param is the InputStream of a message
241 * @param charSetEncoding default character set encoding
242 * @return a Reader with the correct encoding already set
243 * @throws java.io.IOException
244 */
245 public static Reader getReader(final InputStream is, final String charSetEncoding)
246 throws IOException {
247 final PushbackInputStream is2 = getPushbackInputStream(is);
248 final String encoding = getCharSetEncoding(is2, charSetEncoding);
249 InputStreamReader inputStreamReader;
250 try {
251 inputStreamReader = (InputStreamReader)AccessController.doPrivileged(
252 new PrivilegedExceptionAction() {
253 public Object run() throws UnsupportedEncodingException {
254 return new InputStreamReader(is2, encoding);
255 }
256 }
257 );
258 } catch (PrivilegedActionException e) {
259 throw (UnsupportedEncodingException)e.getException();
260 }
261 return new BufferedReader(inputStreamReader);
262 }
263
264 /**
265 * Convenience method to get a PushbackInputStream so that we can read the BOM
266 *
267 * @param is a regular InputStream
268 * @return a PushbackInputStream wrapping the passed one
269 */
270 public static PushbackInputStream getPushbackInputStream(InputStream is) {
271 return new PushbackInputStream(is, BOM_SIZE);
272 }
273
274 /**
275 * Use the BOM Mark to identify the encoding to be used. Fall back to default encoding
276 * specified
277 *
278 * @param is2 PushBackInputStream (it must be a pushback input stream so that we can
279 * unread the BOM)
280 * @param defaultEncoding default encoding style if no BOM
281 * @return the selected character set encoding
282 * @throws java.io.IOException
283 */
284 public static String getCharSetEncoding(PushbackInputStream is2, String defaultEncoding)
285 throws IOException {
286 String encoding;
287 byte bom[] = new byte[BOM_SIZE];
288 int n, unread;
289
290 n = is2.read(bom, 0, bom.length);
291
292 if ((bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) && (bom[2] == (byte)0xBF)) {
293 encoding = "UTF-8";
294 if (log.isDebugEnabled()) {
295 log.debug("char set encoding set from BOM =" + encoding);
296 }
297 unread = n - 3;
298 } else if ((bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF)) {
299 encoding = "UTF-16BE";
300 if (log.isDebugEnabled()) {
301 log.debug("char set encoding set from BOM =" + encoding);
302 }
303 unread = n - 2;
304 } else if ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE)) {
305 encoding = "UTF-16LE";
306 if (log.isDebugEnabled()) {
307 log.debug("char set encoding set from BOM =" + encoding);
308 }
309 unread = n - 2;
310 } else if ((bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) && (bom[2] == (byte)0xFE)
311 && (bom[3] == (byte)0xFF)) {
312 encoding = "UTF-32BE";
313 if (log.isDebugEnabled()) {
314 log.debug("char set encoding set from BOM =" + encoding);
315 }
316 unread = n - 4;
317 } else if ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) && (bom[2] == (byte)0x00)
318 && (bom[3] == (byte)0x00)) {
319 encoding = "UTF-32LE";
320 if (log.isDebugEnabled()) {
321 log.debug("char set encoding set from BOM =" + encoding);
322 }
323 unread = n - 4;
324 } else {
325
326 // Unicode BOM mark not found, unread all bytes
327 encoding = defaultEncoding;
328 if (log.isDebugEnabled()) {
329 log.debug("char set encoding set from default =" + encoding);
330 }
331 unread = n;
332 }
333
334 if (unread > 0) {
335 is2.unread(bom, (n - unread), unread);
336 }
337 return encoding;
338 }
339
340
341 public static String getEnvelopeNamespace(String contentType) {
342 String soapNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
343 if (contentType != null) {
344 if (contentType.indexOf(SOAP12Constants.SOAP_12_CONTENT_TYPE) > -1) {
345 // it is SOAP 1.2
346 soapNS = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
347 } else if (contentType.indexOf(SOAP11Constants.SOAP_11_CONTENT_TYPE) > -1) {
348 // SOAP 1.1
349 soapNS = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
350 }
351 }
352 return soapNS;
353 }
354
355 /**
356 * Extracts and returns the character set encoding from the Content-type header
357 * <p/>
358 * Example: "Content-Type: text/xml; charset=utf-8" would return "utf-8"
359 *
360 * @param contentType a content-type (from HTTP or MIME, for instance)
361 * @return the character set encoding if found, or MessageContext.DEFAULT_CHAR_SET_ENCODING
362 */
363 public static String getCharSetEncoding(String contentType) {
364 if (log.isDebugEnabled()) {
365 log.debug("Input contentType (" + contentType + ")");
366 }
367 if (contentType == null) {
368 // Using the default UTF-8
369 if (log.isDebugEnabled()) {
370 log.debug("CharSetEncoding defaulted (" + MessageContext.DEFAULT_CHAR_SET_ENCODING +
371 ")");
372 }
373 return MessageContext.DEFAULT_CHAR_SET_ENCODING;
374 }
375
376 int index = contentType.indexOf(HTTPConstants.CHAR_SET_ENCODING);
377
378 if (index == -1) { // Charset encoding not found in the content-type header
379 // Using the default UTF-8
380 if (log.isDebugEnabled()) {
381 log.debug("CharSetEncoding defaulted (" + MessageContext.DEFAULT_CHAR_SET_ENCODING +
382 ")");
383 }
384 return MessageContext.DEFAULT_CHAR_SET_ENCODING;
385 }
386
387 // If there are spaces around the '=' sign
388 int indexOfEq = contentType.indexOf("=", index);
389
390 // There can be situations where "charset" is not the last parameter of the Content-Type header
391 int indexOfSemiColon = contentType.indexOf(";", indexOfEq);
392 String value;
393
394 if (indexOfSemiColon > 0) {
395 value = (contentType.substring(indexOfEq + 1, indexOfSemiColon));
396 } else {
397 value = (contentType.substring(indexOfEq + 1, contentType.length())).trim();
398 }
399
400 // There might be "" around the value - if so remove them
401 if (value.indexOf('\"') != -1) {
402 value = value.replaceAll("\"", "");
403 }
404 value = value.trim();
405 if (log.isDebugEnabled()) {
406 log.debug("CharSetEncoding from content-type (" + value + ")");
407 }
408 return value;
409 }
410
411 public static StAXBuilder getAttachmentsBuilder(MessageContext msgContext,
412 InputStream inStream, String contentTypeString,
413 boolean isSOAP)
414 throws OMException, XMLStreamException, FactoryConfigurationError {
415 StAXBuilder builder = null;
416 XMLStreamReader streamReader;
417
418 Attachments attachments = createAttachmentsMap(msgContext, inStream, contentTypeString);
419 String charSetEncoding = getCharSetEncoding(attachments.getSOAPPartContentType());
420
421 if ((charSetEncoding == null)
422 || "null".equalsIgnoreCase(charSetEncoding)) {
423 charSetEncoding = MessageContext.UTF_8;
424 }
425 msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING,
426 charSetEncoding);
427
428 try {
429 PushbackInputStream pis = getPushbackInputStream(attachments.getSOAPPartInputStream());
430 String actualCharSetEncoding = getCharSetEncoding(pis, charSetEncoding);
431
432 streamReader = StAXUtils.createXMLStreamReader(pis, actualCharSetEncoding);
433 } catch (IOException e) {
434 throw new XMLStreamException(e);
435 }
436
437 // Put a reference to Attachments Map in to the message context For
438 // backword compatibility with Axis2 1.0
439 msgContext.setProperty(MTOMConstants.ATTACHMENTS, attachments);
440
441 // Setting the Attachments map to new SwA API
442 msgContext.setAttachmentMap(attachments);
443
444 String soapEnvelopeNamespaceURI = getEnvelopeNamespace(contentTypeString);
445
446 if (isSOAP) {
447 if (attachments.getAttachmentSpecType().equals(
448 MTOMConstants.MTOM_TYPE)) {
449 //Creates the MTOM specific MTOMStAXSOAPModelBuilder
450 builder = new MTOMStAXSOAPModelBuilder(streamReader,
451 attachments, soapEnvelopeNamespaceURI);
452 msgContext.setDoingMTOM(true);
453 } else if (attachments.getAttachmentSpecType().equals(
454 MTOMConstants.SWA_TYPE)) {
455 builder = new StAXSOAPModelBuilder(streamReader,
456 soapEnvelopeNamespaceURI);
457 } else if (attachments.getAttachmentSpecType().equals(
458 MTOMConstants.SWA_TYPE_12)) {
459 builder = new StAXSOAPModelBuilder(streamReader,
460 soapEnvelopeNamespaceURI);
461 }
462
463 }
464 // To handle REST XOP case
465 else {
466 if (attachments.getAttachmentSpecType().equals(MTOMConstants.MTOM_TYPE)) {
467 builder = new XOPAwareStAXOMBuilder(streamReader, attachments);
468
469 } else if (attachments.getAttachmentSpecType().equals(MTOMConstants.SWA_TYPE)) {
470 builder = new StAXOMBuilder(streamReader);
471 } else if (attachments.getAttachmentSpecType().equals(MTOMConstants.SWA_TYPE_12)) {
472 builder = new StAXOMBuilder(streamReader);
473 }
474 }
475
476 return builder;
477 }
478
479 protected static Attachments createAttachmentsMap(MessageContext msgContext,
480 InputStream inStream,
481 String contentTypeString) {
482 boolean fileCacheForAttachments = isAttachmentsCacheEnabled(msgContext);
483
484 String attachmentRepoDir = null;
485 String attachmentSizeThreshold = null;
486
487 if (fileCacheForAttachments) {
488 Object attachmentRepoDirProperty = msgContext
489 .getProperty(Constants.Configuration.ATTACHMENT_TEMP_DIR);
490
491 if (attachmentRepoDirProperty != null) {
492 attachmentRepoDir = (String)attachmentRepoDirProperty;
493 } else {
494 Parameter attachmentRepoDirParameter = msgContext
495 .getParameter(Constants.Configuration.ATTACHMENT_TEMP_DIR);
496 attachmentRepoDir =
497 (attachmentRepoDirParameter != null) ? (String)attachmentRepoDirParameter
498 .getValue()
499 : null;
500 }
501
502 Object attachmentSizeThresholdProperty = msgContext
503 .getProperty(Constants.Configuration.FILE_SIZE_THRESHOLD);
504 if (attachmentSizeThresholdProperty != null
505 && attachmentSizeThresholdProperty instanceof String) {
506 attachmentSizeThreshold = (String)attachmentSizeThresholdProperty;
507 } else {
508 Parameter attachmentSizeThresholdParameter = msgContext
509 .getParameter(Constants.Configuration.FILE_SIZE_THRESHOLD);
510 attachmentSizeThreshold = attachmentSizeThresholdParameter
511 .getValue().toString();
512 }
513 }
514
515 // Get the content-length if it is available
516 int contentLength = 0;
517 Map headers = (Map)msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
518 if (headers != null) {
519 String contentLengthValue = (String)headers.get(HTTPConstants.HEADER_CONTENT_LENGTH);
520 if (contentLengthValue != null) {
521 try {
522 contentLength = new Integer(contentLengthValue);
523 } catch (NumberFormatException e) {
524 if (log.isDebugEnabled()) {
525 log.debug(
526 "Content-Length is not a valid number. Will assume it is not set:" +
527 e);
528 }
529 }
530 }
531 }
532 if (log.isDebugEnabled()) {
533 if (contentLength > 0) {
534 log.debug("Creating an Attachments map. The content-length is" + contentLength);
535 } else {
536 log.debug("Creating an Attachments map.");
537 }
538 }
539 return createAttachments(msgContext,
540 inStream,
541 contentTypeString,
542 fileCacheForAttachments,
543 attachmentRepoDir,
544 attachmentSizeThreshold,
545 contentLength);
546 }
547
548 public static boolean isAttachmentsCacheEnabled(MessageContext msgContext) {
549 Object cacheAttachmentProperty = msgContext
550 .getProperty(Constants.Configuration.CACHE_ATTACHMENTS);
551 String cacheAttachmentString;
552 boolean fileCacheForAttachments;
553
554 if (cacheAttachmentProperty != null && cacheAttachmentProperty instanceof String) {
555 cacheAttachmentString = (String)cacheAttachmentProperty;
556 } else {
557 Parameter parameter_cache_attachment =
558 msgContext.getParameter(Constants.Configuration.CACHE_ATTACHMENTS);
559 cacheAttachmentString = (parameter_cache_attachment != null) ?
560 (String)parameter_cache_attachment.getValue() : null;
561 }
562 fileCacheForAttachments = (Constants.VALUE_TRUE.equals(cacheAttachmentString));
563 return fileCacheForAttachments;
564 }
565
566 public static Attachments createAttachments(MessageContext msgContext,
567 InputStream inStream,
568 String contentTypeString,
569 boolean fileCacheForAttachments,
570 String attachmentRepoDir,
571 String attachmentSizeThreshold,
572 int contentLength) {
573 LifecycleManager manager = null;
574 try {
575 AxisConfiguration configuration = msgContext.getRootContext().getAxisConfiguration();
576 manager = (LifecycleManager)configuration
577 .getParameterValue(DeploymentConstants.ATTACHMENTS_LIFECYCLE_MANAGER);
578 if (manager == null) {
579 manager = new LifecycleManagerImpl();
580 configuration.addParameter(DeploymentConstants.ATTACHMENTS_LIFECYCLE_MANAGER,
581 manager);
582 }
583 } catch (Exception e) {
584 if (log.isDebugEnabled()) {
585 log.debug("Exception getting Attachments LifecycleManager", e);
586 }
587 }
588 return new Attachments(manager,
589 inStream,
590 contentTypeString,
591 fileCacheForAttachments,
592 attachmentRepoDir,
593 attachmentSizeThreshold,
594 contentLength);
595 }
596
597 /**
598 * Utility method to get a StAXBuilder
599 *
600 * @param in an InputStream
601 * @return a StAXSOAPModelBuilder for the given InputStream
602 * @throws XMLStreamException
603 * @deprecated If some one really need this method, please shout.
604 */
605 public static StAXBuilder getBuilder(Reader in) throws XMLStreamException {
606 XMLStreamReader xmlreader = StAXUtils.createXMLStreamReader(in);
607 return new StAXSOAPModelBuilder(xmlreader, null);
608 }
609
610 /**
611 * Creates an OMBuilder for a plain XML message. Default character set encording is used.
612 *
613 * @param inStream InputStream for a XML message
614 * @return Handler to a OMBuilder implementation instance
615 * @throws XMLStreamException
616 */
617 public static StAXBuilder getBuilder(InputStream inStream) throws XMLStreamException {
618 XMLStreamReader xmlReader = StAXUtils.createXMLStreamReader(inStream);
619 return new StAXOMBuilder(xmlReader);
620 }
621
622 /**
623 * Creates an OMBuilder for a plain XML message.
624 *
625 * @param inStream InputStream for a XML message
626 * @param charSetEnc Character set encoding to be used
627 * @return Handler to a OMBuilder implementation instance
628 * @throws XMLStreamException
629 */
630 public static StAXBuilder getBuilder(InputStream inStream, String charSetEnc)
631 throws XMLStreamException {
632 XMLStreamReader xmlReader = StAXUtils.createXMLStreamReader(inStream, charSetEnc);
633 try {
634 return new StAXSOAPModelBuilder(xmlReader);
635 } catch (OMException e) {
636 log.info("OMException in getSOAPBuilder", e);
637 try {
638 log.info("Remaining input stream :[" +
639 new String(IOUtils.getStreamAsByteArray(inStream), charSetEnc) + "]");
640 } catch (IOException e1) {
641 // Nothing here?
642 }
643 throw e;
644 }
645 }
646
647 /**
648 * Creates an OMBuilder for a SOAP message. Default character set encording is used.
649 *
650 * @param inStream InputStream for a SOAP message
651 * @return Handler to a OMBuilder implementation instance
652 * @throws XMLStreamException
653 */
654 public static StAXBuilder getSOAPBuilder(InputStream inStream) throws XMLStreamException {
655 XMLStreamReader xmlReader = StAXUtils.createXMLStreamReader(inStream);
656 try {
657 return new StAXSOAPModelBuilder(xmlReader);
658 } catch (OMException e) {
659 log.info("OMException in getSOAPBuilder", e);
660 try {
661 log.info("Remaining input stream :[" +
662 new String(IOUtils.getStreamAsByteArray(inStream)) + "]");
663 } catch (IOException e1) {
664 // Nothing here?
665 }
666 throw e;
667 }
668 }
669
670 /**
671 * Creates an OMBuilder for a SOAP message.
672 *
673 * @param inStream InputStream for a SOAP message
674 * @param charSetEnc Character set encoding to be used
675 * @return Handler to a OMBuilder implementation instance
676 * @throws XMLStreamException
677 */
678 public static StAXBuilder getSOAPBuilder(InputStream inStream, String charSetEnc)
679 throws XMLStreamException {
680 XMLStreamReader xmlReader = StAXUtils.createXMLStreamReader(inStream, charSetEnc);
681 try {
682 return new StAXSOAPModelBuilder(xmlReader);
683 } catch (OMException e) {
684 log.info("OMException in getSOAPBuilder", e);
685 try {
686 log.info("Remaining input stream :[" +
687 new String(IOUtils.getStreamAsByteArray(inStream), charSetEnc) + "]");
688 } catch (IOException e1) {
689 // Nothing here?
690 }
691 throw e;
692 }
693 }
694
695 public static StAXBuilder getBuilder(SOAPFactory soapFactory, InputStream in, String charSetEnc)
696 throws XMLStreamException {
697 StAXBuilder builder;
698 XMLStreamReader xmlreader = StAXUtils.createXMLStreamReader(in, charSetEnc);
699 builder = new StAXOMBuilder(soapFactory, xmlreader);
700 return builder;
701 }
702
703 /**
704 * Initial work for a builder selector which selects the builder for a given message format
705 * based on the the content type of the recieved message. content-type to builder mapping can be
706 * specified through the Axis2.xml.
707 *
708 * @param type content-type
709 * @param msgContext the active MessageContext
710 * @return the builder registered against the given content-type
711 * @throws AxisFault
712 */
713 public static Builder getBuilderFromSelector(String type, MessageContext msgContext)
714 throws AxisFault {
715 boolean useFallbackBuilder = false;
716 AxisConfiguration configuration =
717 msgContext.getConfigurationContext().getAxisConfiguration();
718 Parameter useFallbackParameter = configuration.getParameter(Constants.Configuration.USE_DEFAULT_FALLBACK_BUILDER);
719 if (useFallbackParameter !=null){
720 useFallbackBuilder = JavaUtils.isTrueExplicitly(useFallbackParameter.getValue(),useFallbackBuilder);
721 }
722 Builder builder = configuration.getMessageBuilder(type,useFallbackBuilder);
723 if (builder != null) {
724 // Check whether the request has a Accept header if so use that as the response
725 // message type.
726 // If thats not present,
727 // Setting the received content-type as the messageType to make
728 // sure that we respond using the received message serialization format.
729
730 Object contentNegotiation = configuration
731 .getParameterValue(Constants.Configuration.ENABLE_HTTP_CONTENT_NEGOTIATION);
732 if (JavaUtils.isTrueExplicitly(contentNegotiation)) {
733 Map transportHeaders =
734 (Map)msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
735 if (transportHeaders != null) {
736 String acceptHeader = (String)transportHeaders.get(HTTPConstants.HEADER_ACCEPT);
737 if (acceptHeader != null) {
738 int index = acceptHeader.indexOf(";");
739 if (index > 0) {
740 acceptHeader = acceptHeader.substring(0, index);
741 }
742 String[] strings = acceptHeader.split(",");
743 for (String string : strings) {
744 String accept = string.trim();
745 // We dont want dynamic content negotoatin to work on text.xml as its
746 // ambiguos as to whether the user requests SOAP 1.1 or POX response
747 if (!HTTPConstants.MEDIA_TYPE_TEXT_XML.equals(accept) &&
748 configuration.getMessageFormatter(accept) != null) {
749 type = string;
750 break;
751 }
752 }
753 }
754 }
755 }
756
757 msgContext.setProperty(Constants.Configuration.MESSAGE_TYPE, type);
758 }
759 return builder;
760 }
761
762 public static void validateSOAPVersion(String soapNamespaceURIFromTransport,
763 SOAPEnvelope envelope) {
764 if (soapNamespaceURIFromTransport != null) {
765 OMNamespace envelopeNamespace = envelope.getNamespace();
766 String namespaceName = envelopeNamespace.getNamespaceURI();
767 if (!(soapNamespaceURIFromTransport.equals(namespaceName))) {
768 throw new SOAPProcessingException(
769 "Transport level information does not match with SOAP" +
770 " Message namespace URI", envelopeNamespace.getPrefix() + ":" +
771 SOAPConstants.FAULT_CODE_VERSION_MISMATCH);
772 }
773 }
774 }
775
776 public static void validateCharSetEncoding(String charsetEncodingFromTransport,
777 String charsetEncodingFromXML,
778 String soapNamespaceURI) throws AxisFault {
779 if ((charsetEncodingFromXML != null)
780 && !"".equals(charsetEncodingFromXML)
781 && (charsetEncodingFromTransport != null)
782 && !charsetEncodingFromXML.equalsIgnoreCase(charsetEncodingFromTransport)
783 && !compatibleEncodings(charsetEncodingFromXML, charsetEncodingFromTransport)) {
784 String faultCode;
785
786 if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapNamespaceURI)) {
787 faultCode = SOAP12Constants.FAULT_CODE_SENDER;
788 } else {
789 faultCode = SOAP11Constants.FAULT_CODE_SENDER;
790 }
791
792 throw new AxisFault("Character Set Encoding from "
793 + "transport information [" + charsetEncodingFromTransport +
794 "] does not match with "
795 + "character set encoding in the received SOAP message [" +
796 charsetEncodingFromXML + "]", faultCode);
797 }
798 }
799
800 /**
801 * check if the pair is [UTF-16,UTF-16LE] [UTF-32, UTF-32LE],[UTF-16,UTF-16BE] [UTF-32,
802 * UTF-32BE] etc.
803 *
804 * @param enc1 encoding style
805 * @param enc2 encoding style
806 * @return true if the encoding styles are compatible, or false otherwise
807 */
808 private static boolean compatibleEncodings(String enc1, String enc2) {
809 enc1 = enc1.toLowerCase();
810 enc2 = enc2.toLowerCase();
811 if (enc1.endsWith("be") || enc1.endsWith("le")) {
812 enc1 = enc1.substring(0, enc1.length() - 2);
813 }
814 if (enc2.endsWith("be") || enc2.endsWith("le")) {
815 enc2 = enc2.substring(0, enc2.length() - 2);
816 }
817 return enc1.equals(enc2);
818 }
819 }