b8552b2dacfd699b38cc60a80797284110340bcd
[holmes/common.git] / holmes-actions / src / main / java / org / onap / holmes / common / dropwizard / ioc / bundle / AutoConfigBundle.java
1 /**
2  * Copyright 2017 ZTE Corporation.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.onap.holmes.common.dropwizard.ioc.bundle;
17
18 import com.codahale.metrics.health.HealthCheck;
19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.google.common.collect.Lists;
21 import io.dropwizard.Configuration;
22 import io.dropwizard.ConfiguredBundle;
23 import io.dropwizard.lifecycle.ServerLifecycleListener;
24 import io.dropwizard.servlets.tasks.Task;
25 import io.dropwizard.setup.Bootstrap;
26 import io.dropwizard.setup.Environment;
27 import java.lang.annotation.Annotation;
28 import java.lang.reflect.Field;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.Set;
32 import java.util.stream.Collectors;
33 import javax.ws.rs.Path;
34 import javax.ws.rs.ext.Provider;
35 import org.eclipse.jetty.util.component.LifeCycle;
36 import org.glassfish.hk2.api.ServiceLocator;
37 import org.glassfish.hk2.api.ServiceLocatorFactory;
38 import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
39 import org.glassfish.hk2.utilities.binding.AbstractBinder;
40 import org.glassfish.jersey.servlet.ServletProperties;
41 import org.jvnet.hk2.annotations.Service;
42 import org.onap.holmes.common.dropwizard.ioc.annotation.BaseService;
43 import org.onap.holmes.common.dropwizard.ioc.annotation.Lazy;
44 import org.onap.holmes.common.dropwizard.ioc.annotation.PostBaseService;
45 import org.onap.holmes.common.dropwizard.ioc.annotation.PreBaseService;
46 import org.onap.holmes.common.dropwizard.ioc.annotation.PreLoad;
47 import org.onap.holmes.common.dropwizard.ioc.annotation.PreServiceLoad;
48 import org.onap.holmes.common.dropwizard.ioc.utils.ServiceBinder;
49 import org.onap.holmes.common.dropwizard.ioc.utils.ServiceLocatorHolder;
50 import org.reflections.Reflections;
51 import org.reflections.scanners.SubTypesScanner;
52 import org.reflections.scanners.TypeAnnotationsScanner;
53 import org.reflections.util.ClasspathHelper;
54 import org.reflections.util.ConfigurationBuilder;
55 import org.reflections.util.FilterBuilder;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 /**
60  * complete the integration of hK2 container and dropwizard
61  * 
62  * @author hu.rui
63  *
64  */
65
66 public class AutoConfigBundle<T extends Configuration> implements ConfiguredBundle<T> {
67
68   private static final Logger LOG = LoggerFactory.getLogger(AutoConfigBundle.class);
69
70   private ServiceLocator locator;
71   private Reflections reflections;
72   private Set<Class<?>> services;
73
74   private Bootstrap<?> bootstrap;
75
76
77   AutoConfigBundle(final String packageName) {
78     this(Lists.newArrayList(packageName));
79   }
80
81   AutoConfigBundle(List<String> packageNames) {
82     FilterBuilder filterBuilder = new FilterBuilder();
83
84     packageNames.stream().forEach(packageName -> {
85       filterBuilder.include(FilterBuilder.prefix(packageName));
86     });
87     ConfigurationBuilder reflectionCfg = new ConfigurationBuilder();
88
89     packageNames.stream().forEach(packageName -> {
90       reflectionCfg.addUrls(ClasspathHelper.forPackage(packageName));
91     });
92
93     reflectionCfg.filterInputsBy(filterBuilder).setScanners(new SubTypesScanner(),
94         new TypeAnnotationsScanner());
95     reflections = new Reflections(reflectionCfg);
96
97     locator = ServiceLocatorFactory.getInstance().create("dw-hk2");
98
99     ServiceLocatorHolder.setLocator(locator);
100
101   }
102
103   public static <T extends Configuration> AutoConfigBundleBuider<T> newBuilder() {
104     return new AutoConfigBundleBuider<T>();
105   }
106
107   @Override
108   public void initialize(final Bootstrap<?> bootstrap) {
109
110     this.bootstrap = bootstrap;
111     registerPreLoadService();
112
113     LOG.debug("Intialzing auto config bundle.");
114   }
115
116   private void registerPreLoadService() {
117
118     registerService(PreLoad.class);
119
120   }
121
122
123   @Override
124   public void run(final T configuration, final Environment environment) throws Exception {
125
126     registerConfigurationProvider(configuration, environment);
127
128
129     registerEnvironment(environment);
130     registerObjectMapper(environment);
131
132     environment.getApplicationContext().getServletContext()
133         .setAttribute(ServletProperties.SERVICE_LOCATOR, locator);
134
135     registerService(PreBaseService.class);
136     registerService(BaseService.class);
137     registerService(PostBaseService.class);
138     this.registerService(PreServiceLoad.class);
139
140
141     registerServices();
142
143     // registerManaged(environment);
144     registerLifecycle(environment);
145     registerServerLifecycleListeners(environment);
146     registerJettyLifeCycleListener(environment);
147     registerTasks(environment);
148     registerHealthChecks(environment);
149     registerProviders(environment);
150     registerResources(environment);
151
152     environment.lifecycle().manage(new ServiceLocatorManaged(locator));
153
154   }
155
156
157
158   private void registerProviders(Environment environment) {
159     reflections.getSubTypesOf(Provider.class).stream().filter(services::contains)
160         .forEach(providerKlass -> {
161           try {
162             environment.jersey().register(locator.getService(providerKlass));
163           } catch (Exception e) {
164             LOG.warn("", e);
165           }
166
167           LOG.info("Registering Dropwizard Provider, class name : {}", providerKlass.getName());
168
169         });
170
171   }
172
173   private void registerTasks(Environment environment) {
174     reflections.getSubTypesOf(Task.class).stream().filter(services::contains).forEach(taskKlass -> {
175       try {
176         environment.admin().addTask(locator.getService(taskKlass));
177       } catch (Exception e) {
178         LOG.warn("", e);
179       }
180       LOG.info("Registering Dropwizard Task, class name : {}", taskKlass.getName());
181     });
182
183   }
184
185   private void registerJettyLifeCycleListener(Environment environment) {
186     reflections.getSubTypesOf(LifeCycle.Listener.class).stream().filter(services::contains)
187         .forEach(lifecycleListenerKlass -> {
188
189           try {
190             environment.lifecycle()
191                 .addLifeCycleListener(locator.getService(lifecycleListenerKlass));
192           } catch (Exception e) {
193             LOG.warn("", e);
194           }
195           LOG.info("Registering Dropwizard lifecycleListener, class name : {}",
196               lifecycleListenerKlass.getName());
197         });
198
199   }
200
201   private void registerServerLifecycleListeners(Environment environment) {
202
203     reflections.getSubTypesOf(ServerLifecycleListener.class).stream().filter(services::contains)
204         .forEach(serverLifecycleListenerKlass -> {
205           try {
206             environment.lifecycle()
207                 .addServerLifecycleListener(locator.getService(serverLifecycleListenerKlass));
208           } catch (Exception e) {
209             LOG.warn("", e);
210           }
211           LOG.info("Registering Dropwizard serverLifecycleListener, class name : {}",
212               serverLifecycleListenerKlass.getName());
213         });
214
215   }
216
217   private void registerLifecycle(Environment environment) {
218     reflections.getSubTypesOf(LifeCycle.class).stream().filter(services::contains)
219         .forEach(lifeCycleKlass -> {
220           try {
221             environment.lifecycle().manage(locator.getService(lifeCycleKlass));
222           } catch (Exception e) {
223             LOG.warn("", e);
224           }
225           LOG.info("Registering Dropwizard LifeCycle, class name : {}", lifeCycleKlass.getName());
226         });
227   }
228
229   /*
230    * private void registerManaged(Environment environment) {
231    * 
232    * reflections.getSubTypesOf(Managed.class).stream().filter(services::contains)
233    * .forEach(managedKlass -> { try {
234    * environment.lifecycle().manage(locator.getService(managedKlass)); } catch (Exception e) {
235    * LOG.warn("", e); } LOG.info("Registering Dropwizard managed, class name : {}",
236    * managedKlass.getName()); });
237    * 
238    * }
239    */
240
241   private void registerObjectMapper(Environment environment) {
242
243     final ObjectMapper objectMapper = environment.getObjectMapper();
244
245     ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
246       @Override
247       protected void configure() {
248         bind(objectMapper).to(ObjectMapper.class);
249
250         LOG.info("Registering Dropwizard objectMapper, class name : {}",
251             objectMapper.getClass().getName());
252       }
253     });
254
255   }
256
257   private void registerEnvironment(final Environment environment) {
258
259     ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
260       @Override
261       protected void configure() {
262         bind(environment).to(Environment.class);
263
264         LOG.info("Registering Dropwizard environment, class name : {}",
265             environment.getClass().getName());
266       }
267     });
268
269   }
270
271   private void registerConfigurationProvider(final T configuration, final Environment environment) {
272
273     ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
274       @Override
275       protected void configure() {
276         bind(configuration);
277         LOG.info("Registering Dropwizard Configuration class name:{}",
278             configuration.getClass().getName());
279         if (configuration instanceof Configuration) {
280           bind((Configuration) configuration).to(Configuration.class);
281           LOG.info("Registering Dropwizard Configuration class name:{}",
282               Configuration.class.getName());
283         }
284
285       }
286     });
287
288     registerSubConfigure(configuration, environment);
289
290   }
291
292   private void registerSubConfigure(final T configuration, final Environment environment) {
293     final List<Field> subDeclaredFields =
294         Arrays.asList(configuration.getClass().getDeclaredFields());
295     List<Field> parentDeclaredFields = Arrays.asList(Configuration.class.getDeclaredFields());
296
297     List<Field> filtersubDeclaredFields = subDeclaredFields.stream()
298         .filter(subDeclaredField -> !subDeclaredField.getType().isPrimitive())
299         .filter(subDeclaredField -> !subDeclaredField.getType().equals(String.class))
300         .filter(subDeclaredField -> !parentDeclaredFields.contains(subDeclaredField))
301         .collect(Collectors.toList());
302
303     ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
304       @Override
305       protected void configure() {
306         filtersubDeclaredFields.forEach(subField -> {
307           subField.setAccessible(true);
308           try {
309             Object subConfig = subField.get(configuration);
310             if (subConfig != null) {
311               bind(subConfig);
312               LOG.info("Registering Dropwizard Sub Configuration class name {}",
313                   subConfig.getClass().getName());
314             }
315
316           } catch (Exception e) {
317             LOG.error("bind sub config:{} fail", subField);
318           }
319         });
320       }
321     });
322
323   }
324
325   private void registerServices() {
326     services = this.reflections.getTypesAnnotatedWith(Service.class, true);
327     if (!services.isEmpty()) {
328       ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
329
330       services.forEach(s -> {
331         LOG.info("Registering Dropwizard service, class name : {}", s.getName());
332       });
333
334       services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
335           .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
336           .forEach(serviceClazz -> {
337             try {
338               long startTime = System.currentTimeMillis();
339               locator.getService(serviceClazz);
340               LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
341                   (System.currentTimeMillis() - startTime));
342             } catch (Exception e) {
343               LOG.warn("", e);
344             }
345
346           });
347
348     } else {
349       LOG.warn("Registering Dropwizard service is empty");
350
351     }
352
353   }
354
355   private void registerResources(final Environment environment) {
356     reflections.getTypesAnnotatedWith(Path.class).stream().forEach(resourceClass -> {
357
358       LOG.info("begin Registering Dropwizard resource, class name : {}", resourceClass.getName());
359       try {
360         Object resourceObject = locator.getService(resourceClass);
361         if (resourceObject != null) {
362           environment.jersey().register(resourceObject);
363           LOG.info("Registering Dropwizard resource, class name : {}", resourceClass.getName());
364         } else {
365           LOG.warn(resourceClass.getName() + " not use Service annotation");
366         }
367       } catch (Exception e) {
368         LOG.error("", e);
369       }
370
371
372     });
373   }
374
375   private void registerHealthChecks(final Environment env) {
376
377     reflections.getSubTypesOf(HealthCheck.class).stream().filter(services::contains)
378         .forEach(healthCheckKlass -> {
379           try {
380             env.healthChecks().register(healthCheckKlass.getName(),
381                 locator.getService(healthCheckKlass));
382           } catch (Exception e) {
383             LOG.warn("", e);
384           }
385           LOG.info("Registering Dropwizard healthCheck, class name : {}",
386               healthCheckKlass.getName());
387         });
388
389   }
390
391
392
393   private void registerService(Class<? extends Annotation> annotationClazz) {
394
395     Set<Class<?>> services = this.reflections.getTypesAnnotatedWith(annotationClazz, true);
396     if (!services.isEmpty()) {
397       ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
398
399       services.forEach(s -> {
400         LOG.info("{} Registering  service, class name : {}", annotationClazz.getName(),
401             s.getName());
402       });
403
404       services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
405           .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
406           .forEach(serviceClazz -> {
407             try {
408               long startTime = System.currentTimeMillis();
409               locator.getService(serviceClazz);
410               LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
411                   (System.currentTimeMillis() - startTime));
412             } catch (Exception e) {
413               LOG.warn("", e);
414             }
415
416           });
417
418     } else {
419       LOG.warn("Registering {} service is empty", annotationClazz.getName());
420
421     }
422
423   }
424 }