Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/delibero.git

Dynamically determine correct app XSL file to include; default to an empty template file; default to a string if all else fails.

AuthorDave Jarvis <email>
Date2015-01-15 01:44:20 GMT-0800
Commitb6aec12ae4fd0fc3c6c23a52eb22ed2382a1cce4
Parent6aac04e
source/java/to/discuss/App.java
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
+import javax.xml.transform.URIResolver;
+
+import to.discuss.util.AppURIResolver;
/**
protected void applyParameters( Transformer t ) {
- t.setParameter( "app", getClass().getSimpleName().toLowerCase() );
+ t.setParameter( "app", getAppName() );
}
private String getDocumentFilename() {
- return String.format(
- "database/%s.xml", getClass().getSimpleName().toLowerCase() );
+ return String.format( "database/%s.xml", getAppName() );
}
protected TransformerFactory getTransformerFactory() {
- return TransformerFactory.newInstance();
+ TransformerFactory tf = TransformerFactory.newInstance();
+ URIResolver resolver = tf.getURIResolver();
+ tf.setURIResolver( new AppURIResolver( this, resolver ) );
+
+ return tf;
}
protected Transformer getTransformer() throws Exception {
return getTransformerFactory().newTransformer( getStylesheet() );
+ }
+
+ /**
+ * Returns the app name, in lowercase.
+ */
+ public String getAppName() {
+ return getClass().getSimpleName().toLowerCase();
}
}
source/java/to/discuss/Base.java
package to.discuss;
+import java.io.FileNotFoundException;
import java.io.InputStream;
+import java.io.IOException;
/**
* @throws Exception Any error opening the file.
*/
- public default InputStream open( String filename ) throws Exception {
+ public default InputStream open( String filename ) throws IOException {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
- return loader.getResourceAsStream( filename );
+ InputStream result = loader.getResourceAsStream( filename );
+
+ if( result == null ) {
+ throw new FileNotFoundException( filename );
+ }
+
+ return result;
}
}
source/java/to/discuss/util/AppURIResolver.java
+/**
+ * MIT License
+ *
+ * Copyright 2015 White Magic Software, Ltd.
+ */
+package to.discuss.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import java.net.URI;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import to.discuss.App;
+import to.discuss.Base;
+
+/**
+ * Extends java.util.Properties to recursively parse ${property} values. This
+ */
+public class AppURIResolver implements URIResolver, Base {
+ private URIResolver delegate;
+ private App app;
+
+ public AppURIResolver( App app, URIResolver delegate ) {
+ setApp( app );
+ setDelegate( delegate );
+ }
+
+ /**
+ * Dynamically resolve the path to the include file based on the app name.
+ */
+ @Override
+ public Source resolve( String href, String base )
+ throws TransformerException {
+ Source result = null;
+ URI uri = null;
+
+ try {
+ uri = new URI( href );
+ }
+ catch( Exception e ) {
+ throw new TransformerException( e );
+ }
+
+ // The XSLT file has a URI path that allows for a file to be included
+ // dynamically.
+ if( "import".equalsIgnoreCase( uri.getScheme() ) &&
+ "discuss.to".equalsIgnoreCase( uri.getAuthority() ) ) {
+ result = openAppTemplate();
+ }
+ else {
+ result = getDelegate().resolve( href, base );
+ }
+
+ return result;
+ }
+
+ /**
+ * Guaranteed to open an XSL template that corresponds to the app name.
+ * If no template is found, or the default template file is missing, this
+ * will return a hard-coded string as a StreamSource.
+ *
+ * @return A valid StreamSource containing a stylesheet DOM.
+ */
+ private Source openAppTemplate() {
+ Source result = null;
+
+ try {
+ result = new StreamSource( open( getStylesheetFilename() ) );
+ }
+ catch( IOException ioe ) {
+ try {
+ result = new StreamSource( open( "xsl/template.xsl" ) );
+ }
+ catch( Exception e ) {
+ result = new StreamSource( getDefaultTemplate() );
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * If the file-based template cannot be found, then use a hard-coded,
+ * fail-safe version.
+ */
+ private Reader getDefaultTemplate() {
+ return new StringReader(
+ "<?xml version='1.0' encoding='utf-8'?>" +
+ "<xsl:stylesheet version='2.0' " +
+ "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" +
+ "</xsl:stylesheet>" );
+ }
+
+ private String getStylesheetFilename() {
+ return String.format( "xsl/%s.xsl", getApp().getAppName() );
+ }
+
+ private void setApp( App app ) {
+ this.app = app;
+ }
+
+ private App getApp() {
+ return this.app;
+ }
+
+ private void setDelegate( URIResolver delegate ) {
+ this.delegate = delegate;
+ }
+
+ private URIResolver getDelegate() {
+ return this.delegate;
+ }
+}
+
+
source/xsl/common.xsl
encoding="utf-8"/>
-<!-- For including CSS and JavaScript references. -->
+<!-- Custom URI resolver to import an XSL file corresponding to the app. -->
+<xsl:include href="import://discuss.to/app"/>
+
+<!-- Include CSS and JavaScript files corresponding to the app. -->
<xsl:param name="app" />
source/xsl/template.xsl
+<?xml version='1.0' encoding='utf-8'?>
+<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+</xsl:stylesheet>
Delta155 lines added, 7 lines removed, 148-line increase