Index: src/main/java/org/codehaus/mojo/antlr/AbstractAntlrMojo.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/AbstractAntlrMojo.java	(revision 8345)
+++ src/main/java/org/codehaus/mojo/antlr/AbstractAntlrMojo.java	Wed Dec 17 08:19:38 CST 2008
@@ -46,7 +46,14 @@
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectHelper;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.CommandLine;
 import org.codehaus.mojo.antlr.options.Grammar;
+import org.codehaus.mojo.antlr.proxy.Helper;
+import org.codehaus.mojo.antlr.metadata.MetadataExtracter;
+import org.codehaus.mojo.antlr.metadata.XRef;
+import org.codehaus.mojo.antlr.plan.GenerationPlan;
+import org.codehaus.mojo.antlr.plan.GenerationPlanBuilder;
 import org.codehaus.plexus.util.StringOutputStream;
 import org.codehaus.plexus.util.StringUtils;
 
@@ -58,6 +65,7 @@
  */
 public abstract class AbstractAntlrMojo
     extends AbstractMojo
+	implements Environment
 {
     // ----------------------------------------------------------------------
     // Mojo parameters
@@ -186,7 +194,15 @@
      */
     private boolean traceTreeParser;
 
+	public File getSourceDirectory() {
+		return sourceDirectory;
+	}
+
+	public File getOutputDirectory() {
+		return outputDirectory;
+	}
+
-    /**
+	/**
      * @throws MojoExecutionException
      */
     protected void executeAntlr()
@@ -194,15 +210,37 @@
     {
         validateParameters();
 
-		// ----------------------------------------------------------------------
-		// Find the Antlr dependency to use for generation
-		// ----------------------------------------------------------------------
+		Artifact antlrArtifact = locateAntlrArtifact();
+		MetadataExtracter metadataExtracter = new MetadataExtracter( this, new Helper( antlrArtifact ) );
+		XRef metadata = metadataExtracter.processMetadata( getGrammars() );
 
+		Iterator generationPlans = new GenerationPlanBuilder( this ).buildGenerationPlans( metadata ).iterator();
+		while ( generationPlans.hasNext() ) {
+			final GenerationPlan plan = ( GenerationPlan ) generationPlans.next();
+			if ( ! plan.isOutOfDate() ) {
+				getLog().info( "grammar [" + plan.getId() + "] was up-to-date; skipping" );
+				continue;
+			}
+
+			getLog().info( "performing grammar generation [" + plan.getId() + "]" );
+			performGeneration( plan, antlrArtifact );
+		}
+
+
+        if ( project != null )
+        {
+            projectHelper.addResource( project, outputDirectory.getAbsolutePath(), Collections
+                .singletonList( "**/**.txt" ), new ArrayList() );
+            project.addCompileSourceRoot( outputDirectory.getAbsolutePath() );
+        }
+    }
+
+	protected final Artifact locateAntlrArtifact() throws NoAntlrDependencyDefinedException {
 		Artifact antlrArtifact = null;
 		if ( project.getCompileArtifacts() != null ) {
 			Iterator projectArtifacts = project.getCompileArtifacts().iterator();
 			while ( projectArtifacts.hasNext() ) {
-				final Artifact artifact = ( Artifact ) projectArtifacts.next();;
+				final Artifact artifact = ( Artifact ) projectArtifacts.next();
 				if ( "antlr".equals( artifact.getGroupId() ) &&
 						( "antlr".equals( artifact.getArtifactId() ) || "antlr-all".equals( artifact.getArtifactId() ) ) ) {
 					antlrArtifact = artifact;
@@ -214,166 +252,152 @@
 			throw new NoAntlrDependencyDefinedException( "project did not define antlr:antlr depenency" );
 		}
 		// TODO : enforce specific version range; e.g. [2.7,3.0) ???
-
-		// ----------------------------------------------------------------------
-        // Call Antlr for each grammar
-        // ----------------------------------------------------------------------
-
-        Grammar[] grammarsUsed = getGrammars();
-
-        for ( int i = 0; i < grammarsUsed.length; i++ )
-        {
-            String grammarName = grammarsUsed[i].getName();
-
-            if ( StringUtils.isEmpty( grammarName ) )
-            {
-                getLog().info( "Empty grammar in the configuration. Skipped." );
-                continue;
+		return antlrArtifact;
-            }
+	}
 
-            File grammar = new File( sourceDirectory, grammarName.trim() );
-
-            if ( !grammar.exists() )
-            {
-                throw new MojoExecutionException( "The grammar '" + grammar.getAbsolutePath() + "' doesnt exist." );
+	protected void performGeneration(GenerationPlan plan, Artifact antlrArtifact) throws MojoExecutionException {
+		if ( ! plan.getGenerationDirectory().getParentFile().exists() ) {
+			plan.getGenerationDirectory().getParentFile().mkdirs();
-            }
+		}
 
-            getLog().info( "Using Antlr grammar: " + grammar );
-
-            File generated = null;
-            try
-            {
-                generated = getGeneratedFile( grammar.getPath(), outputDirectory );
-            }
-            catch ( IOException e )
-            {
-                throw new MojoExecutionException( "Failed to get generated file: " + e.getMessage(), e );
-            }
-
-            if ( generated.exists() )
-            {
-                if ( generated.lastModified() > grammar.lastModified() )
-                {
-                    // it's more recent, skip.
-                    getLog().info( "The grammar is already generated." );
-                    continue;
-                }
-            }
-
-            if ( !generated.getParentFile().exists() )
-            {
-                generated.getParentFile().mkdirs();
-            }
-
-            // ----------------------------------------------------------------------
-            // Wrap arguments
-            // Note: grammar file should be last
-            // ----------------------------------------------------------------------
+		// ----------------------------------------------------------------------
+		// Wrap arguments
+		// Note: grammar file should be last
+		// ----------------------------------------------------------------------
 
-            List arguments = new LinkedList();
-            addArgIf( arguments, debug, "-debug" );
-            addArgIf( arguments, diagnostic, "-diagnostic" );
-            addArgIf( arguments, trace, "-trace" );
-            addArgIf( arguments, traceParser, "-traceParser" );
-            addArgIf( arguments, traceLexer, "-traceLexer" );
-            addArgIf( arguments, traceTreeParser, "-traceTreeParser" );
+		List arguments = new LinkedList();
+		addArgIf( arguments, debug, "-debug" );
+		addArgIf( arguments, diagnostic, "-diagnostic" );
+		addArgIf( arguments, trace, "-trace" );
+		addArgIf( arguments, traceParser, "-traceParser" );
+		addArgIf( arguments, traceLexer, "-traceLexer" );
+		addArgIf( arguments, traceTreeParser, "-traceTreeParser" );
+
-            addArgs( arguments );
+		addArgs( arguments );
+
-            arguments.add( "-o" );
+		arguments.add( "-o" );
-            arguments.add( generated.getParentFile().getPath() );
-            if ( StringUtils.isNotEmpty( grammarsUsed[i].getGlib() ) )
-            {
-                StringBuffer glib = new StringBuffer();
-                StringTokenizer st = new StringTokenizer( grammarsUsed[i].getGlib(), ",; " );
-                while ( st.hasMoreTokens() )
-                {
-                    glib.append( new File( sourceDirectory, st.nextToken().trim() ) );
-                    if ( st.hasMoreTokens() )
-                    {
-                        glib.append( ";" );
+        arguments.add( plan.getGenerationDirectory().getPath() );
+
+		if ( plan.getCollectedSuperGrammarIds().size() > 0 ) {
+			arguments.add( "-glib" );
+			StringBuffer buffer = new StringBuffer();
+			Iterator ids = plan.getCollectedSuperGrammarIds().iterator();
+			while ( ids.hasNext() ) {
+				buffer.append( new File( sourceDirectory, ( String ) ids.next() ) );
+				if ( ids.hasNext() ) {
+					buffer.append( ';' );
-                    }
-                }
+				}
+			}
-                arguments.add( "-glib" );
-                arguments.add( glib.toString() );
+			arguments.add( buffer.toString() );
-            }
+		}
-            arguments.add( grammar.getPath() );
 
-            String[] args = (String[]) arguments.toArray( new String[0] );
+		arguments.add( plan.getSource().getPath() );
 
-            if ( getLog().isDebugEnabled() )
-            {
-                getLog().debug( "antlr args=\n" + StringUtils.join( args, "\n" ) );
+		String[] args = (String[]) arguments.toArray( new String[arguments.size()] );
+
+
+
+		if ( plan.getImportVocabTokenTypesDirectory() != null
+				&& ! plan.getImportVocabTokenTypesDirectory().equals( plan.getGenerationDirectory() ) ) {
+			// we need to spawn a new process to properly set up PWD
+			CommandLine commandLine = new CommandLine( "java" );
+			commandLine.addArgument( "-classpath", false );
+			commandLine.addArgument( generateClasspathForProcessSpawning( antlrArtifact ), true );
+			commandLine.addArgument( "antlr.Tool", false );
+			commandLine.addArguments( args, true );
+			DefaultExecutor executor = new DefaultExecutor();
+			executor.setWorkingDirectory( plan.getImportVocabTokenTypesDirectory() );
+			try {
+				executor.execute( commandLine );
-            }
+			}
+			catch ( IOException e ) {
+				getLog().warn( "Error spawning process to execute antlr tool : " + e.getMessage() );
+			}
 
+			return;
+		}
+
+
+
-            // ----------------------------------------------------------------------
-            // Call Antlr
-            // ----------------------------------------------------------------------
+		// ----------------------------------------------------------------------
+		// Call Antlr
+		// ----------------------------------------------------------------------
 
+		if ( getLog().isDebugEnabled() ) {
+			getLog().debug( "antlr args=\n" + StringUtils.join( args, "\n" ) );
+		}
+
-			boolean failedSetManager = false;
-            SecurityManager oldSm = null;
-            try
-            {
-                oldSm = System.getSecurityManager();
-                System.setSecurityManager( NoExitSecurityManager.INSTANCE );
-            }
-            catch ( SecurityException ex )
-            {
-                //ANTLR-12
-                oldSm = null;
-                failedSetManager = true;
-                //ignore, in embedded environment the security manager can already be set.
-                // in such a case assume the exit call is handled properly..
-                getLog().warn(
-                               "Cannot set custom SecurityManager. "
-                                   + "Antlr's call to System.exit() can cause application shutdown "
-                                   + "if not handled by the current SecurityManager." );
-            }
+		boolean failedSetManager = false;
+		SecurityManager oldSm = null;
+		try
+		{
+			oldSm = System.getSecurityManager();
+			System.setSecurityManager( NoExitSecurityManager.INSTANCE );
+		}
+		catch ( SecurityException ex )
+		{
+			//ANTLR-12
+			oldSm = null;
+			failedSetManager = true;
+			//ignore, in embedded environment the security manager can already be set.
+			// in such a case assume the exit call is handled properly..
+			getLog().warn(
+						   "Cannot set custom SecurityManager. "
+							   + "Antlr's call to System.exit() can cause application shutdown "
+							   + "if not handled by the current SecurityManager." );
+		}
 
+		String originalUserDir = null;
+		if ( plan.getImportVocabTokenTypesDirectory() != null ) {
+			originalUserDir = System.getProperty( "user.dir" );
+			System.setProperty( "user.dir", plan.getImportVocabTokenTypesDirectory().getPath() );
+		}
+
-            PrintStream oldErr = System.err;
+		PrintStream oldErr = System.err;
 
-            OutputStream errOS = new StringOutputStream();
-            PrintStream err = new PrintStream( errOS );
-            System.setErr( err );
+		OutputStream errOS = new StringOutputStream();
+		PrintStream err = new PrintStream( errOS );
+		System.setErr( err );
 
-            try
-            {
-				executeAntlrInIsolatedClassLoader( (String[]) arguments.toArray( new String[0] ), antlrArtifact );
-            }
-            catch ( SecurityException e )
-            {
-                if ( e.getMessage().equals( "exitVM-0" )
-                    || e.getClass().getName().equals( "org.netbeans.core.execution.ExitSecurityException" ) ) //netbeans IDE Sec Manager.
-                {
-                    //ANTLR-12
-                    //now basically every secutiry manager could set different message, how to handle in generic way?
-                    //probably only by external execution
-                    /// in case of NetBeans SecurityManager, it's not possible to distinguish exit codes, rather swallow than fail.
-                    getLog().debug( e );
-                }
-                else
-                {
-                    throw new MojoExecutionException( "Antlr execution failed: " + e.getMessage()
-                        + "\n Error output:\n" + errOS, e );
-                }
-            }
-            finally
-            {
+		try
+		{
+			executeAntlrInIsolatedClassLoader( (String[]) arguments.toArray( new String[0] ), antlrArtifact );
+		}
+		catch ( SecurityException e )
+		{
+			if ( e.getMessage().equals( "exitVM-0" )
+				|| e.getClass().getName().equals( "org.netbeans.core.execution.ExitSecurityException" ) ) //netbeans IDE Sec Manager.
+			{
+				//ANTLR-12
+				//now basically every secutiry manager could set different message, how to handle in generic way?
+				//probably only by external execution
+				/// in case of NetBeans SecurityManager, it's not possible to distinguish exit codes, rather swallow than fail.
+				getLog().debug( e );
+			}
+			else
+			{
+				throw new MojoExecutionException( "Antlr execution failed: " + e.getMessage()
+					+ "\n Error output:\n" + errOS, e );
+			}
+		}
+		finally
+		{
+			if ( originalUserDir != null ) {
+				System.setProperty( "user.dir", originalUserDir );
+			}
-                if ( !failedSetManager )
-                {
-                    System.setSecurityManager( oldSm );
-                }
-                System.setErr( oldErr );
+			if ( !failedSetManager )
+			{
+				System.setSecurityManager( oldSm );
+			}
+			System.setErr( oldErr );
-
-                System.err.println( errOS.toString() );
-            }
-        }
+			System.err.println( errOS.toString() );
+		}
+	}
 
-        if ( project != null )
-        {
-            projectHelper.addResource( project, outputDirectory.getAbsolutePath(), Collections
-                .singletonList( "**/**.txt" ), new ArrayList() );
-            project.addCompileSourceRoot( outputDirectory.getAbsolutePath() );
+	private String generateClasspathForProcessSpawning(Artifact antlrArtifact) {
+		// todo : is maven by itself enough for the generation???
+		return antlrArtifact.getFile().getPath();
-        }
+	}
-    }
 
 
 	private void executeAntlrInIsolatedClassLoader(String[] args, Artifact antlrArtifact) throws MojoExecutionException {
Index: src/main/java/org/codehaus/mojo/antlr/proxy/Tool.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/proxy/Tool.java	Mon Dec 15 15:10:46 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/proxy/Tool.java	Mon Dec 15 15:10:46 CST 2008
@@ -0,0 +1,55 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.proxy;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.codehaus.mojo.antlr.Environment;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Tool {
+	private final Environment environment;
+	private final Object antlrTool;
+
+	public Tool(Environment environment, Helper helper) throws MojoExecutionException {
+		try {
+			antlrTool = helper.getAntlrToolClass().newInstance();
+		}
+		catch ( Throwable t ) {
+			throw new MojoExecutionException( "Unable to instantiate antlr.Tool", t );
+		}
+		this.environment = environment;
+	}
+
+	public Object getAntlrTool() {
+		return antlrTool;
+	}
+
+	public Environment getEnvironment() {
+		return environment;
+	}
+}
Index: src/main/java/org/codehaus/mojo/antlr/metadata/Grammar.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/metadata/Grammar.java	Tue Dec 16 10:37:22 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/metadata/Grammar.java	Tue Dec 16 10:37:22 CST 2008
@@ -0,0 +1,95 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.metadata;
+
+import java.io.File;
+
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Grammar {
+	private final GrammarFile grammarFile;
+	private String className;
+    private String superGrammarName;
+	private String importVocab;
+	private String exportVocab;
+
+	public Grammar(GrammarFile grammarFile) {
+		this.grammarFile = grammarFile;
+		grammarFile.addGrammar( this );
+	}
+
+	public GrammarFile getGrammarFile() {
+		return grammarFile;
+	}
+
+	public String getClassName() {
+		return className;
+	}
+
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+	public String getSuperGrammarName() {
+		return superGrammarName;
+	}
+
+	public void setSuperGrammarName(String superGrammarName) {
+		this.superGrammarName = superGrammarName;
+	}
+
+	public String getImportVocab() {
+		return importVocab;
+	}
+
+	public void setImportVocab(String importVocab) {
+		this.importVocab = importVocab;
+	}
+
+	public String getExportVocab() {
+		return exportVocab;
+	}
+
+	public void setExportVocab(String exportVocab) {
+		this.exportVocab = exportVocab;
+	}
+
+	public String getPackageName() {
+		return getGrammarFile().getPackageName();
+	}
+
+	public String determineGeneratedParserPath() {
+		if ( StringUtils.isEmpty( getPackageName() ) ) {
+			return getClassName() + ".java";
+		}
+		else {
+			return getPackageName().replace( '.', File.separatorChar ) + File.separatorChar + getClassName() + ".java";
+		}
+	}
+}
Index: src/main/java/org/codehaus/mojo/antlr/metadata/XRef.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/metadata/XRef.java	Tue Dec 16 12:54:58 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/metadata/XRef.java	Tue Dec 16 12:54:58 CST 2008
@@ -0,0 +1,80 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.metadata;
+
+import java.util.LinkedHashMap;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class XRef {
+	private final Object antlrHierarchy;
+
+	private LinkedHashMap filesById = new LinkedHashMap();
+	private HashMap filesByExportVocab = new HashMap();
+	private HashMap filesByClassName = new HashMap();
+
+	public XRef(Object antlrHierarchy) {
+		this.antlrHierarchy = antlrHierarchy;
+	}
+
+	public Object getAntlrHierarchy() {
+		return antlrHierarchy;
+	}
+
+	void addGrammarFile(GrammarFile grammarFile) {
+		filesById.put( grammarFile.getId(), grammarFile );
+		Iterator itr = grammarFile.getGrammars().iterator();
+		while ( itr.hasNext() ) {
+			final Grammar grammar = ( Grammar ) itr.next();
+			filesByClassName.put( grammar.getClassName(), grammarFile );
+			if ( grammar.getExportVocab() != null ) {
+				GrammarFile old = ( GrammarFile ) filesByExportVocab.put( grammar.getExportVocab(), grammarFile );
+				if ( old != null && old != grammarFile ) {
+					System.out.println( "[WARNING] : multiple grammars defined the same exportVocab : " + grammar.getExportVocab() );
+				}
+			}
+		}
+	}
+
+	public Iterator iterateGrammarFiles() {
+		return filesById.values().iterator();
+	}
+
+	public GrammarFile getGrammarFileById(String id) {
+		return ( GrammarFile ) filesById.get( id );
+	}
+
+	public GrammarFile getGrammarFileByClassName(String className) {
+		return ( GrammarFile ) filesByClassName.get( className );
+	}
+
+	public GrammarFile getGrammarFileByExportVocab(String exportVocab) {
+		return ( GrammarFile ) filesByExportVocab.get( exportVocab );
+	}
+}
Index: src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlanBuilder.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlanBuilder.java	Tue Dec 16 13:58:06 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlanBuilder.java	Tue Dec 16 13:58:06 CST 2008
@@ -0,0 +1,175 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.plan;
+
+import java.util.LinkedHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.File;
+
+import org.codehaus.mojo.antlr.Environment;
+import org.codehaus.mojo.antlr.metadata.XRef;
+import org.codehaus.mojo.antlr.metadata.GrammarFile;
+import org.codehaus.mojo.antlr.metadata.Grammar;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * TODO : javadoc
+*
+* @author Steve Ebersole
+*/
+public class GenerationPlanBuilder {
+	private final Environment environment;
+	private final LinkedHashMap generationPlans = new LinkedHashMap();
+
+	private XRef metadataXRef;
+
+	public GenerationPlanBuilder(Environment environment) {
+		this.environment = environment;
+	}
+
+	public synchronized List buildGenerationPlans(XRef metadataXRef) {
+		this.metadataXRef = metadataXRef;
+
+		Iterator grammarFiles = metadataXRef.iterateGrammarFiles();
+		while ( grammarFiles.hasNext() ) {
+			final GrammarFile grammarFile = ( GrammarFile ) grammarFiles.next();
+			// NOTE : loacteOrBuildGenerationPlan populates the generationPlans map
+			loacteOrBuildGenerationPlan( grammarFile );
+		}
+
+		metadataXRef = null;
+		return new ArrayList( generationPlans.values() );
+	}
+
+	private GenerationPlan loacteOrBuildGenerationPlan(GrammarFile grammarFile) {
+		GenerationPlan generationPlan = ( GenerationPlan ) generationPlans.get( grammarFile.getId() );
+		if ( generationPlan == null ) {
+			generationPlan = buildGenerationPlan( grammarFile );
+		}
+		return generationPlan;
+	}
+
+	private GenerationPlan buildGenerationPlan(GrammarFile grammarFile) {
+		File generationDirectory = StringUtils.isEmpty( grammarFile.getPackageName() )
+				? environment.getOutputDirectory()
+				: new File( environment.getOutputDirectory(), grammarFile.getPackageName().replace( '.', File.separatorChar ) );
+
+		GenerationPlan generationPlan = new GenerationPlan(
+				grammarFile.getId(),
+				new File( grammarFile.getFileName() ),
+				generationDirectory,
+				grammarFile.getGlibs()
+		);
+
+		File leastRecentGrammarOutput = locateLeastRecentlyModifiedOutputFile( generationDirectory );
+
+		// see if the grammar is out-of-date by way super-grammars from user defined glib options
+		for ( int i = 0; i < grammarFile.getGlibs().length; i++ ) {
+			final GrammarFile superGrammarGrammarFile =  metadataXRef.getGrammarFileById( grammarFile.getGlibs()[i] );
+			final GenerationPlan superGrammarGenerationPlan = loacteOrBuildGenerationPlan( superGrammarGrammarFile );
+			if ( superGrammarGenerationPlan.isOutOfDate() ) {
+				generationPlan.markOutOfDate();
+			}
+			else if ( superGrammarGenerationPlan.getSource().lastModified() > leastRecentGrammarOutput.lastModified() ) {
+				generationPlan.markOutOfDate();
+			}
+		}
+
+		Iterator grammars = grammarFile.getGrammars().iterator();
+		while ( grammars.hasNext() ) {
+			final Grammar grammar = ( Grammar ) grammars.next();
+			final File generatedParserFile = new File( environment.getOutputDirectory(), grammar.determineGeneratedParserPath() );
+
+			if ( ! generatedParserFile.exists() ) {
+				generationPlan.markOutOfDate();
+			}
+			else if ( generatedParserFile.lastModified() < generationPlan.getSource().lastModified() ) {
+				generationPlan.markOutOfDate();
+			}
+
+			// see if the grammar if out-of-date by way of its super-grammar(s) as gleaned from parsing the grammar file
+			if ( StringUtils.isNotEmpty( grammar.getSuperGrammarName() ) ) {
+				final GrammarFile superGrammarGrammarFile =  metadataXRef.getGrammarFileByClassName( grammar.getSuperGrammarName() );
+				if ( superGrammarGrammarFile != null ) {
+					final GenerationPlan superGrammarGenerationPlan = loacteOrBuildGenerationPlan( superGrammarGrammarFile );
+					generationPlan.addSuperGrammarId( superGrammarGenerationPlan.getId() );
+					if ( superGrammarGenerationPlan.isOutOfDate() ) {
+						generationPlan.markOutOfDate();
+					}
+					else if ( superGrammarGenerationPlan.getSource().lastModified() > generatedParserFile.lastModified() ) {
+						generationPlan.markOutOfDate();
+					}
+				}
+			}
+
+			// see if the grammar if out-of-date by way of its importVocab
+			if ( StringUtils.isNotEmpty( grammar.getImportVocab() ) ) {
+				final GrammarFile importVocabGrammarFile = metadataXRef.getGrammarFileByExportVocab( grammar.getImportVocab() );
+				if ( importVocabGrammarFile == null ) {
+					environment.getLog().warn( "unable to locate grammar exporting specifcied import vocab [" + grammar.getImportVocab() + "]" );
+				}
+				else if ( importVocabGrammarFile.getId().equals( grammarFile.getId() ) ) {
+
+				}
+				else {
+					final GenerationPlan importVocabGrammarGenerationPlan = loacteOrBuildGenerationPlan( importVocabGrammarFile );
+					generationPlan.setImportVocabTokenTypesDirectory(
+							importVocabGrammarGenerationPlan.getGenerationDirectory()
+					);
+					if ( importVocabGrammarGenerationPlan.isOutOfDate() ) {
+						generationPlan.markOutOfDate();
+					}
+					else if ( importVocabGrammarGenerationPlan.getSource().lastModified() > generatedParserFile.lastModified() ) {
+						generationPlan.markOutOfDate();
+					}
+				}
+			}
+		}
+
+		generationPlans.put( generationPlan.getId(), generationPlan );
+		return generationPlan;
+	}
+
+	private static File locateLeastRecentlyModifiedOutputFile(File directory) {
+		if ( !directory.exists() ) {
+			return null;
+		}
+
+		File[] contents = directory.listFiles();
+		if ( contents.length == 0 ) {
+			return null;
+		}
+
+		File oldest = contents[0];
+		for ( int i = 1; i < contents.length; i++ ) {
+			if ( contents[i].lastModified() < oldest.lastModified() ) {
+				oldest = contents[i];
+			}
+		}
+
+		return oldest;
+	}
+}
\ No newline at end of file
Index: src/main/java/org/codehaus/mojo/antlr/Environment.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/Environment.java	Mon Dec 15 15:10:46 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/Environment.java	Mon Dec 15 15:10:46 CST 2008
@@ -0,0 +1,41 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr;
+
+import java.io.File;
+
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public interface Environment {
+	public Log getLog();
+
+	public File getSourceDirectory();
+
+	public File getOutputDirectory();
+}
Index: src/main/java/org/codehaus/mojo/antlr/proxy/Helper.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/proxy/Helper.java	Tue Dec 16 00:11:13 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/proxy/Helper.java	Tue Dec 16 00:11:13 CST 2008
@@ -0,0 +1,109 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.proxy;
+
+import java.net.URLClassLoader;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class Helper {
+	public static final Class[] NO_ARG_SIGNATURE = new Class[0];
+	public static final Class[] STRING_ARG_SIGNATURE = new Class[] { String.class };
+	public static final Object[] NO_ARGS = new Object[0];
+
+	private final URLClassLoader antlrClassLoader;
+
+	private final Class antlrToolClass;
+	private final Class antlrPreprocessorToolClass;
+	private final Class antlrHierarchyClass;
+	private final Class antlrGrammarFileClass;
+	private final Class antlrGrammarClass;
+	private final Class antlrOptionClass;
+	private final Class antlrIndexedVectorClass;
+
+	public Helper(Artifact antlrArtifact) throws MojoExecutionException {
+		try {
+			this.antlrClassLoader = new URLClassLoader(
+					new URL[] { antlrArtifact.getFile().toURL() },
+					ClassLoader.getSystemClassLoader()
+			);
+		}
+		catch ( MalformedURLException e ) {
+			throw new MojoExecutionException( "Unable to resolve antlr:antlr artifact url", e );
+		}
+
+		antlrToolClass = loadAntlrClass( "antlr.Tool" );
+		antlrPreprocessorToolClass = loadAntlrClass( "antlr.preprocessor.Tool" );
+		antlrHierarchyClass = loadAntlrClass( "antlr.preprocessor.Hierarchy" );
+		antlrGrammarFileClass = loadAntlrClass( "antlr.preprocessor.GrammarFile" );
+		antlrGrammarClass = loadAntlrClass( "antlr.preprocessor.Grammar" );
+		antlrOptionClass = loadAntlrClass( "antlr.preprocessor.Option" );
+		antlrIndexedVectorClass = loadAntlrClass( "antlr.collections.impl.IndexedVector" );
+	}
+
+	private Class loadAntlrClass(String className) throws MojoExecutionException {
+		try {
+			return antlrClassLoader.loadClass( className );
+		}
+		catch ( ClassNotFoundException e ) {
+			throw new MojoExecutionException( "could not load Antlr class :" + className, e );
+		}
+	}
+
+	public Class getAntlrToolClass() {
+		return antlrToolClass;
+	}
+
+	public Class getAntlrPreprocessorToolClass() {
+		return antlrPreprocessorToolClass;
+	}
+
+	public Class getAntlrHierarchyClass() {
+		return antlrHierarchyClass;
+	}
+
+	public Class getAntlrGrammarFileClass() {
+		return antlrGrammarFileClass;
+	}
+
+	public Class getAntlrGrammarClass() {
+		return antlrGrammarClass;
+	}
+
+	public Class getAntlrOptionClass() {
+		return antlrOptionClass;
+	}
+
+	public Class getAntlrIndexedVectorClass() {
+		return antlrIndexedVectorClass;
+	}
+}
Index: src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlan.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlan.java	Tue Dec 16 13:24:25 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/plan/GenerationPlan.java	Tue Dec 16 13:24:25 CST 2008
@@ -0,0 +1,91 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.plan;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+
+/**
+ * TODO : javadoc
+*
+* @author Steve Ebersole
+*/
+public class GenerationPlan {
+	private final String id;
+	private final File source;
+	private final File generationDirectory;
+
+	private File importVocabTokenTypesDirectory;
+	private boolean outOfDate;
+
+	private LinkedHashSet collectedSuperGrammarIds = new LinkedHashSet();
+
+	GenerationPlan(String id, File source, File generationDirectory, String[] glibIds) {
+		this.id = id;
+		this.source = source;
+		this.generationDirectory = generationDirectory;
+		if ( glibIds != null ) {
+			for ( int i = 0; i < glibIds.length; i++ ) {
+				addSuperGrammarId( glibIds[i] );
+			}
+		}
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public File getSource() {
+		return source;
+	}
+
+	public File getGenerationDirectory() {
+		return generationDirectory;
+	}
+
+	void addSuperGrammarId(String id) {
+		collectedSuperGrammarIds.add( id );
+	}
+
+	public LinkedHashSet getCollectedSuperGrammarIds() {
+		return collectedSuperGrammarIds;
+	}
+
+	public File getImportVocabTokenTypesDirectory() {
+		return importVocabTokenTypesDirectory;
+	}
+
+	void setImportVocabTokenTypesDirectory(File importVocabTokenTypesDirectory) {
+		this.importVocabTokenTypesDirectory = importVocabTokenTypesDirectory;
+	}
+
+	public boolean isOutOfDate() {
+		return outOfDate;
+	}
+
+	void markOutOfDate() {
+		this.outOfDate = true;
+	}
+}
\ No newline at end of file
Index: pom.xml
===================================================================
--- pom.xml	(revision 8345)
+++ pom.xml	Tue Dec 16 15:21:29 CST 2008
@@ -104,7 +104,14 @@
       <version>1.0-beta-1</version>
     </dependency>
 
-    <dependency>
+      <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-exec</artifactId>
+          <version>1.0.0-SNAPSHOT</version>
+      </dependency>
+
+
+    <dependency>
         <groupId>org.apache.maven.shared</groupId>
         <artifactId>maven-plugin-testing-harness</artifactId>
         <version>1.1</version>
Index: src/main/java/org/codehaus/mojo/antlr/metadata/GrammarFile.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/metadata/GrammarFile.java	Tue Dec 16 12:10:53 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/metadata/GrammarFile.java	Tue Dec 16 12:10:53 CST 2008
@@ -0,0 +1,75 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.metadata;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.io.File;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class GrammarFile {
+	private final String id;
+	private final String fileName;
+	private final String[] glibs;
+	private String packageName;
+	private List grammars = new ArrayList();
+
+	public GrammarFile(String id, String fileName, String[] glibs) {
+		this.id = id;
+		this.fileName = fileName;
+		this.glibs = glibs;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public String getFileName() {
+		return fileName;
+	}
+
+	public String[] getGlibs() {
+		return glibs;
+	}
+
+	public String getPackageName() {
+		return packageName;
+	}
+
+	void setPackageName(String packageName) {
+		this.packageName = packageName;
+	}
+
+	void addGrammar(Grammar grammar) {
+		grammars.add( grammar );
+	}
+
+	public List getGrammars() {
+		return grammars;
+	}
+}
Index: src/main/java/org/codehaus/mojo/antlr/metadata/MetadataExtracter.java
===================================================================
--- src/main/java/org/codehaus/mojo/antlr/metadata/MetadataExtracter.java	Tue Dec 16 12:44:16 CST 2008
+++ src/main/java/org/codehaus/mojo/antlr/metadata/MetadataExtracter.java	Tue Dec 16 12:44:16 CST 2008
@@ -0,0 +1,233 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.codehaus.mojo.antlr.metadata;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Enumeration;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.codehaus.mojo.antlr.Environment;
+import org.codehaus.mojo.antlr.proxy.Helper;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class MetadataExtracter {
+	private final Helper helper;
+	private final Environment environment;
+	private final Class antlrHierarchyClass;
+
+	public MetadataExtracter(Environment environment, Helper helper) throws MojoExecutionException {
+		this.environment = environment;
+		this.helper = helper;
+		this.antlrHierarchyClass = helper.getAntlrHierarchyClass();
+	}
+
+	public XRef processMetadata(org.codehaus.mojo.antlr.options.Grammar[] grammars) throws MojoExecutionException {
+		Object hierarchy;
+		Method readGrammarFileMethod;
+		Method getFileMethod;
+		try {
+			Object antlrTool = helper.getAntlrToolClass().newInstance();
+			Constructor ctor = antlrHierarchyClass.getConstructor( new Class[] { helper.getAntlrToolClass() } );
+			hierarchy = ctor.newInstance( new Object[] { antlrTool } );
+
+			readGrammarFileMethod = antlrHierarchyClass.getMethod( "readGrammarFile", Helper.STRING_ARG_SIGNATURE );
+			getFileMethod = antlrHierarchyClass.getMethod( "getFile", Helper.STRING_ARG_SIGNATURE );
+		}
+		catch ( Throwable t ) {
+			throw new MojoExecutionException( "Unable to instantiate Antlr preprocessor tool", causeToUse( t ) );
+		}
+
+		ArrayList files = new ArrayList();
+		for ( int i = 0; i < grammars.length; i++ ) {
+			String grammarName = grammars[i].getName().trim();
+			if ( StringUtils.isEmpty( grammarName ) ) {
+				environment.getLog().info( "Empty grammar in the configuration; skipping." );
+				continue;
+			}
+
+			File grammar = new File( environment.getSourceDirectory(), grammarName );
+
+			if ( !grammar.exists() ) {
+				throw new MojoExecutionException( "The grammar '" + grammar.getAbsolutePath() + "' doesnt exist." );
+			}
+
+			String grammarFilePath = grammar.getPath();
+			GrammarFile grammarFile = new GrammarFile(
+					grammarName,
+					grammarFilePath,
+					StringUtils.isNotEmpty( grammars[i].getGlib() )
+							? StringUtils.split( grammars[i].getGlib(), ":," )
+							: new String[0]
+			);
+
+			// :(  antlr.preprocessor.GrammarFile's only access to package is through a protected field :(
+			try {
+				BufferedReader in = new BufferedReader( new FileReader( grammar ) );
+				try {
+					String line;
+					while ( ( line = in.readLine() ) != null ) {
+						line = line.trim();
+						if ( line.startsWith( "package" ) && line.endsWith( ";" ) ) {
+							grammarFile.setPackageName( line.substring( 8, line.length() -1 ) );
+							break;
+						}
+					}
+				}
+				finally {
+					try {
+						in.close();
+					}
+					catch ( IOException ioe ) {
+					}
+				}
+			}
+			catch ( IOException e ) {
+				e.printStackTrace();
+			}
+
+			files.add( grammarFile );
+
+			try {
+				readGrammarFileMethod.invoke( hierarchy, new Object[] { grammarFilePath } );
+			}
+			catch ( Throwable t ) {
+				throw new MojoExecutionException( "Unable to use Antlr preprocessor to read grammar file", causeToUse( t ) );
+			}
+		}
+
+		XRef xref = new XRef( hierarchy );
+		Iterator itr = files.iterator();
+		while ( itr.hasNext() ) {
+			final GrammarFile gf = ( GrammarFile ) itr.next();
+			String grammarFilePath = gf.getFileName();
+			try {
+				Object antlrGrammarFileDef = getFileMethod.invoke( hierarchy, new Object[] { grammarFilePath } );
+				intrepretMetadata( gf, antlrGrammarFileDef );
+				xref.addGrammarFile( gf );
+			}
+			catch ( Throwable t ) {
+				throw new MojoExecutionException( "Unable to build grammar metadata", causeToUse( t ) );
+			}
+		}
+
+		return xref;
+	}
+
+	private void intrepretMetadata(GrammarFile gf, Object antlrGrammarFileDef) throws MojoExecutionException {
+//		try {
+//			Field headerActionField = helper.getAntlrGrammarFileClass().getDeclaredField( "headerAction" );
+//			headerActionField.setAccessible( true );
+//			String header = ( String ) headerActionField.get( antlrGrammarFileDef );
+//			if ( StringUtils.isNotEmpty( header ) ) {
+//				// locate the package declaration...
+//				StringTokenizer tokenizer = new StringTokenizer( header, System.getProperty("line.separator") );
+//				while ( tokenizer.hasMoreTokens() ) {
+//					final String token = tokenizer.nextToken().trim();
+//					if ( token.startsWith( "package " ) && token.endsWith( ";" ) ) {
+//						gf.setPackageName( token.substring( 8, token.length() -1 ) );
+//					}
+//				}
+//			}
+//		}
+//		catch ( Throwable t ) {
+//			throw new MojoExecutionException( "Error attempting to locate grammar package name", t );
+//		}
+
+		try {
+			Object grammarsVector = helper.getAntlrGrammarFileClass().getMethod( "getGrammars", Helper.NO_ARG_SIGNATURE )
+					.invoke( antlrGrammarFileDef, Helper.NO_ARGS );
+
+			Enumeration grammars = ( Enumeration ) helper.getAntlrIndexedVectorClass().getMethod( "elements", Helper.NO_ARG_SIGNATURE )
+					.invoke( grammarsVector, Helper.NO_ARGS );
+			while ( grammars.hasMoreElements() ) {
+				Grammar grammar = new Grammar( gf );
+				intrepret( grammar, grammars.nextElement() );
+			}
+		}
+		catch ( Throwable t ) {
+			throw new MojoExecutionException( "Error attempting to access grammars within grammar file", t );
+		}
+	}
+
+	private void intrepret(Grammar grammar, Object antlrGrammarDef) throws MojoExecutionException {
+		try {
+			Method getNameMethod = helper.getAntlrGrammarClass().getDeclaredMethod( "getName", Helper.NO_ARG_SIGNATURE );
+			getNameMethod.setAccessible( true );
+			String name = ( String ) getNameMethod.invoke( antlrGrammarDef, Helper.NO_ARGS );
+			grammar.setClassName( name );
+
+			Method getSuperGrammarNameMethod = helper.getAntlrGrammarClass().getMethod( "getSuperGrammarName", Helper.NO_ARG_SIGNATURE );
+			getSuperGrammarNameMethod.setAccessible( true );
+			String superGrammarName = ( String ) getSuperGrammarNameMethod.invoke( antlrGrammarDef, Helper.NO_ARGS );
+			grammar.setSuperGrammarName( superGrammarName );
+
+			Method getOptionsMethod = helper.getAntlrGrammarClass().getMethod( "getOptions", Helper.NO_ARG_SIGNATURE );
+			getOptionsMethod.setAccessible( true );
+			Object options = getOptionsMethod.invoke( antlrGrammarDef, Helper.NO_ARGS );
+
+			Method getElementMethod = helper.getAntlrIndexedVectorClass().getMethod( "getElement", new Class[] { Object.class } );
+			getElementMethod.setAccessible( true );
+
+			Method getRHSMethod = helper.getAntlrOptionClass().getMethod( "getRHS", Helper.NO_ARG_SIGNATURE );
+			getRHSMethod.setAccessible( true );
+
+			Object importVocabOption = getElementMethod.invoke( options, new Object[] { "importVocab" } );
+			if ( importVocabOption != null ) {
+				String importVocab = ( String ) getRHSMethod.invoke( importVocabOption, Helper.NO_ARGS );
+				grammar.setImportVocab( importVocab );
+			}
+
+			Object exportVocabOption = getElementMethod.invoke( options, new Object[] { "exportVocab" } );
+			if  ( exportVocabOption != null ) {
+				String exportVocab = ( String ) getRHSMethod.invoke( exportVocabOption, Helper.NO_ARGS );
+				grammar.setExportVocab( exportVocab );
+			}
+		}
+		catch ( Throwable t ) {
+			throw new MojoExecutionException( "Error accessing  Antlr grammar metadata", t );
+		}
+	}
+
+	private Throwable causeToUse(Throwable throwable) {
+		if ( throwable instanceof InvocationTargetException ) {
+			return ( ( InvocationTargetException ) throwable ).getTargetException();
+		}
+		else {
+			return throwable;
+		}
+	}
+}
