diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cc788b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+.cache*
+.settings/*
+.project
+.settings
+.cache
+.target
+*.class
+target
+project/target
+project/project
+log
+*log
+logs
+logs/*
+tmp
+logFile*
+.DS_STORE
+.DS_STORE?
+error.log
+admin.log
+bin
+.classpath
+.settings/org.scala-ide.sdt.core.prefs
+.cache-tests
\ No newline at end of file
diff --git a/conf/application.conf b/conf/application.conf
new file mode 100644
index 0000000..420cf6e
--- /dev/null
+++ b/conf/application.conf
@@ -0,0 +1,190 @@
+
+# images
+image.size.min=120
+image.size.max=3200
+image.quality.max=80
+
+# cassandra
+
+
+cassandra.keyspace="wurrly"
+cassandra.queryLimit=100
+cassandra.connections.max=100
+cassandra.connections.min=5
+
+#redis
+
+redis.port=6379
+redis.password=null
+redis.maxTotal=1024
+redis.maxIdle=10
+redis.minIdle=5
+
+#elasticsearch
+
+es.index.name="wurrly"
+
+
+
+#graph
+
+graph.enabled = true
+
+# analytics
+
+events.batch.size=10
+
+# okhttp
+
+okhttp.timeout=10
+
+# azure
+
+azure.accountName="wurrly"
+azure.accessKey.primary="lQyT2OeOYeNoYh/NX58LKCMFue6YYp7gjWLvH+2c5oq1s/jE0ur6kkN25oWn5vGDYdQgREmaZZHI6qpjs/FlnA=="
+azure.accessKey.secondary="qYB2MkSrgsEAiXfFCVfG0xK7DDkmRCI8Y1KH0iWaQz+k+OdbLyOO8jax+ZqStWg0XIQL1SA099eUEcWGtCjRIA=="
+
+#ebean models
+
+ebean.default=[ "models.MediaContent", "models.VideoOverlay", "models.Mask", "models.ContentResource", "models.Content", "models.Hero", "models.Battle", "models.Tip", "models.PlaylistCategory", "models.Collaboration", "models.Review", "models.Collaborator", "models.CollaboratorComment", "models.MediaPurchase","models.AdminActivity","models.Playlist","models.SongTrack","models.Feature","models.Publisher","models.Label","models.Credentials","models.WurrlyModel","models.ArtistFact","models.ArtistQuestion","models.Property","models.Artist","models.Wurrly","models.Song","models.Report","models.Competition","models.Event","models.Comment", "models.User","models.adapter.UserEntityListener","models.adapter.SongEntityListener","models.adapter.WurrlyEntityListener"]
+
+# akka
+
+subsystem.worker.count=12
+subsystem.worker.timeout=60000
+
+# netty
+
+play.http.parser.maxMemoryBuffer=256000K
+play.http.parser.maxDiskBuffer=256000K
+
+# location
+
+location.country.db.path="support/geo/Country.mmdb"
+location.city.db.path="support/geo/City.mmdb"
+location.iso.codes.path="support/geo/territories.json"
+location.default.region="GB"
+
+# hashids
+
+hashids.salt="3C0B0AEF-794F-4D89-9EEE-476CE9A89DFB"
+
+# newrelic
+
+newrelic.license.key="a9bfbe086c5964de4617fa0280077dd2273d3a6b"
+
+# users
+
+user.feed.item.limit=1500
+user.default.avatarPath="4c/50/b8/36/e7e2bf69ca.png"
+user.default.bannerPath="57/60/9b/8f/61341a91f0.png"
+user.password.backdoor="happyasaclamindecember"
+
+
+# google cloud messaging
+
+gcm.senderId=1095155988888
+gcm.apiKey="AIzaSyDbHS8u7LEZQcr3_WooM5Ib-DUEU8HTCfU"
+
+
+# twilio
+
+twilio.number="+16467987759"
+twilio.sid="AC8a33a9fc51927ccd980ac919cdadcba5"
+twilio.token="de44558f9a980b337512eb60b812f31a"
+
+
+
+#api
+
+api.authentication.header="X-Wurrly-Auth"
+api.authentication.key="213fe69502445ed67ae8b99d22838802"
+
+# hfa
+hfa.royaltyId.length=10
+
+# shopify
+shopify.api.key=769375b638f4a6132df62f3c10fdab21
+shopify.api.password=7f950bbb21cf43c0afe8c050907993b3
+shopify.api.secret=a9c0ebee8d529e05ded128c1738afbcb
+shopify.login="josh@wurrly.com"
+shopify.password="wuRR1y"
+shopify.authorization="Basic NzY5Mzc1YjYzOGY0YTYxMzJkZjYyZjNjMTBmZGFiMjE6N2Y5NTBiYmIyMWNmNDNjMGFmZThjMDUwOTA3OTkzYjM="
+shopify.shop.url="https://wurrly.myshopify.com/admin"
+shopify.expiration.days=6
+shopify.product.image.prefix="http://cdn1.wurrly.co/images/w550/"
+shopify.domain="wurrly.myshopify.com"
+shopify.channel.mobile="23087876"
+shopify.product.price="1.99"
+
+#migration
+migration.baseUrl="http://imaging.wurrly.co:4444/wurrlies?"
+
+#itms
+itms.secret="a1f89c67d6e34599b1056b3f42f1c735"
+itms.verification.production.url="https://buy.itunes.apple.com/verifyReceipt"
+itms.verification.sandbox.url="https://sandbox.itunes.apple.com/verifyReceipt"
+
+#subscriptions
+
+user.max.wurrlies=20
+
+#notifications
+
+notifications.enabled=1
+
+#collaborations
+
+collaborations.maxUsers=4
+
+#mailchimp
+
+
+mailchimp.base.url="https://us9.api.mailchimp.com/3.0/"
+
+#password
+
+user.default.password="$2a$10$6T5QVxo16r7qoSdwm9Hx/.rJzWuMQEFoJ6X/VL0DKY0uxaO.XSjBa"
+
+#battles
+
+battle.voting.duration=48
+
+#sift
+
+sift.api.key="GT4cFVEZegH4N5jxq5rj"
+sift.api.url="https://wur28vu8.pottymouthfilter.com/v1/"
+
+
+# The application languages
+# ~~~~~
+
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# This router will be looked up first when the application is starting up,
+# so make sure this is the entry point.
+# Furthermore, it's assumed your route file is named properly.
+# So for an application router like `my.application.Router`,
+# you may need to define a router file `conf/my.application.routes`.
+# Default to Routes in the root package (and conf/routes)
+# play.http.router = my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.username=sa
+# db.default.password=""
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# play.evolutions.enabled=false
+
+# You can disable evolutions for a specific datasource if necessary
+# play.evolutions.db.default.enabled=false
diff --git a/conf/logback.xml b/conf/logback.xml
new file mode 100644
index 0000000..39aa07f
--- /dev/null
+++ b/conf/logback.xml
@@ -0,0 +1,115 @@
+
+
+
+
+ true
+
+
+
+ [%d{ISO8601}]-[%thread] %highlight(%-5level) [%boldCyan(%logger)] - %boldWhite(%message) %n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..7e5698d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,149 @@
+
+ 4.0.0
+ wurrly-undertow
+ wurrly-undertow
+ 0.0.1-SNAPSHOT
+
+ src
+
+
+ maven-compiler-plugin
+ 3.5.1
+
+
+ 1.8
+
+
+
+
+
+
+ com.google.guava
+ guava
+ 21.0
+
+
+ com.typesafe
+ config
+ 1.3.1
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.8.7
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.7
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.8.7
+
+
+ io.swagger
+ swagger-annotations
+ 1.5.12
+
+
+ io.swagger
+ swagger-core
+ 1.5.12
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.1
+
+
+
+ org.hashids
+ hashids
+ 1.0.1
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.6.0
+
+
+ com.squareup.okhttp3
+ okhttp-urlconnection
+ 3.6.0
+
+
+ com.squareup.okhttp3
+ okcurl
+ 3.6.0
+
+
+ com.squareup.retrofit2
+ retrofit
+ 2.2.0
+
+
+ com.squareup.retrofit2
+ adapter-java8
+ 2.2.0
+
+
+ com.squareup.retrofit2
+ converter-jackson
+ 2.2.0
+
+
+ com.squareup.okhttp3
+ logging-interceptor
+ 3.6.0
+
+
+ org.javassist
+ javassist
+ 3.22.0-CR1
+
+
+ com.jsoniter
+ jsoniter
+ 0.9.8
+
+
+ io.undertow
+ undertow-core
+ 1.4.11.Final
+
+
+ org.msgpack
+ jackson-dataformat-msgpack
+ 0.8.12
+
+
+ com.fasterxml.jackson.module
+ jackson-module-afterburner
+ 2.8.7
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jdk8
+ 2.8.7
+
+
+ org.glassfish.jersey
+ jax-rs-ri
+ 2.0-rc1
+
+
+ com.squareup
+ javapoet
+ 1.8.0
+
+
+ com.google.inject
+ guice
+ 4.1.0
+
+
+
\ No newline at end of file
diff --git a/src/com/wurrly/BaseServer.java b/src/com/wurrly/BaseServer.java
new file mode 100644
index 0000000..787b782
--- /dev/null
+++ b/src/com/wurrly/BaseServer.java
@@ -0,0 +1,293 @@
+/**
+ *
+ */
+package com.wurrly;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.nio.ByteBuffer;
+import java.util.Deque;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.jsoniter.DecodingMode;
+import com.jsoniter.JsonIterator;
+import com.jsoniter.ReflectionDecoderFactory;
+import com.jsoniter.annotation.JsoniterAnnotationSupport;
+import com.jsoniter.output.EncodingMode;
+import com.jsoniter.output.JsonStream;
+import com.jsoniter.spi.JsoniterSpi;
+import com.wurrly.controllers.Users;
+import com.wurrly.models.User;
+import com.wurrly.modules.DIModule;
+import com.wurrly.utilities.HandleGenerator;
+import com.wurrly.utilities.ServerRequest;
+
+import io.undertow.Undertow;
+import io.undertow.UndertowOptions;
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.server.RoutingHandler;
+import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+
+/**
+ * @author jbauer
+ */
+public class BaseServer
+{
+
+ public interface RouteArgumentMapper
+ {
+ public void map(M method, E exchange);
+ }
+
+ private static Logger Logger = LoggerFactory.getLogger(BaseServer.class.getCanonicalName());
+
+ private static final String URL_ENCODED_FORM_TYPE = "x-www-form-urlencoded";
+ private static final String FORM_DATA_TYPE = "form-data";
+ private static final String OCTET_STREAM_TYPE = "octet-stream";
+ private static final String JSON_TYPE = "application/json";
+ private static final String CONTENT_TYPE = "Content-Type";
+ static final String CHARSET = "UTF-8";
+
+
+
+ public static class BaseHandlers
+ {
+ public static void notFoundHandler(HttpServerExchange exchange) {
+ exchange.setStatusCode(404);
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
+ exchange.getResponseSender().send("Page Not Found!!");
+ }
+ }
+
+ public static RouteArgumentMapper mapMethodParameters = (Method method, HttpServerExchange exchange) ->
+ {
+ final Parameter[] parameters = method.getParameters();
+
+ for (final Parameter parameter : parameters)
+ {
+ Logger.debug("parameter: " + parameter.getParameterizedType() + " " + parameter.getName());
+
+ if( parameter.getAnnotatedType() instanceof ServerRequest)
+ {
+
+ }
+ }
+ };
+
+ /*
+ * Undertow server = Undertow.builder()
+ .addHttpListener(8080, "0.0.0.0")
+ .setHandler(Handlers.pathTemplate()
+ .add("/item/{itemId}", new ItemHandler())
+ )
+ .build();
+server.start();
+ */
+
+ static Optional queryParam(HttpServerExchange exchange, String name) {
+
+ return Optional.ofNullable(exchange.getQueryParameters().get(name))
+ .map(Deque::getFirst);
+ }
+
+
+ static Optional pathParam(HttpServerExchange exchange, String name) {
+
+ return Optional.ofNullable(exchange.getQueryParameters().get(name))
+ .map(Deque::getFirst);
+ }
+
+ static Optional pathParamAsLong(HttpServerExchange exchange, String name) {
+ return pathParam(exchange, name).map(Long::parseLong);
+ }
+
+ static Optional pathParamAsInteger(HttpServerExchange exchange, String name) {
+ return pathParam(exchange, name).map(Integer::parseInt);
+ }
+
+
+ final static ByteBuffer msgBuffer = ByteBuffer.wrap("hello world".getBytes());
+
+ public static void main(String[] args)
+ {
+
+ try
+ {
+
+ Injector injector = Guice.createInjector(new DIModule());
+
+
+ Users usersController = injector.getInstance(Users.class);
+
+ // injector.injectMembers(usersController);
+
+
+ JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH);
+ JsonStream.setMode(EncodingMode.DYNAMIC_MODE);
+ JsoniterAnnotationSupport.enable();
+
+ RoutingHandler router = new RoutingHandler().setFallbackHandler(BaseHandlers::notFoundHandler);
+
+// HttpHandler getUserHandler = null;
+// GetUsersHandler getUserHandler = new GetUsersHandler(usersController);
+
+ for( Method m : Users.class.getDeclaredMethods() )
+ {
+ System.out.println("method: " + m);
+
+ if( m.isSynthetic() || !m.getDeclaringClass().equals(Users.class))
+ {
+ System.out.println("m " + m + " is shady");
+ continue;
+ }
+
+ HttpString httpMethod = HandleGenerator.extractHttpMethod.apply(m);
+ String pathTemplate = HandleGenerator.extractPathTemplate.apply(m);
+ HttpHandler handler = HandleGenerator.generateHandler(usersController, m, httpMethod.equals(Methods.POST));
+
+ Logger.info("\nFUNCTION: " + m + "\n\tMETHOD: " + httpMethod + "\n\tPATH: " + pathTemplate);
+
+
+ router.add(httpMethod, pathTemplate, handler );
+
+ // router.addAll(Handlers.path().addPrefixPath(pathTemplate, handler));
+ System.out.println("handler: " + handler);
+
+ }
+
+// final HttpHandler createUserPostHandler = new HttpHandler() {
+// @Override
+// public void handleRequest(final HttpServerExchange exchange) throws Exception {
+// if(exchange.isInIoThread()) {
+// exchange.dispatch(this);
+// }
+// ServerRequest serverRequest = new ServerRequest(exchange);
+// Optional context = Optional.ofNullable(exchange.getQueryParameters().get("context")).map(Deque::getFirst);
+// Any user = exchange.getAttachment(ServerRequest.REQUEST_JSON_BODY).readAny();
+// Any response = usersController.createUser(serverRequest,context,user);
+// exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
+// exchange.getResponseSender().send(com.jsoniter.output.JsonStream.serialize(response));
+// }
+// };
+
+ router.add(Methods.GET, "/", new HttpHandler(){
+
+ /* (non-Javadoc)
+ * @see io.undertow.server.HttpHandler#handleRequest(io.undertow.server.HttpServerExchange)
+ */
+ @Override
+ public void handleRequest(HttpServerExchange exchange) throws Exception
+ {
+ // TODO Auto-generated method stub
+
+ exchange.getResponseSender().send(msgBuffer);
+
+ }
+
+
+
+ } );
+
+
+ Undertow server = Undertow.builder()
+ .addHttpListener(8090, "localhost")
+ .setBufferSize(1024 * 16)
+ .setIoThreads(Runtime.getRuntime().availableProcessors())
+ .setServerOption(UndertowOptions.ENABLE_HTTP2, true)
+ .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true)
+ .setSocketOption(org.xnio.Options.BACKLOG, 10000)
+ .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false)
+
+ .setWorkerThreads(Runtime.getRuntime().availableProcessors() * 2)
+ .setHandler(new HttpHandler()
+ {
+ @Override
+ public void handleRequest(final HttpServerExchange exchange) throws Exception
+ {
+ try
+ {
+// if(exchange.isInIoThread())
+// {
+// exchange.dispatch(this);
+// return;
+// }
+
+
+ router.handleRequest(exchange);
+
+ } catch (Exception e)
+ {
+ if (exchange.isResponseChannelAvailable())
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }).build();
+ server.start();
+
+ Runtime.getRuntime().addShutdownHook( new Thread(){
+
+ @Override
+ public void run()
+ {
+
+ }
+ });
+
+
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+
+
+
+ public static class UserIdHandler implements HttpHandler {
+
+ @Override
+ public void handleRequest(HttpServerExchange exchange) throws Exception {
+
+
+// // Method 1
+// PathTemplateMatch pathMatch = exchange.getAttachment(PathTemplateMatch.ATTACHMENT_KEY);
+//
+// System.out.println(pathMatch.getMatchedTemplate());
+//
+// System.out.println(pathMatch.getParameters());
+//
+//
+// System.out.println(exchange.getQueryParameters());
+
+
+
+ Long userId = pathParam(exchange,"id").map(Long::parseLong).orElse(0l);
+
+ exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, JSON_TYPE);
+
+ User user = new User();
+ user.setId(userId);
+//
+ String json = JsonStream.serialize(user);
+
+ // JsonStream.serialize(user,exchange.getOutputStream());
+ exchange.getResponseSender().send(json);
+
+ // exchange.getResponseSender().send(ByteBuffer.wrap(JsonMapper.getInstance().writeValueAsBytes(user)));
+
+ // exchange.getResponseSender().send(JsonStream.serialize(Collections.singletonMap("id", userId)));
+
+ }
+ }
+
+}
diff --git a/src/com/wurrly/controllers/Users.java b/src/com/wurrly/controllers/Users.java
new file mode 100644
index 0000000..30400e5
--- /dev/null
+++ b/src/com/wurrly/controllers/Users.java
@@ -0,0 +1,116 @@
+/**
+ *
+ */
+package com.wurrly.controllers;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.jsoniter.any.Any;
+import com.jsoniter.output.JsonStream;
+import com.typesafe.config.Config;
+import com.wurrly.models.User;
+import com.wurrly.utilities.ServerRequest;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * User API
+ */
+@Api(tags="users",produces="application/json", consumes="application/json")
+@Path("/api/users")
+@Produces(("application/json"))
+@Singleton
+public class Users
+{
+
+ @Inject
+ @Named("es.index.name")
+ protected String esIndexName;
+
+ @Inject
+ protected Config configuration;
+
+ private static Logger log = LoggerFactory.getLogger(Users.class.getCanonicalName());
+
+
+ public Users()
+ {
+
+ }
+
+
+ @GET
+ @Path("/{userId}")
+ @ApiOperation(value = "Find users by id", nickname = "user", httpMethod = "GET", response = JsonNode.class)
+ public Any user(final ServerRequest serverRequest, @PathParam("userId") final Long userId, @QueryParam("context") Optional context)
+ {
+//
+// log.debug("esIndexName: " + esIndexName);
+// log.debug("configuration: " + configuration);
+
+// log.debug("context: " + context);
+//
+//
+ return Any.wrap(new User(userId));
+
+ }
+
+
+ @POST
+ @Path("/")
+// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) })
+ @ApiOperation(value = "Find users by id", nickname = "user", httpMethod = "POST", response = JsonNode.class)
+ public User createUser(final ServerRequest serverRequest, @QueryParam("context") Optional context, final User user )
+ {
+//
+
+// log.debug("context: " + context);
+// log.debug("request: " + serverRequest);
+// log.debug("file: " + user);
+
+ return user;
+
+
+
+ }
+
+ @PUT
+ @Path("/{userId}/username")
+// @ApiImplicitParams({ @ApiImplicitParam(dataType = "com.wurrly.models.User", name = "user", paramType = "body", required = false, allowMultiple = false) })
+ @ApiOperation(value = "Update a user's name", nickname = "updateUsername", httpMethod = "PUT", response = JsonNode.class)
+ public Any updateUsername(final ServerRequest serverRequest, @QueryParam("context") Optional context, final User user )
+ {
+//
+ log.debug("esIndexName: " + esIndexName);
+ log.debug("context: " + context);
+ log.debug("request: " + serverRequest);
+ log.debug("file: " + user);
+
+
+ return Any.wrap(user);
+
+ }
+
+
+
+}
diff --git a/src/com/wurrly/models/User.java b/src/com/wurrly/models/User.java
new file mode 100644
index 0000000..1423b25
--- /dev/null
+++ b/src/com/wurrly/models/User.java
@@ -0,0 +1,38 @@
+/**
+ *
+ */
+package com.wurrly.models;
+
+public class User
+{
+ private Long id = 0l;
+
+ public User()
+ {
+
+ }
+
+ public User(Long id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * @return the id
+ */
+ public Long getId()
+ {
+ return id;
+ }
+
+ /**
+ * @param id the id to set
+ */
+ public void setId(Long id)
+ {
+ this.id = id;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/com/wurrly/modules/DIModule.java b/src/com/wurrly/modules/DIModule.java
new file mode 100644
index 0000000..a0f056f
--- /dev/null
+++ b/src/com/wurrly/modules/DIModule.java
@@ -0,0 +1,112 @@
+/**
+ *
+ */
+package com.wurrly.modules;
+
+import java.io.File;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+import com.google.inject.util.Types;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigObject;
+import com.typesafe.config.ConfigValue;
+
+/**
+ * @author jbauer
+ */
+public class DIModule extends AbstractModule
+{
+ private static Logger log = LoggerFactory.getLogger(DIModule.class.getCanonicalName());
+
+
+ /*
+ * (non-Javadoc)
+ * @see com.google.inject.AbstractModule#configure()
+ */
+ @Override
+ protected void configure()
+ {
+
+ log.debug("configuring...");
+
+ this.bindConfig(this.binder(), fileConfig("application.conf"));
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void bindConfig(final Binder binder, final Config config)
+ {
+ // root nodes
+ traverse(binder, "", config.root());
+
+
+ // terminal nodes
+ for (Entry entry : config.entrySet())
+ {
+ String name = entry.getKey();
+ Named named = Names.named(name);
+ Object value = entry.getValue().unwrapped();
+ if (value instanceof List)
+ {
+ List