/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.undertow; import java.io.IOException; import java.nio.ByteBuffer; import io.undertow.client.ClientCallback; import io.undertow.client.ClientConnection; import io.undertow.client.ClientExchange; import io.undertow.client.ClientRequest; import io.undertow.client.UndertowClient; import io.undertow.util.Headers; import io.undertow.util.Protocols; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.TypeConverter; import org.apache.camel.impl.DefaultAsyncProducer; import org.apache.camel.util.ExchangeHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.Xnio; import org.xnio.XnioWorker; /** * The Undertow producer. * * The implementation of Producer is considered as experimental. The Undertow client classes are not thread safe, * their purpose is for the reverse proxy usage inside Undertow itself. This may change in the future versions and * general purpose HTTP client wrapper will be added. Therefore this Producer may be changed too. */ public class UndertowProducer extends DefaultAsyncProducer { private static final Logger LOG = LoggerFactory.getLogger(UndertowProducer.class); private UndertowEndpoint endpoint; public UndertowProducer(UndertowEndpoint endpoint) { super(endpoint); this.endpoint = endpoint; } @Override public UndertowEndpoint getEndpoint() { return endpoint; } @Override public boolean process(Exchange exchange, AsyncCallback callback) { try { final UndertowClient client = UndertowClient.getInstance(); XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY); IoFuture<ClientConnection> connect = client.connect(endpoint.getHttpURI(), worker, new ByteBufferSlicePool(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, 8192, 8192 * 8192), OptionMap.EMPTY); ClientRequest request = new ClientRequest(); request.setProtocol(Protocols.HTTP_1_1); request.setPath(endpoint.getHttpURI().getPath()); Object body = getRequestBody(request, exchange); TypeConverter tc = endpoint.getCamelContext().getTypeConverter(); ByteBuffer bodyAsByte = tc.convertTo(ByteBuffer.class, body); if (body != null) { request.getRequestHeaders().put(Headers.CONTENT_LENGTH, bodyAsByte.array().length); } connect.get().sendRequest(request, new UndertowProducerCallback(bodyAsByte, exchange, callback)); } catch (IOException e) { exchange.setException(e); callback.done(true); return true; } // use async routing engine return false; } private Object getRequestBody(ClientRequest request, Exchange camelExchange) { Object result; result = endpoint.getUndertowHttpBinding().toHttpRequest(request, camelExchange.getIn()); return result; } /** * Everything important happens in callback */ private class UndertowProducerCallback implements ClientCallback<ClientExchange> { private final ByteBuffer body; private final Exchange camelExchange; private final AsyncCallback callback; public UndertowProducerCallback(ByteBuffer body, Exchange camelExchange, AsyncCallback callback) { this.body = body; this.camelExchange = camelExchange; this.callback = callback; } // TODO: Add some logging of those events at trace or debug level @Override public void completed(ClientExchange clientExchange) { clientExchange.setResponseListener(new ClientCallback<ClientExchange>() { @Override public void completed(ClientExchange clientExchange) { try { Message message = endpoint.getUndertowHttpBinding().toCamelMessage(clientExchange, camelExchange); if (ExchangeHelper.isOutCapable(camelExchange)) { camelExchange.setOut(message); } else { camelExchange.setIn(message); } } catch (Exception e) { camelExchange.setException(e); } finally { // make sure to call callback callback.done(false); } } @Override public void failed(IOException e) { camelExchange.setException(e); // make sure to call callback callback.done(false); } }); try { //send body if exists if (body != null) { clientExchange.getRequestChannel().write(body); } } catch (IOException e) { camelExchange.setException(e); // make sure to call callback callback.done(false); } } @Override public void failed(IOException e) { camelExchange.setException(e); // make sure to call callback callback.done(false); } } }