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.camel.component.ahc;
018    
019    import java.io.ByteArrayOutputStream;
020    
021    import com.ning.http.client.AsyncHandler;
022    import com.ning.http.client.AsyncHttpClient;
023    import com.ning.http.client.HttpResponseBodyPart;
024    import com.ning.http.client.HttpResponseHeaders;
025    import com.ning.http.client.HttpResponseStatus;
026    import com.ning.http.client.Request;
027    import org.apache.camel.AsyncCallback;
028    import org.apache.camel.Exchange;
029    import org.apache.camel.impl.DefaultAsyncProducer;
030    
031    /**
032     *
033     */
034    public class AhcProducer extends DefaultAsyncProducer {
035    
036        private final AsyncHttpClient client;
037    
038        public AhcProducer(AhcEndpoint endpoint) {
039            super(endpoint);
040            this.client = endpoint.getClient();
041        }
042    
043        @Override
044        public AhcEndpoint getEndpoint() {
045            return (AhcEndpoint) super.getEndpoint();
046        }
047    
048        @Override
049        @SuppressWarnings("unchecked")
050        public boolean process(Exchange exchange, AsyncCallback callback) {
051            try {
052                // AHC supports async processing
053                Request request = getEndpoint().getBinding().prepareRequest(getEndpoint(), exchange);
054                log.debug("Executing request {} ", request);
055                client.prepareRequest(request).execute(new AhcAsyncHandler(exchange, callback, request.getUrl()));
056                return false;
057            } catch (Exception e) {
058                exchange.setException(e);
059                callback.done(true);
060                return true;
061            }
062        }
063    
064        /**
065         * Camel {@link AsyncHandler} to receive callbacks during the processing of the request.
066         */
067        private final class AhcAsyncHandler implements AsyncHandler<Exchange> {
068    
069            private final Exchange exchange;
070            private final AsyncCallback callback;
071            private final String url;
072            private final ByteArrayOutputStream os;
073            private int contentLength;
074            private int statusCode;
075            private String statusText;
076    
077            private AhcAsyncHandler(Exchange exchange, AsyncCallback callback, String url) {
078                this.exchange = exchange;
079                this.callback = callback;
080                this.url = url;
081                this.os = new ByteArrayOutputStream();
082            }
083    
084            @Override
085            public void onThrowable(Throwable t) {
086                log.trace("{} onThrowable {}", exchange.getExchangeId(), t);
087                try {
088                    getEndpoint().getBinding().onThrowable(getEndpoint(), exchange, t);
089                } catch (Exception e) {
090                    exchange.setException(e);
091                }
092                callback.done(false);
093            }
094    
095            @Override
096            public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
097                // write body parts to stream, which we will bind to the Camel Exchange in onComplete
098                int wrote = bodyPart.writeTo(os);
099                log.trace("{} onBodyPartReceived {} bytes", exchange.getExchangeId(), wrote);
100                contentLength += wrote;
101                return STATE.CONTINUE;
102            }
103    
104            @Override
105            public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
106                log.trace("{} onStatusReceived {}", exchange.getExchangeId(), responseStatus);
107                try {
108                    statusCode = responseStatus.getStatusCode();
109                    statusText = responseStatus.getStatusText();
110                    getEndpoint().getBinding().onStatusReceived(getEndpoint(), exchange, responseStatus);
111                } catch (Exception e) {
112                    exchange.setException(e);
113                }
114                return STATE.CONTINUE;
115            }
116    
117            @Override
118            public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
119                log.trace("{} onHeadersReceived {}", exchange.getExchangeId(), headers);
120                try {
121                    getEndpoint().getBinding().onHeadersReceived(getEndpoint(), exchange, headers);
122                } catch (Exception e) {
123                    exchange.setException(e);
124                }
125                return STATE.CONTINUE;
126            }
127    
128            @Override
129            public Exchange onCompleted() throws Exception {
130                log.trace("{} onCompleted", exchange.getExchangeId());
131                try {
132                    getEndpoint().getBinding().onComplete(getEndpoint(), exchange, url, os, contentLength, statusCode, statusText);
133                } catch (Exception e) {
134                    exchange.setException(e);
135                } finally {
136                    // signal we are done
137                    callback.done(false);
138                }
139                return exchange;
140            }
141    
142            @Override
143            public String toString() {
144                return "AhcAsyncHandler for exchangeId: " + exchange.getExchangeId() + " -> " + url;
145            }
146        }
147    
148    }