Skip to content

Commit

Permalink
Reactively applying API and Proxy configuration changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
nmihajlovski committed Dec 5, 2016
1 parent 6786f3e commit 195755e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 63 deletions.
Expand Up @@ -86,14 +86,23 @@ public int count() {
return added.size() + changed.size() + removed.size(); return added.size() + changed.size() + removed.size();
} }


public <T> Map<String, T> added(Class<T> type) { public <T> Map<String, T> getAddedAs(Class<T> type) {
return Coll.toBeanMap(added, type); return Coll.toBeanMap(added, type);
} }


public <T> Map<String, T> changed(Class<T> type) { public <T> Map<String, T> getChangedAs(Class<T> type) {
return Coll.toBeanMap(changed, type); return Coll.toBeanMap(changed, type);
} }


public <T> Map<String, T> getAddedOrChangedAs(Class<T> type) {
Map<String, Object> addedOrChanged = U.map();

addedOrChanged.putAll(added);
addedOrChanged.putAll(changed);

return Coll.toBeanMap(addedOrChanged, type);
}

@Override @Override
public String toString() { public String toString() {
return "ConfigChanges{" + return "ConfigChanges{" +
Expand Down
2 changes: 2 additions & 0 deletions rapidoid-commons/src/main/resources/rapidoid-classes.txt
Expand Up @@ -653,6 +653,7 @@ org.rapidoid.serialize.Serialize
org.rapidoid.serialize.TypeSpecificDeserializer org.rapidoid.serialize.TypeSpecificDeserializer
org.rapidoid.serialize.TypeSpecificSerializer org.rapidoid.serialize.TypeSpecificSerializer
org.rapidoid.setup.Admin org.rapidoid.setup.Admin
org.rapidoid.setup.APIConfigListener
org.rapidoid.setup.App org.rapidoid.setup.App
org.rapidoid.setup.AppBootstrap org.rapidoid.setup.AppBootstrap
org.rapidoid.setup.AppRestartListener org.rapidoid.setup.AppRestartListener
Expand All @@ -666,6 +667,7 @@ org.rapidoid.setup.OnChanges
org.rapidoid.setup.OnError org.rapidoid.setup.OnError
org.rapidoid.setup.OnRoute org.rapidoid.setup.OnRoute
org.rapidoid.setup.PojoHandlersSetup org.rapidoid.setup.PojoHandlersSetup
org.rapidoid.setup.ProxyConfigListener
org.rapidoid.setup.ReloadUtil org.rapidoid.setup.ReloadUtil
org.rapidoid.setup.ServiceActivator org.rapidoid.setup.ServiceActivator
org.rapidoid.setup.ServiceBootstrap org.rapidoid.setup.ServiceBootstrap
Expand Down
@@ -0,0 +1,88 @@
package org.rapidoid.setup;

/*
* #%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;
import org.rapidoid.config.ConfigChanges;
import org.rapidoid.config.bean.APIConfig;
import org.rapidoid.http.HttpVerb;
import org.rapidoid.http.Req;
import org.rapidoid.http.ReqRespHandler;
import org.rapidoid.http.Resp;
import org.rapidoid.jdbc.JDBC;
import org.rapidoid.lambda.Operation;
import org.rapidoid.u.U;

import java.util.Map;

@Authors("Nikolche Mihajlovski")
@Since("5.3.0")
public class APIConfigListener extends RapidoidThing implements Operation<ConfigChanges> {

@Override
public void execute(ConfigChanges changes) throws Exception {
for (Map.Entry<String, APIConfig> e : changes.getAddedOrChangedAs(APIConfig.class).entrySet()) {

String apiKey = e.getKey().trim();
APIConfig api = e.getValue();

applyAPIEntry(apiKey, api);
}
}

private void applyAPIEntry(String apiKey, final APIConfig api) {
String[] verbUri = apiKey.split("\\s+");

final HttpVerb verb;
String uri;

if (verbUri.length == 1) {
verb = HttpVerb.GET;
uri = verbUri[0];

} else if (verbUri.length == 2) {
verb = HttpVerb.from(verbUri[0]);
uri = verbUri[1];

} else {
throw U.rte("Invalid route!");
}

addApiHandler(api, verb, uri);
}

private void addApiHandler(final APIConfig api, final HttpVerb verb, String uri) {
On.route(verb.name(), uri).json(new ReqRespHandler() {
@Override
public Object execute(Req req, Resp resp) throws Exception {
if (verb == HttpVerb.GET) {
return JDBC.query(api.sql);
} else {
int changes = JDBC.execute(api.sql);
return U.map("success", true, "changes", changes); // FIXME improve
}
}
});
}

}
65 changes: 4 additions & 61 deletions rapidoid-http-server/src/main/java/org/rapidoid/setup/App.java
Expand Up @@ -27,19 +27,12 @@
import org.rapidoid.commons.Arr; import org.rapidoid.commons.Arr;
import org.rapidoid.config.Conf; import org.rapidoid.config.Conf;
import org.rapidoid.config.ConfigHelp; import org.rapidoid.config.ConfigHelp;
import org.rapidoid.config.bean.APIConfig;
import org.rapidoid.config.bean.ProxyConfig;
import org.rapidoid.data.JSON; import org.rapidoid.data.JSON;
import org.rapidoid.env.Env; import org.rapidoid.env.Env;
import org.rapidoid.http.HttpVerb;
import org.rapidoid.http.Req;
import org.rapidoid.http.ReqRespHandler;
import org.rapidoid.http.Resp;
import org.rapidoid.io.Res; import org.rapidoid.io.Res;
import org.rapidoid.ioc.Beans; import org.rapidoid.ioc.Beans;
import org.rapidoid.ioc.IoC; import org.rapidoid.ioc.IoC;
import org.rapidoid.ioc.IoCContext; import org.rapidoid.ioc.IoCContext;
import org.rapidoid.jdbc.JDBC;
import org.rapidoid.job.Jobs; import org.rapidoid.job.Jobs;
import org.rapidoid.log.Log; import org.rapidoid.log.Log;
import org.rapidoid.render.Templates; import org.rapidoid.render.Templates;
Expand All @@ -51,7 +44,6 @@
import org.rapidoid.util.Msc; import org.rapidoid.util.Msc;


import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;


@Authors("Nikolche Mihajlovski") @Authors("Nikolche Mihajlovski")
Expand Down Expand Up @@ -102,65 +94,16 @@ public static AppBootstrap run(String[] args, String... extraArgs) {
public static AppBootstrap boot() { public static AppBootstrap boot() {
Jobs.initialize(); Jobs.initialize();


bootstrapProxy(); registerConfigListeners();
bootstrapAPI();


AppBootstrap bootstrap = new AppBootstrap(); AppBootstrap bootstrap = new AppBootstrap();
bootstrap.services(); bootstrap.services();
return bootstrap; return bootstrap;
} }


private static void bootstrapProxy() { private static void registerConfigListeners() {
if (!Conf.PROXY.isEmpty()) { Conf.PROXY.addChangeListener(new ProxyConfigListener());
for (Map.Entry<String, ProxyConfig> e : Conf.PROXY.toMap(ProxyConfig.class).entrySet()) { Conf.API.addChangeListener(new APIConfigListener());
String uri = e.getKey();
ProxyConfig proxy = e.getValue();
Reverse.proxy().map(uri).to(proxy.upstream.split("\\s*\\,\\s*"));
}
}
}

private static void bootstrapAPI() {
if (!Conf.API.isEmpty()) {
for (Map.Entry<String, APIConfig> e : Conf.API.toMap(APIConfig.class).entrySet()) {

String apiKey = e.getKey().trim();
APIConfig api = e.getValue();

applyAPIEntry(apiKey, api);
}
}
}

private static void applyAPIEntry(String apiKey, final APIConfig api) {
String[] verbUri = apiKey.split("\\s+");

final HttpVerb verb;
String uri;

if (verbUri.length == 1) {
verb = HttpVerb.GET;
uri = verbUri[0];

} else if (verbUri.length == 2) {
verb = HttpVerb.from(verbUri[0]);
uri = verbUri[1];

} else {
throw U.rte("Invalid route!");
}

On.route(verb.name(), uri).json(new ReqRespHandler() {
@Override
public Object execute(Req req, Resp resp) throws Exception {
if (verb == HttpVerb.GET) {
return JDBC.query(api.sql);
} else {
int changes = JDBC.execute(api.sql);
return U.map("success", true, "changes", changes); // FIXME improve
}
}
});
} }


public static void profiles(String... profiles) { public static void profiles(String... profiles) {
Expand Down
@@ -0,0 +1,52 @@
package org.rapidoid.setup;

/*
* #%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;
import org.rapidoid.config.ConfigChanges;
import org.rapidoid.config.bean.ProxyConfig;
import org.rapidoid.lambda.Operation;
import org.rapidoid.reverseproxy.Reverse;

import java.util.Map;

@Authors("Nikolche Mihajlovski")
@Since("5.3.0")
public class ProxyConfigListener extends RapidoidThing implements Operation<ConfigChanges> {

@Override
public void execute(ConfigChanges changes) throws Exception {
for (Map.Entry<String, ProxyConfig> e : changes.getAddedOrChangedAs(ProxyConfig.class).entrySet()) {

String uri = e.getKey().trim();
ProxyConfig proxy = e.getValue();

applyProxyEntry(uri, proxy);
}
}

private void applyProxyEntry(String uri, ProxyConfig proxy) {
Reverse.proxy().map(uri).to(proxy.upstream.split("\\s*\\,\\s*"));
}

}

0 comments on commit 195755e

Please sign in to comment.