001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.transport.http;
021:
022: import org.apache.axiom.om.OMAbstractFactory;
023: import org.apache.axiom.om.OMElement;
024: import org.apache.axiom.om.OMFactory;
025: import org.apache.axiom.om.OMOutputFormat;
026: import org.apache.axis2.AxisFault;
027: import org.apache.axis2.context.MessageContext;
028: import org.apache.axis2.transport.MessageFormatter;
029: import org.apache.axis2.transport.http.util.ComplexPart;
030: import org.apache.axis2.transport.http.util.URLTemplatingUtil;
031: import org.apache.commons.httpclient.methods.multipart.Part;
032: import org.apache.commons.httpclient.methods.multipart.StringPart;
033:
034: import java.io.ByteArrayOutputStream;
035: import java.io.IOException;
036: import java.io.OutputStream;
037: import java.net.URL;
038: import java.util.ArrayList;
039: import java.util.Iterator;
040:
041: /**
042: * Formates the request message as multipart/form-data. An example of this serialization is shown
043: * below which was extracted from the Web Services Description Language (WSDL) Version 2.0 Part 2: Adjuncts
044: * <p/>
045: * The following instance data of an input message:
046: * <p/>
047: * <data>
048: * <town>
049: * <name>Fréjus</name>
050: * <country>France</country>
051: * </town>
052: * <date>@@@@-@@-@@</date>
053: * </data>
054: * <p/>
055: * with the following operation element
056: * <p/>
057: * <operation ref='t:data'
058: * whttp:location='temperature'
059: * whttp:method='POST'
060: * whttp:inputSerialization='multipart/form-data'/>
061: * <p/>
062: * will serialize the message as follow:
063: * <p/>
064: * Content-Type: multipart/form-data; boundary=AaB03x
065: * Content-Length: xxx
066: * <p/>
067: * --AaB03x
068: * Content-Disposition: form-data; name="town"
069: * Content-Type: application/xml
070: * <p/>
071: * <town>
072: * <name>Fréjus</name>
073: * <country>France</country>
074: * </town>
075: * --AaB03x
076: * Content-Disposition: form-data; name="date"
077: * Content-Type: text/plain; charset=utf-8
078: *
079: * @@@@-@@-@@ --AaB03x--
080: */
081: public class MultipartFormDataFormatter implements MessageFormatter {
082:
083: /**
084: * @return a byte array of the message formatted according to the given
085: * message format.
086: */
087: public byte[] getBytes(MessageContext messageContext,
088: OMOutputFormat format) throws AxisFault {
089:
090: OMElement omElement = messageContext.getEnvelope().getBody()
091: .getFirstElement();
092:
093: Part[] parts = createMultipatFormDataRequest(omElement);
094: if (parts.length > 0) {
095: ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
096: try {
097:
098: // This is accessing a class of Commons-FlieUpload
099: Part.sendParts(bytesOut, parts, format
100: .getMimeBoundary().getBytes());
101: } catch (IOException e) {
102: throw AxisFault.makeFault(e);
103: }
104: return bytesOut.toByteArray();
105: }
106:
107: return new byte[0]; //To change body of implemented methods use File | Settings | File Templates.
108: }
109:
110: /**
111: * To support deffered writing transports as in http chunking.. Axis2 was
112: * doing this for some time..
113: * <p/>
114: * Preserve flag can be used to preserve the envelope for later use. This is
115: * usefull when implementing authentication machnisms like NTLM.
116: *
117: * @param outputStream
118: * @param preserve :
119: * do not consume the OM when this is set..
120: */
121: public void writeTo(MessageContext messageContext,
122: OMOutputFormat format, OutputStream outputStream,
123: boolean preserve) throws AxisFault {
124:
125: try {
126: byte[] b = getBytes(messageContext, format);
127:
128: if (b != null && b.length > 0) {
129: outputStream.write(b);
130: } else {
131: outputStream.flush();
132: }
133: } catch (IOException e) {
134: throw new AxisFault(
135: "An error occured while writing the request");
136: }
137: }
138:
139: /**
140: * Different message formats can set their own content types
141: * Eg: JSONFormatter can set the content type as application/json
142: *
143: * @param messageContext
144: * @param format
145: * @param soapAction
146: */
147: public String getContentType(MessageContext messageContext,
148: OMOutputFormat format, String soapAction) {
149:
150: String contentType = HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA;
151: String encoding = format.getCharSetEncoding();
152: if (encoding != null) {
153: contentType += "; charset=" + encoding;
154: }
155: contentType = contentType + "; " + "boundary="
156: + format.getMimeBoundary();
157: return contentType;
158: }
159:
160: /**
161: * Some message formats may want to alter the target url.
162: *
163: * @return the target URL
164: */
165: public URL getTargetAddress(MessageContext messageContext,
166: OMOutputFormat format, URL targetURL) throws AxisFault {
167: // Check whether there is a template in the URL, if so we have to replace then with data
168: // values and create a new target URL.
169: targetURL = URLTemplatingUtil.getTemplatedURL(targetURL,
170: messageContext, false);
171:
172: return targetURL;
173: }
174:
175: /**
176: * @return this only if you want set a transport header for SOAP Action
177: */
178: public String formatSOAPAction(MessageContext messageContext,
179: OMOutputFormat format, String soapAction) {
180: return soapAction;
181: }
182:
183: /**
184: * @param dataOut
185: * @return
186: */
187: private Part[] createMultipatFormDataRequest(OMElement dataOut) {
188: ArrayList parts = new ArrayList();
189: if (dataOut != null) {
190: Iterator iter1 = dataOut.getChildElements();
191: OMFactory omFactory = OMAbstractFactory.getOMFactory();
192: while (iter1.hasNext()) {
193: OMElement ele = (OMElement) iter1.next();
194: Iterator iter2 = ele.getChildElements();
195: // check whether the element is a complex type
196: if (iter2.hasNext()) {
197: OMElement omElement = omFactory.createOMElement(ele
198: .getQName().getLocalPart(), null);
199: omElement.addChild(processComplexType(omElement,
200: ele.getChildElements(), omFactory));
201: parts.add(new ComplexPart(ele.getQName()
202: .getLocalPart(), omElement.toString()));
203: } else {
204: parts.add(new StringPart(ele.getQName()
205: .getLocalPart(), ele.getText()));
206: }
207: }
208: }
209: Part[] partsArray = new Part[parts.size()];
210: return (Part[]) parts.toArray(partsArray);
211: }
212:
213: /**
214: * @param parent
215: * @param iter
216: * @param omFactory
217: * @return
218: */
219: private OMElement processComplexType(OMElement parent,
220: Iterator iter, OMFactory omFactory) {
221:
222: OMElement omElement = null;
223: while (iter.hasNext()) {
224: OMElement ele = (OMElement) iter.next();
225: omElement = omFactory.createOMElement(ele.getQName()
226: .getLocalPart(), null);
227: Iterator iter2 = ele.getChildElements();
228: if (iter2.hasNext()) {
229: parent.addChild(processComplexType(omElement, ele
230: .getChildElements(), omFactory));
231: } else {
232: omElement = omFactory.createOMElement(ele.getQName()
233: .getLocalPart(), null);
234: omElement.setText(ele.getText());
235: parent.addChild(omElement);
236: }
237: }
238: return omElement;
239: }
240: }
|