1 package org.apache.turbine.services.assemblerbroker.util.java;
2
3
4 import java.lang.reflect.InvocationTargetException;
5
6 /*
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements. See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership. The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License. You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied. See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 */
24
25 import java.util.List;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.apache.turbine.modules.Assembler;
32 import org.apache.turbine.modules.GenericLoader;
33 import org.apache.turbine.modules.Loader;
34 import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
35
36 /**
37 * A screen factory that attempts to load a java class from
38 * the module packages defined in the TurbineResource.properties.
39 *
40 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
41 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
42 * @param <T> the specialized assembler type
43 */
44 public abstract class JavaBaseFactory<T extends Assembler>
45 implements AssemblerFactory<T>
46 {
47 /** A vector of packages. */
48 private static List<String> packages = GenericLoader.getPackages();
49
50 /** Logging */
51 protected Logger log = LogManager.getLogger(this.getClass());
52
53 /**
54 * A cache for previously obtained Class instances, which we keep in order
55 * to reduce the Class.forName() overhead (which can be sizable).
56 */
57 private final ConcurrentHashMap<String, Class<T>> classCache = new ConcurrentHashMap<>();
58
59 /**
60 * Get an Assembler.
61 *
62 * @param packageName java package name
63 * @param name name of the requested Assembler
64 * @return an Assembler
65 */
66 @SuppressWarnings("unchecked")
67 public T getAssembler(String packageName, String name)
68 {
69 T assembler = null;
70
71 log.debug("Class Fragment is {}", name);
72
73 if (StringUtils.isNotEmpty(name))
74 {
75 for (String p : packages)
76 {
77 StringBuilder sb = new StringBuilder();
78
79 sb.append(p).append('.').append(packageName).append('.').append(name);
80 String className = sb.toString();
81
82 log.debug("Trying {}", className);
83
84 try
85 {
86 Class<T> servClass = classCache.get(className);
87 if (servClass == null)
88 {
89 servClass = (Class<T>) Class.forName(className);
90 Class<T> _servClass = classCache.putIfAbsent(className, servClass);
91 if (_servClass != null)
92 {
93 servClass = _servClass;
94 }
95 }
96 assembler = servClass.getDeclaredConstructor().newInstance();
97 break; // for()
98 }
99 catch (ClassNotFoundException cnfe)
100 {
101 // Do this so we loop through all the packages.
102 log.debug("{}: Not found", className);
103 }
104 catch (NoClassDefFoundError ncdfe)
105 {
106 // Do this so we loop through all the packages.
107 log.debug("{}: No Class Definition found", className);
108 }
109 // With ClassCastException, InstantiationException we hit big problems
110 catch (ClassCastException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e)
111 {
112 // This means trouble!
113 // Alternatively we can throw this exception so
114 // that it will appear on the client browser
115 log.error("Could not load {}", className, e);
116 break; // for()
117 }
118 }
119 }
120
121 log.debug("Returning: {}", assembler);
122
123 return assembler;
124 }
125
126 /**
127 * Get the loader for this type of assembler
128 *
129 * @return a Loader
130 */
131 @Override
132 public abstract Loader<T> getLoader();
133
134 /**
135 * Get the size of a possibly configured cache
136 *
137 * @return the size of the cache in bytes
138 */
139 @Override
140 public int getCacheSize()
141 {
142 return getLoader().getCacheSize();
143 }
144 }