我第一个JAVA程序终于完成了,是一个eclipse的控制台插件。本插件的目的是,实现一个通用的控制台,当启动一个进程时,将进程的输入输出显示在Console View中。
Console的使用,通过接口来完成。主要的方法是open和close。当然可以继续增加其它一些方法,如改变尺寸等
public interface IMyConsole {
void open();
void close();
...
}
希望使用时能够尽量简便,例如希望在eclipse中开启一个cmd控制台:
IMyConsole console;
...
ProcessBuilder builder = new ProcessBuilder("cmd.exe");
try {
Process proc = builder.start();
console = new ConsoleFactory("Windows cmd", null,
proc.getOutputStream(),
proc.getInputStream(),
proc.getErrorStream());
console.open();
} catch (IOException e) {
e.printStackTrace();
}
...
实例化console时候,需要指明控制台的stdin,stdout和stderr。这样就可以灵活用于各种情况,如执行一个进程、socket流、文件流等。同时,也可以指定只使用stdout和stderr,作为纯粹的输出控制台。当然,如果将这些用法再封装一层就好了。实例创建出来后,调用open()方法即可打开控制台。
类的框架如下:
(研究了几个小时UML,结果发现这东西不是一会就能玩明白的,干脆用土办法画图了)
Console插件说白了就是五个数据流:键盘输入,屏幕输出,目标的stdin/stdout/stderr。这几个接起来就搞定了。数据流中间要分别建立线程,用BufferedStream来读写。分别建立线程是防止阻塞,而用Buffer是提高效率。这些东西要是都用C来写,那可就麻烦了。JAVA里面全都帮我搞定了,很舒服。
下面具体实现:
1)新建一个Plug-in Project,选择”Hello, World”模板。这个模板创建一个工具栏上的按钮,点击此按钮后出现一个显示”Hello, World”的Messagebox。以此为基础进行修改。
2)向导中点击Finish后,默认打开的是menifest.mf。点击View下方的Dependences标签,在左侧的Required Plug-ins栏选”Add…”,输入org.eclipse.ui.console,选择”OK”。这是基本的控制台插件。按”ctrl-s”保存。
3)在下方Extensions标签栏中,点击”add…”,找到org.eclipse.ui.consoleFactories,选中后,点击”Finish”。这就增加了一个Console View,用于控制台的操作和显示。按”ctrl-s”保存。
4)点击右侧”class*:”,创建一个新class。使用默认设置即可。
5)然后写代码:
Action.java:
package com.study.terminal.actions;
public class SampleAction implements IWorkbenchWindowActionDelegate {
...
private IMyConsole console;//加上这个
...
//修改这个
public void run(IAction action) {
ProcessBuilder builder = new ProcessBuilder("cmd.exe");
try {
Process proc = builder.start();
console = new ConsoleFactory("MyConsole", null, proc
.getOutputStream(), proc.getInputStream(), proc
.getErrorStream());
console.open();
} catch (IOException e) {}
...
}
}
IMyConsole.java:
package com.study.terminal;
public interface IMyConsole {
void open();
void close();
}
ConsoleFactory.java:
package com.study.terminal;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleListener;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.IOConsole;
import org.eclipse.ui.console.IOConsoleInputStream;
import org.eclipse.ui.console.IOConsoleOutputStream;
public class ConsoleFactory extends IOConsole implements IMyConsole {
private IOConsoleInputStream bisInInner;// keyboard input stream
private BufferedOutputStream bosOutOuter;// stream output to app
private IOConsoleOutputStream bosOutInner;// stream output to console view
private BufferedInputStream bisInOuter;// stream input from app's stdout
private IOConsoleOutputStream bosErrInner;// stream output to console view
private BufferedInputStream bisErrOuter;// stream input from app's stderr
private class streamThread implements Runnable {
private InputStream is;
private OutputStream os;
public streamThread(InputStream is, OutputStream os) {
this.is = is;
this.os = os;
}
public void run() {
if (is == null || os == null) {
return;
}
byte[] data = new byte[1];
try {
while (is.read(data) != -1) {
switch (data[0]) {
case '\n':
os.write(data);
os.flush();
break;
case '\r':
// ignore it
break;
default:
os.write(data);
break;
}
}
} catch (IOException e) {
close();
}
}
}
private class Listener implements IConsoleListener {
@Override
public void consolesAdded(IConsole[] consoles) {
}
@Override
public void consolesRemoved(IConsole[] consoles) {
for (int i = 0; i < consoles.length; i++) {
if (ConsoleFactory.this == consoles[i]) {
ConsolePlugin.getDefault().getConsoleManager()
.removeConsoleListener(this);
close();
}
}
}
}
public ConsoleFactory(String name, ImageDescriptor imageDescriptor,
OutputStream stdinOuter, InputStream stdoutOuter,
InputStream stderrOuter) {
super(name, imageDescriptor);
IConsoleManager manager = ConsolePlugin.getDefault()
.getConsoleManager();
manager.addConsoleListener(new Listener());
IConsole[] existing = manager.getConsoles();
boolean exists = false;
for (int i = 0; i < existing.length; i++) {
if (this == existing[i])
exists = true;
}
if (!exists) {
if (stdinOuter != null) {
bisInInner = getInputStream();
bosOutOuter = new BufferedOutputStream(stdinOuter);
}
if (stdoutOuter != null) {
bosOutInner = newOutputStream();
bisInOuter = new BufferedInputStream(stdoutOuter);
}
if (stderrOuter != null) {
bosErrInner = newOutputStream();
bisErrOuter = new BufferedInputStream(stderrOuter);
}
manager.addConsoles(new IConsole[] { this });
}
}
public void open() {
IConsoleManager manager = ConsolePlugin.getDefault()
.getConsoleManager();
manager.showConsoleView(this);
// keyboard input thread
if (bisInInner != null && bosOutOuter != null) {
streamThread stdinThread = new streamThread(bisInInner, bosOutOuter);
new Thread(stdinThread).start();
}
// stdout of app
if (bisInOuter != null && bosOutInner != null) {
streamThread stdoutThread = new streamThread(bisInOuter,
bosOutInner);
new Thread(stdoutThread).start();
}
// stderr of app
if (bisErrOuter != null && bosErrInner != null) {
streamThread stderrThread = new streamThread(bisErrOuter,
bosErrInner);
new Thread(stderrThread).start();
}
}
public void close() {
try {
if (bisInInner != null) {
bisInInner.close();
bisInInner = null;
}
} catch (IOException e) {
}
try{
if (bosOutOuter != null) {
bosOutOuter.flush();
bosOutOuter.close();
bosOutOuter = null;
}
} catch (IOException e) {
}
try {
if (bisInOuter != null) {
bisInOuter.close();
bisInOuter = null;
}
} catch (IOException e) {
}
try {
if (bosOutOuter != null) {
bosOutOuter.flush();
bosOutOuter.close();
bosOutOuter = null;
}
} catch (IOException e) {
}
try {
if (bisErrOuter != null) {
bisErrOuter.close();
bisErrOuter = null;
}
} catch (IOException e) {
}
try {
if (bosErrInner != null) {
bosErrInner.flush();
bosErrInner.close();
bosErrInner = null;
}
} catch (IOException e) {
}
IConsoleManager manager = ConsolePlugin.getDefault()
.getConsoleManager();
manager.removeConsoles(new IConsole[] { this });
}
}