扩展OSGi控制台,通过web访问操作console,支持3.4、3.6

         当我们在开发基于OSGi的应用时,不可避免的要通过它的控制台进行相关调试。在开发阶段,调试可以直接在eclipse控制台输入相关命令,而当我们把程序部署到web服务器上后就不能再采用这样的方式了。但幸运的是,我们可以扩console以满足自己的需要,因此可以实现一个通过web访问console的方式。扩展conso可以参考基于 Equinox 的 OSGi Console 的研究和探索

         由于equinox 3.4和3.6在代码结构上的差异,要扩展一个通用的通过web控制的console,用反射是个好的选择,eg. FrameworkConsole的构造函数不一致,3.6已经没有OSGi这个类...以下是详细实现:

WebConsoleServlet.java,发布该servlet让客户端访问,并通过参数cmd传输相关的OSGi命令:

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
			IOException {
		response.setContentType("text/html;charset=utf-8");
		response.setCharacterEncoding("utf-8");
		try {
			String command = request.getParameter("cmd");
			try {
				final CommandServiceFacade facade = CommandServiceFacade.INSTANCE;
				facade.setContext(Activator.bundleContext);
				facade.setOut(response);
				facade.execute(command);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
CommandServiceFacade.java,封装具体实现:

public class CommandServiceFacade {
    private static final String OSGI_VERION_3_4 = "3.4";
    private static final String OSGI_VERION_3_6 = "3.6";

    /**
     * OSGi版本号.
     */
    private String osgiVersion = null;

    /**
     * bundle上下文容器.
     */
    private BundleContext context = null;

    /**
     * FrameworkConsole输出流,适用于OSGi3.4.
     */
    private PrintWriter out = null;

    /**
     * FrameworkConsole输出流,适用于OSGi3.6.
     */
    private OutputStream outputStream = null;

    /**
     * 单例.
     */
    public static final CommandServiceFacade INSTANCE = new CommandServiceFacade();

    /**
     * 私有构造函数.
     */
    private CommandServiceFacade() {
    }

    /**
     * 设置bundle上下文环境.
     * 
     * @param context
     *            bundle上下文容器.
     */
    public void setContext(final BundleContext context) {
        this.context = context;
    }

    /**
     * 设置Console输出流.
     */
    public void setOut(final HttpServletResponse response) {
        try {
            if (OSGI_VERION_3_6.equals(getOSGiVersion())) {
                this.outputStream = response.getOutputStream();
            } else if (OSGI_VERION_3_4.equals(getOSGiVersion())) {
                this.out = response.getWriter();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置控制台输出流.
     */
    public void setOut(final OutputStream os) {
        try {
            if (OSGI_VERION_3_6.equals(getOSGiVersion())) {
                this.outputStream = os;
            } else if (OSGI_VERION_3_4.equals(getOSGiVersion())) {
                this.out = new PrintWriter(new OutputStreamWriter(os, "GB2312"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * <pre>
     * 执行控制台命令. 
     * 由于OSGi3.4和3.6在代码结构上的差异,要扩展一个通用的通过web控制的console,用反射是个好的选择.
     * eg. FrameworkConsole的构造函数不一致,3.6已经没有OSGi这个类...
     * </pre>
     */
    public void execute(final String command) {
        if (null == command || command.length() == 0) {
            return;
        }
        final ClassLoader systemBundleCL = context.getBundle(0).getClass().getClassLoader();
        if (OSGI_VERION_3_6.equals(getOSGiVersion())) {
            try {
                final ServiceTracker cpTracker = new ServiceTracker(context, CommandProvider.class.getName(), null);
                cpTracker.open();
                final Class conSessClass = systemBundleCL
                        .loadClass("org.eclipse.osgi.framework.internal.core.FrameworkConsoleSession");
                final Constructor conSessConstructor = conSessClass.getConstructor(new Class[] { InputStream.class,
                        OutputStream.class, Socket.class });
                // Class FrameworkConsoleSession
                final Object conSess = conSessConstructor.newInstance(new Object[] {
                        new ByteArrayInputStream(command.getBytes()), outputStream, null });
                final Class fcClass = systemBundleCL
                        .loadClass("org.eclipse.osgi.framework.internal.core.FrameworkConsole");
                final Class csClass = systemBundleCL.loadClass("org.eclipse.osgi.framework.console.ConsoleSession");
                final Constructor fcConstructor = fcClass.getConstructor(new Class[] { BundleContext.class, csClass,
                        Boolean.TYPE, ServiceTracker.class });
                // Class FrameworkConsole
                final Object fc = fcConstructor
                        .newInstance(new Object[] { context, conSess, Boolean.FALSE, cpTracker });
                fcClass.getMethod("run", null).invoke(fc, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (OSGI_VERION_3_4.equals(getOSGiVersion())) {
            try {
                final Class fcClass = systemBundleCL
                        .loadClass("org.eclipse.osgi.framework.internal.core.FrameworkConsole");
                final Class osgiClass = systemBundleCL.loadClass("org.eclipse.osgi.framework.internal.core.OSGi");
                final Constructor fcConstructor = fcClass.getConstructor(new Class[] { osgiClass, String[].class });
                // Class FrameworkConsole
                final Object fc = fcConstructor.newInstance(new Object[] { getOsgi(), new String[0] });
                final Class intpClass = systemBundleCL
                        .loadClass("org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter");
                final Constructor intpConstructor = intpClass.getConstructor(new Class[] { String.class,
                        Object[].class, fcClass });
                // Class FrameworkCommandInterpreter
                final Object interpreter = intpConstructor.newInstance(new Object[] { command, getServices(), fc });
                final Field out = intpClass.getDeclaredField("out");
                out.setAccessible(true);
                out.set(interpreter, this.out);
                final Method nextArgument = intpClass.getMethod("nextArgument", null);
                final Method execute = intpClass.getMethod("execute", String.class);
                execute.invoke(interpreter, (String) nextArgument.invoke(interpreter, null));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // 暂不处理其他版本
        }
    }

    /**
     * 获取OSGi的版本,只取前2位.
     * 
     * @return OSGi的版本
     */
    private String getOSGiVersion() {
        if (null == this.osgiVersion && context != null) {
            this.osgiVersion = context.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION).toString()
                    .substring(0, 3);
        }
        return this.osgiVersion;
    }

    /**
     * OSGi framework对象.
     * 
     * @return OSGi framework.
     */
    private static Object getOsgi() {
        Object osgi = null;
        try {
            Field osgiField = EclipseStarter.class.getDeclaredField("osgi");
            osgiField.setAccessible(true);
            osgi = osgiField.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return osgi;
    }

    /**
     * @return service对象数组.
     */
    private Object[] getServices() {
        final ServiceTracker cptracker = new ServiceTracker(context, CommandProvider.class.getName(), null);
        cptracker.open();
        final ServiceReference[] serviceRefs = cptracker.getServiceReferences();
        if (serviceRefs == null) {
            return new Object[0];
        }
        Util.dsort(serviceRefs, 0, serviceRefs.length);
        final Object[] serviceObjects = new Object[serviceRefs.length];
        for (int i = 0; i < serviceRefs.length; i++) {
            serviceObjects[i] = context.getService(serviceRefs[i]);
        }
        return serviceObjects;
    }
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值