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