|
|
|
|
|
|
Mixing Cocoa, Java, a Command Line application, and Threads on Mac OS X
by Matt Warner <http://www.warnertechnology.com>
Summary
When Apple introduced Mac OS X, Cocoa became framework for "native" (non-Carbon) applications. The language of choice, or at least the one in all the documentation, is Objective C. Personally, I'm not thrilled with the idea of learning the semantics of Objective C since I'm already familiar with C, C++, and Java. Fortunately, Cocoa supports development in Java, although the documentation and examples are sparse. This tutorial is an attempt to document by example working with Java and Cocoa. The example here simply puts a GUI on the "ls" (list) command, which is called in a thread.
Details
There are two ways to do threads in Java. Sun's web site tries to explain the difference, but it wasn't very clear, IMHO.
See the "implements Runnable" approach and the "extends Thread" approach below. You can also Download the example project (10KB; contains both versions).
Java code using the Runnable Thread approach.
|
/* do_ls */
import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;
import java.io.*;
public class do_ls implements Runnable {
private Thread lsThread=null;
static Process theProcess;
NSButton doButton; /* IBOutlet */
NSTextView lsoutput; /* IBOutlet */
NSTextField toList; /* IBOutlet */
public void getls(NSTextField sender) { /* IBAction */
doButton.setTitle("running");
doButton.setEnabled(false);
try {
if (lsThread!=null) {
// wait up to 1 second (1000ms) for it to finish, and then just kill it if it's
// not playing nice
lsThread.join(1000);
if (lsThread.isAlive()) {
System.out.println("Thread still alive.");
System.out.println("Interrupting old thread.");
lsThread.interrupt();
System.out.println("Done with old thread.");
}
lsThread=null;
}
} catch (Exception e) { System.out.println("Error while joining thread "+e); }
if (lsThread == null) {
lsThread = new Thread(this,toList.stringValue());
lsThread.start();
//while (lsThread.isAlive()) {
// do nothing in this case. Just wait.
// }
//System.out.println("Thread finished");
}
}
public void run() {
Thread myThread=Thread.currentThread();
BufferedReader theReader=null;
String theoutput=new String();
//while (lsThread==myThread) {
try {
theProcess=Runtime.getRuntime().exec("/bin/ls -l "+myThread.getName());
theReader=new BufferedReader(new InputStreamReader(theProcess.getInputStream()));
if (theReader!=null) {
while ((theoutput=theReader.readLine())!=null) {
appendResultText(theoutput+"\n");
}
}
else appendResultText("No output to list");
} catch (Exception e){
System.out.println("Threw an exception in the runtime: "+e);
// the VM doesn't want us to sleep anymore,
// so get back to work
}
// we're done, so reenable the button
try {
theProcess.destroy();
doButton.setTitle("Do It");
doButton.setEnabled(true);
// terminate and rejoin the parent
}
catch (Exception e) { System.out.println("Error while cleaning up thread "+e); }
//}
}
public void appendResultText(String theText) {
//System.err.println("appendResultText was called.");
NSRange position=new NSRange(lsoutput.string().length(), 0);
lsoutput.replaceCharactersInRange(position, theText);
}
}
|
This is the "extends Thread" example:
|
/* do_ls */
// Written 13 April 2002 by Matt Warner <matt@warnertechnology.com>
// This is the version that uses the "extends Thread" version of Java threads
//
import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;
import java.io.*;
public class do_ls {
NSButton doButton; /* IBOutlet */
NSTextView lsoutput; /* IBOutlet */
NSTextField toList; /* IBOutlet */
public void getls(NSTextField sender) { /* IBAction */
doButton.setTitle("running");
doButton.setEnabled(false);
new fetchls(toList.stringValue()).start();
// here we can return control to the system while the thread will does its thing.
// The thread reenables the button once it's finished, so we're done here.
}
public void appendResultText(String theText) {
NSRange position=new NSRange(lsoutput.string().length(), 0);
lsoutput.replaceCharactersInRange(position, theText);
}
class fetchls extends Thread {
private String theString;
public fetchls(String theString) {
super(theString);
this.theString=theString;
}
public void run() {
BufferedReader theReader=null;
String theoutput=new String();
Process theProcess=null;
// this next step would be necessary for a thread that repeatedly does something
// and has to be sent a signal to stop gracefully. This is essentially a semaphore.
// while (somevariable==true) {
try {
theProcess=Runtime.getRuntime().exec("/bin/ls -l "+theString);
theReader=new BufferedReader(new InputStreamReader(theProcess.getInputStream()));
if (theReader!=null) {
while ((theoutput=theReader.readLine())!=null) {
appendResultText(theoutput+"\n");
}
}
else appendResultText("No output to list");
} catch (Exception e){
System.out.println("Threw an exception in the runtime: "+e);
}
// we're done, so reenable the button
try {
theProcess.destroy();
doButton.setTitle("Do It");
doButton.setEnabled(true);
}
catch (Exception e) { System.out.println("Error while cleaning up thread "+e); }
//}
}
}
}
|
|