View Javadoc

1   /*
2    *  Copyright 1999-2004 The Apache Software Foundation.
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  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                 // Process each specified resource path
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