1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.fatwire.gst.foundation.controller.support;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.net.URL;
26 import java.util.Enumeration;
27 import java.util.LinkedList;
28 import java.util.List;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletContextEvent;
32 import javax.servlet.ServletContextListener;
33
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.commons.logging.Log;
36
37 import com.fatwire.gst.foundation.controller.AppContext;
38 import com.fatwire.gst.foundation.controller.action.support.DefaultWebAppContext;
39 import com.fatwire.gst.foundation.facade.logging.LogUtil;
40
41
42
43
44
45
46
47
48 public class WebAppContextLoader implements ServletContextListener {
49 private static final String GROOVY_WEB_CONTEXT = "com.fatwire.gst.foundation.groovy.context.GroovyWebContext";
50 private static final String GROOVY_CLASSNAME = "groovy.util.GroovyScriptEngine";
51 public static final String CONTEXTS = "gsf-contexts";
52
53 protected static final Log LOG = LogUtil.getLog(WebAppContextLoader.class);
54 boolean booted = false;
55 private static final Class<?>[] ARGS = new Class[] { ServletContext.class, AppContext.class };
56
57 @Override
58 public void contextInitialized(final ServletContextEvent sce) {
59 final ServletContext context = sce.getServletContext();
60 if (context.getMajorVersion() == 2 && context.getMinorVersion() < 4) {
61 throw new IllegalStateException(
62 "Servlet Container is configured for version 2.3 or less. This ServletContextListener does not support 2.3 and earlier as the load order of Listeners is not guaranteed.");
63 }
64
65 configureWebAppContext(context);
66
67 }
68
69 public AppContext configureWebAppContext(final ServletContext context) {
70 AppContext parent = null;
71
72 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
73
74 parent = configureFromInitParam(context, cl);
75 if (parent == null) {
76 try {
77 parent = configureFromServiceLocator(context, cl);
78 } catch (IOException e) {
79 LOG.debug("Exception when loadding the service descriptor for the AppContext from the classpath.", e);
80 }
81 }
82 if (parent == null) {
83
84
85 final String groovyPath = context.getRealPath("/WEB-INF/gsf-groovy");
86
87 if (new File(groovyPath).isDirectory() && isGroovyOnClassPath(cl)) {
88 try {
89 parent = createAppContext(cl, GROOVY_WEB_CONTEXT, context, null);
90 } catch (final Exception e) {
91 LOG.warn("Exception when creating the GroovyWebContext as a default option", e);
92 }
93 }
94 }
95 if (parent == null) {
96 parent = new DefaultWebAppContext(context);
97 parent.init();
98 }
99
100 if (parent != null) {
101 context.setAttribute(WebAppContext.WEB_CONTEXT_NAME, parent);
102 }
103 booted = true;
104 return parent;
105
106 }
107
108 private static final String PREFIX = "META-INF/";
109
110 private AppContext configureFromServiceLocator(ServletContext context, ClassLoader cl) throws IOException {
111 String fullName = PREFIX + CONTEXTS;
112
113 int c = 0;
114 List<String> init = new LinkedList<String>();
115 Enumeration<URL> configs = cl.getResources(fullName);
116 while (configs.hasMoreElements()) {
117
118 URL u = configs.nextElement();
119 if (c++ > 0)
120 throw new IllegalStateException("Found second service locator in classpath at " + u
121 + ". Please make sure that only one " + fullName
122 + " file is found on the classpath or configure the AppContext through web.xml");
123 InputStream in = null;
124 BufferedReader r = null;
125
126 try {
127 in = u.openStream();
128 r = new BufferedReader(new InputStreamReader(in, "utf-8"));
129 String s = null;
130 while ((s = r.readLine()) != null) {
131 if (StringUtils.isNotBlank(s) && !StringUtils.startsWith(s, "#")) {
132 init.add(s);
133 }
134 }
135 } catch (IOException e) {
136 throw new RuntimeException("Error reading configuration file", e);
137 } finally {
138 try {
139 if (r != null)
140 r.close();
141 if (in != null)
142 in.close();
143 } catch (IOException e) {
144 throw new RuntimeException("Error closing configuration file", e);
145 }
146 }
147 return this.createFromString(context, cl, init.toArray(new String[init.size()]));
148 }
149
150 return null;
151 }
152
153
154
155
156
157
158
159
160 protected AppContext configureFromInitParam(final ServletContext context, final ClassLoader cl) {
161 final String init = context.getInitParameter(CONTEXTS);
162 AppContext parent = null;
163
164 if (init != null) {
165 parent = createFromString(context, cl, init.split(","));
166 }
167 return parent;
168 }
169
170 private AppContext createFromString(final ServletContext context, final ClassLoader cl, final String[] c) {
171 AppContext parent = null;
172
173 if (c != null) {
174
175 for (int i = c.length - 1; i >= 0; i--) {
176
177 try {
178 final AppContext n = createAppContext(cl, c[i], context, parent);
179 if (n != null) {
180 parent = n;
181 }
182 } catch (final IllegalArgumentException e) {
183 LOG.warn(e);
184 } catch (final InstantiationException e) {
185 LOG.warn(e);
186 } catch (final IllegalAccessException e) {
187 LOG.warn(e);
188 } catch (final InvocationTargetException e) {
189 LOG.warn(e);
190 } catch (final SecurityException e) {
191 LOG.warn(e);
192 } catch (final NoSuchMethodException e) {
193 LOG.warn(e);
194 } catch (final ClassNotFoundException e) {
195 LOG.warn(e);
196 }
197
198 }
199
200 }
201 return parent;
202 }
203
204 private boolean isGroovyOnClassPath(final ClassLoader cl) {
205 try {
206 cl.loadClass(GROOVY_CLASSNAME);
207 } catch (final ClassNotFoundException e) {
208 return false;
209 }
210 return true;
211 }
212
213 @Override
214 public void contextDestroyed(final ServletContextEvent sce) {
215 sce.getServletContext().removeAttribute(WebAppContext.WEB_CONTEXT_NAME);
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 AppContext createAppContext(final ClassLoader cl, final String c, final ServletContext context,
233 final AppContext parent) throws ClassNotFoundException, SecurityException, NoSuchMethodException,
234 InstantiationException, IllegalAccessException, InvocationTargetException {
235 @SuppressWarnings("unchecked")
236 final Class<AppContext> cls = (Class<AppContext>) cl.loadClass(c);
237 final Constructor<AppContext> ctr = cls.getConstructor(ARGS);
238 AppContext n;
239 n = ctr.newInstance(context, parent);
240 if (n != null) {
241 LOG.info("Creating AppContext from class " + c);
242 n.init();
243 }
244 return n;
245
246 }
247
248 }