/*
 * [The "BSD license"]
 *  Copyright (c) 2011 Terence Parr
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.stringtemplate.v4;

import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.Token;
import org.stringtemplate.v4.compiler.CompiledST;
import org.stringtemplate.v4.compiler.STException;
import org.stringtemplate.v4.misc.ErrorType;
import org.stringtemplate.v4.misc.Misc;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

// TODO: caching?

A directory or directory tree full of templates and/or group files. We load files on-demand. Dir search path: current working dir then CLASSPATH (as a resource). Do not look for templates outside of this dir subtree (except via imports).
/** A directory or directory tree full of templates and/or group files. * We load files on-demand. Dir search path: current working dir then * CLASSPATH (as a resource). Do not look for templates outside of this dir * subtree (except via imports). */
public class STGroupDir extends STGroup { public String groupDirName; public URL root; public STGroupDir(String dirName) { this(dirName, '<', '>'); } public STGroupDir(String dirName, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.groupDirName = dirName; File dir = new File(dirName); if ( dir.exists() && dir.isDirectory() ) { // we found the directory and it'll be file based try { root = dir.toURI().toURL(); } catch (MalformedURLException e) { throw new STException("can't load dir "+dirName, e); } if ( verbose ) System.out.println("STGroupDir("+dirName+") found at "+root); } else { ClassLoader cl = Thread.currentThread().getContextClassLoader(); root = cl.getResource(dirName); if ( root==null ) { cl = this.getClass().getClassLoader(); root = cl.getResource(dirName); } if ( verbose ) System.out.println("STGroupDir("+dirName+") found via CLASSPATH at "+root); if ( root==null ) { throw new IllegalArgumentException("No such directory: "+ dirName); } } } public STGroupDir(String dirName, String encoding) { this(dirName, encoding, '<', '>'); } public STGroupDir(String dirName, String encoding, char delimiterStartChar, char delimiterStopChar) { this(dirName, delimiterStartChar, delimiterStopChar); this.encoding = encoding; } public STGroupDir(URL root, String encoding, char delimiterStartChar, char delimiterStopChar) { super(delimiterStartChar, delimiterStopChar); this.groupDirName = new File(root.getFile()).getName(); this.root = root; this.encoding = encoding; } @Override public void importTemplates(Token fileNameToken) { String msg = "import illegal in group files embedded in STGroupDirs; "+ "import "+fileNameToken.getText()+" in STGroupDir "+this.getName(); throw new UnsupportedOperationException(msg); }
Load a template from directory or group file. Group file is given precedence over directory with same name. name is always fully-qualified.
/** Load a template from directory or group file. Group file is given * precedence over directory with same name. {@code name} is always fully-qualified. */
@Override protected CompiledST load(String name) { if ( verbose ) System.out.println("STGroupDir.load("+name+")"); String parent = Misc.getParent(name); // must have parent; it's fully-qualified String prefix = Misc.getPrefix(name); // if (parent.isEmpty()) { // // no need to check for a group file as name has no parent // return loadTemplateFile("/", name+TEMPLATE_FILE_EXTENSION); // load t.st file // } URL groupFileURL; try { // see if parent of template name is a group file groupFileURL = new URL(root+parent+GROUP_FILE_EXTENSION); } catch (MalformedURLException e) { errMgr.internalError(null, "bad URL: "+root+parent+GROUP_FILE_EXTENSION, e); return null; } InputStream is = null; try { is = groupFileURL.openStream(); } catch (IOException ioe) { // must not be in a group file String unqualifiedName = Misc.getFileName(name); return loadTemplateFile(prefix, unqualifiedName+TEMPLATE_FILE_EXTENSION); // load t.st file } finally { // clean up try { if (is!=null ) is.close(); } catch (IOException ioe) { errMgr.internalError(null, "can't close template file stream "+name, ioe); } } loadGroupFile(prefix, root+parent+GROUP_FILE_EXTENSION); return rawGetTemplate(name); }
Load .st as relative file name relative to root by prefix.
/** Load .st as relative file name relative to root by {@code prefix}. */
public CompiledST loadTemplateFile(String prefix, String unqualifiedFileName) { if ( verbose ) System.out.println("loadTemplateFile("+unqualifiedFileName+") in groupdir "+ "from "+root+" prefix="+prefix); URL f; try { f = new URL(root+prefix+unqualifiedFileName); } catch (MalformedURLException me) { errMgr.runTimeError(null, null, ErrorType.INVALID_TEMPLATE_NAME, me, root + unqualifiedFileName); return null; } ANTLRInputStream fs; try { fs = new ANTLRInputStream(f.openStream(), encoding); fs.name = unqualifiedFileName; } catch (IOException ioe) { if ( verbose ) System.out.println(root+"/"+unqualifiedFileName+" doesn't exist"); //errMgr.IOError(null, ErrorType.NO_SUCH_TEMPLATE, ioe, unqualifiedFileName); return null; } return loadTemplateFile(prefix, unqualifiedFileName, fs); } @Override public String getName() { return groupDirName; } @Override public String getFileName() { return root.getFile(); } @Override public URL getRootDirURL() { return root; } }