diff --git a/README.md b/README.md
index 25e89a1..1c52f33 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,11 @@ entirely with spring, and tell the spring service which components to enable usi
With **dropwizard-spring** it is not necessary to subclass `com.yammer.dropwizard.Service`, instead you reference the provided
`com.hmsonline.dropwizard.spring.SpringService` class as your service class.
+With **dropwizard-spring** 0.7+ it is possible to use your own `com.yammer.dropwizard.Service` (Application in dropwizard 0.7)
+and use the provided `com.hmsonline.dropwizard.spring.SpringBundle` class by adding `bootstrap.addBundle(new SpringBundle());`
+to the `initialize` method of your dropwizard Service/Application class. This allows you to subclass the SpringServiceConfiguration
+dropwizard Configuration object to add your own configuration settings, and also introduce your own logic into your
+dropwizard Service/Application.
## Maven Configuration
@@ -108,6 +113,34 @@ This is required to have maven build a "fat," executable jar file.
configLocations:
- conf/dropwizard-beans.xml
+ # Beans to be created from the configuration provided
+ # These will be constructed *before* the configLocations are parsed allowing their values to be used.
+ #
+ # Example below reflects this equivalent spring XML config:
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ #
+ beans:
+ uniqueBeanNameHere:
+ clazz: class.to.Construct
+ config:
+ key1: "value1"
+ key2: 1234
+ key3: true
+ remoteApi:
+ clazz: com.myapp.config.RemoteAPI
+ config:
+ url: "http://api.domain.com/rest/v2/"
+ username: "myuser"
+ password: "some-password-hash"
+
# Servlet Filter
# List of FilterConfiguration
filters:
diff --git a/pom.xml b/pom.xml
index 35e416c..f328be9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.hmsonline
dropwizard-spring
- 0.6.2-SNAPSHOT
+ 0.7.0-SNAPSHOT
jar
Spring Integration for DropWizard
https://github.com/hmsonline/dropwizard-spring
@@ -30,6 +30,7 @@
UTF-8
0.7.0
3.2.8.RELEASE
+ 1.7.0
@@ -67,6 +68,11 @@
spring-web
${spring.version}
+
+ commons-beanutils
+ commons-beanutils
+ ${beanutils.version}
+
junit
junit
diff --git a/src/main/java/com/hmsonline/dropwizard/spring/BeanConfiguration.java b/src/main/java/com/hmsonline/dropwizard/spring/BeanConfiguration.java
new file mode 100644
index 0000000..c8e6cfe
--- /dev/null
+++ b/src/main/java/com/hmsonline/dropwizard/spring/BeanConfiguration.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2015 Hardiker Ltd.
+package com.hmsonline.dropwizard.spring;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Map;
+
+public class BeanConfiguration {
+
+ @JsonProperty
+ private String clazz; // Filter class.
+
+ @JsonProperty
+ private Map config; // Init params.
+
+ public String getClazz() {
+ return clazz;
+ }
+
+ public void setClazz(String clazz) {
+ this.clazz = clazz;
+ }
+
+ public Map getConfig() {
+ return config;
+ }
+
+ public void setConfig(Map config) {
+ this.config = config;
+ }
+}
diff --git a/src/main/java/com/hmsonline/dropwizard/spring/SpringBundle.java b/src/main/java/com/hmsonline/dropwizard/spring/SpringBundle.java
new file mode 100644
index 0000000..bddf71f
--- /dev/null
+++ b/src/main/java/com/hmsonline/dropwizard/spring/SpringBundle.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2015 Hardiker Ltd.
+package com.hmsonline.dropwizard.spring;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.hmsonline.dropwizard.spring.web.XmlRestWebApplicationContext;
+import io.dropwizard.ConfiguredBundle;
+import io.dropwizard.setup.Bootstrap;
+import io.dropwizard.setup.Environment;
+import org.springframework.context.ApplicationContext;
+
+import java.util.List;
+
+
+public class SpringBundle implements ConfiguredBundle {
+
+ SpringService service = new SpringService();
+
+ @Override
+ public void initialize(Bootstrap> bootstrap) {
+ // This is needed to avoid an exception when deserializing Json to an ArrayList
+ bootstrap.getObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
+ }
+
+ @Override
+ public void run(SpringServiceConfiguration configuration, Environment environment) {
+ SpringConfiguration config = configuration.getSpring();
+
+ ApplicationContext parentCtx = initSpringParent();
+
+ Dropwizard dw = (Dropwizard) parentCtx.getBean("dropwizard");
+ dw.setConfiguration(configuration);
+ dw.setEnvironment(environment);
+
+ parentCtx = wrapApplicationContext(parentCtx, config);
+ parentCtx = initSpringConfigBasedBeans(parentCtx, config);
+
+ ApplicationContext appCtx = initSpring(config, parentCtx);
+ loadResourceBeans(config.getResources(), appCtx, environment);
+ loadHealthCheckBeans(config.getHealthChecks(), appCtx, environment);
+ loadManagedBeans(config.getManaged(), appCtx, environment);
+ loadLifeCycleBeans(config.getLifeCycles(), appCtx, environment);
+ loadJerseyProviders(config.getJerseyProviders(), appCtx, environment);
+ loadTasks(config.getTasks(), appCtx, environment);
+
+ // Load filter or listeners for WebApplicationContext.
+ if (appCtx instanceof XmlRestWebApplicationContext) {
+ try {
+ loadWebConfigs(environment, config, appCtx);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("CNFE when loading spring web configs: " + e.getMessage(), e);
+ }
+ }
+
+ enableJerseyFeatures(config.getEnabledJerseyFeatures(), environment);
+ disableJerseyFeatures(config.getDisabledJerseyFeatures(), environment);
+ }
+
+ /**
+ * This allows you to wrap the ApplicationContext, potentially with another ApplicationContext to extend the base
+ * functionality to meet your needs. Don't forget to refresh any new ApplicationContext's you create!
+ *
+ * @param parent Root Application Context
+ * @param config SpringConfiguration object for reference
+ * @return Application Context for further use
+ */
+ @SuppressWarnings("unused")
+ protected ApplicationContext wrapApplicationContext(ApplicationContext parent, SpringConfiguration config) {
+ return parent;
+ }
+
+ void loadWebConfigs(Environment environment, SpringConfiguration config, ApplicationContext appCtx) throws ClassNotFoundException {
+ service.loadWebConfigs(environment, config, appCtx);
+ }
+
+ void loadResourceBeans(List resources, ApplicationContext ctx, Environment env) {
+ service.loadResourceBeans(resources, ctx, env);
+ }
+
+ void loadHealthCheckBeans(List healthChecks, ApplicationContext ctx, Environment env) {
+ service.loadHealthCheckBeans(healthChecks, ctx, env);
+ }
+
+ void loadManagedBeans(List manageds, ApplicationContext ctx, Environment env) {
+ service.loadManagedBeans(manageds, ctx, env);
+ }
+
+ void loadLifeCycleBeans(List lifeCycles, ApplicationContext ctx, Environment env) {
+ service.loadLifeCycleBeans(lifeCycles, ctx, env);
+ }
+
+ void loadJerseyProviders(List providers, ApplicationContext ctx, Environment env) {
+ service.loadJerseyProviders(providers, ctx, env);
+ }
+
+ void loadTasks(List tasks, ApplicationContext ctx, Environment env) {
+ service.loadTasks(tasks, ctx, env);
+ }
+
+ void enableJerseyFeatures(List features, Environment env) {
+ service.enableJerseyFeatures(features, env);
+ }
+
+ void disableJerseyFeatures(List features, Environment env) {
+ service.disableJerseyFeatures(features, env);
+ }
+
+ ApplicationContext initSpringParent() {
+ return service.initSpringParent();
+ }
+
+ ApplicationContext initSpringConfigBasedBeans(ApplicationContext parent, SpringConfiguration springConfiguration) {
+ return service.initSpringConfigBasedBeans(parent, springConfiguration);
+ }
+
+ ApplicationContext initSpring(SpringConfiguration config, ApplicationContext parent) {
+ return service.initSpring(config, parent);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/hmsonline/dropwizard/spring/SpringConfiguration.java b/src/main/java/com/hmsonline/dropwizard/spring/SpringConfiguration.java
index 2d9a542..11b4150 100644
--- a/src/main/java/com/hmsonline/dropwizard/spring/SpringConfiguration.java
+++ b/src/main/java/com/hmsonline/dropwizard/spring/SpringConfiguration.java
@@ -1,4 +1,5 @@
// Copyright (c) 2012 Health Market Science, Inc.
+// Extended by Hardiker Ltd
package com.hmsonline.dropwizard.spring;
@@ -35,6 +36,9 @@ public class SpringConfiguration extends Configuration {
@JsonProperty
private List resources;
+ @JsonProperty
+ private Map beans;
+
@JsonProperty
private List healthChecks;
@@ -75,6 +79,10 @@ public List getResources() {
return resources;
}
+ public Map getBeans() {
+ return beans;
+ }
+
public List getHealthChecks() {
return healthChecks;
}
diff --git a/src/main/java/com/hmsonline/dropwizard/spring/SpringService.java b/src/main/java/com/hmsonline/dropwizard/spring/SpringService.java
index 42e4366..759bf16 100644
--- a/src/main/java/com/hmsonline/dropwizard/spring/SpringService.java
+++ b/src/main/java/com/hmsonline/dropwizard/spring/SpringService.java
@@ -1,4 +1,5 @@
// Copyright (c) 2012 Health Market Science, Inc.
+// Extended by Hardiker Ltd
package com.hmsonline.dropwizard.spring;
import java.text.MessageFormat;
@@ -16,6 +17,7 @@
import io.dropwizard.servlets.tasks.Task;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
+import org.apache.commons.beanutils.PropertyUtils;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.slf4j.Logger;
@@ -24,6 +26,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
+import org.springframework.context.support.StaticApplicationContext;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
@@ -58,6 +61,8 @@ public void run(SpringServiceConfiguration configuration, Environment environmen
dw.setConfiguration(configuration);
dw.setEnvironment(environment);
+ parentCtx = initSpringConfigBasedBeans(parentCtx, config);
+
ApplicationContext appCtx = initSpring(config, parentCtx);
loadResourceBeans(config.getResources(), appCtx, environment);
loadHealthCheckBeans(config.getHealthChecks(), appCtx, environment);
@@ -78,7 +83,7 @@ public void run(SpringServiceConfiguration configuration, Environment environmen
/**
* Load filter, servlets or listeners for WebApplicationContext.
*/
- private void loadWebConfigs(Environment environment, SpringConfiguration config, ApplicationContext appCtx) throws ClassNotFoundException {
+ void loadWebConfigs(Environment environment, SpringConfiguration config, ApplicationContext appCtx) throws ClassNotFoundException {
// Load filters.
loadFilters(config.getFilters(), environment);
@@ -93,7 +98,7 @@ private void loadWebConfigs(Environment environment, SpringConfiguration config,
* Load all filters.
*/
@SuppressWarnings("unchecked")
- private void loadFilters(Map filters, Environment environment) throws ClassNotFoundException {
+ void loadFilters(Map filters, Environment environment) throws ClassNotFoundException {
if (filters != null) {
for (Map.Entry filterEntry : filters.entrySet()) {
FilterConfiguration filter = filterEntry.getValue();
@@ -121,7 +126,7 @@ private void loadFilters(Map filters, Environment e
* Load all servlets.
*/
@SuppressWarnings("unchecked")
- private void loadServlets(Map servlets, Environment environment) throws ClassNotFoundException {
+ void loadServlets(Map servlets, Environment environment) throws ClassNotFoundException {
if (servlets != null) {
for (Map.Entry servletEntry : servlets.entrySet()) {
ServletConfiguration servlet = servletEntry.getValue();
@@ -145,7 +150,7 @@ private void loadServlets(Map servlets, Environmen
}
}
- private void loadResourceBeans(List resources, ApplicationContext ctx, Environment env) {
+ void loadResourceBeans(List resources, ApplicationContext ctx, Environment env) {
if (resources != null) {
for (String resource : resources) {
try {
@@ -158,7 +163,7 @@ private void loadResourceBeans(List resources, ApplicationContext ctx, E
}
- private void loadHealthCheckBeans(List healthChecks, ApplicationContext ctx, Environment env) {
+ void loadHealthCheckBeans(List healthChecks, ApplicationContext ctx, Environment env) {
if (healthChecks != null) {
for (String healthCheck : healthChecks) {
try {
@@ -171,7 +176,7 @@ private void loadHealthCheckBeans(List healthChecks, ApplicationContext
}
}
- private void loadManagedBeans(List manageds, ApplicationContext ctx, Environment env) {
+ void loadManagedBeans(List manageds, ApplicationContext ctx, Environment env) {
if (manageds != null) {
for (String managed : manageds) {
try {
@@ -183,7 +188,7 @@ private void loadManagedBeans(List manageds, ApplicationContext ctx, Env
}
}
- private void loadLifeCycleBeans(List lifeCycles, ApplicationContext ctx, Environment env) {
+ void loadLifeCycleBeans(List lifeCycles, ApplicationContext ctx, Environment env) {
if (lifeCycles != null) {
for (String lifeCycle : lifeCycles) {
try {
@@ -195,7 +200,7 @@ private void loadLifeCycleBeans(List lifeCycles, ApplicationContext ctx,
}
}
- private void loadJerseyProviders(List providers, ApplicationContext ctx, Environment env) {
+ void loadJerseyProviders(List providers, ApplicationContext ctx, Environment env) {
if (providers != null) {
for (String provider : providers) {
try {
@@ -207,7 +212,7 @@ private void loadJerseyProviders(List providers, ApplicationContext ctx,
}
}
- private void loadTasks(List tasks, ApplicationContext ctx, Environment env) {
+ void loadTasks(List tasks, ApplicationContext ctx, Environment env) {
if (tasks != null) {
for (String task : tasks) {
try {
@@ -219,7 +224,7 @@ private void loadTasks(List tasks, ApplicationContext ctx, Environment e
}
}
- private void enableJerseyFeatures(List features, Environment env) {
+ void enableJerseyFeatures(List features, Environment env) {
if (features != null) {
for (String feature : features) {
env.jersey().enable(feature);
@@ -227,7 +232,7 @@ private void enableJerseyFeatures(List features, Environment env) {
}
}
- private void disableJerseyFeatures(List features, Environment env) {
+ void disableJerseyFeatures(List features, Environment env) {
if (features != null) {
for (String feature : features) {
env.jersey().disable(feature);
@@ -235,13 +240,42 @@ private void disableJerseyFeatures(List features, Environment env) {
}
}
- private ApplicationContext initSpringParent() {
+ ApplicationContext initSpringParent() {
ApplicationContext parent = new ClassPathXmlApplicationContext(
new String[]{"dropwizardSpringApplicationContext.xml"}, true);
return parent;
}
- private ApplicationContext initSpring(SpringConfiguration config, ApplicationContext parent) {
+ ApplicationContext initSpringConfigBasedBeans(ApplicationContext parent, SpringConfiguration springConfiguration) {
+ StaticApplicationContext child = new StaticApplicationContext(parent);
+ child.refresh();
+
+ Map beanConfigs = springConfiguration.getBeans();
+ if (beanConfigs != null) {
+ try {
+ for (Map.Entry beanEntry : beanConfigs.entrySet()) {
+ String title = beanEntry.getKey();
+ BeanConfiguration beanConfig = beanEntry.getValue();
+
+ Class clazz = Class.forName(beanConfig.getClazz());
+ child.registerSingleton(title, clazz);
+
+ Object bean = child.getBean(title, clazz);
+ for (Map.Entry entry : beanConfig.getConfig().entrySet()) {
+ PropertyUtils.setProperty(bean, entry.getKey(), entry.getValue());
+ }
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ return child;
+ }
+
+ ApplicationContext initSpring(SpringConfiguration config, ApplicationContext parent) {
ApplicationContext appCtx = null;
// Get Application Context Type
String ctxType = config.getAppContextType();
@@ -269,7 +303,7 @@ private ApplicationContext initSpring(SpringConfiguration config, ApplicationCon
return appCtx;
}
- private void logNoSuchBeanDefinitionException(NoSuchBeanDefinitionException nsbde) {
+ void logNoSuchBeanDefinitionException(NoSuchBeanDefinitionException nsbde) {
if (LOG.isWarnEnabled()) {
LOG.warn("Skipping missing Spring bean: ", nsbde);
}