Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * JBoss, Home of Professional Open Source.
   * Copyright 2014 Red Hat, Inc., and individual contributors
   * as indicated by the @author tags.
   *
   * Licensed 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 io.undertow.server.handlers.proxy;
 
 
 import java.net.URI;
 import java.util.Map;
 import java.util.Set;
 
 import static io.undertow.server.handlers.proxy.ProxyConnectionPool.AvailabilityType.*;
 import static org.xnio.IoUtils.safeClose;

Initial implementation of a load balancing proxy client. This initial implementation is rather simplistic, and will likely change.

Author(s):
Stuart Douglas
 
 public class LoadBalancingProxyClient implements ProxyClient {

    
The attachment key that is used to attach the proxy connection to the exchange.

This cannot be static as otherwise a connection from a different client could be re-used.

 
     private final AttachmentKey<ExclusiveConnectionHolderexclusiveConnectionKey = AttachmentKey.create(ExclusiveConnectionHolder.class);


    
Time in seconds between retries for problem servers
 
     private volatile int problemServerRetry = 10;
 
     private final Set<StringsessionCookieNames = new CopyOnWriteArraySet<>();

    
The number of connections to create per thread
 
     private volatile int connectionsPerThread = 10;
     private volatile int maxQueueSize = 0;

    
The hosts list.
 
     private volatile Host[] hosts = {};
 
     private final AtomicInteger currentHost = new AtomicInteger(0);
     private final UndertowClient client;
 
     private final Map<StringHostroutes = new CopyOnWriteMap<>();
 
     private final ExclusivityChecker exclusivityChecker;
 
     private static final ProxyTarget PROXY_TARGET = new ProxyTarget() {
     };
 
     public LoadBalancingProxyClient() {
         this(UndertowClient.getInstance());
     }
 
     public LoadBalancingProxyClient(UndertowClient client) {
         this(clientnull);
     }
 
     public LoadBalancingProxyClient(ExclusivityChecker client) {
         this(UndertowClient.getInstance(), client);
     }
 
    public LoadBalancingProxyClient(UndertowClient clientExclusivityChecker exclusivityChecker) {
        this. = client;
        this. = exclusivityChecker;
        .add("JSESSIONID");
    }
    public LoadBalancingProxyClient addSessionCookieName(final String sessionCookieName) {
        .add(sessionCookieName);
        return this;
    }
    public LoadBalancingProxyClient removeSessionCookieName(final String sessionCookieName) {
        .remove(sessionCookieName);
        return this;
    }
    public LoadBalancingProxyClient setProblemServerRetry(int problemServerRetry) {
        this. = problemServerRetry;
        return this;
    }
    public int getProblemServerRetry() {
        return ;
    }
    public int getConnectionsPerThread() {
        return ;
    }
    public LoadBalancingProxyClient setConnectionsPerThread(int connectionsPerThread) {
        this. = connectionsPerThread;
        return this;
    }
    public int getMaxQueueSize() {
        return ;
    }
    public LoadBalancingProxyClient setMaxQueueSize(int maxQueueSize) {
        this. = maxQueueSize;
        return this;
    }
    public synchronized LoadBalancingProxyClient addHost(final URI host) {
        return addHost(hostnullnull);
    }
    public synchronized LoadBalancingProxyClient addHost(final URI hostXnioSsl ssl) {
        return addHost(hostnullssl);
    }
    public synchronized LoadBalancingProxyClient addHost(final URI hostString jvmRoute) {
        return addHost(hostjvmRoutenull);
    }
    public synchronized LoadBalancingProxyClient addHost(final URI hostString jvmRouteXnioSsl ssl) {
        Host h = new Host(jvmRoutenullhostssl.);
        Host[] existing = ;
        Host[] newHosts = new Host[existing.length + 1];
        System.arraycopy(existing, 0, newHosts, 0, existing.length);
        newHosts[existing.length] = h;
        this. = newHosts;
        if (jvmRoute != null) {
            this..put(jvmRouteh);
        }
        return this;
    }
    public synchronized LoadBalancingProxyClient addHost(final URI hostString jvmRouteXnioSsl sslOptionMap options) {
        return addHost(nullhostjvmRoutessloptions);
    }
    public synchronized LoadBalancingProxyClient addHost(final InetSocketAddress bindAddressfinal URI hostString jvmRouteXnioSsl sslOptionMap options) {
        Host h = new Host(jvmRoutebindAddresshostssloptions);
        Host[] existing = ;
        Host[] newHosts = new Host[existing.length + 1];
        System.arraycopy(existing, 0, newHosts, 0, existing.length);
        newHosts[existing.length] = h;
        this. = newHosts;
        if (jvmRoute != null) {
            this..put(jvmRouteh);
        }
        return this;
    }
    public synchronized LoadBalancingProxyClient removeHost(final URI uri) {
        int found = -1;
        Host[] existing = ;
        Host removedHost = null;
        for (int i = 0; i < existing.length; ++i) {
            if (existing[i]..equals(uri)) {
                found = i;
                removedHost = existing[i];
                break;
            }
        }
        if (found == -1) {
            return this;
        }
        Host[] newHosts = new Host[existing.length - 1];
        System.arraycopy(existing, 0, newHosts, 0, found);
        System.arraycopy(existingfound + 1, newHostsfoundexisting.length - found - 1);
        this. = newHosts;
        removedHost.connectionPool.close();
        if (removedHost.jvmRoute != null) {
            .remove(removedHost.jvmRoute);
        }
        return this;
    }
    @Override
    public ProxyTarget findTarget(HttpServerExchange exchange) {
        return ;
    }
    @Override
    public void getConnection(ProxyTarget targetHttpServerExchange exchangefinal ProxyCallback<ProxyConnectioncallbacklong timeoutTimeUnit timeUnit) {
        final ExclusiveConnectionHolder holder = exchange.getConnection().getAttachment();
        if (holder != null && holder.connection.getConnection().isOpen()) {
            // Something has already caused an exclusive connection to be allocated so keep using it.
            callback.completed(exchangeholder.connection);
            return;
        }
        final Host host = selectHost(exchange);
        if (host == null) {
            callback.couldNotResolveBackend(exchange);
        } else {
            if (holder != null || ( != null && .isExclusivityRequired(exchange))) {
                // If we have a holder, even if the connection was closed we now exclusivity was already requested so our client
                // may be assuming it still exists.
                host.connectionPool.connect(targetexchangenew ProxyCallback<ProxyConnection>() {
                    @Override
                    public void completed(HttpServerExchange exchangeProxyConnection result) {
                        if (holder != null) {
                            holder.connection = result;
                        } else {
                            final ExclusiveConnectionHolder newHolder = new ExclusiveConnectionHolder();
                            newHolder.connection = result;
                            ServerConnection connection = exchange.getConnection();
                            connection.putAttachment(newHolder);
                            connection.addCloseListener(new ServerConnection.CloseListener() {
                                @Override
                                public void closed(ServerConnection connection) {
                                    ClientConnection clientConnection = newHolder.connection.getConnection();
                                    if (clientConnection.isOpen()) {
                                        safeClose(clientConnection);
                                    }
                                }
                            });
                        }
                        callback.completed(exchangeresult);
                    }
                    @Override
                    public void queuedRequestFailed(HttpServerExchange exchange) {
                        callback.queuedRequestFailed(exchange);
                    }
                    @Override
                    public void failed(HttpServerExchange exchange) {
                        ..proxyFailedToConnectToBackend(exchange.getRequestURI(), host.uri);
                        callback.failed(exchange);
                    }
                    @Override
                    public void couldNotResolveBackend(HttpServerExchange exchange) {
                        callback.couldNotResolveBackend(exchange);
                    }
                }, timeouttimeUnittrue);
            } else {
                host.connectionPool.connect(targetexchangecallbacktimeouttimeUnitfalse);
            }
        }
    }
    protected Host selectHost(HttpServerExchange exchange) {
        Host[] hosts = this.;
        if (hosts.length == 0) {
            return null;
        }
        Host sticky = findStickyHost(exchange);
        if (sticky != null) {
            return sticky;
        }
        int host = .incrementAndGet() % hosts.length;
        final int startHost = host//if the all hosts have problems we come back to this one
        Host full = null;
        Host problem = null;
        do {
            Host selected = hosts[host];
            ProxyConnectionPool.AvailabilityType available = selected.connectionPool.available();
            if (available == ) {
                return selected;
            } else if (available ==  && full == null) {
                full = selected;
            } else if ((available ==  || available == ) && problem == null) {
                problem = selected;
            }
            host = (host + 1) % hosts.length;
        } while (host != startHost);
        if (full != null) {
            return full;
        }
        if (problem != null) {
            return problem;
        }
        //no available hosts
        return null;
    }
    protected Host findStickyHost(HttpServerExchange exchange) {
        Map<StringCookiecookies = exchange.getRequestCookies();
        for (String cookieName : ) {
            Cookie sk = cookies.get(cookieName);
            if (sk != null) {
                int index = sk.getValue().indexOf('.');
                if (index == -1) {
                    continue;
                }
                String route = sk.getValue().substring(index + 1);
                index = route.indexOf('.');
                if (index != -1) {
                    route = route.substring(0, index);
                }
                return .get(route);
            }
        }
        return null;
    }
    protected final class Host extends ConnectionPoolErrorHandler.SimpleConnectionPoolErrorHandler implements ConnectionPoolManager {
        final ProxyConnectionPool connectionPool;
        final String jvmRoute;
        final URI uri;
        final XnioSsl ssl;
        private Host(String jvmRouteInetSocketAddress bindAddressURI uriXnioSsl sslOptionMap options) {
            this. = new ProxyConnectionPool(thisbindAddressurissloptions);
            this. = jvmRoute;
            this. = uri;
            this. = ssl;
        }
        @Override
        public int getProblemServerRetry() {
            return ;
        }
        @Override
        public int getMaxConnections() {
            return ;
        }
        @Override
        public int getMaxCachedConnections() {
            return ;
        }
        @Override
        public int getSMaxConnections() {
            return ;
        }
        @Override
        public long getTtl() {
            return -1;
        }
        @Override
        public int getMaxQueueSize() {
            return ;
        }
    }
    private static class ExclusiveConnectionHolder {
        private ProxyConnection connection;
    }
New to GrepCode? Check out our FAQ X