2 * Copyright 2017 ZTE Corporation.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.openo.dropwizard.ioc.bundle;
18 import java.lang.annotation.Annotation;
19 import java.lang.reflect.Field;
20 import java.util.Arrays;
21 import java.util.List;
23 import java.util.stream.Collectors;
25 import javax.ws.rs.Path;
26 import javax.ws.rs.ext.Provider;
28 import org.eclipse.jetty.util.component.LifeCycle;
29 import org.glassfish.hk2.api.ServiceLocator;
30 import org.glassfish.hk2.api.ServiceLocatorFactory;
31 import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
32 import org.glassfish.hk2.utilities.binding.AbstractBinder;
33 import org.glassfish.jersey.servlet.ServletProperties;
34 import org.jvnet.hk2.annotations.Service;
35 import org.openo.dropwizard.ioc.annotation.BaseService;
36 import org.openo.dropwizard.ioc.annotation.Lazy;
37 import org.openo.dropwizard.ioc.annotation.PostBaseService;
38 import org.openo.dropwizard.ioc.annotation.PreBaseService;
39 import org.openo.dropwizard.ioc.annotation.PreLoad;
40 import org.openo.dropwizard.ioc.annotation.PreServiceLoad;
41 import org.openo.dropwizard.ioc.utils.ServiceBinder;
42 import org.openo.dropwizard.ioc.utils.ServiceLocatorHolder;
43 import org.reflections.Reflections;
44 import org.reflections.scanners.SubTypesScanner;
45 import org.reflections.scanners.TypeAnnotationsScanner;
46 import org.reflections.util.ClasspathHelper;
47 import org.reflections.util.ConfigurationBuilder;
48 import org.reflections.util.FilterBuilder;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 import com.codahale.metrics.health.HealthCheck;
53 import com.fasterxml.jackson.databind.ObjectMapper;
54 import com.google.common.collect.Lists;
56 import io.dropwizard.Configuration;
57 import io.dropwizard.ConfiguredBundle;
58 import io.dropwizard.configuration.ConfigurationSourceProvider;
59 import io.dropwizard.lifecycle.Managed;
60 import io.dropwizard.lifecycle.ServerLifecycleListener;
61 import io.dropwizard.servlets.tasks.Task;
62 import io.dropwizard.setup.Bootstrap;
63 import io.dropwizard.setup.Environment;
66 * complete the integration of hK2 container and dropwizard
72 public class AutoConfigBundle<T extends Configuration> implements ConfiguredBundle<T> {
74 private static final Logger LOG = LoggerFactory.getLogger(AutoConfigBundle.class);
76 private ServiceLocator locator;
77 private Reflections reflections;
78 private Set<Class<?>> services;
80 private Bootstrap<?> bootstrap;
83 AutoConfigBundle(final String packageName) {
84 this(Lists.newArrayList(packageName));
87 AutoConfigBundle(List<String> packageNames) {
88 FilterBuilder filterBuilder = new FilterBuilder();
90 packageNames.stream().forEach(packageName -> {
91 filterBuilder.include(FilterBuilder.prefix(packageName));
93 ConfigurationBuilder reflectionCfg = new ConfigurationBuilder();
95 packageNames.stream().forEach(packageName -> {
96 reflectionCfg.addUrls(ClasspathHelper.forPackage(packageName));
99 reflectionCfg.filterInputsBy(filterBuilder).setScanners(new SubTypesScanner(),
100 new TypeAnnotationsScanner());
101 reflections = new Reflections(reflectionCfg);
103 locator = ServiceLocatorFactory.getInstance().create("dw-hk2");
105 ServiceLocatorHolder.setLocator(locator);
109 public static <T extends Configuration> AutoConfigBundleBuider<T> newBuilder() {
110 return new AutoConfigBundleBuider<T>();
114 public void initialize(final Bootstrap<?> bootstrap) {
116 this.bootstrap = bootstrap;
117 registerPreLoadService();
119 LOG.debug("Intialzing auto config bundle.");
122 private void registerPreLoadService() {
124 registerService(PreLoad.class);
130 public void run(final T configuration, final Environment environment) throws Exception {
132 registerConfigurationProvider(configuration, environment);
135 registerEnvironment(environment);
136 registerObjectMapper(environment);
138 environment.getApplicationContext().getServletContext()
139 .setAttribute(ServletProperties.SERVICE_LOCATOR, locator);
141 registerService(PreBaseService.class);
142 registerService(BaseService.class);
143 registerService(PostBaseService.class);
144 this.registerService(PreServiceLoad.class);
149 // registerManaged(environment);
150 registerLifecycle(environment);
151 registerServerLifecycleListeners(environment);
152 registerJettyLifeCycleListener(environment);
153 registerTasks(environment);
154 registerHealthChecks(environment);
155 registerProviders(environment);
156 registerResources(environment);
158 environment.lifecycle().manage(new ServiceLocatorManaged(locator));
164 private void registerProviders(Environment environment) {
165 reflections.getSubTypesOf(Provider.class).stream().filter(services::contains)
166 .forEach(providerKlass -> {
168 environment.jersey().register(locator.getService(providerKlass));
169 } catch (Exception e) {
173 LOG.info("Registering Dropwizard Provider, class name : {}", providerKlass.getName());
179 private void registerTasks(Environment environment) {
180 reflections.getSubTypesOf(Task.class).stream().filter(services::contains).forEach(taskKlass -> {
182 environment.admin().addTask(locator.getService(taskKlass));
183 } catch (Exception e) {
186 LOG.info("Registering Dropwizard Task, class name : {}", taskKlass.getName());
191 private void registerJettyLifeCycleListener(Environment environment) {
192 reflections.getSubTypesOf(LifeCycle.Listener.class).stream().filter(services::contains)
193 .forEach(lifecycleListenerKlass -> {
196 environment.lifecycle()
197 .addLifeCycleListener(locator.getService(lifecycleListenerKlass));
198 } catch (Exception e) {
201 LOG.info("Registering Dropwizard lifecycleListener, class name : {}",
202 lifecycleListenerKlass.getName());
207 private void registerServerLifecycleListeners(Environment environment) {
209 reflections.getSubTypesOf(ServerLifecycleListener.class).stream().filter(services::contains)
210 .forEach(serverLifecycleListenerKlass -> {
212 environment.lifecycle()
213 .addServerLifecycleListener(locator.getService(serverLifecycleListenerKlass));
214 } catch (Exception e) {
217 LOG.info("Registering Dropwizard serverLifecycleListener, class name : {}",
218 serverLifecycleListenerKlass.getName());
223 private void registerLifecycle(Environment environment) {
224 reflections.getSubTypesOf(LifeCycle.class).stream().filter(services::contains)
225 .forEach(lifeCycleKlass -> {
227 environment.lifecycle().manage(locator.getService(lifeCycleKlass));
228 } catch (Exception e) {
231 LOG.info("Registering Dropwizard LifeCycle, class name : {}", lifeCycleKlass.getName());
236 * private void registerManaged(Environment environment) {
238 * reflections.getSubTypesOf(Managed.class).stream().filter(services::contains)
239 * .forEach(managedKlass -> { try {
240 * environment.lifecycle().manage(locator.getService(managedKlass)); } catch (Exception e) {
241 * LOG.warn("", e); } LOG.info("Registering Dropwizard managed, class name : {}",
242 * managedKlass.getName()); });
247 private void registerObjectMapper(Environment environment) {
249 final ObjectMapper objectMapper = environment.getObjectMapper();
251 ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
253 protected void configure() {
254 bind(objectMapper).to(ObjectMapper.class);
256 LOG.info("Registering Dropwizard objectMapper, class name : {}",
257 objectMapper.getClass().getName());
263 private void registerEnvironment(final Environment environment) {
265 ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
267 protected void configure() {
268 bind(environment).to(Environment.class);
270 LOG.info("Registering Dropwizard environment, class name : {}",
271 environment.getClass().getName());
277 private void registerConfigurationProvider(final T configuration, final Environment environment) {
279 ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
281 protected void configure() {
283 LOG.info("Registering Dropwizard Configuration class name:{}",
284 configuration.getClass().getName());
285 if (configuration instanceof Configuration) {
286 bind((Configuration) configuration).to(Configuration.class);
287 LOG.info("Registering Dropwizard Configuration class name:{}",
288 Configuration.class.getName());
294 registerSubConfigure(configuration, environment);
298 private void registerSubConfigure(final T configuration, final Environment environment) {
299 final List<Field> subDeclaredFields =
300 Arrays.asList(configuration.getClass().getDeclaredFields());
301 List<Field> parentDeclaredFields = Arrays.asList(Configuration.class.getDeclaredFields());
303 List<Field> filtersubDeclaredFields = subDeclaredFields.stream()
304 .filter(subDeclaredField -> !subDeclaredField.getType().isPrimitive())
305 .filter(subDeclaredField -> !subDeclaredField.getType().equals(String.class))
306 .filter(subDeclaredField -> !parentDeclaredFields.contains(subDeclaredField))
307 .collect(Collectors.toList());
309 ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
311 protected void configure() {
312 filtersubDeclaredFields.forEach(subField -> {
313 subField.setAccessible(true);
315 Object subConfig = subField.get(configuration);
316 if (subConfig != null) {
318 LOG.info("Registering Dropwizard Sub Configuration class name {}",
319 subConfig.getClass().getName());
322 } catch (Exception e) {
323 LOG.error("bind sub config:{} fail", subField);
331 private void registerServices() {
332 services = this.reflections.getTypesAnnotatedWith(Service.class, true);
333 if (!services.isEmpty()) {
334 ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
336 services.forEach(s -> {
337 LOG.info("Registering Dropwizard service, class name : {}", s.getName());
340 services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
341 .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
342 .forEach(serviceClazz -> {
344 long startTime = System.currentTimeMillis();
345 locator.getService(serviceClazz);
346 LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
347 (System.currentTimeMillis() - startTime));
348 } catch (Exception e) {
355 LOG.warn("Registering Dropwizard service is empty");
361 private void registerResources(final Environment environment) {
362 reflections.getTypesAnnotatedWith(Path.class).stream().forEach(resourceClass -> {
364 LOG.info("begin Registering Dropwizard resource, class name : {}", resourceClass.getName());
366 Object resourceObject = locator.getService(resourceClass);
367 if (resourceObject != null) {
368 environment.jersey().register(resourceObject);
369 LOG.info("Registering Dropwizard resource, class name : {}", resourceClass.getName());
371 LOG.warn(resourceClass.getName() + " not use Service annotation");
373 } catch (Exception e) {
381 private void registerHealthChecks(final Environment env) {
383 reflections.getSubTypesOf(HealthCheck.class).stream().filter(services::contains)
384 .forEach(healthCheckKlass -> {
386 env.healthChecks().register(healthCheckKlass.getName(),
387 locator.getService(healthCheckKlass));
388 } catch (Exception e) {
391 LOG.info("Registering Dropwizard healthCheck, class name : {}",
392 healthCheckKlass.getName());
399 private void registerService(Class<? extends Annotation> annotationClazz) {
401 Set<Class<?>> services = this.reflections.getTypesAnnotatedWith(annotationClazz, true);
402 if (!services.isEmpty()) {
403 ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
405 services.forEach(s -> {
406 LOG.info("{} Registering service, class name : {}", annotationClazz.getName(),
410 services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
411 .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
412 .forEach(serviceClazz -> {
414 long startTime = System.currentTimeMillis();
415 locator.getService(serviceClazz);
416 LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
417 (System.currentTimeMillis() - startTime));
418 } catch (Exception e) {
425 LOG.warn("Registering {} service is empty", annotationClazz.getName());