破门点滴(Java技术版)

在日常学习和工作中记录

  语源科技BlogJava :: 首页 ::  :: 聚合  :: 管理
  15 Posts :: 7 Stories :: 36 Comments :: 0 Trackbacks
根据插件ID(Namespace)和路径找出视图源文件
2004-12-23 19:58:14

主要任务,根据插件 ID ( Namespace )和路径找出视图源文件。

基本上完成文件的读取:

              Bundle nsbundle = Platform.getBundle(pluginId);  // 获取 bundle( 插件 )

              URL url = nsbundle.getEntry( target );             //    获取资源路径

              url = Platform.asLocalURL( url );             // 返回物理文件路径 URL

 

以上参数说明:

pluginId 插件 ID                     例如: org.softme.triones.hello

              target   资源文件相对路径    例如: templates/index.vm

 

结果范例:

file:/D:/netshop/triones/plugins/org.softme.triones.hello_0.0.1/templates/index. vm

其中: file:/D:/netshop/triones/ 是 Triones 系统安装路径。

第二步:创建 netshop web 应用

问题出现:

2004-12-23 19:46:38 StandardContext[/netshop]Exception sending context initialized event to listener instance of class org.softme.triones.TrionesContextListener

java.lang.Error: factory already defined

         at java.net.URL.setURLStreamHandlerFactory(Unknown Source)

         at org.eclipse.osgi.framework.internal.core.Framework.initialize(Framework.java:154)

         at org.eclipse.osgi.framework.internal.core.Framework.<init>(Framework.java:95)

         at org.eclipse.osgi.framework.internal.core.OSGi.createFramework(OSGi.java:90)

         at org.eclipse.osgi.framework.internal.core.OSGi.<init>(OSGi.java:31)

         at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:215)

         at org.softme.triones.launcher.TrionesStarter.basicRun(TrionesStarter.java:1063)

         at org.softme.triones.launcher.TrionesStarter.launch(TrionesStarter.java:672)

         at org.softme.triones.TrionesContextListener.contextInitialized(TrionesContextListener.java:51)

 

原因:在一个虚拟机中,该方法只能被调用一次。

参考:

“ java.net.URL 是各种协议,包括已知和未知的入口,通过 URL.setURLStreamHandlerFactory(URLStreamHandlerFactory handlerFactory) 方法可以设置新的协议处理器的工厂类的实例,在一个虚拟机中,该方法只能被调用一次。除了利用这种方式向系统注册外,还可以通过设置系统属性 java.handler.protol.pkg 或者 sun.net.www.protocol 来实现注册。系统会按照 setURLStreamHandlerFactory() 、 java.handler.protol.pkg 、 sun.net.www.protocol 三种方法,从高优先级到低优先级的进行搜索特定协议对应的处理器。 java.handler.protol.pkg 对应的值的构成是用 | 分隔的各个协议处理器的类,格式为 ..Handler | ..Handler | ... 。 sun.net.www.protocol 的设置方式是 sun.net.www.protocol..Handler ,这个 sun.net.www.protocol..Handler 会被追加到第二种方式得到的值后面,然后逐个加载。注意,设置属性的时候,只需要写上 handler 的 package 中 protocol 之前的部分,例如对于 myProtocol 协议,则, myProtocol 的处理器的类命名格式为 myPackage.myProtocol.Handler ,或者是 sun.net.www.protocol.myProtocol.Handler, 设置属性的时候,只需要写上 myPackage 即可,剩下的部分, URL 类会自动处理的。

 

看样子必须改回用反射来初始化框架了。

改回成反射调用的模式依然出现以上错误,看来可能是与 tomcat 发生了冲突,先下 tomcat 的源码等明天查查看。

果然,发现 Tomcat 已经调用了此方法: org.apache.catalina.loader.WebappLoader

// Register a stream handler factory for the JNDI protocol

        URLStreamHandlerFactory streamHandlerFactory =

            new DirContextURLStreamHandlerFactory();

        if (first) {

            first = false;

            try {

                URL.setURLStreamHandlerFactory(streamHandlerFactory);

            } catch (Exception e) {

                // Log and continue anyway, this is not critical

                log.error("Error registering jndi stream handler", e);

            } catch (Throwable t) {

                // This is likely a dual registration

                log.info("Dual registration of jndi stream handler: "

                         + t.getMessage());

            }

        }

 

尝试将 Eclipse 中 OSGi 的 Framework 对象进行更改:

org.eclipse.osgi.framework.internal.core.Framework

initialize() 方法,跳过二次注册 setURLStreamHandlerFactory 的错误:

/* install URLStreamHandlerFactory */

                   try{

                            URL.setURLStreamHandlerFactory(new

 StreamHandlerFactory(systemBundle.context, adaptor));

                   } catch (Throwable t) {

                            // This is likely a dual registration

                            if (Debug.DEBUG && Debug.DEBUG_GENERAL)

                                     System.out.println("Dual registration of jndi stream handler: "

                     + t.getMessage());

                   }

 

运行出现错误, Eclipse 无法加载插件:

j ava.net.MalformedURLException: unknown protocol: reference

         at java.net.URL.<init>(Unknown Source)

         at org.eclipse.core.runtime.adaptor.EclipseStarter.searchForBundle(EclipseStarter.java:366)

         at org.eclipse.core.runtime.adaptor.EclipseStarter.getInitialBundles(EclipseStarter.java:466)

         at org.eclipse.core.runtime.adaptor.EclipseStarter.loadBasicBundles(EclipseStarter.java:418)

         at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:222)

         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

         at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

         at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

         at java.lang.reflect.Method.invoke(Unknown Source)

         at org.softme.triones.launcher.TrionesInvokeStarter.basicRun(TrionesInvokeStarter.java:342)

         at org.softme.triones.launcher.TrionesInvokeStarter.launch(TrionesInvokeStarter.java:899)

         at org.softme.triones.TrionesContextListener.

 

只能先研究以上参考中更新 protocol 注册的第二种或第三种方法了。

Eclipse 采用了 URLStreamHandlerProxy 的代理机制来处理,实际的服务定义在 OSGi 的 service org.osgi.service.url. URLStreamHandlerService 实现中。解决了 Java JVM 对 URLStreamHandler 进行缓存而不能支持动态加载的问题。

因此,看来不能够去掉 Eclipse 中对 URL. setURLStreamHandlerFactory 的调用。

 

解决办法呢? ………………………………………….????????????????????????

 

讨论:

方案一:在 JVM 的 URL 协议注册机制中寻求其他入口点。

困难度 100 %: JVM 协议注册的第二种和第三种方法都无法支持 Eclipse 的入口。

因为 Eclipse 通过对 Factory 的扩展支持了协议处理器( Handler )的动态加载,以及嵌入了 OSGi 服务机制,所以无法采取其他入口实现 Eclipse 加载机制。

方案二:修改 Eclipse 框架,避开 setURLStreamHandlerFactory 的调用。

困难度 100% :原因同上。

方案三:修改 JRE 中 java.net.URL 对象,允许多 factory 设置。

困难度 10% 。



不得窥道门,不得悟佛门,不得入窄门,实乃破门。
posted on 2006-03-27 10:29 破门 阅读(858) 评论(0)  编辑  收藏 所属分类: Triones