001: package tcl.lang;
002:
003: import java.lang.reflect.*;
004:
005: /**
006: * This command is the only means to safely call a blocking
007: * Java method like a modal AWT dialog box. If you used
008: * java::call directly the entire application would hang
009: * because the AWT blocks the calling thread in an AWT
010: * modal dialos show() method. You would use this command
011: * in place of the java::call method or a java instance
012: * method. It will invoke a static or instance Java method
013: * using another thread so that the calling thread will not block.
014: * This command is unsupported and undocumented so you should
015: * only need to use it if you run into this problem.
016: */
017:
018: public class UnsupportedJDetachCallCmd implements Command, Runnable {
019: private boolean inuse = false;
020:
021: private Thread t = null;
022: private boolean started = false; // true if "detached" thread is running
023:
024: // These are the Java objects that we pass over to the other
025: // thread so that it can invoke the method.
026:
027: private Object[] call_args;
028: private Method call_method;
029: private Object call_javaObj;
030:
031: public void cmdProc(Interp interp, TclObject[] argv)
032: throws TclException {
033:
034: if (argv.length < 3) {
035: throw new TclNumArgsException(interp, 1, argv,
036: "classorObj signature ?arg arg ...?");
037: }
038:
039: int startIdx = 3;
040: int count = argv.length - startIdx;
041:
042: if (inuse) {
043: throw new TclException(interp,
044: "java_detachcall invoked when Thread was already in use");
045: }
046:
047: // get java objects needed in the call
048:
049: TclObject reflectObj = argv[1];
050: TclObject signature = argv[2];
051:
052: //System.out.println("reflectObj is \"" + reflectObj + "\"");
053: //System.out.println("signature is \"" + signature + "\"");
054:
055: Class javaCl;
056:
057: try {
058: // try to get the class by name
059: call_javaObj = null;
060: javaCl = JavaInvoke.getClassByName(interp, reflectObj
061: .toString());
062: } catch (TclException e) {
063: // if that did not work it must be a reflect object
064:
065: try {
066: call_javaObj = ReflectObject.get(interp, reflectObj);
067: javaCl = ReflectObject.getClass(interp, reflectObj);
068: } catch (TclException e2) {
069: throw new TclException(interp,
070: "unknown java class or object \"" + reflectObj
071: + "\"");
072: }
073: }
074:
075: FuncSig sig;
076:
077: // Check for a static method signature first, then try and instance sig.
078: try {
079: sig = FuncSig.get(interp, javaCl, signature, argv,
080: startIdx, count, true);
081: } catch (TclException e) {
082: sig = FuncSig.get(interp, javaCl, signature, argv,
083: startIdx, count, false);
084: }
085:
086: call_method = (Method) sig.func;
087:
088: //System.out.println("call_javaObj is \"" + call_javaObj + "\"");
089: //System.out.println("javaCl is \"" + javaCl + "\"");
090: //System.out.println("call_method is \"" + call_method + "\"");
091:
092: Class[] paramTypes = call_method.getParameterTypes();
093:
094: if (count != paramTypes.length) {
095: throw new TclException(interp, "wrong # args for calling "
096: + "method \"" + signature + "\"");
097: }
098:
099: if (count == 0) {
100: call_args = new Object[0];
101: } else {
102: call_args = new Object[count];
103: for (int i = 0; i < count; i++) {
104: call_args[i] = JavaInvoke.convertTclObject(interp,
105: paramTypes[i], argv[i + startIdx]);
106: }
107: }
108:
109: // create the thread if it was not done already
110:
111: if (t == null) {
112: t = new Thread(this );
113: t.setDaemon(true);
114: t.setName("DetachCall service");
115: t.start();
116:
117: //System.out.println("java_detachcall: created thread");
118: //System.out.flush();
119:
120: // wait until the other thread has been started and is waiting
121: // for an event to process from this thread
122:
123: while (!started) {
124: Thread.yield();
125: Thread.yield();
126: }
127:
128: Thread.yield();
129: Thread.yield();
130: Thread.yield();
131:
132: //System.out.println("java_detachcall: thread has been started");
133: //System.out.flush();
134:
135: }
136:
137: // signal the other thread
138:
139: //System.out.println("java_detachcall: thread has been signaled");
140: //System.out.flush();
141:
142: synchronized (this ) {
143: notify(); // tell other thread it should process the call
144: }
145:
146: // return from this method invocation with no result
147: interp.resetResult();
148:
149: //System.out.println("java_detachcall: returning");
150: //System.out.flush();
151:
152: }
153:
154: public void run() {
155: started = true; // set once to indicate that this thread is ready
156:
157: //System.out.println("detached_thread: started up");
158: //System.out.flush();
159:
160: // enter service loop waiting for blocking Java calls
161:
162: //System.out.println("detached_thread: entering service loop");
163: //System.out.flush();
164:
165: while (true) {
166: inuse = false;
167:
168: try {
169: synchronized (this ) {
170: wait(); // wait for next service request
171: }
172: } catch (InterruptedException e) {
173: e.printStackTrace();
174: }
175:
176: //System.out.println("detached_thread: servicing event");
177: //System.out.flush();
178:
179: inuse = true;
180:
181: // service the event by invoking the Java method
182:
183: try {
184: call_method.invoke(call_javaObj, call_args);
185: } catch (Exception e) {
186: e.printStackTrace();
187: }
188:
189: // do nothing with the result of the method invocation
190: }
191:
192: }
193:
194: }
|