/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * 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.kie.server.router.proxy; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import io.undertow.server.HttpServerExchange; import io.undertow.server.handlers.proxy.LoadBalancingProxyClient; import io.undertow.server.handlers.proxy.ProxyCallback; import io.undertow.server.handlers.proxy.ProxyClient; import io.undertow.server.handlers.proxy.ProxyConnection; import org.jboss.logging.Logger; import org.kie.server.router.Configuration; import org.kie.server.router.ConfigurationListener; import org.kie.server.router.spi.ContainerResolver; import org.kie.server.router.spi.RestrictionPolicy; public class KieServerProxyClient implements ProxyClient, ConfigurationListener { private static final Logger log = Logger.getLogger(KieServerProxyClient.class); private ServiceLoader<ContainerResolver> containerResolverServiceLoader = ServiceLoader.load(ContainerResolver.class); private ServiceLoader<RestrictionPolicy> restrictionPolicyServiceLoader = ServiceLoader.load(RestrictionPolicy.class); private ContainerResolver containerResolver = new DefaultContainerResolver(); private RestrictionPolicy restrictionPolicy = new DefaultRestrictionPolicy(); private Map<String, LoadBalancingProxyClient> containerClients = new ConcurrentHashMap<>(); private Configuration configuration; public KieServerProxyClient(Configuration configuration) { this.configuration = configuration; this.configuration.addListener(this); List<ContainerResolver> foundResolvers = new ArrayList<>(); containerResolverServiceLoader.forEach(cr -> foundResolvers.add(cr)); List<RestrictionPolicy> foundPolicies = new ArrayList<>(); restrictionPolicyServiceLoader.forEach(p -> foundPolicies.add(p)); if (foundPolicies.size() > 1 || foundResolvers.size() > 1) { throw new IllegalStateException("Found more than one RestrictionPolicy " + foundPolicies + " or ContainerResolver " + foundResolvers); } if (!foundResolvers.isEmpty()) { this.containerResolver = foundResolvers.get(0); } if (!foundPolicies.isEmpty()) { this.restrictionPolicy = foundPolicies.get(0); } log.infof("Using '%s' container resolver and restriction policy '%s'", containerResolver, restrictionPolicy); } public synchronized void addContainer(String containerId, URI serverURI) { LoadBalancingProxyClient client = containerClients.get(containerId); if (client == null) { client = new LoadBalancingProxyClient(); containerClients.put(containerId, client); } client.addHost(serverURI); } public synchronized void removeContainer(String containerId, URI serverURI) { LoadBalancingProxyClient client = containerClients.get(containerId); if (client == null) { log.debugf("No backend server found for %s and server URI %s", containerId, serverURI); return; } client.removeHost(serverURI); } @Override public ProxyTarget findTarget(HttpServerExchange exchange) { String containerId = containerResolver.resolveContainerId(exchange, configuration.getContainerInfosPerContainer()); if (restrictionPolicy.restrictedEndpoint(exchange, containerId)) { log.debugf("URL %s is restricted according to policy %s", exchange.getRelativePath(), restrictionPolicy.toString()); return null; } LoadBalancingProxyClient client = containerClients.get(containerId); if (client == null) { return null; } return client.findTarget(exchange); } @Override public void getConnection(ProxyTarget target, HttpServerExchange exchange, ProxyCallback<ProxyConnection> callback, long timeout, TimeUnit timeUnit) { String containerId = containerResolver.resolveContainerId(exchange, configuration.getContainerInfosPerContainer()); LoadBalancingProxyClient client = containerClients.get(containerId); client.getConnection(target, exchange, callback, timeout, timeUnit); } @Override public void onContainerAdded(String container, String serverUrl) { addContainer(container, URI.create(serverUrl)); } @Override public void onContainerRemoved(String container, String serverUrl) { removeContainer(container, URI.create(serverUrl)); } }