Fix Bugs Identified by Sonar
[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           bind((Configuration) configuration).to(Configuration.class);
280           LOG.info("Registering Dropwizard Configuration class name:{}",
281               Configuration.class.getName());
282       }
283     });
284
285     registerSubConfigure(configuration, environment);
286
287   }
288
289   private void registerSubConfigure(final T configuration, final Environment environment) {
290     final List<Field> subDeclaredFields =
291         Arrays.asList(configuration.getClass().getDeclaredFields());
292     List<Field> parentDeclaredFields = Arrays.asList(Configuration.class.getDeclaredFields());
293
294     List<Field> filtersubDeclaredFields = subDeclaredFields.stream()
295         .filter(subDeclaredField -> !subDeclaredField.getType().isPrimitive())
296         .filter(subDeclaredField -> !subDeclaredField.getType().equals(String.class))
297         .filter(subDeclaredField -> !parentDeclaredFields.contains(subDeclaredField))
298         .collect(Collectors.toList());
299
300     ServiceLocatorUtilities.bind(locator, new AbstractBinder() {
301       @Override
302       protected void configure() {
303         filtersubDeclaredFields.forEach(subField -> {
304           subField.setAccessible(true);
305           try {
306             Object subConfig = subField.get(configuration);
307             if (subConfig != null) {
308               bind(subConfig);
309               LOG.info("Registering Dropwizard Sub Configuration class name {}",
310                   subConfig.getClass().getName());
311             }
312
313           } catch (Exception e) {
314             LOG.error("bind sub config:{} fail", subField);
315           }
316         });
317       }
318     });
319
320   }
321
322   private void registerServices() {
323     services = this.reflections.getTypesAnnotatedWith(Service.class, true);
324     if (!services.isEmpty()) {
325       ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
326
327       services.forEach(s -> {
328         LOG.info("Registering Dropwizard service, class name : {}", s.getName());
329       });
330
331       services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
332           .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
333           .forEach(serviceClazz -> {
334             try {
335               long startTime = System.currentTimeMillis();
336               locator.getService(serviceClazz);
337               LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
338                   (System.currentTimeMillis() - startTime));
339             } catch (Exception e) {
340               LOG.warn("", e);
341             }
342
343           });
344
345     } else {
346       LOG.warn("Registering Dropwizard service is empty");
347
348     }
349
350   }
351
352   private void registerResources(final Environment environment) {
353     reflections.getTypesAnnotatedWith(Path.class).stream().forEach(resourceClass -> {
354
355       LOG.info("begin Registering Dropwizard resource, class name : {}", resourceClass.getName());
356       try {
357         Object resourceObject = locator.getService(resourceClass);
358         if (resourceObject != null) {
359           environment.jersey().register(resourceObject);
360           LOG.info("Registering Dropwizard resource, class name : {}", resourceClass.getName());
361         } else {
362           LOG.warn(resourceClass.getName() + " not use Service annotation");
363         }
364       } catch (Exception e) {
365         LOG.error("", e);
366       }
367
368
369     });
370   }
371
372   private void registerHealthChecks(final Environment env) {
373
374     reflections.getSubTypesOf(HealthCheck.class).stream().filter(services::contains)
375         .forEach(healthCheckKlass -> {
376           try {
377             env.healthChecks().register(healthCheckKlass.getName(),
378                 locator.getService(healthCheckKlass));
379           } catch (Exception e) {
380             LOG.warn("", e);
381           }
382           LOG.info("Registering Dropwizard healthCheck, class name : {}",
383               healthCheckKlass.getName());
384         });
385
386   }
387
388
389
390   private void registerService(Class<? extends Annotation> annotationClazz) {
391
392     Set<Class<?>> services = this.reflections.getTypesAnnotatedWith(annotationClazz, true);
393     if (!services.isEmpty()) {
394       ServiceLocatorUtilities.bind(locator, new ServiceBinder(services));
395
396       services.forEach(s -> {
397         LOG.info("{} Registering  service, class name : {}", annotationClazz.getName(),
398             s.getName());
399       });
400
401       services.stream().filter(serviceClazz -> (serviceClazz.getAnnotation(Lazy.class) == null))
402           .peek(serviceClazz -> LOG.info("active service, class name : {}", serviceClazz.getName()))
403           .forEach(serviceClazz -> {
404             try {
405               long startTime = System.currentTimeMillis();
406               locator.getService(serviceClazz);
407               LOG.info("active service, class name : {},cost time:{}", serviceClazz.getName(),
408                   (System.currentTimeMillis() - startTime));
409             } catch (Exception e) {
410               LOG.warn("", e);
411             }
412
413           });
414
415     } else {
416       LOG.warn("Registering {} service is empty", annotationClazz.getName());
417
418     }
419
420   }
421 }