1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.struts.flow;
17
18 import java.util.*;
19 import java.io.*;
20
21 import javax.servlet.ServletContext;
22 import javax.servlet.ServletException;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.struts.action.ActionServlet;
27 import org.apache.struts.action.PlugIn;
28 import org.apache.struts.config.ModuleConfig;
29 import org.apache.struts.flow.core.Factory;
30 import org.apache.struts.flow.core.CompilingInterpreter;
31 import org.apache.struts.flow.core.javascript.fom.FOM_JavaScriptInterpreter;
32 import org.apache.struts.flow.core.DefaultFlowVariableFactory;
33 import org.apache.struts.flow.sugar.SugarWrapFactory;
34 import org.apache.struts.flow.ibatis.SqlMap;
35 import org.apache.struts.flow.core.source.impl.ChainSourceResolver;
36
37 import org.apache.commons.chain.web.servlet.ServletWebContext;
38
39 import com.ibatis.sqlmap.client.*;
40 import com.ibatis.common.resources.*;
41
42 /***
43 * Initializes the Flow interpreter and loads system and user scripts. There
44 * are two mutually exclusive ways to specify scripts:
45 * <ol>
46 * <li> <code>scripts</code> - A comma-delimited list of scripts to load. All
47 * loaded scripts share the same script scope.</li>
48 * <li> <code>scriptBase</code> - The base path to use when resolving
49 * scripts. Each action mapping then needs to set the <code>script</code>
50 * property for the name of the actual script. The scripts will be looked up
51 * by concatinating the script base with the script name. Each script gets
52 * its own scope.</li>
53 * </ol>
54 * <p>
55 *
56 * Scripts can be located either in the webapp directory, as an absolute path
57 * on the filesystem, or in the classpath like in a jar file. </p> <p>
58 *
59 * The following optional properties can be specified:</p>
60 * <ul>
61 * <li> <code>debugger</code> - Whether to enable the Swing debugger</li>
62 *
63 * <li> <code>reloadScripts</code> - Whether to enable the reloading of
64 * scripts if their contents have been modified. The check for modification
65 * occurs every <code>checkTime</code> interval</li>
66 * <li> <code>checkTime</code> - The interval time in milliseconds between
67 * checking for script modifications, if enabled</li>
68 * <li> <code>timeToLive</code> - The length in milliseconds continuations
69 * will live from when they were last accessed</li>
70 * </ul>
71 *
72 */
73 public final class FlowPlugIn implements PlugIn {
74
75 /*** Servlet context key flow interpreter is stored under */
76 public final static String INTERPRETER_KEY = "interpreter";
77
78 /*** Servlet context key flow interpreters are stored under */
79 public final static String INTERPRETERS_KEY = "interpreters";
80
81 /*** Commons Logging instance. */
82 private static Log log = LogFactory.getLog(FlowPlugIn.class);
83
84 private ServletContext context;
85 private String scripts = null;
86 private String scriptBase = null;
87 private List classesToRegister = new ArrayList();
88
89 private boolean debugger = false;
90 private boolean reloadScripts;
91 private long checkTime;
92
93 private int ttl;
94
95
96 /***
97 * Gets a comma delimitted list of user scripts.
98 *
99 *@return comma delimited list of user script path names
100 */
101 public String getScripts() {
102 return scripts;
103 }
104
105
106 /***
107 * Sets a comma delimitted list of user scripts.
108 *
109 *@param scripts delimited list of user script path names
110 */
111 public void setScripts(String scripts) {
112 this.scripts = scripts;
113 }
114
115
116 /***
117 * Sets the base path to resolve scripts against
118 *
119 *@param scriptBase The base path
120 */
121 public void setScriptBase(String scriptBase) {
122 this.scriptBase = scriptBase;
123 }
124
125
126 /***
127 * Sets the value of reloadScripts.
128 *
129 *@param reloadScripts The value to assign reloadScripts.
130 */
131 public void setReloadScripts(boolean reloadScripts) {
132 this.reloadScripts = reloadScripts;
133 }
134
135
136 /***
137 * Sets the value of checkTime.
138 *
139 *@param checkTime The value to assign checkTime.
140 */
141 public void setCheckTime(long checkTime) {
142 this.checkTime = checkTime;
143 }
144
145
146 /***
147 * Sets the debugger attribute of the FlowPlugIn object
148 *
149 *@param val The new debugger value
150 */
151 public void setDebugger(boolean val) {
152 debugger = val;
153 }
154
155
156 /***
157 * Sets the timeToLive attribute of the FlowPlugIn object
158 *
159 *@param ttl The new timeToLive value
160 */
161 public void setTimeToLive(int ttl) {
162 this.ttl = ttl;
163 }
164
165 public void setSqlMapConfig(String path) {
166 try {
167 Reader reader = Resources.getResourceAsReader(path);
168 SqlMapClient client = SqlMapClientBuilder.buildSqlMapClient(reader);
169 SqlMap.setSqlMapClient(client);
170 classesToRegister.add(SqlMap.class);
171
172 Map classes = SqlMap.buildNamespaceClasses();
173
174 for (Iterator i = classes.values().iterator(); i.hasNext(); ) {
175 Class cls = (Class) i.next();
176 log.info("Registring "+cls.getName());
177 classesToRegister.add(cls);
178 }
179 } catch (Exception ex) {
180 ex.printStackTrace();
181 }
182 }
183
184
185 /***
186 * Initialize the flow interpreter
187 *
188 *@param servlet The ActionServlet for this web application
189 *@param config The ModuleConfig for our owning module
190 *@exception ServletException if we cannot configure ourselves correctly
191 */
192 public void init(ActionServlet servlet, ModuleConfig config)
193 throws ServletException {
194
195 if ((scripts == null || scripts.length() == 0) && scriptBase == null) {
196 throw new ServletException("No scripts or script base defined");
197 }
198 String key = INTERPRETER_KEY+"/"+config.getPrefix();
199 context = servlet.getServletContext();
200 Factory.setLogger(new CommonsLogger());
201 Factory.getContinuationsManager().setDefaultTimeToLive(ttl);
202
203 if (scripts != null && scripts.length() > 0) {
204 CompilingInterpreter interp = createInterpreter(config.getPrefix());
205 context.setAttribute(key, interp);
206 String path = null;
207 String paths = scripts;
208 try {
209
210 while (paths.length() > 0) {
211 int comma = paths.indexOf(',');
212 if (comma >= 0) {
213 path = paths.substring(0, comma).trim();
214 paths = paths.substring(comma + 1);
215 } else {
216 path = paths.trim();
217 paths = "";
218 }
219
220 if (path.length() < 1) {
221 break;
222 }
223 if (log.isInfoEnabled()) {
224 log.info("Registering script '" + path + "'");
225 }
226 interp.register(path);
227 }
228 } catch (Exception ex) {
229 throw new ServletException("Unable to create global JavaScript interpreter and register scripts", ex);
230 }
231 } else {
232 Map map =
233 new HashMap() {
234 public Object get(Object key) {
235 CompilingInterpreter interp = (CompilingInterpreter) super.get(key);
236 if (interp == null) {
237 if (log.isDebugEnabled()) {
238 log.debug("Creating interpreter for " + key);
239 }
240 interp = createInterpreter(key.toString());
241 interp.register(scriptBase + key);
242 put(key, interp);
243 }
244 return interp;
245 }
246 };
247 context.setAttribute(key, map);
248 }
249 }
250
251
252 private CompilingInterpreter createInterpreter(String id) {
253 FOM_JavaScriptInterpreter interp = new FOM_JavaScriptInterpreter();
254 interp.setInterpreterID(id);
255 interp.setSourceResolver(new ChainSourceResolver(new ServletWebContext(context, null, null)));
256 interp.setDebugger(debugger);
257 interp.setCheckTime(checkTime);
258 interp.setReloadScripts(reloadScripts);
259 interp.setWrapFactory(new SugarWrapFactory());
260 interp.initialize(classesToRegister);
261 interp.register("/org/apache/struts/flow/core/javascript/fom/fom_system.js");
262 interp.addFlowVariable("struts", new DefaultFlowVariableFactory(Struts.class));
263 interp.addFlowVariable("sqlMap", new DefaultFlowVariableFactory(SqlMap.class));
264 return interp;
265 }
266
267
268 /***
269 * Release any resources that were allocated at initialization, including
270 * any continuations.
271 */
272 public void destroy() {
273
274 log.info("Finalizing flow plug in");
275 Factory.getContinuationsManager().destroy();
276
277 context.removeAttribute(INTERPRETER_KEY);
278 context.removeAttribute(INTERPRETERS_KEY);
279 scriptBase = null;
280 context = null;
281 scripts = null;
282 }
283
284 }
285