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: package org.apache.axis2.transport.nhttp;
020:
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.nio.channels.Channels;
024: import java.nio.channels.ReadableByteChannel;
025: import java.util.Iterator;
026: import java.util.Map;
027:
028: import org.apache.axiom.om.OMOutputFormat;
029: import org.apache.axis2.AxisFault;
030: import org.apache.axis2.addressing.EndpointReference;
031: import org.apache.axis2.context.MessageContext;
032: import org.apache.axis2.transport.MessageFormatter;
033: import org.apache.axis2.transport.TransportUtils;
034: import org.apache.axis2.transport.http.HTTPConstants;
035: import org.apache.axis2.transport.nhttp.util.PipeImpl;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.apache.http.Header;
039: import org.apache.http.HttpEntityEnclosingRequest;
040: import org.apache.http.HttpHost;
041: import org.apache.http.HttpRequest;
042: import org.apache.http.entity.BasicHttpEntity;
043: import org.apache.http.message.BasicHttpEntityEnclosingRequest;
044: import org.apache.http.protocol.HTTP;
045:
046: /**
047: * Represents an outgoing Axis2 HTTP/s request. It holds the EPR of the destination, the
048: * Axis2 MessageContext to be sent, an HttpHost object which captures information about the
049: * destination, and a Pipe used to write the message stream to the destination
050: */
051: public class Axis2HttpRequest {
052:
053: private static final Log log = LogFactory
054: .getLog(Axis2HttpRequest.class);
055:
056: /** the EPR of the destination */
057: private EndpointReference epr = null;
058: /** the HttpHost that contains the HTTP connection information */
059: private HttpHost httpHost = null;
060: /** the message context being sent */
061: private MessageContext msgContext = null;
062: /** the Pipe which facilitates the serialization output to be written to the channel */
063: private PipeImpl pipe = null;
064: /** The Axis2 MessageFormatter that will ensure proper serialization as per Axis2 semantics */
065: MessageFormatter messageFormatter = null;
066: /** The OM Output format holder */
067: OMOutputFormat format = null;
068:
069: public Axis2HttpRequest(EndpointReference epr, HttpHost httpHost,
070: MessageContext msgContext) {
071: this .epr = epr;
072: this .httpHost = httpHost;
073: this .msgContext = msgContext;
074: this .format = Util.getOMOutputFormat(msgContext);
075: try {
076: messageFormatter = TransportUtils
077: .getMessageFormatter(msgContext);
078: } catch (AxisFault axisFault) {
079: log.error("Cannot find a suitable MessageFormatter : "
080: + axisFault.getMessage());
081: }
082: try {
083: this .pipe = new PipeImpl();
084: } catch (IOException e) {
085: log.error("Error creating pipe to write message body");
086: }
087: }
088:
089: public EndpointReference getEpr() {
090: return epr;
091: }
092:
093: public HttpHost getHttpHost() {
094: return httpHost;
095: }
096:
097: public MessageContext getMsgContext() {
098: return msgContext;
099: }
100:
101: /**
102: * Create and return a new HttpPost request to the destination EPR
103: * @return the HttpRequest to be sent out
104: */
105: public HttpRequest getRequest() throws IOException {
106: HttpEntityEnclosingRequest httpRequest = new BasicHttpEntityEnclosingRequest(
107: "POST", epr.getAddress());
108: httpRequest.setEntity(new BasicHttpEntity());
109:
110: // set any transport headers
111: Object o = msgContext
112: .getProperty(MessageContext.TRANSPORT_HEADERS);
113: if (o != null && o instanceof Map) {
114: Map headers = (Map) o;
115: Iterator iter = headers.keySet().iterator();
116: while (iter.hasNext()) {
117: Object header = iter.next();
118: Object value = headers.get(header);
119: if (header instanceof String && value != null
120: && value instanceof String) {
121: httpRequest.setHeader((String) header,
122: (String) value);
123: }
124: }
125: }
126:
127: // if the message is SOAP 11 (for which a SOAPAction is *required*), and
128: // the msg context has a SOAPAction or a WSA-Action (give pref to SOAPAction)
129: // use that over any transport header that may be available
130: String soapAction = msgContext.getSoapAction();
131: if (soapAction == null) {
132: soapAction = msgContext.getWSAAction();
133: }
134: if (soapAction == null) {
135: msgContext.getAxisOperation().getSoapAction();
136: }
137:
138: if (msgContext.isSOAP11() && soapAction != null
139: && soapAction.length() > 0) {
140: Header existingHeader = httpRequest
141: .getFirstHeader(HTTPConstants.HEADER_SOAP_ACTION);
142: if (existingHeader != null) {
143: httpRequest.removeHeader(existingHeader);
144: }
145: httpRequest.setHeader(HTTPConstants.HEADER_SOAP_ACTION,
146: soapAction);
147: }
148:
149: httpRequest.setHeader(HTTP.CONTENT_TYPE, messageFormatter
150: .getContentType(msgContext, format, msgContext
151: .getSoapAction()));
152:
153: return httpRequest;
154: }
155:
156: /**
157: * Return the source channel of the pipe that bridges the serialized output to the socket
158: * @return source channel to read serialized message contents
159: */
160: public ReadableByteChannel getSourceChannel() {
161: log
162: .debug("get source channel of the pipe on which the outgoing response is written");
163: return pipe.source();
164: }
165:
166: /**
167: * Start streaming the message into the Pipe, so that the contents could be read off the source
168: * channel returned by getSourceChannel()
169: * @throws AxisFault on error
170: */
171: public void streamMessageContents() throws AxisFault {
172:
173: log.debug("start streaming outgoing http request");
174: OutputStream out = Channels.newOutputStream(pipe.sink());
175:
176: messageFormatter.writeTo(msgContext, format, out, true);
177: try {
178: out.flush();
179: out.close();
180: } catch (IOException e) {
181: handleException("Error closing outgoing message stream", e);
182: }
183: }
184:
185: // -------------- utility methods -------------
186: private void handleException(String msg, Exception e)
187: throws AxisFault {
188: log.error(msg, e);
189: throw new AxisFault(msg, e);
190: }
191: }
|