OSGi 中的速度:如何从类路径加载模板

发布于 2024-12-22 06:15:59 字数 617 浏览 4 评论 0原文

我正在开发一个带有速度模板引擎的 OSGi 应用程序。 它非常适合通过文件加载器加载我的模板,但现在我必须在我的 jar 中实现此模板并将其作为资源加载。

我怎样才能让它发挥作用?

我的代码:

ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", 
    ClasspathResourceLoader.class.getName());
ve.setProperty("classpath.resource.loader.path", "/velocitytemplates");
ve.init();

ve.getTemplate("foo.vm");

这会抛出一个异常,例如

无法找到资源“index.vm”

原因:

org.apache.velocity.exception.ResourceNotFoundException:无法找到资源“index.vm”

I am developing an application for OSGi with velocity template engine.
It works great for loading my templates by file loader but now I have to implement this templates in my jar and load it as resources.

How can i made it work?

My Code:

ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", 
    ClasspathResourceLoader.class.getName());
ve.setProperty("classpath.resource.loader.path", "/velocitytemplates");
ve.init();

ve.getTemplate("foo.vm");

This will throw an exception like

Unable to find resource 'index.vm'

Caused by:

org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'index.vm'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

机场等船 2024-12-29 06:15:59

遗憾的是 Velocity 对 OSGi 并不友好。因此,您无法使用内置的 ClasspathResourceLoader,并且也很难添加自定义开发的 ResourceLoader。

我建议您应该以任何普通方式将模板作为 Reader 获取,并选择以下方法之一:

  • 如果需要合并模板,请使用 VelocityEngine evaulate 函数
    模板很少(性能并不那么重要)
  • 使用 Velocity 的内部类手动创建模板

如果您不必经常合并模板,因此性能不是关键要求,则可以使用第一个选项。

下面是第二个选项的示例,其中创建的模板对象可以通过调用合并函数来重用(期望您已经获得了 vm 文件或资源的读取器):

RuntimeInstance runtimeInstance = new RuntimeInstance();
runtimeInstance.init();
SimpleNode simpleNode = runtimeInstance.parse(reader, "nameOfYourTemplateResource");

Template template = new Template();
simpleNode.init(new InternalContextAdapterImpl(new VelocityContext()), runtimeInstance);
template.setData(simpleNode);

template.merge(...);
...

要在 OSGi 中获得 vm 文件的读取器,您需要应该选择一个与您的虚拟机资源位于同一包中的类,并调用 SameBundleClass.class.getResourceAsStream... 您可以使用 InputStreamReader 将流转换为写入器。

请注意,该示例遗漏了一些 try-catch-finally 块。

Sadly Velocity is not that OSGi friendly. Therefore you cannot use the built in ClasspathResourceLoader and it is hard to add a custom developed ResourceLoader as well.

I suggest that you should get your template as a Reader in any of the ordinary ways and choose one of the following:

  • Use the VelocityEngine evaulate function if you need to merge the
    template rarely (performance does not matter that much)
  • Create a Template by hand with the inner classes of Velocity

The first option can be used if you do not have to merge your templates very often so performance is not a key requirement.

Here is a sample for the second option where the created template object can be reused by calling the merge function on it (expecting that you already got a Reader to your vm file or resource):

RuntimeInstance runtimeInstance = new RuntimeInstance();
runtimeInstance.init();
SimpleNode simpleNode = runtimeInstance.parse(reader, "nameOfYourTemplateResource");

Template template = new Template();
simpleNode.init(new InternalContextAdapterImpl(new VelocityContext()), runtimeInstance);
template.setData(simpleNode);

template.merge(...);
...

To get a reader for the vm file in OSGi you should choose a class that is surely in the same bundle as your vm resource and call SameBundleClass.class.getResourceAsStream... You can transform your stream to writer with InputStreamReader than.

Please note that the example misses some try-catch-finally block.

逆蝶 2024-12-29 06:15:59

需要验证的两件事

1. 类路径问题

确保通过 MANIFEST.MF 设置 OSGi 包的类路径以包含一个点:

Bundle-ClassPath: .

点表示将包的根包含在类加载层次结构中,其中您的文件夹“velocitytemplates” “可能存在。

并且您需要将 Velocity jar 文件放在模板文件所在的同一个包中,因为否则您将遇到类加载问题,因为 Velocity 将驻留在不同的包中,因此根本看不到“velocitytemplates”类路径。

2. ClasspathResourceLoader 没有“路径”

ClasspathResourceLoader 不支持设置“路径”,因为它根据定义使用类路径,因此要么将“velocitytemplates”添加到 OSGi 包 (MANIFESt.MF) 中的类路径,要么引用速度具有完整路径的模板,即“velocitytemplates/index.vm”

Two things to verify

1. Classpath issues

Make sure you set the classpath of the OSGi bundle via the MANIFEST.MF to include a dot:

Bundle-ClassPath: .

The dot means to include the root of the bundle in the class-loading hierarchy, where your folder "velocitytemplates" likely resides.

And you need to have the Velocity jar-files in the same bundle where your template-files reside, because otherwise you'll get classloading issues as Velocity would reside in a different bundle and thus would not see the "velocitytemplates" at all in its classpath.

2. There is no "path" for ClasspathResourceLoader

ClasspathResourceLoader does not support setting a "path", as it uses the Classpath by definition, so either add "velocitytemplates" to the Classpath in the OSGi bundle (MANIFESt.MF) or reference the velocity templates with complete path, i.e. "velocitytemplates/index.vm"

烟花易冷人易散 2024-12-29 06:15:59

我在基于类加载器的模板中遇到了类似的问题,我想指定不同的根。我通过子类化 ClasspathResourceLoader 来解决这个问题。

package my.package;

import java.io.InputStream;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

public class PrefixedClasspathResourceLoader 
    extends ClasspathResourceLoader
{
    /** Prefix to be added to any names */
    private String prefix = "";

    @Override
    public void init(ExtendedProperties configuration) {
        prefix = configuration.getString("prefix","");
    }

    @Override
    public InputStream getResourceStream(String name)
            throws ResourceNotFoundException 
    {
        return super.getResourceStream(prefix+name);
    }
}

通过这种方式设置以下属性

resource.loader=myloader
myloader.resource.loader.class=my.package.PrefixedClasspathResourceLoader
myloader.resource.loader.prefix=/velocitytemplates/

,如果您有一个名为“index.vm”的模板,velocity 将使用类加载器来查找名为“/velocitytemplates/index.vm”的资源

I encountered a similar problem with class loader based templates where I wanted to specify a different root. I worked around it by subclassing ClasspathResourceLoader.

package my.package;

import java.io.InputStream;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

public class PrefixedClasspathResourceLoader 
    extends ClasspathResourceLoader
{
    /** Prefix to be added to any names */
    private String prefix = "";

    @Override
    public void init(ExtendedProperties configuration) {
        prefix = configuration.getString("prefix","");
    }

    @Override
    public InputStream getResourceStream(String name)
            throws ResourceNotFoundException 
    {
        return super.getResourceStream(prefix+name);
    }
}

With the following properties set

resource.loader=myloader
myloader.resource.loader.class=my.package.PrefixedClasspathResourceLoader
myloader.resource.loader.prefix=/velocitytemplates/

this way if you've got a template called "index.vm", velocity will use the classloader to find a resource called "/velocitytemplates/index.vm"

寄风 2024-12-29 06:15:59

2天后,我和一位同事找到了 Velocity Engine 默认的解决方案: file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader

一样

public static final class PdfResourceLoader extends ResourceLoader

@Override
public void init(ExtendedProperties configuration)
{
}

@Override
public InputStream getResourceStream(String source) throws ResourceNotFoundException
{
  return getClass().getResourceAsStream(source);
}

@Override
public boolean isSourceModified(Resource resource)
{
  return false;
}

@Override
public long getLastModified(Resource resource)
{
  return 0;
}
}

创建了自己的类资源加载器,就像设置新的上下文类 加载程序

Thread.currentThread().setContextClassLoader(PdfResourceLoader.class.getClassLoader());  
    VelocityEngine ve = new VelocityEngine();

更改了速度引擎内默认的属性

ve.setProperty("resource.loader", "pdf"); 
ve.setProperty("pdf.resource.loader.class",
PdfResourceLoader.class.getName());
ve.init(); 

示例名称路径模板

String pathTemplate = "/templates/yourTemplateName.html";      
Template t = ve.getTemplate(pathTemplate, "UTF-8"); 

它是

After 2 days I and a colleague have found the solution Velocity Engine have for default: file.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader

Created own class Resource loader like that

public static final class PdfResourceLoader extends ResourceLoader

@Override
public void init(ExtendedProperties configuration)
{
}

@Override
public InputStream getResourceStream(String source) throws ResourceNotFoundException
{
  return getClass().getResourceAsStream(source);
}

@Override
public boolean isSourceModified(Resource resource)
{
  return false;
}

@Override
public long getLastModified(Resource resource)
{
  return 0;
}
}

set the new context class loader

Thread.currentThread().setContextClassLoader(PdfResourceLoader.class.getClassLoader());  
    VelocityEngine ve = new VelocityEngine();

changed the property for default inside the velocity engine

ve.setProperty("resource.loader", "pdf"); 
ve.setProperty("pdf.resource.loader.class",
PdfResourceLoader.class.getName());
ve.init(); 

Example name path template

String pathTemplate = "/templates/yourTemplateName.html";      
Template t = ve.getTemplate(pathTemplate, "UTF-8"); 

That it's

看海 2024-12-29 06:15:59

哇,这个问题很老了,没有一个答案被标记。因此,我将尝试解释该问题并提供另一种解决方案。

OSGi 类路径的问题是,每个包都有它自己的私有类加载器。该捆绑包类加载器必须在类路径和 Velocity 类上具有模板资源。如果 Velocity 类由另一个包提供,则 Velocity 的 ClasspathResourceLoader 将找不到模板资源,因为它们不在该包的类路径上。

因此,您必须

  1. 确保 Velocity 的 ClasspathResourceLoader 位于与模板相同的类路径中(由 @centic 提到),或者
  2. 实现并配置一个能够查找资源的自定义 ResourceLoader(由 @gary-stand-with- 提到)乌克兰)。

对于后一个选项,我会选择另一种方法,并专门使用了解资源的显式类加载器实例来配置 ClasspathResourceLoader。

Wow this question is quite old and none of the answers are marked. So I'll try to explain the problem and to provide another solution.

The problem with OSGi classpaths is, that every bundle has it's own private classloader. That bundle classloader must have the template resources on the classpath and the Velocity classes. If the Velocity classes are provided by another bundle, Velocity's ClasspathResourceLoader will not find the template resources because they are not on that bundle's classpath.

So either you have to

  1. ensure that the Velocity's ClasspathResourceLoader is located in the very same classpath as the templates (mentioned by @centic) or
  2. implement and configure a custom ResourceLoader that is able to find the resources (mentioned by @gary-stand-with-ukraine).

For the latter option I would choose another approach and would specialize ClasspathResourceLoader to be configured with the explicit class loader instance which is aware of the resources.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文