/*
* Name: Generator
* Authors: Richard Rodger
*
* Copyright (c) 2003-2006 Richard Rodger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
// package
package org.jostraca;
// import
import org.jostraca.util.Standard;
import org.jostraca.util.PropertySet;
import org.jostraca.util.UserMessageHandler;
import org.jostraca.util.RecordingUserMessageHandler;
import org.jostraca.util.ListUtil;
import org.jostraca.util.StandardException;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
/** A utility class that you can use inside your own applications for generating code.
* <p> You will need to include <code>jostraca.jar</code>
* (found in the {@link <a href="http://www.jostraca.org/doc/ref/nrefstdfafall.htm">lib</a>} folder of the distribution)
* in your classpath.
* The simplest example is:
* <pre style="foreground:#336;background:#f0f0ff;display:block;border:1px solid #669">
*
* Generator g = new Generator();
* g.generate( "template.jtm" );
* </pre>
* You can specify the template using a String file path or a File object.
* </p>
* <p>
* <code>Generator</code> uses the default internal configuration so that it will
* work without any configuration files. To use Jostraca configuration files,
* specify a configuration folder using the constructors {@link #Generator(File)}
* or {@link #Generator(String)}.
* </p>
* <p>
* You can also specify the settings to use when generating by passing in a
* {@link PropertySet} object, with your required settings.
* For example:
* <pre style="foreground:#336;background:#f0f0ff;display:block;border:1px solid #669">
*
* Generator g = new Generator();
* PropertySet ps = new PropertySet();
* ps.set( "main.MakeBackup", "no" );
* g.setCmdPropertySet( ps );
* g.generate( "template.jtm" );
* </pre>
* For a complete list of all configuration settings see the
* {@link <a href="http://www.jostraca.org/doc/ref/nrefconfall.htm">Configuration Settings</a>} reference.
* </p>
* <p>
* To generate more than one template, use the {@link #generate(String[])}
* and {@link #generate(File[])} methods.
* </p>
* <p>
* You can use the same <code>Generator</code> object multiple times.
* </p>
* <p>If the template you are generating only generates one output file, you
* can retrieve the result of the generation by calling {@link Template#getResult} on the
* {@link Template} object that is returned by the <code>generate</code> methods.
* Note that this only works when you are using Java as the template script, and when you
* execute the template CodeWriter internally (this is the default).
* </p>
* <p>
* To gain access to any error messages use the {@link #getUserMessageHandler} method.
* This returns a {@link org.jostraca.util.RecordingUserMessageHandler} object by default,
* which you will need to cast from the {@link org.jostraca.util.UserMessageHandler} interface returned by getUserMessageHandler.
* To use your own UserMessageHandler,
* use the method {@link #generate(String,UserMessageHandler)} and its equivalents.
* To send output to <code>STDOUT</code>, use the {@link org.jostraca.util.CommandLineUserMessageHandler}
* as the UserMessageHandler parameter.
* </p>
*/
public class Generator {
private static final String WNFM = " was null for method: ";
private static final String ARG = "Argument ";
private static final String CF = ARG+"pConfigFolder";
private static final String TM = ARG+"pTemplate";
private static final String UMH = ARG+"pUserMessageHandler";
private static final String TMS = ARG+"pTemplates";
private static final String UMHP = ", UserMessageHandler pUserMessageHandler )";
private static final String GM = "generate( ";
private Service iService = null;
private File iConfigFolder = null;
private UserMessageHandler iUserMessageHandler = new RecordingUserMessageHandler();
private PropertySet iCmdPropertySet = null;
private Object iContext = null;
private boolean iAlwaysGenerate = true;
/** Create a new Generator with the default configuration. */
public Generator() {
init( new File( Standard.DOT ) );
}
/** Create a new Generator with configuration files in the specified configuration folder.
* Jostraca stores configuration files in the {@link <a href="http://www.jostraca.org/doc/ref/nrefstdfafall.htm">conf</a>}
* folder of the distribution, so you can use these to get the defautl behaviour.
* @param pConfigFolder folder path
*/
public Generator( String pConfigFolder ) {
String MN = "Generator( String pConfigFolder )";
if( null == pConfigFolder ) {
throw new JostracaException( CF+WNFM+MN );
}
init( new File( pConfigFolder ) );
}
/** Create a new Generator with configuration files in the specified configuration folder.
* @param pConfigFolder config folder
* @see #Generator(String)
*/
public Generator( File pConfigFolder ) {
String MN = "Generator( File pConfigFolder )";
if( null == pConfigFolder ) {
throw new JostracaException( CF+WNFM+MN );
}
init( pConfigFolder );
}
/** Initialise from config folder.
* @param pConfigFolder config folder
*/
protected void init( File pConfigFolder ) {
if( !pConfigFolder.exists() ) {
throw new JostracaException( "Argument pConfigFolder='"+pConfigFolder.getAbsolutePath()+"' specifies a folder that does not exist" );
}
if( !pConfigFolder.canRead() ) {
throw new JostracaException( "Argument pConfigFolder='"+pConfigFolder.getAbsolutePath()+"' specifies a folder that does not have sufficient read permissions" );
}
iService = new Service();
iConfigFolder = pConfigFolder;
iCmdPropertySet = new PropertySet();
}
/** Specifically set some configuration properties. These settings are handled equivalently
* to command line options.
* @see <a href="http://www.jostraca.org/doc/ref/nrefconfall.htm">Configuration Settings</a>
*/
public void setCmdPropertySet( PropertySet pCmdPropertySet ) {
if( null == pCmdPropertySet ) {
throw new JostracaException( "Argument pCmdPropertySet was null for method: setCmdPropertySet( PropertySet pCmdPropertySet )" );
}
// this ensures that internally set settings are preserved if not specified by user
iCmdPropertySet.overrideWith( pCmdPropertySet );
}
/** <p>
* Set a context object (which can be anything) for the template. This object is then
* available directly to the template by calling <a href="http://www.jostraca.org/doc/ref/nreftmsrvall.htm#_setContext">_getContext</a>.
* </p><p>
* NOTE: this will only work if the template scripting lanaguage is <i>Java</i> and
* the template is generated <i>internally</i> (this is the default).
* </p>
*/
public void setContext( Object pContext ) {
if( null == pContext ) {
throw new JostracaException( "Argument pContext was null for method: setContext( Object pContext )" );
}
iContext = pContext;
}
/** Always generate template, even if up-to-date (default: <code>true</code>).
* <p>Set this to false is you do not wish to regenerate templates
* that are up-to-date. Note that this means that some templates may not return
* any results from the the {@link org.jostraca.Template#getResult} method as they will not have
* been executed.</p>
* <p>If you set
* <a href="http://www.jostraca.org/doc/ref/nrefconfall.htm#main.ExecuteCodeWriter">main.ExecuteCodeWriter</a> directly using {@link #setCmdPropertySet} then that setting has precedence and this option is ignored.</p>
*
* @param pAlwaysGenerate always generate template
*/
public void setAlwaysGenerate( boolean pAlwaysGenerate ) {
iAlwaysGenerate = pAlwaysGenerate;
}
/** Generate the specified template.
* @param pTemplate template file path
*/
public Template generate( File pTemplate ) {
String MN = GM+"File pTemplate )";
if( null == pTemplate ) {
throw new JostracaException( TM+WNFM+MN );
}
Template tm = generate( pTemplate.getAbsolutePath(), iUserMessageHandler );
return tm;
}
/** Generate the specified template. Messages are sent to the
* specified {@link org.jostraca.util.UserMessageHandler}.
* @param pTemplate template file path
* @param pUserMessageHandler UserMessageHandler implementation
*/
public Template generate( File pTemplate, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"File pTemplate"+UMHP;
if( null == pTemplate ) {
throw new JostracaException( TM+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( UMH+WNFM+MN );
}
Template tm = generate( pTemplate.getAbsolutePath(), pUserMessageHandler );
return tm;
}
/** Generate more than one template.
* @see #generate(File)
*/
public Template[] generate( File[] pTemplates ) {
String MN = GM+"File[] pTemplates )";
if( null == pTemplates ) {
throw new JostracaException( TM+WNFM+MN );
}
Template[] tma = generate( pTemplates, iUserMessageHandler );
return tma;
}
/** Generate more than one template.
* @see #generate(File,UserMessageHandler)
*/
public Template[] generate( File[] pTemplates, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"File[] pTemplates"+UMHP;
if( null == pTemplates ) {
throw new JostracaException( TM+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( UMH+WNFM+MN );
}
int numTM = pTemplates.length;
String[] tmpaths = new String[ numTM ];
for( int tmI = 0; tmI < numTM; tmI++ ) {
if( null == pTemplates[tmI] ) {
throw new JostracaException( "Argument element pTemplate["+tmI+"]"+WNFM+GM+"File[] pTemplates )" );
}
tmpaths[ tmI ] = pTemplates[tmI].getAbsolutePath();
}
Template[] tma = generate( tmpaths, pUserMessageHandler );
return tma;
}
/** Generate the specified template.
* @param pTemplate template file path
*/
public Template generate( String pTemplate ) {
String MN = GM+"String pTemplate )";
if( null == pTemplate ) {
throw new JostracaException( TM+WNFM+MN );
}
Template[] tma = generate( new String[] { pTemplate } );
if( 0 < tma.length ) {
return tma[0];
}
else {
throw new JostracaException( "No template generated" );
}
}
/** Generate the specified template. Messages are sent to the
* specified {@link org.jostraca.util.UserMessageHandler}.
* @param pTemplate template file path
* @param pUserMessageHandler UserMessageHandler implementation
*/
public Template generate( String pTemplate, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"String pTemplate"+UMHP;
if( null == pTemplate ) {
throw new JostracaException( TM+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( TM+WNFM+MN );
}
Template[] tma = generate( new String[] { pTemplate }, pUserMessageHandler );
if( 0 < tma.length ) {
return tma[0];
}
else {
throw new JostracaException( "No template generated" );
}
}
/** Generate more than one template.
* @see #generate(String)
*/
public Template[] generate( String[] pTemplates ) {
String MN = GM+"String[] pTemplates )";
if( null == pTemplates ) {
throw new JostracaException( TM+WNFM+MN );
}
Template[] tma = generate( pTemplates, iUserMessageHandler );
return tma;
}
/** Generate more than one template.
* @see #generate(String,UserMessageHandler)
*/
public Template[] generate( String[] pTemplates, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"String[] pTemplates"+UMHP;
if( null == pTemplates ) {
throw new JostracaException( TM+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( UMH+WNFM+MN );
}
int numTM = pTemplates.length;
ArrayList tmpaths = new ArrayList();
for( int tmI = 0; tmI < numTM; tmI++ ) {
if( null == pTemplates[tmI] ) {
throw new JostracaException( "Argument element pTemplate["+tmI+"]"+WNFM+GM+"String[] pTemplates )" );
}
try {
tmpaths.add( new BasicTemplatePath( pTemplates[tmI] ) );
}
catch( TemplateException te ) {
throw new JostracaException( "Argument element pTemplate["+tmI+"] could not be used to define a template: "
+te.getMessage() );
}
}
List tmlist = generate( tmpaths, pUserMessageHandler );
return (Template[]) tmlist.toArray( new Template[tmlist.size()] );
}
/** Generate the specified template. The template is specified by using
* the abstract template path description {@link org.jostraca.TemplatePath}.
* @param pTemplatePath template file path
* @see #generate(File)
*/
public Template generate( TemplatePath pTemplatePath ) {
String MN = GM+"TemplatePath pTemplatePath )";
if( null == pTemplatePath ) {
throw new JostracaException( TM+WNFM+MN );
}
List tmlist = generate( ListUtil.make( pTemplatePath ) );
if( 0 < tmlist.size() ) {
return (Template)tmlist.get(0);
}
else {
throw new JostracaException( "No template generated" );
}
}
/** Generate the specified template. Messages are sent to the
* specified {@link org.jostraca.util.UserMessageHandler}.
* @param pTemplatePath template file path
* @param pUserMessageHandler UserMessageHandler implementation
* @see #generate(TemplatePath)
*/
public Template generate( TemplatePath pTemplatePath, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"TemplatePath pTemplatePath )";
if( null == pTemplatePath ) {
throw new JostracaException( TM+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( UMH+WNFM+MN );
}
List tmlist = generate( ListUtil.make( pTemplatePath ), pUserMessageHandler );
if( 0 < tmlist.size() ) {
return (Template)tmlist.get(0);
}
else {
throw new JostracaException( "No template generated" );
}
}
/** Generate more than one template.
* @return List of Template objects
* @see #generate(TemplatePath)
*/
public List generate( List pTemplatePaths ) {
String MN = GM+"TemplatePath[] pTemplate )";
if( null == pTemplatePaths ) {
throw new JostracaException( TMS+WNFM+MN );
}
List tmlist = generate( pTemplatePaths, iUserMessageHandler );
return tmlist;
}
/** Generate more than one template.
* @return List of Template objects
* @see #generate(TemplatePath,UserMessageHandler)
*/
public List generate( List pTemplatePaths, UserMessageHandler pUserMessageHandler ) {
String MN = GM+"TemplatePath[] pTemplate"+UMHP;
if( null == pTemplatePaths ) {
throw new JostracaException( TMS+WNFM+MN );
}
if( null == pUserMessageHandler ) {
throw new JostracaException( UMH+WNFM+MN );
}
try {
// REVIEW: load system, local config using ConfigFolder
iService.loadConfigFromFolder( iConfigFolder, new ArrayList() );
if( iAlwaysGenerate ) {
if( !iCmdPropertySet.has( Property.main_ExecuteCodeWriter ) ) {
iCmdPropertySet.set( Property.main_ExecuteCodeWriter, Standard.YES );
}
}
iService.addPropertySet( Service.CONF_cmdline, iCmdPropertySet );
iService.setUserMessageHandler( pUserMessageHandler );
iUserMessageHandler = pUserMessageHandler;
iService.setTemplatePaths( pTemplatePaths );
if( null != iContext ) {
iService.setContextForTemplate( iContext );
}
// REVIEW: need some sort of result object from build
List tmlist = iService.build();
return tmlist;
}
catch( StandardException se ) { throw se; }
catch( Exception e ) {
// REVIEW: this is a hack - need to move formatting out of RecordingUserMessageHandler
RecordingUserMessageHandler rumh = new RecordingUserMessageHandler();
rumh.error( e );
throw new JostracaException( rumh.toString() );
}
}
/** Return the {@link org.jostraca.util.UserMessageHandler} used during generation.
* By default this is a {@link org.jostraca.util.RecordingUserMessageHandler}, unless you
* have provided your own via a method such as {@link #generate(File,UserMessageHandler)}.
* Use the <code>toString</code> methods to gain access to the error message Strings.
*/
public UserMessageHandler getUserMessageHandler() {
return iUserMessageHandler;
}
/** Return the internal instance of the {@link org.jostraca.Service} object used to perform the generation. */
public Service getService() {
return iService;
}
}