001: /*
002: * Copyright (c) 2005 Advanced Micro Devices, Inc.
003: *
004: * See the file "license.amd" for information on usage and
005: * redistribution of this file, and for a DISCLAIMER OF ALL
006: * WARRANTIES.
007: *
008: * RCS: @(#) $Id: TJCCompileCmd.java,v 1.4 2006/08/06 00:38:58 mdejong Exp $
009: *
010: */
011:
012: package tcl.lang;
013:
014: import java.util.ArrayList;
015:
016: public class TJCCompileCmd implements Command {
017:
018: // Implementation of TJC::compile used to compile
019: // Tcl commands into Java byte code and load them
020: // into the JVM at runtime.
021:
022: public void cmdProc(Interp interp, TclObject[] objv)
023: throws TclException {
024: // Usage:
025: //
026: // TJC::compile cmd
027: // TJC::compile cmd -readycmd {my_command_ready_cmd}
028: // TJC::compile cmd -readyvar myarr(cmd)
029: //
030: // TJC::compile -java JINFO -readycmd {my_java_ready_cmd}
031: // TJC::compile -java JINFO -readyvar my_java_status
032:
033: if (objv.length < 2 || objv.length == 3 || objv.length > 5) {
034: throw new TclNumArgsException(interp, 1, objv,
035: "?cmd? ?options?");
036: }
037:
038: String javaInfo = null;
039: String cmd = null;
040: String readycmd = null;
041: String readyvar = null;
042: int next;
043:
044: // Argument 1 can be a command name or -java
045: // if there are 3 or more arguments
046:
047: cmd = objv[1].toString();
048:
049: if (cmd.equals("-java")) {
050: // -java usage requires either a -readycmd
051: // or a -readyvar argument pair since
052: // the user code needs some way to know
053: // when the source has been compiled
054: // and loaded into the JVM.
055:
056: if (objv.length != 5) {
057: throw new TclNumArgsException(interp, 1, objv,
058: "?cmd? ?options?");
059: }
060:
061: // javaInfo should be a list of length 2, with the
062: // following contents: {JCLASSNAME JSRCCODE}
063:
064: TclObject obj = objv[2];
065: if (TclList.getLength(interp, obj) != 2) {
066: throw new TclException(interp,
067: "-java JINFO argument must be a 2 element list of {JCLASSNAME JSRCCODE}");
068: }
069: javaInfo = objv[2].toString();
070: cmd = null;
071: next = 3;
072: } else {
073: next = 2;
074: }
075:
076: if (next == objv.length) {
077: // TJC::command cmd
078: } else {
079: // There should be 2 more arguments, either
080: // -readycmd cmd or -readyvar var.
081:
082: if ((next + 2) != objv.length) {
083: throw new TclNumArgsException(interp, 1, objv,
084: "?cmd? ?options?");
085: }
086:
087: String option = objv[next].toString();
088: String value = objv[next + 1].toString();
089:
090: if (option.equals("-readycmd")) {
091: readycmd = value;
092: } else if (option.equals("-readyvar")) {
093: readyvar = value;
094: } else {
095: throw new TclNumArgsException(interp, 1, objv,
096: "?cmd? ?options?");
097: }
098: }
099:
100: // Double check settings
101:
102: if (javaInfo != null && cmd != null) {
103: throw new TclRuntimeError("can set both cmd and -java");
104: }
105: if (readycmd != null && readyvar != null) {
106: throw new TclRuntimeError(
107: "can set both -readyvar and -readycmd");
108: }
109:
110: // If compiling a Java class, init helper method that
111: // will be invoked when the Java method is compiled.
112:
113: if (javaInfo != null) {
114: JavaCompile(interp, javaInfo, readycmd, readyvar);
115: } else {
116: TclCompile(interp, cmd, readycmd, readyvar);
117: }
118:
119: return;
120: }
121:
122: // Process Java source code, compile it to byte code and
123: // then load the byte code into the interp.
124:
125: static void JavaCompile(Interp interp, String javaInfo,
126: String readyCmd, String readyVar) throws TclException {
127: // Make sure compiler thread is running
128: TJCThread.startThread();
129:
130: TJCCompileJavaCmd cjobj = new TJCCompileJavaCmd(interp,
131: javaInfo, readyCmd, readyVar);
132:
133: // The fully qualified Java source file name must be passed
134: // to the compiler layer. For example, a class named Test11
135: // in the package foo.bar must be compiled with the source
136: // file name "foo/bar/Test11.java". The user needs to pass
137: // the class name in the JINFO argument, so construct the
138: // Java file name from the Java class name.
139:
140: String javaFileName = cjobj.getJavaFileName();
141: String javaSrc = cjobj.getJavaSource();
142:
143: if (cjobj.debug) {
144: System.out.println("Sending Java file name: "
145: + javaFileName);
146: System.out.println("Sending javaSrc:\n" + javaSrc);
147: }
148:
149: TJCThread.compileJavaSource(javaFileName, javaSrc, cjobj);
150: }
151:
152: // Compile Tcl proc currently defined in the interpreter.
153:
154: static void TclCompile(Interp interp, String cmd, String readyCmd,
155: String readyVar) throws TclException {
156: int i, len;
157:
158: String fullyQualifiedCmd;
159:
160: // Make sure compiler thread is running
161: TJCThread.startThread();
162:
163: // Lookup Procedure in the interp.
164:
165: Procedure proc = Procedure.findProc(interp, cmd);
166: if (proc == null) {
167: throw new TclException(interp, "\"" + cmd
168: + "\" isn't a procedure");
169: }
170:
171: // Generate non-unique Java class name based on the
172: // Tcl proc name. The proc includes any namespace
173: // qualifiers.
174:
175: StringBuffer pname = new StringBuffer(64);
176: StringBuffer cname = new StringBuffer(64);
177:
178: if (cmd.startsWith("::")) {
179: // already fully qualified
180: pname.append(cmd);
181: } else {
182: // make it fully qualified
183: String nsName = proc.wcmd.ns.fullName;
184:
185: if (nsName.equals("::")) {
186: pname.append(nsName);
187: } else {
188: pname.append(nsName);
189: pname.append("::");
190: }
191: pname.append(NamespaceCmd.tail(cmd));
192: }
193:
194: if (false) {
195: // Debug
196: interp.eval("namespace current", 0);
197: String cns = interp.getResult().toString();
198: System.out.println("current namespace is \"" + cns + "\"");
199: System.out.println("looked up proc \"" + cmd + "\"");
200: System.out.println("found proc in namespace \""
201: + proc.wcmd.ns.fullName + "\"");
202: System.out.println("fully qualified name is \""
203: + pname.toString());
204: }
205:
206: // Generate Java class name for Tcl proc
207:
208: fullyQualifiedCmd = pname.toString();
209:
210: String upper = fullyQualifiedCmd;
211: boolean cap = true;
212: len = upper.length();
213: for (i = 0; i < len; i++) {
214: char c = upper.charAt(i);
215: if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
216: || (c >= '0' && c <= '9')) {
217: if (cap) {
218: c = Character.toUpperCase(c);
219: cap = false;
220: }
221: cname.append(c);
222: } else {
223: cap = true;
224: }
225: }
226: cname.append("Cmd");
227: String javaClassName = cname.toString();
228:
229: // Determine if a Tcl proc with this name
230: // was already compiled and loaded into
231: // the current ClassLoader. In this case,
232: // we need to make the Java class name
233: // unique so that the ClassLoader does not
234: // fail to load the class once it has
235: // been compiled.
236:
237: if (isClassDefined(interp, javaClassName)) {
238: String prefix = cname.toString();
239: String suffix = null;
240:
241: for (i = 2; i < Integer.MAX_VALUE; i++) {
242: suffix = String.valueOf(i);
243:
244: if (!isClassDefined(interp, prefix + suffix)) {
245: break;
246: }
247: }
248: if (i == Integer.MAX_VALUE) {
249: // This should never happen
250: throw new TclRuntimeError("suffix integer overflow");
251: }
252:
253: cname.append(suffix);
254: javaClassName = cname.toString();
255: }
256:
257: // Generate proc declaration
258:
259: TclObject procList = TclList.newInstance();
260: TclList.append(interp, procList, TclString.newInstance("proc"));
261: TclList.append(interp, procList, TclString.newInstance(cmd));
262:
263: // Build up args list from the Procedure object
264:
265: TclObject args = TclList.newInstance();
266: len = proc.argList.length;
267: for (i = 0; i < len; i++) {
268: TclObject name = proc.argList[i][0];
269: TclObject defval = proc.argList[i][1];
270:
271: if (defval == null) {
272: TclList.append(interp, args, TclString.newInstance(name
273: .toString()));
274: } else {
275: TclObject defpair = TclList.newInstance();
276: TclList.append(interp, defpair, TclString
277: .newInstance(name.toString()));
278: TclList.append(interp, defpair, TclString
279: .newInstance(defval.toString()));
280: TclList.append(interp, args, defpair);
281: }
282: }
283: if (proc.isVarArgs) {
284: TclList.append(interp, args, TclString.newInstance("args"));
285: }
286: TclList.append(interp, procList, TclString.newInstance(args));
287:
288: // Get proc body and append it to the proc decl
289:
290: TclList.append(interp, procList, TclString
291: .newInstance(proc.body.toString()));
292:
293: TJCCompileTclCmd ctobj = new TJCCompileTclCmd(interp,
294: fullyQualifiedCmd, readyCmd, readyVar);
295:
296: if (ctobj.debug) {
297: System.out.println("Sending proc decl\n"
298: + procList.toString());
299: }
300:
301: TJCThread.compileTclSource(javaClassName, procList.toString(),
302: ctobj);
303: }
304:
305: // Return true if a Java class with the given name has
306: // already been defined in the ClassLoader for the
307: // given interp.
308:
309: static boolean isClassDefined(Interp interp, String javaClassName) {
310: final boolean debug = false;
311:
312: TclClassLoader tclClassLoader = (TclClassLoader) interp
313: .getClassLoader();
314: Class alreadyLoaded = null;
315:
316: try {
317: if (debug) {
318: System.out
319: .println("checking for duplicate class name : "
320: + javaClassName);
321: }
322:
323: alreadyLoaded = tclClassLoader.loadClass(javaClassName);
324: } catch (ClassNotFoundException e) {
325: // No-op
326: } catch (PackageNameException e) {
327: // Should not be possible to catch a PackageNameException
328: // since the Java class is not in the tcl.* or java.* packages.
329:
330: throw new TclRuntimeError(
331: "unexpected PackageNameException :"
332: + e.getMessage());
333: }
334:
335: boolean isDefined = (alreadyLoaded != null);
336:
337: if (debug) {
338: System.out.println("class isDefined is " + isDefined);
339: }
340:
341: return isDefined;
342: }
343:
344: } // end class TJCCompileCmd
345:
346: // Helper class to load compiled class into the
347: // current thread and register a compiled command
348: // implementation in the current interp. An
349: // instance of this object is created for each
350: // command that is compiled.
351:
352: class TJCCompileTclCmd extends TclEvent implements
353: TJCThread.CompiledClassReady {
354: final boolean debug = false;
355:
356: final Interp interp;
357: final String cmd;
358: final String readyCmd;
359: final String readyVar;
360:
361: boolean status;
362: String errorMsg = "";
363: String className = null; // Java class name for this command
364: byte[] classBytes = null; // Java class bytes for this command
365:
366: TJCCompileTclCmd(Interp interp, String cmd, String readyCmd,
367: String readyVar) {
368: this .interp = interp;
369: this .cmd = cmd;
370: this .readyCmd = readyCmd;
371: this .readyVar = readyVar;
372: }
373:
374: // Invoked by TJCThread when a compile job is finished.
375: // This implementation will queue an event in the original
376: // thread that will replace the Tcl command with a
377: // compiled implementation of the command.
378:
379: public void compiled(final String geninfo, // Name of Tcl command that was compiled.
380: final String jfilename, // File name for Java source,
381: // like "Test.java".
382: final String jsrcode, // Java source that was compiled.
383: final ArrayList cnames, // List of compiled class names.
384: final ArrayList cdata, // List of compiled class data as byte[].
385: final int status, final String msg) {
386: // Add an event to the thread safe Tcl event queue that
387: // will replace the existing command with a compiled one.
388:
389: if (debug) {
390: System.out
391: .println("TJCCompileTclCmd CompiledClassReady.compiled()");
392: System.out.println("geninfo was " + geninfo);
393: System.out.println("jfilename was " + jfilename);
394: System.out.println("jsrcode was " + jsrcode);
395: System.out.println("cnames was " + cnames);
396: if (cdata == null) {
397: System.out.println("cdata was null");
398: } else {
399: System.out.println("cdata length was " + cdata.size());
400: }
401: }
402:
403: // Check compile status:
404:
405: if (status == TJCThread.STATUS_OK) {
406: this .status = true;
407:
408: if (debug) {
409: System.out.println("Status was OK");
410: }
411: } else {
412: this .status = false;
413: this .errorMsg = msg;
414:
415: if (debug) {
416: System.out.println("Status was not OK");
417: System.out.println("errorMsg was \"" + this .errorMsg
418: + "\"");
419: }
420: }
421:
422: // Tcl command should compile into one class file.
423:
424: if (cdata == null) {
425: // Error should be indicated in errorMsg
426: } else if (cdata.size() == 1) {
427: className = (String) cnames.get(0); // Name of class, could be null if not known
428: classBytes = (byte[]) cdata.get(0);
429: } else {
430: this .status = false;
431: this .errorMsg = "unexpected number of class files "
432: + cdata.size();
433:
434: if (debug) {
435: System.out.println("Status was not OK");
436: System.out.println("errorMsg was \"" + this .errorMsg
437: + "\"");
438: }
439: }
440:
441: interp.getNotifier().queueEvent(this , TCL.QUEUE_TAIL);
442:
443: // Don't wait for the event to be processed in the
444: // original thread. Just continue to process the
445: // next event in TJCThread.
446: //event.sync();
447: }
448:
449: // Invoked by the original thread (not by TJCThread)
450: // when the original thread enters the event loop.
451: // This method will replace the Tcl proc with the
452: // compiled implementation of the proc.
453:
454: public int processEvent(int flags) {
455: if (debug) {
456: System.out.println("TJCCompileTclCmd.processEvent()");
457: }
458:
459: // If the compile failed, report that now
460: if (status == false) {
461: readyReport();
462: return 1;
463: }
464:
465: // Otherwise, load the class file via the TclClassLoader
466: // and replace the Tcl proc with the compiled command.
467:
468: TclClassLoader tclClassLoader = (TclClassLoader) interp
469: .getClassLoader();
470: // Flush class loader cache in case it holds the last ref to
471: // a previously loaded version of this same class (Tcl command).
472: if (className != null) {
473: tclClassLoader.removeCache(className);
474: }
475: Class class_obj = tclClassLoader.defineClass(className,
476: classBytes);
477: if (class_obj == null) {
478: // Class could not be loaded, status is fail
479: status = false;
480: errorMsg = "class not loaded by TclClassLoader";
481: readyReport();
482: return 1;
483: }
484:
485: Object o = null;
486: String instErr = null;
487: if (className == null) {
488: className = class_obj.getName();
489: }
490: try {
491: o = class_obj.newInstance();
492: } catch (InstantiationException ie) {
493: instErr = "instance of class " + className
494: + " could not be created";
495: } catch (IllegalAccessException iae) {
496: instErr = "instance of class " + className
497: + " could not be created";
498: }
499: if (!(o instanceof TJC.CompiledCommand)) {
500: instErr = "instance of class " + className
501: + " must extend TJC.CompiledCommand";
502: }
503: if (instErr != null) {
504: status = false;
505: errorMsg = instErr;
506: readyReport();
507: return 1;
508: }
509: TJC.CompiledCommand cmdObj = (TJC.CompiledCommand) o;
510: try {
511: if (debug) {
512: System.out.println("now to create command \"" + cmd
513: + "\"");
514: }
515: TJC.createCommand(interp, cmd, cmdObj);
516: } catch (TclException te) {
517: status = false;
518: errorMsg = te.getMessage();
519: readyReport();
520: return 1;
521: }
522:
523: readyReport(); // Report success
524: return 1;
525: }
526:
527: // This method is invoked to indicate that a command has been
528: // compiled and installer, or that it failed. This method
529: // will set a -readyvar or invoke a -readycmd callback
530: // if one was indicated via the TJC::compile command.
531:
532: void readyReport() {
533: try {
534:
535: if (readyVar != null) {
536: // Set readyVar to: {STATUS CMDNAME MSG}
537: //
538: // STATUS: OK or FAIL
539: // CMDNAME: Name of Tcl command
540: // MSG: text of error message if (STATUS == FAIL)
541:
542: TclObject tlist = TclList.newInstance();
543:
544: // STATUS:
545: if (status) {
546: TclList.append(interp, tlist, TclString
547: .newInstance("OK"));
548: } else {
549: TclList.append(interp, tlist, TclString
550: .newInstance("FAIL"));
551: }
552:
553: // CMDNAME:
554: TclList.append(interp, tlist, TclString
555: .newInstance(cmd));
556:
557: // MSG:
558: TclList.append(interp, tlist, TclString
559: .newInstance(errorMsg));
560:
561: if (debug) {
562: System.out.println("now to set readyVar: "
563: + readyVar + " " + tlist);
564: }
565:
566: interp.setVar(readyVar, null, tlist, TCL.GLOBAL_ONLY);
567: } else if (readyCmd != null) {
568: // Invoke readyCmd with the following arguments:
569: // readyCmd STATUS CMDNAME MSG
570: //
571: // STATUS: OK or FAIL
572: // CMDNAME: Name of Tcl command
573: // MSG: text of error message if (STATUS == FAIL)
574:
575: TclObject tlist = TclList.newInstance();
576:
577: // readyCmd
578: TclList.append(interp, tlist, TclString
579: .newInstance(readyCmd));
580:
581: // STATUS:
582: if (status) {
583: TclList.append(interp, tlist, TclString
584: .newInstance("OK"));
585: } else {
586: TclList.append(interp, tlist, TclString
587: .newInstance("FAIL"));
588: }
589:
590: // CMDNAME:
591: TclList.append(interp, tlist, TclString
592: .newInstance(cmd));
593:
594: // MSG:
595: TclList.append(interp, tlist, TclString
596: .newInstance(errorMsg));
597:
598: if (debug) {
599: System.out
600: .println("now to eval readyCmd: " + tlist);
601: }
602:
603: interp.eval(tlist, TCL.EVAL_GLOBAL);
604: }
605:
606: } catch (TclException te) {
607: // TclException should not be thrown above
608: te.printStackTrace(System.err);
609: }
610: }
611: }
612:
613: // Helper class to load compiled class into the current
614: // thread.
615:
616: class TJCCompileJavaCmd extends TclEvent implements
617: TJCThread.CompiledClassReady {
618: final boolean debug = false;
619:
620: final Interp interp;
621: final TclObject javaInfo;
622: final String readyCmd;
623: final String readyVar;
624:
625: boolean status;
626: String errorMsg = "";
627:
628: ArrayList cnames; // Array of class names
629: ArrayList cdata; // Array of class bytes
630:
631: TJCCompileJavaCmd(Interp interp, String javaInfo, String readyCmd,
632: String readyVar) {
633: this .interp = interp;
634: // Allocate new TclObject so we don't need to worry about
635: // releasing it.
636: this .javaInfo = TclString.newInstance(javaInfo);
637: this .readyCmd = readyCmd;
638: this .readyVar = readyVar;
639: }
640:
641: // Invoked by TJCThread when a compile job is finished.
642: // This implementation will queue an event in the original
643: // thread that will define the Java class.
644:
645: public void compiled(final String geninfo, // Unused
646: final String jfilename, // File name for Java source,
647: // like "Test.java".
648: final String jsrcode, // Java source that was compiled.
649: final ArrayList cnames, // List of compiled class names.
650: final ArrayList cdata, // List of compiled class data as byte[].
651: final int status, final String msg) {
652: // Add an event to the thread safe Tcl event queue that
653: // will define the Java class.
654:
655: if (debug) {
656: System.out
657: .println("TJCCompileJavaCmd CompiledClassReady.compiled()");
658: System.out.println("geninfo was " + geninfo);
659: System.out.println("jfilename was " + jfilename);
660: System.out.println("jsrcode was " + jsrcode);
661: System.out.println("cnames was " + cnames);
662: if (cdata == null) {
663: System.out.println("cdata was null");
664: } else {
665: System.out.println("cdata length was " + cdata.size());
666: }
667: }
668:
669: // Check compile status:
670:
671: if (status == TJCThread.STATUS_OK) {
672: this .status = true;
673:
674: if (debug) {
675: System.out.println("Status was OK");
676: }
677: } else {
678: this .status = false;
679: this .errorMsg = msg;
680:
681: if (debug) {
682: System.out.println("Status was not OK");
683: System.out.println("errorMsg was \"" + this .errorMsg
684: + "\"");
685: }
686: }
687:
688: // A Java class declaration can compile into multiple classes.
689:
690: if (cdata == null) {
691: // Error should be indicated in errorMsg
692: } else {
693: this .cnames = cnames;
694: this .cdata = cdata;
695: }
696:
697: interp.getNotifier().queueEvent(this , TCL.QUEUE_TAIL);
698:
699: // Don't wait for the event to be processed in the
700: // original thread. Just continue to process the
701: // next event in TJCThread.
702: //event.sync();
703: }
704:
705: // Invoked by the original thread (not by TJCThread)
706: // when the original thread enters the event loop.
707: // This method will define the Java class in
708: // the interpreter.
709:
710: public int processEvent(int flags) {
711: Class cl;
712:
713: if (debug) {
714: System.out.println("TJCCompileJavaCmd.processEvent()");
715: }
716:
717: // If the compile failed, report that now
718: if (status == false) {
719: readyReport();
720: return 1;
721: }
722:
723: // Otherwise, load the classes via the TclClassLoader.
724:
725: TclClassLoader tclClassLoader = (TclClassLoader) interp
726: .getClassLoader();
727:
728: // Class names may or may not be known, if class name is the empty
729: // string then query the class name from the class object after
730: // the class is defined.
731:
732: ArrayList resolved_cnames = new ArrayList();
733:
734: for (int i = 0; i < cdata.size(); i++) {
735: String cname = null;
736: if (cnames != null) {
737: cname = (String) cnames.get(i);
738: if (cname.length() == 0) {
739: cname = null;
740: }
741: }
742: byte[] classBytes = (byte[]) cdata.get(i);
743: cl = tclClassLoader.defineClass(cname, classBytes);
744: if (cl == null) {
745: // Class could not be loaded, status is fail
746: status = false;
747: if (cname != null) {
748: errorMsg = "class \"" + cname
749: + "\" not loaded by TclClassLoader";
750: } else {
751: errorMsg = "class not loaded by TclClassLoader";
752: }
753: readyReport();
754: return 1;
755: }
756: if (cname == null) {
757: cname = cl.getName();
758: }
759: resolved_cnames.add(cname);
760: }
761: cnames = resolved_cnames;
762:
763: readyReport(); // Report success
764: return 1;
765: }
766:
767: // This method is invoked to indicate that a Java class
768: // was compiled and loaded, or that it failed. This method
769: // will set a -readyvar or invoke a -readycmd callback
770: // if one was indicated via the TJC::compile command.
771:
772: void readyReport() {
773: try {
774:
775: if (readyVar != null) {
776: // Set readyVar to: {STATUS CLASSNAMES MSG}
777: //
778: // STATUS: OK or FAIL
779: // CLASSNAMES: List of fully qualified Java class names
780: // MSG: text of error message if (STATUS == FAIL)
781:
782: TclObject tlist = TclList.newInstance();
783:
784: // STATUS:
785: if (status) {
786: TclList.append(interp, tlist, TclString
787: .newInstance("OK"));
788: } else {
789: TclList.append(interp, tlist, TclString
790: .newInstance("FAIL"));
791: }
792:
793: // CLASSNAMES:
794: TclObject cnames_list = TclList.newInstance();
795: if (cnames != null) {
796: for (int i = 0; i < cnames.size(); i++) {
797: String cname = (String) cnames.get(i);
798: TclList.append(interp, cnames_list, TclString
799: .newInstance(cname));
800: }
801: }
802: TclList.append(interp, tlist, cnames_list);
803:
804: // MSG:
805: TclList.append(interp, tlist, TclString
806: .newInstance(errorMsg));
807:
808: if (debug) {
809: System.out.println("now to set readyVar: "
810: + readyVar + " " + tlist);
811: }
812:
813: interp.setVar(readyVar, null, tlist, TCL.GLOBAL_ONLY);
814: } else if (readyCmd != null) {
815: // Invoke readyCmd with the following arguments:
816: // readyCmd STATUS CLASSNAMES MSG
817: //
818: // STATUS: OK or FAIL
819: // CLASSNAMES: List of fully qualified Java class names
820: // MSG: text of error message if (STATUS == FAIL)
821:
822: TclObject tlist = TclList.newInstance();
823:
824: // readyCmd
825: TclList.append(interp, tlist, TclString
826: .newInstance(readyCmd));
827:
828: // STATUS:
829: if (status) {
830: TclList.append(interp, tlist, TclString
831: .newInstance("OK"));
832: } else {
833: TclList.append(interp, tlist, TclString
834: .newInstance("FAIL"));
835: }
836:
837: // CLASSNAMES:
838: TclObject cnames_list = TclList.newInstance();
839: if (cnames != null) {
840: for (int i = 0; i < cnames.size(); i++) {
841: String cname = (String) cnames.get(i);
842: TclList.append(interp, cnames_list, TclString
843: .newInstance(cname));
844: }
845: }
846: TclList.append(interp, tlist, cnames_list);
847:
848: // MSG:
849: TclList.append(interp, tlist, TclString
850: .newInstance(errorMsg));
851:
852: if (debug) {
853: System.out
854: .println("now to eval readyCmd: " + tlist);
855: }
856:
857: interp.eval(tlist, TCL.EVAL_GLOBAL);
858: }
859:
860: } catch (TclException te) {
861: // TclException should not be thrown above
862: te.printStackTrace(System.err);
863: }
864: }
865:
866: // Get the fully qualified Java file name for the given
867: // javaInfo pair.
868:
869: String getJavaFileName() throws TclException {
870: TclObject obj = TclList.index(interp, javaInfo, 0);
871: String clName = obj.toString();
872:
873: // Generate file name from the class name.
874: // "Foo" -> "Foo.java"
875: // "one.two.Three" -> "one/two/Three.java"
876:
877: StringBuffer nbuff = new StringBuffer(64);
878: if (clName.indexOf('.') == -1) {
879: // Default package
880: nbuff.append(clName);
881: } else {
882: // Replace each instance of '.' with '/'
883: nbuff.append(clName.replace('.', '/'));
884: }
885: nbuff.append(".java");
886: return nbuff.toString();
887: }
888:
889: // Get the Java source code portion of the javaInfo pair.
890:
891: String getJavaSource() throws TclException {
892: TclObject src = TclList.index(interp, javaInfo, 1);
893: return src.toString();
894: }
895:
896: }
|