执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件
Posted
技术标签:
【中文标题】执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件【英文标题】:How to reference an included file in OSGi bundle when performing java.io.File or FileInputStream 【发布时间】:2011-04-18 03:22:33 【问题描述】:我正在使用 aQute Bnd 工具集来创建一个 OSGi 包,并与一些依赖的“资源”文件打包在一起。这包括我创建的资源目录中的 *.css 文件和 *.xsd 文件。
我在 bundle.bnd 文件中包含以下内容:
Include-Resource: resources/=resources/
当我进行构建时,生成的 *.jar 文件在 jar 包文件的顶层目录的资源目录中具有 *.css 和 *.xsd 文件。
但是,在实际代码中,我很难将其引用为我的类路径的一部分:
我尝试了以下方法:
new File("resources/example.css");
我也试过了:
URL cssFile = this.getClass().getResource("resources/example.css");
try
file = new File(cssFile.toURI()));
catch(Exception e)
e.printStackTrace();
我得到一个 NullPointException 错误或一个 File cannot be found IOException 错误(取决于我使用哪一个)。在调试配置模式下的 Eclipse Equinox 和 Apache Felix(我们用于部署)中运行时出现此错误。注意我试图在 BundleActivator 之外的 Java 类中执行此操作。
我是否需要始终引用 BundleActivator 的上下文,例如?
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
@Override
public void start(BundleContext context) throws Exception
/* Service to host the Bundle interface. */
ServletContainerService service = new ServletContainerService();
service.addServlet(new ServletContainer(new AxisServlet(), true));
this.serverReg = context.registerService(ServletContainerService.class.getName(), service, null);
cssFile = new File(context.getClass.getResource("resource/example.css"));
我认为上述方法可行,但意味着我将不得不传递似乎不优雅的 cssFile 引用。
是否有任何方法可以引用包含在 bundle/.jar 文件中的任何给定 Java 类中的 bundle jar 文件中的“resources”目录的路径?如果涉及到BundleContext,有没有办法在任何Java类中引用它?
任何帮助将不胜感激。
我已经查看了 Including additional resources with OSGi bundles,但您似乎需要 BundleContext。
我可能已经找到了一个可能的解决方案:http://www.vogella.de/blog/tag/plugin/
看起来 Vogella 有一些示例代码:
URL url;
try
url = new URL("platform:/plugin/de.vogella.rcp.plugin.filereader/files/test.txt");
InputStream inputStream = url.openConnection().getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
catch (IOException e)
e.printStackTrace();
如果它不是插件并且我使用不同的 OSGi 环境(例如),是否有人知道此路径是否相同。 Equinox Eclipse 与 Apache Felix?
例如url = new URL("platform:/plugin/de.vogella.rcp.plugin.filereader/files/test.txt");
【问题讨论】:
【参考方案1】:Bundle interface 有一个 getEntry(java.lang.String path)
方法,该方法返回一个 Url,并记录为:
返回此包中指定路径的条目的 URL。这个包的类加载器不用于搜索条目。仅在此捆绑包的内容中搜索条目。 指定的路径总是相对于这个包的根目录,并且可能以“/”开头。路径值“/”表示这个包的根。
【讨论】:
有没有办法在 BundleActivator 的上下文之外访问它?我猜你指的是做这样的事情: public void start(BundleContext context) Bundle bundle = context.getBundle(); InputStream in = bundle.getEntry("/resource/example.css").openStream(); 。但是,我正在寻找一种解决方案(如果有的话)在 BundleActivator 之外访问它。我看了eclipsezone.com/eclipse/forums/t101557.html,但还是很困惑 您是否正在寻找一种从捆绑包 id 获取捆绑对象的方法? 我可以得到条目,但问题是 getEntry() 只提供相对路径,而不是包的完整(根)路径:techinfopad.com/spring/…。【参考方案2】:我认为答案应该很简单:
URL cssFile = this.getClass().getResource("/resources/example.css");
即确保路径中有一个前导斜杠。你有它没有前导斜杠,这将使它与你调用的类“相对”。
或者以下应该可以工作:
this.getClass().getClassLoader().getResource("resources/example.css");
【讨论】:
我选择了这个解决方案,但在尝试导入所有目录的值时遇到了问题,例如我正在使用 BluePrint CSS 并且 this.getClass().getClassLoader().getResource("resources/css") 有问题,因为不仅有很多文件,还有子目录。我最终将文件“复制”到了一个临时位置,但这会导致一些性能问题。【参考方案3】:如果您使用 Eclipse/Equinox 进行构建,那么您可以通过调用以下内容从 BundleActivator 中包含的 BundleContext 中获取 Bundle 的位置:
Bundle yourBundle = Platform.getBundle("bundleSymbolicName");
Path relativePathToBundle = new Path("/relativePath");
FileLocator.openStream(yourBundle, relativePathToBundle, false);
Platform 和 FileLocator 类来自 org.eclipse.core.runtime 插件,因此如果您对它有依赖关系,那么上述内容应该允许您访问您的资源。
【讨论】:
我试图避免使用 org.eclipse.core.runtime 插件,因为我们的部署决定使用 Apache Felix(除非有办法合并它)。如果我在 Eclipse 运行时环境下运行,上述方法有效。以上是关于执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件的主要内容,如果未能解决你的问题,请参考以下文章