You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by tf...@apache.org on 2007/10/12 22:18:07 UTC

svn commit: r584257 - in /db/torque: generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java site/trunk/xdocs/changes.xml

Author: tfischer
Date: Fri Oct 12 13:18:01 2007
New Revision: 584257

URL: http://svn.apache.org/viewvc?rev=584257&view=rev
Log:
Create nicely trimmed output in the generator.
Resolves TORQUE-71.
Thanks to Thoralf Rickert for the patch.

Modified:
    db/torque/generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java
    db/torque/site/trunk/xdocs/changes.xml

Modified: db/torque/generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java
URL: http://svn.apache.org/viewvc/db/torque/generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java?rev=584257&r1=584256&r2=584257&view=diff
==============================================================================
--- db/torque/generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java (original)
+++ db/torque/generator/trunk/src/java/org/apache/torque/task/TorqueDataModelTask.java Fri Oct 12 13:18:01 2007
@@ -19,7 +19,16 @@
  * under the License.
  */
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Hashtable;
@@ -28,6 +37,8 @@
 import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
+import org.apache.texen.Generator;
+import org.apache.texen.ant.TexenTask;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.DirectoryScanner;
 import org.apache.tools.ant.types.FileSet;
@@ -35,8 +46,13 @@
 import org.apache.torque.engine.database.model.Database;
 import org.apache.torque.engine.database.transform.XmlToAppData;
 import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.context.Context;
-import org.apache.texen.ant.TexenTask;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
 
 /**
  * A base torque task that uses either a single XML schema
@@ -372,4 +388,390 @@
             }
         }
     }
+    /**
+     * This message fragment (telling users to consult the log or
+     * invoke ant with the -debug flag) is appended to rethrown
+     * exception messages.
+     */
+    private final static String ERR_MSG_FRAGMENT = 
+        ". For more information consult the velocity log, or invoke ant " +
+    "with the -debug flag.";
+
+    /**
+     * This method creates an VelocityEngine instance, parses
+     * every template and creates the corresponding output.
+     * 
+     * Unfortunately the TextenTask.execute() method makes
+     * everything for us but we just want to set our own
+     * VelocityTemplateLoader. 
+     * TODO: change once TEXEN-14 is resolved and out.
+     *  
+     * @see org.apache.texen.ant.TexenTask#execute()
+     */
+    public void execute() throws BuildException 
+    {
+        // Make sure the template path is set.
+        if (templatePath == null && useClasspath == false)
+        {
+            throw new BuildException(
+                "The template path needs to be defined if you are not using "
+                        + "the classpath for locating templates!");
+        }
+
+        // Make sure the control template is set.
+        if (controlTemplate == null)
+        {
+            throw new BuildException(
+                    "The control template needs to be defined!");
+        }
+
+        // Make sure the output directory is set.
+        if (outputDirectory == null)
+        {
+            throw new BuildException(
+                    "The output directory needs to be defined!");
+        }
+
+        // Make sure there is an output file.
+        if (outputFile == null)
+        {
+            throw new BuildException("The output file needs to be defined!");
+        }
+
+        VelocityEngine ve = new VelocityEngine();
+
+        try
+        {
+            // Setup the Velocity Runtime.
+            if (templatePath != null)
+            {
+                log("Using templatePath: " + templatePath, project.MSG_VERBOSE);
+                ve.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH,
+                        templatePath);
+
+                // TR: We need our own FileResourceLoader
+                ve.addProperty(VelocityEngine.RESOURCE_LOADER, "torquefile");
+                ve.setProperty("torquefile." + VelocityEngine.RESOURCE_LOADER
+                        + ".instance", new TorqueFileResourceLoader(this));
+            }
+
+            if (useClasspath)
+            {
+                log("Using classpath");
+                // TR: We need our own ClasspathResourceLoader
+                ve.addProperty(VelocityEngine.RESOURCE_LOADER, "classpath");
+
+                ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER
+                        + ".instance", new TorqueClasspathResourceLoader(this));
+
+                ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER
+                        + ".cache", "false");
+
+                ve.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER
+                        + ".modificationCheckInterval", "2");
+            }
+
+            ve.init();
+
+            // Create the text generator.
+            Generator generator = Generator.getInstance();
+            generator.setVelocityEngine(ve);
+            generator.setOutputPath(outputDirectory);
+            generator.setInputEncoding(inputEncoding);
+            generator.setOutputEncoding(outputEncoding);
+
+            if (templatePath != null)
+            {
+                generator.setTemplatePath(templatePath);
+            }
+
+            // Make sure the output directory exists, if it doesn't
+            // then create it.
+            File file = new File(outputDirectory);
+            if (!file.exists())
+            {
+                file.mkdirs();
+            }
+
+            String path = outputDirectory + File.separator + outputFile;
+            log("Generating to file " + path, project.MSG_INFO);
+            Writer writer = generator.getWriter(path, outputEncoding);
+
+            // The generator and the output path should
+            // be placed in the init context here and
+            // not in the generator class itself.
+            Context c = initControlContext();
+
+            // Everything in the generator class should be
+            // pulled out and placed in here. What the generator
+            // class does can probably be added to the Velocity
+            // class and the generator class can probably
+            // be removed all together.
+            populateInitialContext(c);
+
+            // Feed all the options into the initial
+            // control context so they are available
+            // in the control/worker templates.
+            if (contextProperties != null)
+            {
+                Iterator i = contextProperties.getKeys();
+
+                while (i.hasNext())
+                {
+                    String property = (String) i.next();
+                    String value = contextProperties.getString(property);
+
+                    // Now lets quickly check to see if what
+                    // we have is numeric and try to put it
+                    // into the context as an Integer.
+                    try
+                    {
+                        c.put(property, new Integer(value));
+                    } catch (NumberFormatException nfe)
+                    {
+                        // Now we will try to place the value into
+                        // the context as a boolean value if it
+                        // maps to a valid boolean value.
+                        String booleanString = contextProperties
+                                .testBoolean(value);
+
+                        if (booleanString != null)
+                        {
+                            c.put(property, new Boolean(booleanString));
+                        } else
+                        {
+                            // We are going to do something special
+                            // for properties that have a "file.contents"
+                            // suffix: for these properties will pull
+                            // in the contents of the file and make
+                            // them available in the context. So for
+                            // a line like the following in a properties file:
+                            //
+                            // license.file.contents = license.txt
+                            //
+                            // We will pull in the contents of license.txt
+                            // and make it available in the context as
+                            // $license. This should make texen a little
+                            // more flexible.
+                            if (property.endsWith("file.contents"))
+                            {
+                                // We need to turn the license file from
+                                // relative to
+                                // absolute, and let Ant help :)
+                                value = org.apache.velocity.util.StringUtils
+                                        .fileContentsToString(project
+                                                .resolveFile(value)
+                                                .getCanonicalPath());
+
+                                property = property.substring(0, property
+                                        .indexOf("file.contents") - 1);
+                            }
+
+                            c.put(property, value);
+                        }
+                    }
+                }
+            }
+
+            writer.write(generator.parse(controlTemplate, c));
+            writer.flush();
+            writer.close();
+            generator.shutdown();
+            cleanup();
+        } 
+        catch (BuildException e)
+        {
+            throw e;
+        } 
+        catch (MethodInvocationException e)
+        {
+            throw new BuildException("Exception thrown by '"
+                    + e.getReferenceName() + "." + e.getMethodName() + "'"
+                    + ERR_MSG_FRAGMENT, e.getWrappedThrowable());
+        } 
+        catch (ParseErrorException e)
+        {
+            throw new BuildException(
+                    "Velocity syntax error" + ERR_MSG_FRAGMENT, e);
+        } 
+        catch (ResourceNotFoundException e)
+        {
+            throw new BuildException(
+                    "Resource not found" + ERR_MSG_FRAGMENT, 
+                    e);
+        } 
+        catch (Exception e)
+        {
+            throw new BuildException(
+                    "Generation failed" + ERR_MSG_FRAGMENT, 
+                    e);
+        }
+    }
+
+    /**
+     * This method filters the template and replaces some
+     * unwanted characters. For example it removes leading
+     * spaces in front of velocity commands and replaces
+     * tabs with spaces to prevent bounces in different
+     * code editors with different tab-width-setting.
+     * 
+     * @param resource the input stream to filter
+     * 
+     * @return the filtered input stream.
+     * 
+     * @throws IOException if creating, reading or writing to a stream fails.
+     */
+    protected InputStream filter(InputStream resource) throws IOException
+    {
+        InputStreamReader streamReader;
+        if (inputEncoding != null)
+        {
+            streamReader = new InputStreamReader(resource, inputEncoding);
+        }
+        else
+        {
+            streamReader = new InputStreamReader(resource);
+        }
+        LineNumberReader lineNumberReader = new LineNumberReader(streamReader);
+        String line = null;
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = null;
+        if (inputEncoding != null)
+        {
+            ps = new PrintStream(baos, true, inputEncoding);
+        }
+        else
+        {
+            ps = new PrintStream(baos, true);
+        }
+
+        while ((line = lineNumberReader.readLine()) != null)
+        {
+            // remove leading spaces in front of velocity commands and comments
+            line = line.replaceAll("^\\s*#", "#");
+            // replace tabs with spaces to prevent bounces in editors
+            line = line.replaceAll("\t", "    ");
+            ps.println(line);
+        }
+        ps.flush();
+        ps.close();
+
+        return new ByteArrayInputStream(baos.toByteArray());
+    }
+
+    
+    /**
+     * A custom classpath resource loader which filters tabs and removes spaces
+     * from lines with velocity commands. 
+     */
+    public static class TorqueClasspathResourceLoader 
+            extends ClasspathResourceLoader
+    {
+        /**
+         * The task in which this resource loader is used.
+         */
+        private TorqueDataModelTask task;
+        
+        /**
+         * Constructor.
+         *
+         * @param task the task in which this resource loader is used.
+         */
+        public TorqueClasspathResourceLoader(TorqueDataModelTask task)
+        {
+            this.task = task;
+        }
+        
+        /**
+         * @see org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader#getResourceStream(java.lang.String)
+         */
+        public synchronized InputStream getResourceStream(String name) 
+                throws ResourceNotFoundException 
+        {
+            InputStream source = null;
+            try 
+            {
+                source = super.getResourceStream(name);
+                return task.filter(source);
+            } 
+            catch (IOException uee)
+            {
+                task.log(uee.getMessage());
+                throw new ResourceNotFoundException(uee.getMessage());
+            }
+            finally
+            {
+                if (source != null)
+                {
+                    try
+                    {
+                        source.close();
+                    }
+                    catch (IOException e)
+                    {
+                        task.log(e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * A custom file resource loader which filters tabs and removes spaces
+     * from lines with velocity commands. 
+     */
+    public static class TorqueFileResourceLoader
+            extends FileResourceLoader
+    {
+        /**
+         * The task in which this resource loader is used.
+         */
+        private TorqueDataModelTask task;
+        
+        /**
+         * Constructor.
+         *
+         * @param task the task in which this resource loader is used.
+         */
+        public TorqueFileResourceLoader(TorqueDataModelTask task)
+        {
+            this.task = task;
+        }
+        
+        /**
+         * @see org.apache.velocity.runtime.resource.loader.FileResourceLoader#getResourceStream(java.lang.String)
+         */
+        public synchronized InputStream getResourceStream(
+                String name) 
+                throws ResourceNotFoundException
+        {
+            InputStream source = null;
+            try 
+            {
+                source = super.getResourceStream(name);
+                return task.filter(source);
+            } 
+            catch (IOException uee)
+            {
+                task.log(uee.getMessage());
+                throw new ResourceNotFoundException(uee.getMessage());
+            }
+            finally
+            {
+                if (source != null)
+                {
+                    try
+                    {
+                        source.close();
+                    }
+                    catch (IOException e)
+                    {
+                        task.log(e.getMessage());
+                    }
+                }
+            }
+        }
+    }
 }
+
+

Modified: db/torque/site/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/db/torque/site/trunk/xdocs/changes.xml?rev=584257&r1=584256&r2=584257&view=diff
==============================================================================
--- db/torque/site/trunk/xdocs/changes.xml (original)
+++ db/torque/site/trunk/xdocs/changes.xml Fri Oct 12 13:18:01 2007
@@ -31,6 +31,9 @@
 
   <body>
   <release version="3.3-RC3" date="in SVN">
+    <action type="change" dev="tfischer" issue="TORQUE-71" due-to="Thoralf Rickert">
+      Create nicely trimmed output in the generator.
+    </action>
     <action type="add" dev="tfischer" issue="TORQUE-101" due-to="Marc Kannegiesser">
       Implemented the goal id-broker-init-sql in the Maven2 plugin.
     </action>



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org