diff --git a/rapidoid-commons/src/main/resources/rapidoid-classes.txt b/rapidoid-commons/src/main/resources/rapidoid-classes.txt index 5646dfd933..f7f7237333 100644 --- a/rapidoid-commons/src/main/resources/rapidoid-classes.txt +++ b/rapidoid-commons/src/main/resources/rapidoid-classes.txt @@ -539,8 +539,10 @@ org.rapidoid.render.XNode org.rapidoid.reverseproxy.AbstractReverseProxyBean org.rapidoid.reverseproxy.LoadBalancer org.rapidoid.reverseproxy.ProxyMapping +org.rapidoid.reverseproxy.ProxyUpstream org.rapidoid.reverseproxy.Reverse org.rapidoid.reverseproxy.ReverseProxy +org.rapidoid.reverseproxy.ReverseProxyMapDSL org.rapidoid.reverseproxy.RoundRobinLoadBalancer org.rapidoid.scan.ClasspathUtil org.rapidoid.scan.Scan diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/LoadBalancer.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/LoadBalancer.java index a621ebad5e..fc2efd1947 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/LoadBalancer.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/LoadBalancer.java @@ -24,10 +24,12 @@ import org.rapidoid.annotation.Since; import org.rapidoid.http.Req; +import java.util.List; + @Authors("Nikolche Mihajlovski") @Since("5.2.0") public interface LoadBalancer { - String getTargetUrl(Req req); + ProxyUpstream pickUpstream(Req req, List candidates); } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyMapping.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyMapping.java index 72f05adb5b..66c47e6c3d 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyMapping.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyMapping.java @@ -23,6 +23,7 @@ import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; +import org.rapidoid.commons.Str; import org.rapidoid.http.Req; import java.util.List; @@ -33,21 +34,26 @@ public class ProxyMapping extends RapidoidThing { private final String prefix; - private final List targets; + private volatile List upstreams; - private volatile LoadBalancer loadBalancer = new RoundRobinLoadBalancer(this); + private volatile LoadBalancer loadBalancer = new RoundRobinLoadBalancer(); - public ProxyMapping(String prefix, List targets) { + public ProxyMapping(String prefix, List upstreams) { this.prefix = prefix; - this.targets = targets; + this.upstreams = upstreams; } public String prefix() { return prefix; } - public List targets() { - return targets; + public List upstreams() { + return upstreams; + } + + public ProxyMapping upstreams(List upstreams) { + this.upstreams = upstreams; + return this; } public boolean matches(Req req) { @@ -55,7 +61,11 @@ public boolean matches(Req req) { } public String getTargetUrl(Req req) { - return loadBalancer.getTargetUrl(req); + ProxyUpstream upstream = loadBalancer.pickUpstream(req, upstreams); + + String trimmed = Str.triml(req.uri(), prefix()); + + return upstream.url() + trimmed; } public LoadBalancer loadBalancer() { diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyUpstream.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyUpstream.java new file mode 100644 index 0000000000..08c8785cb9 --- /dev/null +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ProxyUpstream.java @@ -0,0 +1,40 @@ +package org.rapidoid.reverseproxy; + +/* + * #%L + * rapidoid-http-server + * %% + * Copyright (C) 2014 - 2016 Nikolche Mihajlovski and contributors + * %% + * 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. + * #L% + */ + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; + +@Authors("Nikolche Mihajlovski") +@Since("5.2.0") +public class ProxyUpstream extends RapidoidThing { + + private final String url; + + public ProxyUpstream(String url) { + this.url = url; + } + + public String url() { + return url; + } +} diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxy.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxy.java index 157fd6ffcc..1193408c7d 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxy.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxy.java @@ -6,7 +6,6 @@ import org.rapidoid.concurrent.Callback; import org.rapidoid.http.*; import org.rapidoid.http.impl.HttpIO; -import org.rapidoid.log.Log; import org.rapidoid.u.U; import java.util.List; @@ -14,7 +13,7 @@ /* * #%L - * rapidoid-web + * rapidoid-http-server * %% * Copyright (C) 2014 - 2016 Nikolche Mihajlovski and contributors * %% @@ -124,13 +123,12 @@ protected HttpClient createClient() { .maxConnPerRoute(maxConnPerRoute()); } - public ProxyMapping map(String uriPrefix, List targets) { - Log.info("Reverse proxy mapping", "!uriPrefix", uriPrefix, "!targets", targets); - - ProxyMapping mapping = new ProxyMapping(uriPrefix, targets); - mappings.add(mapping); + public ReverseProxyMapDSL map(String uriPrefix) { + return new ReverseProxyMapDSL(this, uriPrefix); + } - return mapping; + public List mappings() { + return mappings; } } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxyMapDSL.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxyMapDSL.java new file mode 100644 index 0000000000..9607e64c10 --- /dev/null +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/ReverseProxyMapDSL.java @@ -0,0 +1,63 @@ +package org.rapidoid.reverseproxy; + +import org.rapidoid.RapidoidThing; +import org.rapidoid.annotation.Authors; +import org.rapidoid.annotation.Since; +import org.rapidoid.log.Log; +import org.rapidoid.u.U; + +import java.util.List; + +/* + * #%L + * rapidoid-http-server + * %% + * Copyright (C) 2014 - 2016 Nikolche Mihajlovski and contributors + * %% + * 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. + * #L% + */ + +@Authors("Nikolche Mihajlovski") +@Since("5.2.0") +public class ReverseProxyMapDSL extends RapidoidThing { + + private final ReverseProxy proxy; + + private final String uriPrefix; + + public ReverseProxyMapDSL(ReverseProxy proxy, String uriPrefix) { + this.proxy = proxy; + this.uriPrefix = uriPrefix; + } + + public ProxyMapping to(String... upstreams) { + return to(U.list(upstreams)); + } + + public ProxyMapping to(List upstreams) { + Log.info("Reverse proxy mapping", "!uriPrefix", uriPrefix, "!upstreams", upstreams); + + List proxyUpstreams = U.list(); + + for (String upstream : upstreams) { + proxyUpstreams.add(new ProxyUpstream(upstream)); + } + + ProxyMapping mapping = new ProxyMapping(uriPrefix, proxyUpstreams); + proxy.mappings().add(mapping); + + return mapping; + } + +} diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/RoundRobinLoadBalancer.java b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/RoundRobinLoadBalancer.java index a96012bf11..91a2ef4aac 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/RoundRobinLoadBalancer.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/reverseproxy/RoundRobinLoadBalancer.java @@ -23,7 +23,6 @@ import org.rapidoid.RapidoidThing; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; -import org.rapidoid.commons.Str; import org.rapidoid.http.Req; import java.util.List; @@ -33,24 +32,15 @@ @Since("5.2.0") public class RoundRobinLoadBalancer extends RapidoidThing implements LoadBalancer { - private final ProxyMapping mapping; - private final AtomicLong counter = new AtomicLong(); - public RoundRobinLoadBalancer(ProxyMapping mapping) { - this.mapping = mapping; - } - @Override - public String getTargetUrl(Req req) { - long n = counter.incrementAndGet(); + public ProxyUpstream pickUpstream(Req req, List candidates) { + long n = counter.getAndIncrement(); - List targets = mapping.targets(); - int index = (int) (n % targets.size()); - String target = targets.get(index); + int index = (int) (n % candidates.size()); - String trimmed = Str.triml(req.uri(), mapping.prefix()); - return target + trimmed; + return candidates.get(index); } } diff --git a/rapidoid-http-server/src/main/java/org/rapidoid/setup/App.java b/rapidoid-http-server/src/main/java/org/rapidoid/setup/App.java index a45632239f..c1d458b717 100644 --- a/rapidoid-http-server/src/main/java/org/rapidoid/setup/App.java +++ b/rapidoid-http-server/src/main/java/org/rapidoid/setup/App.java @@ -251,10 +251,10 @@ public static AppBootstrap bootstrap(String... args) { private static void processProxyArg(String arg) { String[] parts = arg.split("->"); + U.must(parts.length == 2, "Expected /uri->target proxy mapping!"); - List targets = U.list(parts[1].split("\\,")); - Reverse.proxy().map(parts[0], targets); + Reverse.proxy().map(parts[0]).to(parts[1].split("\\,")); } static void filterAndInvokeMainClasses(Object[] beans) {