首页 文章

使用Eclipse启动任务将展开的软件包部署到Apache Felix

提问于
浏览
1

我正在寻找一种方法来(重新)部署一个爆炸的捆绑包(意思是没有震动,但在文件夹中)从Eclipse内部运行Apache Felix OSGi容器,最好是使用启动任务 .

我找到了this问题,答案很接近,但这取决于在Gogo shell中输入命令,这对于长期开发使用来说不方便 . 我为此启动了任务机制,但如果有同样快速和方便的替代方案,我也对此持开放态度 .

现在我认为如果我可以从Eclipse启动任务中发出Gogo shell命令,那将是一个解决方案,但我也无法理解如何做到这一点 . 我认为我需要Remote Shell捆绑包吗?

我开始考虑用Java编写一个telnet客户端,它可以连接到Remote Shell软件包并以自动方式执行Gogo命令 . 我已经看过some example已经可以根据我的需要进行修改......但是我从中得到了一种感觉'reinventing the wheel' . 当然有更好的方法吗?

一些背景知识可以帮助您了解我在做什么:

我已经设置了一个Eclipse 'OSGiContainer'项目,该项目基本上包含Apache Felix jar和我要部署的第三方软件包(如Gogo shell),类似于here描述的项目设置 . 然后我创建了第二个包含我的包的'MyBundle'项目 . 我想通过启动OSGiContainer项目来启动OSGi容器,然后在我的bundle上开发并通过将MyBundle项目启动到OSGiContainer来测试我的更改,我想在开发过程中保持一直运行 .

项目布局:

  • OSGiContainer

  • bin(包含felix jar)

  • 捆绑(第三方捆绑)

  • conf(Felix'config.properties文件)

  • MyBundle

  • src

  • 目标

然后我可以通过在Gogo shell上调用这些命令将我的bundle部署到OSGi容器:

install reference:file:../MyBundle/target/classes
start <bundleId>

要重新部署,我调用这些命令:

stop <bundleId>
uninstall <bundleId>
install reference:file:../MyBundle/target/classes
start <bundleId>

你可以想象每次在shell上调用4个命令都不是那么有趣......所以即使你能给我一个方法来把它归结为更少的命令来输入它也将是一个很大的改进 .

UPDATE

我唠叨了一下,想出了下面的课程 . 它是telnet示例的一个改编版本,带有一些小的更改和一个main方法,带有必要的命令来卸载一个bundle然后重新安装并启动它 . bundle的路径应作为程序的参数给出,如下所示:

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());
        }
    }
}

1 回答

  • 1

    当我遇到相同的要求(尽可能快地从目标/类部署bundle)时,我的第一个想法也是扩展我的容器的一些shell功能 . 然而,我的第二个想法是编写一个简单的包,打开一个永远在顶部的窗口,我只需将Eclipse(或总指挥官或其他)中的任何项目拖放到该窗口即可 . 代码检查被删除的文件夹是否具有目标/类文件夹以及是否具有该文件夹将被部署 .

    源代码位于https://github.com/everit-org/osgi-richconsole

    依赖关系可以从maven-central获得 .

    依赖是:

    <dependency>
        <groupId>org.everit.osgi.dev</groupId>
        <artifactId>org.everit.osgi.dev.richconsole</artifactId>
        <version>1.2.0</version>
    </dependency>
    

    您可以在开发时使用它,并在设置实时服务器时将其删除 . 然而,没有必要好像容器在无头模式下运行,弹出窗口未示出 .

    我称之为richconsole,因为我希望将来有更多的功能(不只是部署):)

相关问题