All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.component.undertow.UndertowProducer Maven / Gradle / Ivy

There is a newer version: 4.8.0
Show newest version
/**
 * 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.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.net.ssl.SSLContext;

import io.undertow.client.ClientRequest;
import io.undertow.client.UndertowClient;
import io.undertow.protocols.ssl.UndertowXnioSsl;
import io.undertow.server.DefaultByteBufferPool;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.TypeConverter;
import org.apache.camel.http.common.cookie.CookieHandler;
import org.apache.camel.impl.DefaultAsyncProducer;
import org.apache.camel.util.URISupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xnio.OptionMap;
import org.xnio.Xnio;
import org.xnio.XnioWorker;
import org.xnio.ssl.XnioSsl;

/**
 * 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 UndertowClient client;
    private final UndertowEndpoint endpoint;
    private final OptionMap options;
    private DefaultByteBufferPool pool;
    private XnioSsl ssl;
    private XnioWorker worker;

    public UndertowProducer(final UndertowEndpoint endpoint, final OptionMap options) {
        super(endpoint);
        this.endpoint = endpoint;
        this.options = options;
    }

    @Override
    public UndertowEndpoint getEndpoint() {
        return endpoint;
    }

    @Override
    public boolean process(final Exchange camelExchange, final AsyncCallback callback) {
        final URI uri;
        final HttpString method;
        try {
            final String exchangeUri = UndertowHelper.createURL(camelExchange, getEndpoint());
            uri = UndertowHelper.createURI(camelExchange, exchangeUri, getEndpoint());
            method = UndertowHelper.createMethod(camelExchange, endpoint, camelExchange.getIn().getBody() != null);
        } catch (final URISyntaxException e) {
            camelExchange.setException(e);
            callback.done(true);
            return true;
        }

        final String pathAndQuery = URISupport.pathAndQueryOf(uri);

        final UndertowHttpBinding undertowHttpBinding = endpoint.getUndertowHttpBinding();

        final CookieHandler cookieHandler = endpoint.getCookieHandler();
        final Map> cookieHeaders;
        if (cookieHandler != null) {
            try {
                cookieHeaders = cookieHandler.loadCookies(camelExchange, uri);
            } catch (final IOException e) {
                camelExchange.setException(e);
                callback.done(true);
                return true;
            }
        } else {
            cookieHeaders = Collections.emptyMap();
        }

        final ClientRequest request = new ClientRequest();
        request.setMethod(method);
        request.setPath(pathAndQuery);

        final HeaderMap requestHeaders = request.getRequestHeaders();

        // Set the Host header
        final Message message = camelExchange.getIn();
        final String host = message.getHeader(Headers.HOST_STRING, String.class);
        requestHeaders.put(Headers.HOST, Optional.ofNullable(host).orElseGet(() -> uri.getAuthority()));

        final Object body = undertowHttpBinding.toHttpRequest(request, camelExchange.getIn());

        final TypeConverter tc = endpoint.getCamelContext().getTypeConverter();
        final ByteBuffer bodyAsByte = tc.tryConvertTo(ByteBuffer.class, body);

        // As tryConvertTo is used to convert the body, we should do null check
        // or the call bodyAsByte.remaining() may throw an NPE
        if (body != null && bodyAsByte != null) {
            requestHeaders.put(Headers.CONTENT_LENGTH, bodyAsByte.remaining());
        }

        for (final Map.Entry> entry : cookieHeaders.entrySet()) {
            requestHeaders.putAll(HttpString.tryFromString(entry.getKey()), entry.getValue());
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Executing http {} method: {}", method, pathAndQuery);
        }

        final UndertowClientCallback clientCallback = new UndertowClientCallback(camelExchange, callback, getEndpoint(),
            request, bodyAsByte);

        // when connect succeeds or fails UndertowClientCallback will
        // get notified on a I/O thread run by Xnio worker. The writing
        // of request and reading of response is performed also in the
        // callback
        client.connect(clientCallback, uri, worker, ssl, pool, options);

        // the call above will proceed on Xnio I/O thread we will
        // notify the exchange asynchronously when the HTTP exchange
        // ends with success or failure from UndertowClientCallback
        return false;
    }

    @Override
    protected void doStart() throws Exception {
        super.doStart();

        // as in Undertow tests
        pool = new DefaultByteBufferPool(true, 17 * 1024);

        final Xnio xnio = Xnio.getInstance();
        worker = xnio.createWorker(options);

        final SSLContext sslContext = getEndpoint().getSslContext();
        if (sslContext != null) {
            ssl = new UndertowXnioSsl(xnio, options, sslContext);
        }

        client = UndertowClient.getInstance();

        LOG.debug("Created worker: {} with options: {}", worker, options);
    }

    @Override
    protected void doStop() throws Exception {
        super.doStop();

        if (worker != null && !worker.isShutdown()) {
            LOG.debug("Shutting down worker: {}", worker);
            worker.shutdown();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy