1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package tools.gsf.config;
17
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import javax.servlet.ServletContext;
22 import javax.servlet.ServletContextEvent;
23 import javax.servlet.ServletContextListener;
24 import javax.servlet.annotation.WebListener;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.Set;
28
29 import static tools.gsf.config.ReflectionUtils.readConfigurationResource;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 @WebListener
60 public class ServletContextLoader implements ServletContextListener {
61
62 private static final Logger LOG = LoggerFactory.getLogger(ServletContextLoader.class);
63
64
65
66
67 public static final String GSF_FACTORY_PRODUCER = "gsf-factory-producer";
68
69
70
71
72 public static final String CONFIG_FILE = "META-INF/gsf-factory-producer";
73
74 @Override
75 public void contextInitialized(ServletContextEvent servletContextEvent) {
76 final ServletContext context = servletContextEvent.getServletContext();
77 if (context.getMajorVersion() == 3 && context.getMinorVersion() < 0) {
78 throw new IllegalStateException("Servlet Container is configured for version less than 3.0. " +
79 "This ServletContextListener does not support 2.x and earlier as the load order of " +
80 "Listeners is not guaranteed.");
81 }
82
83 FactoryProducer factoryProducer = null;
84
85 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
86
87 if (factoryProducer == null) {
88 factoryProducer = configureFromInitParam(context, classLoader);
89 if (factoryProducer != null) {
90 LOG.info("FactoryProducer configured from init param: " + factoryProducer.getClass().getName());
91 }
92 }
93
94 if (factoryProducer == null) {
95 factoryProducer = configureFromServiceLocator(classLoader);
96 if (factoryProducer != null) {
97 LOG.info("FactoryProducer configured from service locator: " + factoryProducer.getClass().getName());
98 }
99 }
100
101 if (factoryProducer == null) {
102 factoryProducer = new DefaultFactoryProducer();
103 LOG.info("FactoryProducer defaulting to: " + factoryProducer.getClass().getName());
104 }
105
106 context.setAttribute(GSF_FACTORY_PRODUCER, factoryProducer);
107
108 }
109
110 @Override
111 public void contextDestroyed(ServletContextEvent servletContextEvent) {
112 servletContextEvent.getServletContext().removeAttribute(GSF_FACTORY_PRODUCER);
113 LOG.info("FactoryProducer un-registered from servlet context.");
114 }
115
116 private FactoryProducer configureFromInitParam(ServletContext servletContext, ClassLoader classLoader) {
117 String factoryProducerClassName = servletContext.getInitParameter(GSF_FACTORY_PRODUCER);
118 return instantiateFactoryProducer(factoryProducerClassName, classLoader);
119 }
120
121 private FactoryProducer configureFromServiceLocator(ClassLoader classLoader) {
122 Set<String> classes = readConfigurationResource(classLoader, CONFIG_FILE);
123 switch (classes.size()) {
124 case 0: {
125
126 return null;
127 }
128 case 1: {
129
130 String fpClass = classes.iterator().next();
131 return instantiateFactoryProducer(fpClass, classLoader);
132 }
133 default: {
134
135 throw new IllegalStateException("Too many lines in the " + CONFIG_FILE +
136 " configuration file. Only one FactoryProducer class name is allowed.");
137 }
138 }
139 }
140
141 private static FactoryProducer instantiateFactoryProducer(String className, ClassLoader classLoader) {
142 if (className == null) {
143 return null;
144 }
145 try {
146 @SuppressWarnings("unchecked")
147 Class<FactoryProducer> cls = (Class<FactoryProducer>) classLoader.loadClass(className);
148 Constructor<FactoryProducer> constructor = cls.getConstructor();
149 return constructor.newInstance();
150 } catch (ClassNotFoundException e) {
151 throw new IllegalArgumentException("Could not find FactoryProducer class: " + className, e);
152 } catch (NoSuchMethodException e) {
153 throw new IllegalStateException("Could not locate zero-arg constructor for FactoryProducer in class: " + className, e);
154 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
155 throw new IllegalStateException("Could not invoke constructor for FactoryProducer class: " + className, e);
156 }
157 }
158 }