001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.http.endpoints;
018    
019    import java.io.ByteArrayOutputStream;
020    import java.io.Reader;
021    import java.net.URI;
022    import java.util.Map;
023    
024    import javax.jbi.messaging.ExchangeStatus;
025    import javax.jbi.messaging.Fault;
026    import javax.jbi.messaging.InOnly;
027    import javax.jbi.messaging.InOptionalOut;
028    import javax.jbi.messaging.InOut;
029    import javax.jbi.messaging.MessageExchange;
030    import javax.jbi.messaging.NormalizedMessage;
031    import javax.xml.transform.stream.StreamResult;
032    import javax.xml.transform.stream.StreamSource;
033    
034    import org.apache.commons.httpclient.HttpStatus;
035    import org.apache.servicemix.expression.Expression;
036    import org.apache.servicemix.http.jetty.SmxHttpExchange;
037    import org.apache.servicemix.jbi.jaxp.SourceTransformer;
038    import org.apache.servicemix.jbi.jaxp.StAXSourceTransformer;
039    import org.mortbay.io.ByteArrayBuffer;
040    import org.mortbay.jetty.HttpHeaders;
041    import org.mortbay.jetty.HttpMethods;
042    
043    /**
044     * Default marshaler used for non-soap provider endpoints.
045     *
046     * @author gnodet
047     * @since 3.2
048     */
049    public class DefaultHttpProviderMarshaler implements HttpProviderMarshaler {
050    
051        private SourceTransformer transformer = new StAXSourceTransformer();
052        private String locationURI;
053        private Expression locationURIExpression;
054        private String method;
055        private Expression methodExpression;
056        private String contentType = "text/xml";
057        private Expression contentTypeExpression;
058        private Map<String, String> headers;
059    
060        public String getLocationURI() {
061            return locationURI;
062        }
063    
064        public void setLocationURI(String locationUri) {
065            this.locationURI = locationUri;
066        }
067    
068        public Expression getLocationURIExpression() {
069            return locationURIExpression;
070        }
071    
072        public void setLocationURIExpression(Expression locationUriExpression) {
073            this.locationURIExpression = locationUriExpression;
074        }
075    
076        public String getMethod() {
077            return method;
078        }
079    
080        public void setMethod(String method) {
081            this.method = method;
082        }
083    
084        public Expression getMethodExpression() {
085            return methodExpression;
086        }
087    
088        public void setMethodExpression(Expression methodExpression) {
089            this.methodExpression = methodExpression;
090        }
091    
092        public String getContentType() {
093            return contentType;
094        }
095    
096        public void setContentType(String contentType) {
097            this.contentType = contentType;
098        }
099    
100        public Expression getContentTypeExpression() {
101            return contentTypeExpression;
102        }
103    
104        public void setContentTypeExpression(Expression contentTypeExpression) {
105            this.contentTypeExpression = contentTypeExpression;
106        }
107    
108        public Map<String, String> getHeaders() {
109            return headers;
110        }
111    
112        public void setHeaders(Map<String, String> headers) {
113            this.headers = headers;
114        }
115    
116        protected String getLocationUri(MessageExchange exchange, NormalizedMessage inMsg) throws Exception {
117            String uri = null;
118            if (locationURIExpression != null) {
119                Object o = locationURIExpression.evaluate(exchange, inMsg);
120                uri = (o != null) ? o.toString() : null;
121            }
122            if (uri == null) {
123                uri = locationURI;
124            }
125            if (uri == null) {
126                throw new IllegalStateException("Unable to find URI for exchange");
127            }
128            return uri;
129        }
130    
131        protected String getMethod(MessageExchange exchange, NormalizedMessage inMsg) throws Exception {
132            String mth = null;
133            if (methodExpression != null) {
134                Object o = methodExpression.evaluate(exchange, inMsg);
135                mth = (o != null) ? o.toString() : null;
136            }
137            if (mth == null) {
138                mth = method;
139            }
140            if (mth == null) {
141                if (inMsg.getContent() == null) {
142                    mth = HttpMethods.GET;
143                } else {
144                    mth = HttpMethods.POST;
145                }
146            }
147            return mth;
148        }
149    
150        protected String getContentType(MessageExchange exchange, NormalizedMessage inMsg) throws Exception {
151            String content = null;
152            if (contentTypeExpression != null) {
153                Object o = contentTypeExpression.evaluate(exchange, inMsg);
154                content = (o != null) ? o.toString() : null;
155            }
156            if (content == null) {
157                content = contentType;
158            }
159            if (content == null) {
160                throw new IllegalStateException("ContentType must not be null");
161            }
162            return content;
163        }
164    
165        public void createRequest(final MessageExchange exchange,
166                                  final NormalizedMessage inMsg,
167                                  final SmxHttpExchange httpExchange) throws Exception {
168            httpExchange.setURL(getLocationUri(exchange, inMsg));
169    
170            // Temporary fix for bug in jetty-client 6.1.5
171            // http://fisheye.codehaus.org/browse/jetty-contrib/jetty/trunk/contrib/client/src/main/java/org/mortbay/jetty/client/HttpConnection.java?r1=374&r2=378
172            httpExchange.addRequestHeader(HttpHeaders.HOST_BUFFER, new ByteArrayBuffer(new URI(getLocationUri(exchange, inMsg)).getHost()));
173    
174            httpExchange.setMethod(getMethod(exchange, inMsg));
175            httpExchange.setRequestHeader(HttpHeaders.CONTENT_TYPE, getContentType(exchange, inMsg));
176            if (getHeaders() != null) {
177                for (Map.Entry<String, String> e : getHeaders().entrySet()) {
178                    httpExchange.setRequestHeader(e.getKey(), e.getValue());
179                }
180            }
181            if (inMsg.getContent() != null) {
182                ByteArrayOutputStream baos = new ByteArrayOutputStream();
183                transformer.toResult(inMsg.getContent(), new StreamResult(baos));
184                httpExchange.setRequestContent(new ByteArrayBuffer(baos.toByteArray()));
185            }
186        }
187    
188        public void handleResponse(MessageExchange exchange, SmxHttpExchange httpExchange) throws Exception {
189            int response = httpExchange.getResponseStatus();
190            if (response != HttpStatus.SC_OK && response != HttpStatus.SC_ACCEPTED) {
191                if (!(exchange instanceof InOnly)) {
192                    Fault fault = exchange.createFault();
193                    fault.setContent(new StreamSource(httpExchange.getResponseReader()));
194                    exchange.setFault(fault);
195                } else {
196                    throw new Exception("Invalid status response: " + response);
197                }
198            } else if (exchange instanceof InOut) {
199                NormalizedMessage msg = exchange.createMessage();
200                msg.setContent(new StreamSource(httpExchange.getResponseReader()));
201                exchange.setMessage(msg, "out");
202            } else if (exchange instanceof InOptionalOut) {
203                Reader r = httpExchange.getResponseReader();
204                if (r != null) {
205                    NormalizedMessage msg = exchange.createMessage();
206                    msg.setContent(new StreamSource(r));
207                    exchange.setMessage(msg, "out");
208                } else {
209                    exchange.setStatus(ExchangeStatus.DONE);
210                }
211            } else {
212                exchange.setStatus(ExchangeStatus.DONE);
213    
214            }
215        }
216    
217        public void handleException(MessageExchange exchange, SmxHttpExchange httpExchange, Throwable ex) {
218            exchange.setError((Exception)ex);
219        }
220    
221    }