URIResolver, Docbook and XSL Transform - java

I am attempting to transform some Docbook XSL to HTML using Java / Xalan and a mixture of the official Docbook XSL files from https://sourceforge.net/projects/docbook/files/docbook-xsl/1.76.1/ with some local xsl files that provide some customizations and overrides.
I want to prevent my application from having to download external resources or access local files. So I have implemented a class that extends the URIResolver interface.
The problem is that the resolve(final String href, final String base) function is not providing enough information to identify the particular file that is being requested.
For example, one of the local override files is imported from the xsl file using <xsl:import href="../../../xsl/html.xsl"/>. In this case the href parameter for my resolver class is set to ../../../xsl/html.xsl, which is fine. The html.xsl file then imports a file called defaults.xsl. The href parameter is set to only defaults.xsl, and the base parameter is set to null.
This might be followed by an import of http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl, in which case the href parameter is set to http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl. However, if the docbook.xsl imports a file called defaults.xsl, the href parameter is also set to defaults.xsl and base is set to null.
The issue is that the href and base parameters don't uniquely identify the resource, and you can't guess which file is being requested by watching the order of the previous hrefs either. Is there some trick to finding out exactly what context a file is being requested in?

Does the Source you are creating the transform from have a system ID? If not, this might be a reason why your base is always null in your URI resolver.
If you are creating transforms from input streams, you can manually assign a system ID to a source. You can generate an artificial one if necessary and use that artificial URI in your URI resolver to map back to a base URI. Also make sure the sources you create in your URI resolver also have system IDs or the same problem will occur with resources imported from those files.

Related

Tomcat 7 get resource using new URL and "classpath" string , ClassLoader.getSystemClassLoader().getResource return null

I try to get file resource in tomcat 7 using this code :
confFileUrl = new URL("classpath:/conf/plugins/my_app_conf.txt");
final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
URLConnection urlc = resourceUrl.openConnection();
The WEB-INF looks like this :
WEB-INF/classes/conf/plugins/my_app_conf.txt
i need to load it and verify it exist and pass it as URL object to Thired party app ( Accepes only URL object )
But the problem is that :
ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
result allways null
Any idea why ?
Note: You're mixing file names in your question: gappFileUrl vs confFileUrl.
As you specifically check SystemClassLoader, you won't get your webapp's classloader, thus there's nothing to find.
Use this.getClass().getResourceAsStream(name) to utilize the webapp's classloader (or, to be more precise, the classloader that has loaded the current class. Hopefully it's also from within WEB-INF/lib or WEB-INF/classes. If it isn't, pick a class that can be found there.
Also note that a web application is not necessarily "exploded" (unzipped) into the file system, but can legitimately be served from a WAR file. Thus, you'll need to use stream-operations, and can't expect any file-based operations to work consistently.
Edit (after your comment): I've never used the classpath: component int the URL. From https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html (emphasis mine):
The method getResource() returns a URL for the resource. The URL (and its representation) is specific to the implementation and the JVM (that is, the URL obtained in one runtime instance may not work in another). Its protocol is usually specific to the ClassLoader loading the resource. If the resource does not exist or is not visible due to security considerations, the methods return null.
If the client code wants to read the contents of the resource as an InputStream, it can apply the openStream() method on the URL. This is common enough to justify adding getResourceAsStream() to Class and ClassLoader. getResourceAsStream() the same as calling getResource().openStream(), except that getResourceAsStream() catches IO exceptions returns a null InputStream.
...
The getResource and getResourceAsStream methods find a resource with a given name. They return null if they do not find a resource with the specified name. The rules for searching for resources associated with a given class are implemented by the class's ClassLoader. The Class methods delegate to ClassLoader methods, after applying a naming convention: if the resource name starts with "/", it is used as is. Otherwise, the name of the package is prepended, after converting all periods (.) to slashes (/).
Based on that: Try loading a resource named "/conf/plugins/my_app_conf.txt". And you don't need to go through the URL construction, but you can pass that name right to getResourceAsStream, e.g. ...getResourceAsStream("/conf/plugins/my_app_conf.txt");

Set current compilation time in a java class or jsf page

I have a WAR archive compiled with maven.
I want to insert the compilation timestamp in a jsf page.
How can I change a string in a jsf page at compilation time ?
Example
<div>Compiled at (copilationTime)</div>
Must became
<div>Compiled at 2017-01-01 15:50</div>
If it is too complicate, I have an applicationscooped bean and i wrote
<div>Compiled at ${MyApp.compilationTime}</div>
But in my class how can i set 'xxxx'?
public class MyApp{
String compilationTime = 'xxxx';
public String getCompilationTime(){
return compilationTime;
}
}
I think you're talking about a variation of resource filtering via maven-resources-plugin. The idea is this:
You ask Maven to filter a certain resource (either a src/main/resources resource, or a variation of it, via maven-resources-plugin, a src/main/webapp resource via maven-war-plugin) in which you have placed the Maven pre-defined variable ${maven.build.timestamp}
You make sure that the filtered resource is included in your project
You read that resource either via Class.getResourceAsStream (or a variation of it), or via servlet mechanisms (depending where you place it).
You use the value in your JSF.
Please note that you can ask Maven to replace a filter a variable directly in your JSF and cut some steps.
From this answer you can get a reference to a file:
final File classFile = new File(MyApp.class.getProtectionDomain().getCodeSource().getLocation().getPath());
and then from here you get the property:
BasicFileAttributes attr = Files.readAttributes(classFile, BasicFileAttributes.class);
String compilationTime = attr.creationTime().toString();
You can use #CompileTime from Kolobok and create a field
#CompileTime
private static long ct; // This field will contain compilation time in ms

Loading templates in Freemarker templates without setting Directory or Class for template loading

Is there any way of loading the Freemarker templates directly without having need to first load the Directory from which templates will be loaded or setting the Class relative to which templates will be loaded.
i.e Is there any way so that i can load a template like
Template template = getTemplate("PathToTemplate/myTemplate.ftl");
I need this, because user specifies the complete path to ftl files. So,first i have to separate directory name and file name, then i am doing
Configuration cfg = new Configuration();
int indexOfLast = templatePath.lastIndexOf("\\");
String dir = templatePath;
String fileName="";
if(indexOfLast>=0){
dir = templatePath.substring(0,indexOfLast);
fileName= templatePath.substring(indexOfLast+1,templatePath.length());
}
cfg.setDirectoryForTemplateLoading(new File(dir));
Template template = cfg.getTemplate(fileName);
I do not want to do all this.
Templates can be created by directly calling a Template constructor, to which you pass a String or Reader as argument. Then of course you get that Reader or String from wherever you want. This approach has two disadvantages though:
Other templates won't be able to #import or #include those templates, as FreeMarker doesn't know how to load them (only you do)
Caching those templates (if that's needed anyway) is up to you
If the above two is a problem for you, then see Seelenvirtuose's answer: create a TemplateLoader that interprets the template names as full paths.
As of your example code, know that the Configuration instance will clear its template cache every time you replace the TemplateLoader. Also note that it's not thread-safe to do.
The getTemplate method is heavily overloaded. As per the documentation the method getTemplate(String, Locale, String, boolean) will eventually be called regardless which getTemplate method you called.
This method's documentation expresses the following:
The exact syntax of the name is interpreted by the underlying TemplateLoader, but the cache makes some assumptions. First, the name is expected to be a hierarchical path, with path components separated by a slash character (not with backslash!). The path (the name) given here must not begin with slash; it's always interpreted relative to the "template root directory".
There are two notable things:
The name parameter is already handling a hierarchical path, but must not begin with a slash. So maybe you could set the configuration's directory once to the root of your disk and then simply provide the full path (but without the leading slash).
The documentation explains something about a TemplateLoader. So you can simply write an implementation of that interface for loading the template. In that implementation you have full hands on the provided name.

How to implement dynamic referenced configuration in Java?

I have a configuration (config.properties) something like
app.rootDir=
app.reportDir=${app.rootDir}/report
The app.rootDir is not a fixed parameter and it must be initialized by external module. I need keep the ${app.reportDir} keep dynamic reference to ${app.rootDir}.
Use pseudo code to illustrate the problem:
// Init the root dir as '/usr/app'
config.setValue('app.rootDir','/usr/app');
// I need the reportDir to be '/usr/app/report'
String reportDir = config.getValue('app.reportDir');
I can write some codes to get this feature but I'd like to know if there is any existing library do this?
I can use properties, yaml, or json as configuration file type, according to the library availability.

Log4j: Changing XML with DOMConfigurator?

I am using log4j with Java and wanted to configure my XML-Config-File (I need to use XML for the ErrorHandler), so that some Properties in the XML (like the Backup-Value for the RollingFileAppender) could be changed within the DOMConfigurator of the log4j-API. This class also got the subst()-method, which should substitute the chosen values, but I really donĀ“t know how to handle it.
If their is no way changing the config with the DOMConfigurator, which else possibilities did I got to easily correct values in an ambiguous XML-File (So to say, because the XML-Tags are not unique or only their Tag-names, which are values itself)? My XML is kind of static or hand-written.
Why can't you fix the original XML file on the disk?
If for some reason that's not possible, I would rather try altering the configuration directly via Logger, after the config file has been loaded.

Categories

Resources