简体   繁体   English

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

[英]Velocity in OSGi: how to load templates from classpath

I am developing an application for OSGi with velocity template engine. 我正在开发一个带速度模板引擎的OSGi应用程序。 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. 它适用于通过文件加载器加载我的模板,但现在我必须在我的jar中实现这个模板并将其作为资源加载。

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' 无法找到资源'index.vm'

Caused by: 引起:

org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'index.vm' org.apache.velocity.exception.ResourceNotFoundException:无法找到资源'index.vm'

Sadly Velocity is not that OSGi friendly. 可悲的是Velocity并不是OSGi友好的。 Therefore you cannot use the built in ClasspathResourceLoader and it is hard to add a custom developed ResourceLoader as well. 因此,您无法使用内置的ClasspathResourceLoader,也很难添加自定义开发的ResourceLoader。

I suggest that you should get your template as a Reader in any of the ordinary ways and choose one of the following: 我建议您以任何常规方式将模板作为Reader使用,并选择以下选项之一:

  • Use the VelocityEngine evaulate function if you need to merge the template rarely (performance does not matter that much) 如果您需要很少合并模板,请使用VelocityEngine evaulate函数(性能无关紧要)
  • Create a Template by hand with the inner classes of Velocity 手动创建模板与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): 下面是第二个选项的示例,其中可以通过调用其上的合并函数来重用创建的模板对象(期望您已经有一个读取器到您的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(...);
...

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. 要获得OSGi中vm文件的读者,您应该选择一个肯定与vm资源在同一个包中的类,并调用SameBundleClass.class.getResourceAsStream ...您可以使用InputStreamReader将您的流转换为writer。

Please note that the example misses some try-catch-finally block. 请注意,该示例错过了一些try-catch-finally块。

Two things to verify 要验证两件事

1. Classpath issues 1.类路径问题

Make sure you set the classpath of the OSGi bundle via the MANIFEST.MF to include a dot: 确保通过MANIFEST.MF设置OSGi包的类路径以包含一个点:

Bundle-ClassPath: .

The dot means to include the root of the bundle in the class-loading hierarchy, where your folder "velocitytemplates" likely resides. 点表示在类加载层次结构中包含bundle的根,您的文件夹“velocitytemplates”可能驻留在该层次结构中。

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. 并且你需要将Velocity jar文件放在模板文件所在的同一个包中,否则你会得到类加载问题,因为Velocity将驻留在另一个包中,因此根本不会看到“velocitytemplates”类路径。

2. There is no "path" for ClasspathResourceLoader 2. 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, ie "velocitytemplates/index.vm" ClasspathResourceLoader不支持设置“路径”,因为它根据定义使用Classpath,因此要么将“velocitytemplates”添加到OSGi包中的Classpath(MANIFESt.MF),要么使用完整路径引用速度模板,即“velocitytemplates / index” .vm”

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 2天后,我和一位同事发现了Velocity Engine默认的解决方案:file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader

Created own class Resource loader like that 像这样创建自己的类Resource loader

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 就是这样

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. 我通过继承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" 这样,如果你有一个名为“index.vm”的模板,velocity将使用类加载器来查找名为“/velocitytemplates/index.vm”的资源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM