我正在寻找一种方法来从 Eclipse 中(重新)部署一个分解的捆绑包(意味着不是 jarred,而是在一个文件夹中)到一个正在运行的 Apache Felix OSGi 容器,最好使用启动任务。
我发现了这个问题,它有一个接近的答案,但它取决于在 Gogo shell 中输入命令,这不方便长期开发使用。我想为此使用 Eclipse 的启动任务机制,但如果有同样快速和方便的替代方案,我也愿意接受。
现在我认为,如果我可以从 Eclipse 启动任务中触发 Gogo shell 命令,那将是一个解决方案,但我也无法理解如何做到这一点。我想我需要 Remote Shell 捆绑包,对吗?
我开始考虑用 Java 编写一个 telnet 客户端,它可以连接到 Remote Shell 包并以自动方式执行 Gogo 命令。我已经看到了一些 示例,我可以对其进行修改以满足我的需要……但是,我从中得到了一种“重新发明轮子”的感觉。肯定有更好的方法吗?
一些背景可以帮助您了解我在做什么:
我已经建立了一个 Eclipse 'OSGiContainer' 项目,它基本上包含 Apache Felix jar 和我想要部署的第三方包(如 Gogo shell),类似于此处描述的项目设置。然后我创建了第二个包含我的包的“MyBundle”项目。我想通过启动 OSGiContainer 项目来启动 OSGi 容器,然后在我的包上进行开发并通过将 MyBundle 项目启动到我只想在开发过程中一直运行的 OSGiContainer 中来测试我的更改。
项目布局:
- OSGi容器
- bin(包含 felix jar)
- 捆绑包(第三方捆绑包)
- conf(Felix 的 config.properties 文件)
- 我的捆绑
- 源代码
- 目标
- 班级
然后我可以通过在 Gogo shell 上调用这些命令将我的包部署到 OSGi 容器:
install reference:file:../MyBundle/target/classes
start <bundleId>
要重新部署,我调用这些命令:
stop <bundleId>
uninstall <bundleId>
install reference:file:../MyBundle/target/classes
start <bundleId>
您可以想象每次必须在 shell 上调用 4 个命令并没有那么有趣……因此,即使您可以给我一种方法来将其归结为更少的命令来键入,这已经是一个很大的改进了。
更新
我修改了一下,想出了下面的课程。它是对 telnet 示例的改编,做了一些小改动,并提供了一个带有必要命令的 main 方法,用于卸载捆绑包,然后重新安装并启动它。捆绑包的路径应作为程序的参数给出,如下所示:
reference:file:../MyBundle/target/classes
我仍然非常欢迎这个问题的答案,因为我根本不喜欢这个解决方案。然而,我已经证实这有效:
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.SocketException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.net.telnet.TelnetClient;
public class GogoDeployer {
static class Responder extends Thread {
private StringBuilder builder = new StringBuilder();
private final GogoDeployer checker;
private CountDownLatch latch;
private String waitFor = null;
private boolean isKeepRunning = true;
Responder(GogoDeployer checker) {
this.checker = checker;
}
boolean foundWaitFor(String waitFor) {
return builder.toString().contains(waitFor);
}
public synchronized String getAndClearBuffer() {
String result = builder.toString();
builder = new StringBuilder();
return result;
}
@Override
public void run() {
while (isKeepRunning) {
String s;
try {
s = checker.messageQueue.take();
} catch (InterruptedException e) {
break;
}
synchronized (Responder.class) {
builder.append(s);
}
if (waitFor != null && latch != null && foundWaitFor(waitFor)) {
latch.countDown();
}
}
System.out.println("Responder stopped.");
}
public String waitFor(String waitFor) {
synchronized (Responder.class) {
if (foundWaitFor(waitFor)) {
return getAndClearBuffer();
}
}
this.waitFor = waitFor;
latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
String result = null;
synchronized (Responder.class) {
result = builder.toString();
builder = new StringBuilder();
}
return result;
}
}
static class TelnetReader extends Thread {
private boolean isKeepRunning = true;
private final GogoDeployer checker;
private final TelnetClient tc;
TelnetReader(GogoDeployer checker, TelnetClient tc) {
this.checker = checker;
this.tc = tc;
}
@Override
public void run() {
InputStream instr = tc.getInputStream();
try {
byte[] buff = new byte[1024];
int ret_read = 0;
do {
if (instr.available() > 0) {
ret_read = instr.read(buff);
}
if (ret_read > 0) {
checker.sendForResponse(new String(buff, 0, ret_read));
ret_read = 0;
}
} while (isKeepRunning && (ret_read >= 0));
} catch (Exception e) {
System.err.println("Exception while reading socket:" + e.getMessage());
}
try {
tc.disconnect();
checker.stop();
System.out.println("Disconnected.");
} catch (Exception e) {
System.err.println("Exception while closing telnet:" + e.getMessage());
}
}
}
private static final String prompt = "g!";
private static GogoDeployer client;
private String host;
private BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();
private int port;
private TelnetReader reader;
private Responder responder;
private TelnetClient tc;
public GogoDeployer(String host, int port) {
this.host = host;
this.port = port;
}
public void stop() {
responder.isKeepRunning = false;
reader.isKeepRunning = false;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
responder.interrupt();
reader.interrupt();
}
public void send(String command) {
PrintStream ps = new PrintStream(tc.getOutputStream());
ps.println(command);
ps.flush();
}
public void sendForResponse(String s) {
messageQueue.add(s);
}
public void connect() throws SocketException, IOException {
tc = new TelnetClient();
tc.connect(host, port);
reader = new TelnetReader(this, tc);
reader.start();
responder = new Responder(this);
responder.start();
}
public String waitFor(String s) {
return responder.waitFor(s);
}
private static String exec(String cmd) {
String result = "";
System.out.println(cmd);
client.send(cmd);
result = client.waitFor(prompt);
return result;
}
public static void main(String[] args) {
try {
String project = args[0];
client = new GogoDeployer("localhost", 6666);
client.connect();
System.out.println(client.waitFor(prompt));
System.out.println(exec("uninstall " + project));
String result = exec("install " + project);
System.out.println(result);
int start = result.indexOf(":");
int stop = result.indexOf(prompt);
String bundleId = result.substring(start + 1, stop).trim();
System.out.println(exec("start " + bundleId));
client.stop();
} catch (SocketException e) {
System.err.println("Unable to conect to Gogo remote shell: " + e.getMessage());
} catch (IOException e) {
System.err.println("Unable to conect to Gogo remote shell: " + e.getMessage());
}
}
}