Source Code Cross Referenced for NetRexxEngine.java in  » Scripting » bsf-2.4.0 » org » apache » bsf » engines » netrexx » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » bsf 2.4.0 » org.apache.bsf.engines.netrexx 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2004,2004 The Apache Software Foundation.
003:         * 
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         * 
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:
017:        package org.apache.bsf.engines.netrexx;
018:
019:        import java.io.File;
020:        import java.io.FileOutputStream;
021:        import java.io.FilenameFilter;
022:        import java.io.PrintWriter;
023:        import java.lang.reflect.InvocationTargetException;
024:        import java.lang.reflect.Method;
025:        import java.util.Hashtable;
026:        import java.util.Vector;
027:
028:        import org.apache.bsf.BSFDeclaredBean;
029:        import org.apache.bsf.BSFException;
030:        import org.apache.bsf.BSFManager;
031:        import org.apache.bsf.util.BSFEngineImpl;
032:        import org.apache.bsf.util.BSFFunctions;
033:        import org.apache.bsf.util.EngineUtils;
034:        import org.apache.bsf.util.MethodUtils;
035:        import org.apache.bsf.util.StringUtils;
036:        import org.apache.commons.logging.Log;
037:        import org.apache.commons.logging.LogFactory;
038:
039:        /**
040:         * This is the interface to NetRexx from the
041:         * Bean Scripting Framework.
042:         * <p>
043:         * The NetRexx code must be written script-style, without a "class" or
044:         * "properties" section preceeding the executable code. The NetRexxEngine will
045:         * generate a prefix for this code:
046:         * <pre>
047:         * <code>
048:         * class $$CLASSNAME$$;
049:         * method BSFNetRexxEngineEntry(bsf=org.apache.bsf.BSFManager) public static;
050:         * </code>
051:         * </pre>
052:         * $$CLASSNAME$$ will be replaced by a generated classname of the form
053:         * BSFNetRexx*, and the bsf parameter can be used to retrieve application
054:         * objects registered with the Bean Scripting Framework.
055:         * <p>
056:         * If you use the placeholder string $$CLASSNAME$$ elsewhere
057:         * in your script -- including within text strings -- BSFNetRexxEngine will
058:         * replace it with the generated name of the class before the NetRexx code
059:         * is compiled.
060:         * <p>
061:         * If you need to use full NetRexx functionality, we recommend that your
062:         * NetRexx script define and invoke a "minor class", with or without the
063:         * "dependent" keyword as suits your needs. You'll have to use $$CLASSNAME$$
064:         * in naming the minor class, since the name of the main class is synthesized;
065:         * for example, to create the minor class "bar" you'd write
066:         * "class $$CLASSNAME$$.Bar".
067:         * <p>
068:         * <h2>Hazards:</h2>
069:         * <p>
070:         * Since NetRexx has to be _compiled_ to a Java classfile, invoking it involves
071:         * a fair amount of computation to load and execute the compiler. We are
072:         * currently making an attempt to manage that by caching the class
073:         * after it has been loaded, but the indexing is fairly primitive; we
074:         * hash against the script string to find the class for it.
075:         * <p>
076:         * Minor-class .class files are now being deleted after the major class loads.
077:         * This coould potentially cause problems.
078:         *
079:         * @author  Joe Kesselman
080:         * @author  Sanjiva Weerawarana
081:         */
082:        public class NetRexxEngine extends BSFEngineImpl {
083:            BSFFunctions mgrfuncs;
084:            static Hashtable codeToClass = new Hashtable();
085:            static String serializeCompilation = "";
086:            static String placeholder = "$$CLASSNAME$$";
087:            String minorPrefix;
088:
089:            private Log logger = LogFactory.getLog(this .getClass().getName());
090:
091:            /**
092:             * Create a scratchfile, open it for writing, return its name.
093:             * Relies on the filesystem to provide us with uniqueness testing.
094:             * NOTE THAT uniqueFileOffset continues to count; we don't want to
095:             * risk reusing a classname we have previously loaded in this session
096:             * even if the classfile has been deleted.
097:             *
098:             * I've made the offset static, due to concerns about reuse/reentrancy
099:             * of the NetRexx engine.
100:             */
101:            private static int uniqueFileOffset = 0;
102:
103:            private class GeneratedFile {
104:                File file = null;
105:                FileOutputStream fos = null;
106:                String className = null;
107:
108:                GeneratedFile(File file, FileOutputStream fos, String className) {
109:                    this .file = file;
110:                    this .fos = fos;
111:                    this .className = className;
112:                }
113:            }
114:
115:            // rexxclass used to be an instance variable, on the theory that
116:            // each NetRexxEngine was an instance of a specific script.
117:            // BSF is currently reusing Engines, so caching the class
118:            // no longer makes sense.
119:            // Class rexxclass;
120:
121:            /**
122:             * Constructor.
123:             */
124:            public NetRexxEngine() {
125:                /*
126:                  The following line is intended to cause the constructor to
127:                  throw a NoClassDefFoundError if the NetRexxC.zip dependency
128:                  is not resolved.
129:                  
130:                  If this line was not here, the problem would not surface until
131:                  the actual processing of a script. We want to know all is well
132:                  at the time the engine is instantiated, not when we attempt to
133:                  process a script.
134:                 */
135:
136:                new netrexx.lang.BadArgumentException();
137:            }
138:
139:            /**
140:             * Return an object from an extension.
141:             * @param object object from which to call our static method
142:             * @param method The name of the method to call.
143:             * @param args an array of arguments to be
144:             * passed to the extension, which may be either
145:             * Vectors of Nodes, or Strings.
146:             */
147:            public Object call(Object object, String method, Object[] args)
148:                    throws BSFException {
149:                throw new BSFException(BSFException.REASON_UNSUPPORTED_FEATURE,
150:                        "NetRexx doesn't currently support call()", null);
151:            }
152:
153:            /**
154:             * Invoke a static method.
155:             * @param rexxclass Class to invoke the method against
156:             * @param method The name of the method to call.
157:             * @param args an array of arguments to be
158:             * passed to the extension, which may be either
159:             * Vectors of Nodes, or Strings.
160:             */
161:            Object callStatic(Class rexxclass, String method, Object[] args)
162:                    throws BSFException {
163:                //***** ISSUE: Currently supports only static methods
164:                Object retval = null;
165:                try {
166:                    if (rexxclass != null) {
167:                        //***** This should call the lookup used in BML, for typesafety
168:                        Class[] argtypes = new Class[args.length];
169:                        for (int i = 0; i < args.length; ++i)
170:                            argtypes[i] = args[i].getClass();
171:
172:                        Method m = MethodUtils.getMethod(rexxclass, method,
173:                                argtypes);
174:                        retval = m.invoke(null, args);
175:                    } else {
176:                        logger.error("NetRexxEngine: ERROR: rexxclass==null!");
177:                    }
178:                } catch (Exception e) {
179:                    e.printStackTrace();
180:                    if (e instanceof  InvocationTargetException) {
181:                        Throwable t = ((InvocationTargetException) e)
182:                                .getTargetException();
183:                        t.printStackTrace();
184:                    }
185:                    throw new BSFException(BSFException.REASON_IO_ERROR, e
186:                            .getMessage(), e);
187:                }
188:                return retval;
189:            }
190:
191:            public void declareBean(BSFDeclaredBean bean) throws BSFException {
192:            }
193:
194:            /**
195:             * Override impl of execute. In NetRexx, methods which do not wish
196:             * to return a value should be invoked via exec, which will cause them
197:             * to be generated without the "returns" clause.
198:             * Those which wish to return a value should call eval instead.
199:             * which will add "returns java.lang.Object" to the header.
200:             *
201:             * Note: It would be nice to have the "real" return type avaialable, so
202:             * we could do something more type-safe than Object, and so we could
203:             * return primitive types without having to enclose them in their
204:             * object wrappers. BSF does not currently support that concept.
205:             */
206:            public Object eval(String source, int lineNo, int columnNo,
207:                    Object script) throws BSFException {
208:                return execEvalShared(source, lineNo, columnNo, script, true);
209:            }
210:
211:            /**
212:             * Override impl of execute. In NetRexx, methods which do not wish
213:             * to return a value should be invoked via exec, which will cause them
214:             * to be generated without the "returns" clause.
215:             * Those which wish to return a value should call eval instead.
216:             * which will add "returns java.lang.Object" to the header.
217:             */
218:            public void exec(String source, int lineNo, int columnNo,
219:                    Object script) throws BSFException {
220:                execEvalShared(source, lineNo, columnNo, script, false);
221:            }
222:
223:            /**
224:             * This is shared code for the exec() and eval() operations. It will
225:             * evaluate a string containing a NetRexx method body -- which may be
226:             * as simple as a single return statement.
227:             * It should store the "bsf" handle where the
228:             * script can get to it, for callback purposes.
229:             * <p>
230:             * Note that NetRexx compilation imposes serious overhead -- 11 seconds for
231:             * the first compile, about 3 thereafter -- but in exchange you get
232:             * Java-like speeds once the classes have been created (minus the cache
233:             * lookup cost).
234:             * <p>
235:             * Nobody knows whether javac is threadsafe.
236:             * I'm going to serialize access to the compilers to protect it.
237:             */
238:            public Object execEvalShared(String source, int lineNo,
239:                    int columnNo, Object oscript, boolean returnsObject)
240:                    throws BSFException {
241:                Object retval = null;
242:                String classname = null;
243:                GeneratedFile gf = null;
244:
245:                // Moved into the exec process; see comment above.
246:                Class rexxclass = null;
247:
248:                String basescript = oscript.toString();
249:                String script = basescript; // May be altered by $$CLASSNAME$$ expansion
250:
251:                try {
252:                    // Do we already have a class exactly matching this code?
253:                    rexxclass = (Class) codeToClass.get(basescript);
254:
255:                    if (rexxclass != null)
256:
257:                    {
258:                        logger.debug("NetRexxEngine: Found pre-compiled class"
259:                                + " for script '" + basescript + "'");
260:                        classname = rexxclass.getName();
261:                    } else {
262:                        gf = openUniqueFile(tempDir, "BSFNetRexx", ".nrx");
263:                        if (gf == null)
264:                            throw new BSFException(
265:                                    "couldn't create NetRexx scratchfile");
266:
267:                        // Obtain classname
268:                        classname = gf.className;
269:
270:                        // Decide whether to declare a return type
271:                        String returnsDecl = "";
272:                        if (returnsObject)
273:                            returnsDecl = "returns java.lang.Object";
274:
275:                        // Write the kluge header to the file.
276:                        // ***** By doing so we give up the ability to use Property blocks.
277:                        gf.fos.write(("class " + classname + ";\n").getBytes());
278:                        gf.fos
279:                                .write(("method BSFNetRexxEngineEntry(bsf=org.apache.bsf.util.BSFFunctions) "
280:                                        + " public static " + returnsDecl + ";\n")
281:                                        .getBytes());
282:
283:                        // Edit the script to replace placeholder with the generated
284:                        // classname. Note that this occurs _after_ the cache was
285:                        // checked!
286:                        int startpoint, endpoint;
287:                        if ((startpoint = script.indexOf(placeholder)) >= 0) {
288:                            StringBuffer changed = new StringBuffer();
289:                            for (; startpoint >= 0; startpoint = script
290:                                    .indexOf(placeholder, startpoint)) {
291:                                changed.setLength(0); // Reset for 2nd pass or later
292:                                if (startpoint > 0)
293:                                    changed.append(script.substring(0,
294:                                            startpoint));
295:                                changed.append(classname);
296:                                endpoint = startpoint + placeholder.length();
297:                                if (endpoint < script.length())
298:                                    changed.append(script.substring(endpoint));
299:                                script = changed.toString();
300:                            }
301:                        }
302:
303:                        BSFDeclaredBean tempBean;
304:                        String className;
305:
306:                        for (int i = 0; i < declaredBeans.size(); i++) {
307:                            tempBean = (BSFDeclaredBean) declaredBeans
308:                                    .elementAt(i);
309:                            className = StringUtils.getClassName(tempBean.type);
310:
311:                            gf.fos
312:                                    .write((tempBean.name + " =" + className
313:                                            + "   bsf.lookupBean(\""
314:                                            + tempBean.name + "\");")
315:                                            .getBytes());
316:                        }
317:
318:                        if (returnsObject)
319:                            gf.fos.write("return ".getBytes());
320:
321:                        // Copy the input to the file.
322:                        // Assumes all available -- probably mistake, but same as
323:                        // other engines.
324:                        gf.fos.write(script.getBytes());
325:                        gf.fos.close();
326:
327:                        logger.debug("NetRexxEngine: wrote temp file "
328:                                + gf.file.getPath() + ", now compiling");
329:
330:                        // Compile through Java to .class file
331:                        String command = gf.file.getPath(); //classname;
332:                        if (logger.isDebugEnabled()) {
333:                            command += " -verbose4";
334:                        } else {
335:                            command += " -noverbose";
336:                            command += " -noconsole";
337:                        }
338:
339:                        netrexx.lang.Rexx cmdline = new netrexx.lang.Rexx(
340:                                command);
341:                        int retValue;
342:
343:                        // May not be threadsafe. Serialize access on static object:
344:                        synchronized (serializeCompilation) {
345:                            // compile to a .java file
346:                            retValue = COM.ibm.netrexx.process.NetRexxC.main(
347:                                    cmdline, new PrintWriter(System.err));
348:                        }
349:
350:                        // Check if there were errors while compiling the Rexx code.
351:                        if (retValue == 2) {
352:                            throw new BSFException(
353:                                    BSFException.REASON_EXECUTION_ERROR,
354:                                    "There were NetRexx errors.");
355:                        }
356:
357:                        // Load class.
358:                        logger.debug("NetRexxEngine: loading class "
359:                                + classname);
360:                        rexxclass = EngineUtils.loadClass(mgr, classname);
361:
362:                        // Stash class for reuse
363:                        codeToClass.put(basescript, rexxclass);
364:                    }
365:
366:                    Object[] args = { mgrfuncs };
367:                    retval = callStatic(rexxclass, "BSFNetRexxEngineEntry",
368:                            args);
369:                } catch (BSFException e) {
370:                    // Just forward the exception on.
371:                    throw e;
372:                } catch (Exception e) {
373:                    e.printStackTrace();
374:                    if (e instanceof  InvocationTargetException) {
375:                        Throwable t = ((InvocationTargetException) e)
376:                                .getTargetException();
377:                        t.printStackTrace();
378:                    }
379:                    throw new BSFException(BSFException.REASON_IO_ERROR, e
380:                            .getMessage(), e);
381:                } finally {
382:                    // Cleanup: delete the .nrx and .class files
383:                    // (if any) generated by NetRexx Trace requests.
384:
385:                    if (gf != null && gf.file != null && gf.file.exists())
386:                        gf.file.delete(); // .nrx file
387:
388:                    if (classname != null) {
389:                        // Generated src
390:                        File file = new File(tempDir + File.separatorChar
391:                                + classname + ".java");
392:                        if (file.exists())
393:                            file.delete();
394:
395:                        // Generated class
396:                        file = new File(classname + ".class");
397:                        if (file.exists())
398:                            file.delete();
399:
400:                        // Can this be done without disrupting trace?
401:                        file = new File(tempDir + File.separatorChar
402:                                + classname + ".crossref");
403:                        if (file.exists())
404:                            file.delete();
405:
406:                        // Search for and clean up minor classes, classname$xxx.class
407:                        file = new File(tempDir);
408:                        minorPrefix = classname + "$"; // Indirect arg to filter
409:                        String[] minor_classfiles = file.list(
410:                        // ANONYMOUS CLASS for filter:
411:                                new FilenameFilter() {
412:                                    // Starts with classname$ and ends with .class
413:                                    public boolean accept(File dir, String name) {
414:                                        return (0 == name.indexOf(minorPrefix))
415:                                                && (name.lastIndexOf(".class") == name
416:                                                        .length() - 6);
417:                                    }
418:                                });
419:                        if (minor_classfiles != null)
420:                            for (int i = minor_classfiles.length; i > 0;) {
421:                                file = new File(minor_classfiles[--i]);
422:                                file.delete();
423:                            }
424:                    }
425:                }
426:
427:                return retval;
428:            }
429:
430:            public void initialize(BSFManager mgr, String lang,
431:                    Vector declaredBeans) throws BSFException {
432:                super .initialize(mgr, lang, declaredBeans);
433:                mgrfuncs = new BSFFunctions(mgr, this );
434:            }
435:
436:            private GeneratedFile openUniqueFile(String directory,
437:                    String prefix, String suffix) {
438:                File file = null, obj = null;
439:                FileOutputStream fos = null;
440:                int max = 1000; // Don't try forever
441:                GeneratedFile gf = null;
442:                int i;
443:                String className = null;
444:                for (i = max, ++uniqueFileOffset; fos == null && i > 0; --i, ++uniqueFileOffset) {
445:                    // Probably a timing hazard here... ***************
446:                    try {
447:                        className = prefix + uniqueFileOffset;
448:                        file = new File(directory + File.separatorChar
449:                                + className + suffix);
450:                        obj = new File(directory + File.separatorChar
451:                                + className + ".class");
452:                        if (file != null && !file.exists() & obj != null
453:                                & !obj.exists())
454:                            fos = new FileOutputStream(file);
455:                    } catch (Exception e) {
456:                        // File could not be opened for write, or Security Exception
457:                        // was thrown. If someone else created the file before we could
458:                        // open it, that's probably a threading conflict and we don't
459:                        // bother reporting it.
460:                        if (!file.exists()) {
461:                            logger.error("openUniqueFile: unexpected " + e);
462:                        }
463:                    }
464:                }
465:                if (fos == null)
466:                    logger.error("openUniqueFile: Failed " + max + "attempts.");
467:                else
468:                    gf = new GeneratedFile(file, fos, className);
469:                return gf;
470:            }
471:
472:            public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
473:            }
474:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.