/**
*
*/
package com.trendrr.strest;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yaml.snakeyaml.Yaml;
import com.trendrr.oss.DynMap;
import com.trendrr.oss.DynMapFactory;
import com.trendrr.oss.FileHelper;
import com.trendrr.strest.server.StrestServer;
/**
* @author Dustin Norlander
* @created Mar 1, 2012
*
*/
public class StrestServerBuilder {
protected Log log = LogFactory.getLog(StrestServerBuilder.class);
DynMap config = new DynMap();
StrestServer server = new StrestServer();
Set<String> filterNamespaces = new HashSet<String>();
/**
* build the server instance and return it.
* @return
* @throws Exception
*/
public StrestServer build() throws Exception {
server.initialize(config);
for (String nm : this.filterNamespaces) {
server.getRouter().setFilters(nm, config.getList(String.class, nm +".filters"));
}
return server;
}
/**
* adds a config file. will merge with any previous config files added
*
* Config file is assumed to be either
* json or yaml. See example_config.yaml for more.
*
* if more then one filename is passed, the subsequent config files will override any fields in the previous ones.
* this allows you to chain config files
* @param filename
* @return
* @throws Exception
*/
public StrestServerBuilder addConfigFile(String filename) throws Exception {
DynMap conf = this.dynMapFromFile(filename);
if (conf == null) {
log.warn("Unable to parse config file: " + filename);
return this;
}
return this.addConfig(conf);
}
/**
* adds a config file. will merge with any previous configuration options added
* @param filename
* @return
* @throws Exception
*/
public StrestServerBuilder addConfig(DynMap config) throws Exception {
//test for namespaces
for (String key: config.keySet()) {
DynMap mp = config.getMap(key); //this isn't very fast, but I don't think it needs to be.
if (mp == null)
continue;
if (mp.getList(String.class, "filters") != null) {
this.filterNamespaces.add(key);
}
}
this.config.extend(config);
return this;
}
/**
* add a filter to be executed for the given namespace (usually namespace is either default,html,api)
* @param namespace
* @param filter should be fully qualified classname ex: "com.trendrr.cheshire.filters.SessionFilter"
* @return
*/
public StrestServerBuilder addFilters(String namespace, String ...filters) {
this.config.addToListWithDot(namespace + ".filters", (java.lang.Object[])filters);
this.filterNamespaces.add(namespace);
return this;
}
/**
* add filters. these will be applied to all controllers.
* @param filters
* @return
*/
public StrestServerBuilder addFilter(String ...filters) {
this.config.addToListWithDot("filters", (java.lang.Object[])filters);
return this;
}
/**
* add controller packages. these will be recursively searched for controller instances.
* @param filters
* @return
*/
public StrestServerBuilder addControllerPackage(String ...packages) {
this.config.addToListWithDot("controller_packages", (java.lang.Object[])packages);
return this;
}
public StrestServerBuilder addListenerHttp(int port) {
return this.addListener("http", port, null);
}
public StrestServerBuilder addListenerJson(int port) {
return this.addListener("json", port, null);
}
public StrestServerBuilder addListenerZmq(int port) {
return this.addListener("zmq", port, "com.trendrr.strest.contrib.zmq.StrestZMQServerListener");
}
public StrestServerBuilder addListener(String name, int port, String className) {
this.config.putWithDot("listeners." + name + ".port", port);
this.config.putWithDot("listeners." + name + ".classname", className);
return this;
}
/**
* number of io threads to use. usually 2*number of cores.
* @param numThreads
* @return
*/
public StrestServerBuilder numThreadsIO(int numThreads) {
this.config.putWithDot("threads.io", numThreads);
return this;
}
/**
* number of worker threads. adjust based on amount of blocking io done in controllers
* @param numThreads
* @return
*/
public StrestServerBuilder numThreadsWorker(int numThreads) {
this.config.putWithDot("threads.worker", numThreads);
return this;
}
private DynMap dynMapFromFile(String filename) throws Exception {
if (filename.endsWith("yaml")) {
Yaml yaml = new Yaml();
String document = FileHelper.loadString(filename);
Map map = (Map) yaml.load(document);
return DynMapFactory.instance(map);
} else if (filename.endsWith("xml")) {
//TODO (or not..)
}
//assume json
return DynMapFactory.instanceFromFile(filename);
}
}