cff9da0d5c6b8468380edddda500f7612c12c560
[sdc.git] /
1 /*
2  * Copyright © 2016-2017 European Support Limited
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
17 package org.openecomp.core.factory.impl;
18
19
20 import org.apache.commons.lang3.StringUtils;
21 import org.openecomp.sdc.common.errors.CoreException;
22 import org.openecomp.sdc.common.errors.ErrorCategory;
23 import org.openecomp.sdc.common.errors.ErrorCode;
24
25 import java.util.Collection;
26 import java.util.Map;
27 import java.util.concurrent.ConcurrentHashMap;
28
29 import static org.openecomp.core.utilities.CommonMethods.newInstance;
30
31 public abstract class AbstractFactoryBase {
32
33   /**
34    * Temporary registry of default implementations. The map keeps class names rather then class
35    * types to allow unloading of those classes from memory by garbage collector if factory is not
36    * actually used.
37    */
38   private static final Map<String, String> REGISTRY = new ConcurrentHashMap<>();
39
40   /**
41    * Cached factory instances.
42    */
43   private static final Map<String, AbstractFactoryBase> FACTORY_MAP = new ConcurrentHashMap<>();
44
45   /**
46    * Registers implementor for an abstract factory. The method accepts Java classes rather then
47    * class names to ensure type safety at compilation time.
48    *
49    * @param <I>     Java interface type instantiated by abstract factory
50    * @param <F>     Type specific abstract factory for concrete Java interface
51    * @param factory Java class of a type specific abstract factory
52    * @param impl    Java class of type specific factory implementor
53    */
54   public static <I, F extends AbstractFactoryBase> void registerFactory(Class<F> factory,
55                                                                         Class<? extends F> impl) {
56     if (factory == null) {
57       throw new CoreException(
58           new ErrorCode.ErrorCodeBuilder().withId("E0001").withMessage("Mandatory input factory.")
59               .withCategory(ErrorCategory.SYSTEM).build());
60     }
61
62     if (impl == null) {
63       throw new CoreException(
64           new ErrorCode.ErrorCodeBuilder().withId("E0001").withMessage("Mandatory input impl.")
65               .withCategory(ErrorCategory.SYSTEM).build());
66     }
67     if (FACTORY_MAP.containsKey(factory.getName())) {
68       FACTORY_MAP.remove(factory.getName());
69     }
70     REGISTRY.put(factory.getName(), impl.getName());
71   } // registerFactory
72
73   // TODO: Remove
74   protected static void registerFactory(String factoryName, String implName) {
75     REGISTRY.put(factoryName, implName);
76   } // registerFactory
77
78   /**
79    * Unregister factory.
80    *
81    * @param <F>     the type parameter
82    * @param factory the factory
83    */
84   public static <F extends AbstractFactoryBase> void unregisterFactory(Class<F> factory) {
85     if (factory == null) {
86       throw new CoreException(
87           new ErrorCode.ErrorCodeBuilder().withId("E0001").withMessage("Mandatory input factory.")
88               .withCategory(ErrorCategory.SYSTEM).build());
89     }
90
91     FACTORY_MAP.remove(factory.getName());
92   }
93
94   /**
95    * Instantiates the configured implementation of an abstract factory.
96    *
97    * @param <I>         Java interface type instantiated by abstract factory
98    * @param <F>         Type specific abstract factory for concrete Java interface
99    * @param factoryType Java class of type specific abstract factory
100    * @return Instance of implementation class
101    */
102   @SuppressWarnings("unchecked")
103   public static <I, F extends AbstractFactoryBase> F getInstance(Class<F> factoryType) {
104     if (factoryType == null) {
105       throw new CoreException(
106           new ErrorCode.ErrorCodeBuilder().withId("E0001")
107               .withMessage("Mandatory input factory type.").withCategory(ErrorCategory.SYSTEM)
108               .build());
109
110     }
111     // Pick up factory instance from cache
112     F factory = (F) FACTORY_MAP.get(factoryType.getName());
113     // Check for the first time access
114     if (factory == null) {
115       // Synchronize factory instantiation
116       synchronized (factoryType) {
117         // Re-check the factory instance
118         factory = (F) FACTORY_MAP.get(factoryType.getName());
119         if (factory == null) {
120           // Get the implementation class name
121           String implName = REGISTRY.get(factoryType.getName());
122
123           if (StringUtils.isEmpty(implName)) {
124             throw new CoreException(
125                 new ErrorCode.ErrorCodeBuilder().withId("E0001")
126                     .withMessage("Mandatory input factory implementation.")
127                     .withCategory(ErrorCategory.SYSTEM).build());
128           }
129
130           factory = newInstance(implName, factoryType);
131
132           factory.init();
133
134           // Cache the instantiated singleton
135           FACTORY_MAP.put(factoryType.getName(), factory);
136         }
137       }
138     }
139
140     return factory;
141
142   } // getInstance
143
144
145   /**
146    * Is factory registered boolean.
147    *
148    * @param <F>         the type parameter
149    * @param factoryType the factory type
150    * @return the boolean
151    */
152   public static <F extends AbstractFactoryBase> boolean isFactoryRegistered(Class<F> factoryType) {
153     boolean isFactoryRegistered = false;
154     if (factoryType == null) {
155       throw new CoreException(
156           new ErrorCode.ErrorCodeBuilder().withId("E0001")
157               .withMessage("Mandatory input factory type.").withCategory(ErrorCategory.SYSTEM)
158               .build());
159     }
160     // Pick up factory instance from cache
161     F factory = (F) FACTORY_MAP.get(factoryType.getName());
162     // Check for the first time access
163     if (factory != null) {
164       isFactoryRegistered = true;
165     } else {
166       // Get the implementation class name
167       String implName = REGISTRY.get(factoryType.getName());
168       if (StringUtils.isNotEmpty(implName)) {
169         isFactoryRegistered = true;
170       }
171     }
172     return isFactoryRegistered;
173   }
174
175   /**
176    * Stop all.
177    */
178   public static void stopAll() {
179     Collection<AbstractFactoryBase> factorylist = FACTORY_MAP.values();
180     for (AbstractFactoryBase factory : factorylist) {
181       factory.stop();
182     }
183   }
184
185   protected void init() {
186     // allows custom initialization
187     // noop by default
188   }
189
190   protected void stop() {
191     // allows custom shutdown
192     // noop by default
193   }
194
195 }