KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > create > ScriptedCreator


1 /*
2  * Copyright 2005 Joe Walker
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.directwebremoting.create;
17
18 import java.io.File JavaDoc;
19 import java.io.RandomAccessFile JavaDoc;
20
21 import javax.servlet.ServletContext JavaDoc;
22
23 import org.apache.bsf.BSFException;
24 import org.apache.bsf.BSFManager;
25 import org.directwebremoting.WebContext;
26 import org.directwebremoting.WebContextFactory;
27 import org.directwebremoting.extend.Creator;
28 import org.directwebremoting.util.LocalUtil;
29 import org.directwebremoting.util.Logger;
30 import org.directwebremoting.util.Messages;
31
32 /**
33  * A creator that uses BeanShell to evaluate some script to create an object.
34  * @author Joe Walker [joe at getahead dot ltd dot uk]
35  * @author Dennis [devel at muhlesteins dot com]
36  */

37 public class ScriptedCreator extends AbstractCreator implements Creator
38 {
39     /**
40      * Set up some defaults
41      */

42     public ScriptedCreator()
43     {
44         // The default is <b>true</b>. This parameter is only used if scriptPath is
45
// used instead of script. When reloadable is true, ScriptedCreator will
46
// check to see if the script has been modified before returning the
47
// existing created class.
48
setCacheable(false);
49     }
50
51     /**
52      * The language that we are scripting in. Passed to BSF.
53      * @return Returns the language.
54      */

55     public String JavaDoc getLanguage()
56     {
57         return language;
58     }
59
60     /**
61      * @param language The language to set.
62      */

63     public void setLanguage(String JavaDoc language)
64     {
65         // It would be good to be ablt to check this, but this seems to fail
66
// almost all the time
67
// if (BSFManager.isLanguageRegistered(language))
68
// {
69
// throw new IllegalArgumentException(Messages.getString("ScriptedCreator.IllegalLanguage", language));
70
// }
71
this.language = language;
72     }
73
74     /**
75      * Are we caching the script (default: false)
76      * @return Returns the reloadable variable
77      */

78     public boolean isReloadable()
79     {
80         return reloadable;
81     }
82
83     /**
84      * @param reloadable Whether or not to reload the script.
85      * The default is <b>true</b>. This parameter is only used if scriptPath is
86      * used instead of script. When reloadable is true, ScriptedCreator will
87      * check to see if the script has been modified before returning the
88      * existing created class.
89      */

90     public void setReloadable(boolean reloadable)
91     {
92         this.reloadable = reloadable;
93
94         if (reloadable)
95         {
96             setCacheable(false);
97         }
98     }
99
100     /**
101      * Are we using dynamic classes (i.e. classes generated by BeanShell or
102      * similar) in which case we want to reuse class defs.
103      * @return Returns the useDynamicClasses flag state.
104      */

105     public boolean isUseDynamicClasses()
106     {
107         return useDynamicClasses;
108     }
109
110     /**
111      * Are we using dynamic classes (i.e. classes generated by BeanShell or
112      * similar) in which case we want to reuse class defs.
113      * @param useDynamicClasses The useDynamicClasses flag state.
114      */

115     public void setUseDynamicClasses(boolean useDynamicClasses)
116     {
117         this.useDynamicClasses = useDynamicClasses;
118     }
119
120     /**
121      * @return Returns the path of the script.
122      */

123     public String JavaDoc getScriptPath()
124     {
125         return scriptPath;
126     }
127
128     /**
129      * @param scriptPath Context reletive path to script.
130      */

131     public void setScriptPath(String JavaDoc scriptPath)
132     {
133         if (scriptSrc != null)
134         {
135             throw new IllegalArgumentException JavaDoc(Messages.getString("ScriptCreator.MultipleScript"));
136         }
137
138         this.scriptPath = scriptPath;
139     }
140
141     /**
142      * @return Whether or not the script (located at scriptPath) has been modified.
143      */

144     private boolean scriptUpdated()
145     {
146         if (null == scriptPath)
147         {
148             return false;
149         }
150
151         ServletContext JavaDoc sc = WebContextFactory.get().getServletContext();
152         File JavaDoc scriptFile = new File JavaDoc(sc.getRealPath(scriptPath));
153         if (scriptModified < scriptFile.lastModified())
154         {
155             log.debug("Script has been updated.");
156             clazz = null; // make sure that this gets re-compiled.
157
return true;
158         }
159
160         return false;
161     }
162
163     /**
164      * @return Returns the script.
165      * @throws InstantiationException
166      */

167     public String JavaDoc getScript() throws InstantiationException JavaDoc
168     {
169         if (scriptSrc != null)
170         {
171             return scriptSrc;
172         }
173
174         if (scriptPath == null)
175         {
176             throw new InstantiationException JavaDoc(Messages.getString("ScriptedCreator.MissingScript"));
177         }
178
179         if (cachedScript != null && (!reloadable || !scriptUpdated()))
180         {
181             return cachedScript;
182         }
183
184         // load the script from the path
185
log.debug("Loading Script from Path: " + scriptPath);
186         RandomAccessFile JavaDoc in = null;
187
188         try
189         {
190             ServletContext JavaDoc sc = WebContextFactory.get().getServletContext();
191             File JavaDoc scriptFile = new File JavaDoc(sc.getRealPath(scriptPath));
192
193             // This uses the platform default encoding. If there are complaints
194
// from people wanting to read script files that are not in the
195
// default platform encoding then we will need a new param that is
196
// used here.
197
scriptModified = scriptFile.lastModified();
198             in = new RandomAccessFile JavaDoc(scriptFile, "r");
199             byte bytes[] = new byte[(int) in.length()];
200             in.readFully(bytes);
201             cachedScript = new String JavaDoc(bytes);
202
203             return cachedScript;
204         }
205         catch (Exception JavaDoc ex)
206         {
207             log.error(ex.getMessage(), ex);
208             throw new InstantiationException JavaDoc(Messages.getString("ScriptCreator.MissingScript"));
209         }
210         finally
211         {
212             LocalUtil.close(in);
213         }
214     }
215
216     /**
217      * @param scriptSrc The script to set.
218      */

219     public void setScript(String JavaDoc scriptSrc)
220     {
221         if (scriptPath != null)
222         {
223             throw new IllegalArgumentException JavaDoc(Messages.getString("ScriptCreator.MultipleScript"));
224         }
225
226         if (scriptSrc == null || scriptSrc.trim().length() == 0)
227         {
228             throw new IllegalArgumentException JavaDoc(Messages.getString("ScriptedCreator.MissingScript"));
229         }
230
231         this.scriptSrc = scriptSrc;
232     }
233
234     /**
235      * What sort of class do we create?
236      * @param classname The name of the class
237      */

238     public void setClass(String JavaDoc classname)
239     {
240         try
241         {
242             this.clazz = LocalUtil.classForName(classname);
243         }
244         catch (ClassNotFoundException JavaDoc ex)
245         {
246             throw new IllegalArgumentException JavaDoc(Messages.getString("Creator.ClassNotFound", classname));
247         }
248     }
249
250     /* (non-Javadoc)
251      * @see org.directwebremoting.Creator#getType()
252      */

253     public Class JavaDoc getType()
254     {
255         if (clazz == null || (reloadable && scriptUpdated()))
256         {
257             try
258             {
259                 clazz = getInstance().getClass();
260             }
261             catch (InstantiationException JavaDoc ex)
262             {
263                 log.error("Failed to instansiate object to detect type.", ex);
264                 return Object JavaDoc.class;
265             }
266         }
267
268         return clazz;
269     }
270
271     /* (non-Javadoc)
272      * @see org.directwebremoting.Creator#getInstance()
273      */

274     public Object JavaDoc getInstance() throws InstantiationException JavaDoc
275     {
276         try
277         {
278             if (useDynamicClasses && clazz != null)
279             {
280                 return clazz.newInstance();
281             }
282
283             BSFManager bsfman = new BSFManager();
284
285             try
286             {
287                 WebContext context = WebContextFactory.get();
288                 bsfman.declareBean("context", context, context.getClass());
289             }
290             catch (BSFException ex)
291             {
292                 log.warn("Failed to register WebContext with scripting engine: " + ex.getMessage());
293             }
294
295             return bsfman.eval(language, (null == scriptPath ? "dwr.xml" : scriptPath), 0, 0, getScript());
296         }
297         catch (Exception JavaDoc ex)
298         {
299             log.error("Error executing script", ex);
300             throw new InstantiationException JavaDoc(Messages.getString("Creator.IllegalAccess"));
301         }
302     }
303
304     /**
305      * The log stream
306      */

307     private static final Logger log = Logger.getLogger(ScriptedCreator.class);
308
309     /**
310      * The cached type of object that we are creating.
311      */

312     private Class JavaDoc clazz = null;
313
314     /**
315      * The language that we are scripting in. Passed to BSF.
316      */

317     private String JavaDoc language = null;
318
319     /**
320      * The script that we are asking BSF to execute in order to get an object.
321      */

322     private String JavaDoc scriptSrc = null;
323
324     /**
325      * The path of the script we are asking BSF to execute.
326      */

327     private String JavaDoc scriptPath = null;
328
329     /**
330      * Whether or not to reload the script. Only used if scriptPath is used.
331      * ie: An inline script is not reloadable
332      */

333     private boolean reloadable = true;
334
335     /**
336      * By default we assume that our scripts do not create classes dynamically.
337      * If they do then we need to take some special care of them.
338      */

339     private boolean useDynamicClasses = false;
340
341     /**
342      * Script modified time. Only used when scriptPath is used.
343      */

344     private long scriptModified = -1;
345
346     /**
347      * Contents of script loaded from scriptPath
348      */

349     private String JavaDoc cachedScript;
350 }
351
Popular Tags