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.synapse.transport.base;
021:
022: import org.apache.axis2.engine.AxisConfiguration;
023: import org.apache.axis2.description.AxisService;
024: import org.apache.axis2.description.Parameter;
025: import org.apache.axis2.AxisFault;
026: import org.apache.axis2.Constants;
027: import org.apache.axis2.builder.BuilderUtil;
028: import org.apache.axis2.transport.http.HTTPTransportUtils;
029: import org.apache.synapse.transport.vfs.PollTableEntry;
030: import org.apache.axis2.context.MessageContext;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.axiom.soap.*;
034: import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
035: import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory;
036: import org.apache.axiom.om.util.StAXUtils;
037: import org.apache.axiom.om.impl.builder.StAXBuilder;
038: import org.apache.axiom.om.impl.builder.StAXOMBuilder;
039: import org.apache.axiom.om.impl.llom.OMTextImpl;
040: import org.apache.axiom.om.OMOutputFormat;
041: import org.apache.axiom.om.OMElement;
042: import org.apache.axiom.om.OMText;
043: import org.apache.axiom.om.OMAbstractFactory;
044: import org.apache.axiom.attachments.ByteArrayDataSource;
045:
046: import javax.xml.namespace.QName;
047: import javax.xml.stream.XMLStreamException;
048: import javax.xml.stream.XMLStreamReader;
049: import javax.activation.DataHandler;
050: import java.io.InputStream;
051: import java.io.IOException;
052: import java.util.List;
053: import java.util.Iterator;
054:
055: public abstract class BaseUtils {
056:
057: private static final Log log = LogFactory.getLog(BaseUtils.class);
058:
059: /**
060: * Return a QName from the String passed in of the form {ns}element
061: * @param obj a QName or a String containing a QName in {ns}element form
062: * @return a corresponding QName object
063: */
064: public static QName getQNameFromString(Object obj) {
065: String value;
066: if (obj instanceof QName) {
067: return (QName) obj;
068: } else {
069: value = obj.toString();
070: }
071: int open = value.indexOf('{');
072: int close = value.indexOf('}');
073: if (close > open && open > -1 && value.length() > close) {
074: return new QName(value.substring(open + 1, close - open),
075: value.substring(close + 1));
076: } else {
077: return new QName(value);
078: }
079: }
080:
081: /**
082: * Marks the given service as faulty with the given comment
083: *
084: * @param serviceName service name
085: * @param msg comment for being faulty
086: * @param axisCfg configuration context
087: */
088: public static void markServiceAsFaulty(String serviceName,
089: String msg, AxisConfiguration axisCfg) {
090: if (serviceName != null) {
091: try {
092: AxisService service = axisCfg.getService(serviceName);
093: axisCfg.getFaultyServices().put(service.getName(), msg);
094:
095: } catch (AxisFault axisFault) {
096: log.warn("Error marking service : " + serviceName
097: + " as faulty", axisFault);
098: }
099: }
100: }
101:
102: /**
103: * Create a SOAP envelope using SOAP 1.1 or 1.2 depending on the namespace
104: * @param in InputStream for the payload
105: * @param namespace the SOAP namespace
106: * @return the SOAP envelope for the correct version
107: * @throws javax.xml.stream.XMLStreamException on error
108: */
109: public static SOAPEnvelope getEnvelope(InputStream in,
110: String namespace) throws XMLStreamException {
111:
112: try {
113: in.reset();
114: } catch (IOException ignore) {
115: }
116: XMLStreamReader xmlreader = StAXUtils.createXMLStreamReader(in,
117: MessageContext.DEFAULT_CHAR_SET_ENCODING);
118: StAXBuilder builder = new StAXSOAPModelBuilder(xmlreader,
119: namespace);
120: return (SOAPEnvelope) builder.getDocumentElement();
121: }
122:
123: /**
124: * Get the OMOutput format for the given message
125: * @param msgContext the axis message context
126: * @return the OMOutput format to be used
127: */
128: public static OMOutputFormat getOMOutputFormat(
129: MessageContext msgContext) {
130:
131: OMOutputFormat format = new OMOutputFormat();
132: msgContext.setDoingMTOM(HTTPTransportUtils
133: .doWriteMTOM(msgContext));
134: msgContext.setDoingSwA(HTTPTransportUtils
135: .doWriteSwA(msgContext));
136: msgContext.setDoingREST(HTTPTransportUtils
137: .isDoingREST(msgContext));
138: format.setSOAP11(msgContext.isSOAP11());
139: format.setDoOptimize(msgContext.isDoingMTOM());
140: format.setDoingSWA(msgContext.isDoingSwA());
141:
142: format.setCharSetEncoding(HTTPTransportUtils
143: .getCharSetEncoding(msgContext));
144: Object mimeBoundaryProperty = msgContext
145: .getProperty(Constants.Configuration.MIME_BOUNDARY);
146: if (mimeBoundaryProperty != null) {
147: format.setMimeBoundary((String) mimeBoundaryProperty);
148: }
149: return format;
150: }
151:
152: public static long getMinPollTime(List pollTable) {
153: Iterator iter = pollTable.iterator();
154: long min = AbstractPollingTransportListener.DEFAULT_POLL_INTERVAL;
155:
156: while (iter.hasNext()) {
157: PollTableEntry entry = (PollTableEntry) iter.next();
158: if (entry.getPollInterval() < min) {
159: min = entry.getPollInterval();
160: }
161: }
162: return min;
163: }
164:
165: /**
166: * Create a SOAPEnvelope from the given message and set it into
167: * the axis MessageContext passed
168: *
169: * @param message the message object
170: * @param msgContext the axis MessageContext
171: * @param contentType
172: * @throws AxisFault on errors encountered while setting the envelope to the message context
173: */
174: public void setSOAPEnvelope(Object message,
175: MessageContext msgContext, String contentType)
176: throws AxisFault {
177:
178: SOAPEnvelope envelope = null;
179: StAXBuilder builder = null;
180:
181: String charSetEnc = BuilderUtil.getCharSetEncoding(contentType);
182: InputStream in = getInputStream(message);
183:
184: // handle SOAP payloads when a correct content type is available
185: try {
186: if (contentType != null) {
187: if (contentType
188: .indexOf(BaseConstants.MULTIPART_RELATED) > -1) {
189: builder = BuilderUtil.getAttachmentsBuilder(
190: msgContext, in, contentType, true);
191: envelope = (SOAPEnvelope) builder
192: .getDocumentElement();
193:
194: } else {
195: builder = BuilderUtil
196: .getSOAPBuilder(in, charSetEnc);
197: envelope = (SOAPEnvelope) builder
198: .getDocumentElement();
199: }
200: }
201: } catch (Exception ignore) {
202: try {
203: in.close();
204: } catch (IOException e) {
205: }
206: in = getInputStream(message);
207: }
208:
209: // handle SOAP when content type is missing, or any other POX, binary or text payload
210: if (builder == null) {
211:
212: SOAPFactory soapFactory = new SOAP11Factory();
213: try {
214: builder = new StAXOMBuilder(StAXUtils
215: .createXMLStreamReader(in, charSetEnc));
216: builder.setOMBuilderFactory(OMAbstractFactory
217: .getOMFactory());
218: String ns = builder.getDocumentElement().getNamespace()
219: .getNamespaceURI();
220:
221: if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI
222: .equals(ns)) {
223: envelope = BaseUtils
224: .getEnvelope(
225: in,
226: SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
227:
228: } else if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI
229: .equals(ns)) {
230: envelope = BaseUtils
231: .getEnvelope(
232: in,
233: SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
234:
235: } else {
236: // this is POX ... mark message as REST
237: msgContext.setDoingREST(true);
238: envelope = soapFactory.getDefaultEnvelope();
239: envelope.getBody().addChild(
240: builder.getDocumentElement());
241: }
242:
243: } catch (Exception e) {
244: envelope = handleLegacyMessage(msgContext, message);
245: }
246: }
247:
248: // Set the encoding scheme in the message context
249: msgContext.setProperty(
250: Constants.Configuration.CHARACTER_SET_ENCODING,
251: charSetEnc);
252:
253: String charEncOfMessage = builder == null ? null : builder
254: .getDocument() == null ? null : builder.getDocument()
255: .getCharsetEncoding();
256:
257: if (charEncOfMessage != null
258: && !(charEncOfMessage.trim().length() == 0)
259: && !charEncOfMessage.equalsIgnoreCase(charSetEnc)) {
260: handleException("Charset encoding of transport differs from that of the payload");
261: }
262:
263: msgContext.setEnvelope(envelope);
264: }
265:
266: /**
267: * Handle a non SOAP and non XML message, and create a SOAPEnvelope to hold the
268: * pure text or binary content as necessary
269: *
270: * @param msgContext the axis message context
271: * @param message the legacy message
272: * @return the SOAP envelope
273: */
274: private SOAPEnvelope handleLegacyMessage(MessageContext msgContext,
275: Object message) {
276:
277: SOAPFactory soapFactory = new SOAP11Factory();
278: SOAPEnvelope envelope = null;
279:
280: if (log.isDebugEnabled()) {
281: log.debug("Non SOAP/XML message received");
282: }
283:
284: // pick the name of the element that will act as the wrapper element for the
285: // non-xml payload. If service doesn't define one, default
286: Parameter wrapperParam = msgContext.getAxisService()
287: .getParameter(BaseConstants.WRAPPER_PARAM);
288:
289: QName wrapperQName = null;
290: OMElement wrapper = null;
291: if (wrapperParam != null) {
292: wrapperQName = BaseUtils.getQNameFromString(wrapperParam
293: .getValue());
294: }
295:
296: String textPayload = getMessageTextPayload(message);
297: if (textPayload != null) {
298: OMTextImpl textData = (OMTextImpl) soapFactory
299: .createOMText(textPayload);
300:
301: if (wrapperQName == null) {
302: wrapperQName = BaseConstants.DEFAULT_TEXT_WRAPPER;
303: }
304: wrapper = soapFactory.createOMElement(wrapperQName, null);
305: wrapper.addChild(textData);
306:
307: } else {
308: byte[] msgBytes = getMessageBinaryPayload(message);
309: if (msgBytes != null) {
310: DataHandler dataHandler = new DataHandler(
311: new ByteArrayDataSource(msgBytes));
312: OMText textData = soapFactory.createOMText(dataHandler,
313: true);
314: if (wrapperQName == null) {
315: wrapperQName = BaseConstants.DEFAULT_BINARY_WRAPPER;
316: }
317: wrapper = soapFactory.createOMElement(wrapperQName,
318: null);
319: wrapper.addChild(textData);
320: msgContext.setDoingMTOM(true);
321:
322: } else {
323: handleException("Unable to read payload from message of type : "
324: + message.getClass().getName());
325: }
326: }
327:
328: envelope = soapFactory.getDefaultEnvelope();
329: envelope.getBody().addChild(wrapper);
330:
331: return envelope;
332: }
333:
334: /**
335: * Get a String property from a message
336: *
337: * @param message the message object
338: * @param property property name
339: * @return property value
340: */
341: public abstract String getProperty(Object message, String property);
342:
343: /**
344: * Get an InputStream to the message payload
345: *
346: * @param message Object
347: * @return an InputStream to the payload
348: */
349: public abstract InputStream getInputStream(Object message);
350:
351: /**
352: * Get the message payload as a String, if the message is a non-SOAP, non-XML, plain text message
353: *
354: * @param message the message Object
355: * @return the plain text payload of the message if applicable
356: */
357: public abstract String getMessageTextPayload(Object message);
358:
359: /**
360: * Get the message payload as a byte[], if the message is a non-SOAP, non-XML, binary message
361: *
362: * @param message the message Object
363: * @return the payload of the message as a byte[]
364: */
365: public abstract byte[] getMessageBinaryPayload(Object message);
366:
367: protected static void handleException(String s) {
368: log.error(s);
369: throw new BaseTransportException(s);
370: }
371:
372: protected static void handleException(String s, Exception e) {
373: log.error(s, e);
374: throw new BaseTransportException(s, e);
375: }
376:
377: /**
378: * Utility method to check if a string is not null and not empty
379: * @param str the string to check
380: * @return true if not null and not empty
381: */
382: public static boolean isValid(String str) {
383: return (str != null && str.trim().length() > 0);
384: }
385:
386: public static String getRequiredServiceParam(AxisService service,
387: String paramName) throws AxisFault {
388: Parameter param = service.getParameter(paramName);
389: if (param != null && param.getValue() != null
390: && param.getValue() instanceof String) {
391: return (String) param.getValue();
392: } else {
393: throw new AxisFault("Cannot find parameter : " + paramName
394: + " for service : " + service.getName());
395: }
396: }
397:
398: public static String getOptionalServiceParam(AxisService service,
399: String paramName) throws AxisFault {
400: Parameter param = service.getParameter(paramName);
401: if (param != null && param.getValue() != null
402: && param.getValue() instanceof String) {
403: return (String) param.getValue();
404: } else {
405: return null;
406: }
407: }
408:
409: public static boolean isUsingTransport(AxisService service,
410: String transportName) {
411: boolean process = service.isEnableAllTransports();
412: if (process) {
413: return true;
414:
415: } else {
416: List transports = service.getExposedTransports();
417: for (int i = 0; i < transports.size(); i++) {
418: if (transportName.equals(transports.get(i))) {
419: return true;
420: }
421: }
422: }
423: return false;
424: }
425: }
|