| Author | Dave Jarvis <email> |
|---|---|
| Date | 2015-03-08 19:51:22 GMT-0700 |
| Commit | f90899b8928ca2c478606b3d23bf01770aedde4f |
| Parent | acdc3b4 |
| /** | ||
| - * Creates a new tree with the given payload. | ||
| + * Creates a new tree with the given context. | ||
| */ | ||
| - private Tree<Payload> createTree( ParserRuleContext payload ) { | ||
| - return new QueryTree<Payload>( new Payload( payload ) ); | ||
| + private Tree<Payload> createTree( ParserRuleContext ctx ) { | ||
| + return new QueryTree<Payload>( new Payload( ctx ) ); | ||
| } | ||
| } |
| package com.whitemagicsoftware.rxm.tree; | ||
| +import java.lang.reflect.Constructor; | ||
| + | ||
| import com.whitemagicsoftware.rxm.grammar.QueryParser; | ||
| import org.antlr.v4.runtime.ParserRuleContext; | ||
| import org.antlr.v4.runtime.Token; | ||
| /** | ||
| - * The wrapper class for ParserRuleContext. This class uses an implicit | ||
| - * factory technique to derive the | ||
| + * <p> | ||
| + * The wrapper class for ParserRuleContext. This class employs an implicit | ||
| + * factory technique to derive the transformation class instances. The | ||
| + * tree associated with this payload is required to determine the context | ||
| + * for each document (output) format-specific Parser Rule. | ||
| + * </p> | ||
| + * <p> | ||
| + * The implicit factory works as follows. The Payload is associated with | ||
| + * a particular instance of Tree. The particular Tree instance is in a | ||
| + * package. The package name includes the factory method for creating the | ||
| + * requisite *Context parser classes. The *Context parser classes are | ||
| + * responsible for producing the correct code (e.g., SQL) to generate the | ||
| + * respective output document. | ||
| + * </p> | ||
| + * By virtue of the Tree being in the package with te *Context classes, | ||
| + * the *Context class names themselves can be derived, and therefore | ||
| + * instantiated. (The *Context class names directly correspond to QueryParser | ||
| + * inner class names and are therefore coupled to the language grammar.) | ||
| + * <p> | ||
| */ | ||
| public class Payload extends ParserRuleContext { | ||
| /** Wrapped parser rule context instance. */ | ||
| private ParserRuleContext ctx; | ||
| + | ||
| + /** Parser rule context instance for transforming the payload. */ | ||
| + private ParserRuleContext transformer; | ||
| + /** Abstract Syntax Tree (the factory tree). */ | ||
| private Tree<Payload> tree; | ||
| public Payload( ParserRuleContext ctx ) { | ||
| setParserRuleContext( ctx ); | ||
| } | ||
| @Override | ||
| public Token getStart() { | ||
| - //System.out.println( getTree().getClass().getPackage().getName() ); | ||
| - //System.out.println( getParserRuleContext().getClass().getSimpleName() ); | ||
| - return getParserRuleContext().getStart(); | ||
| + return getTransformer().getStart(); | ||
| } | ||
| @Override | ||
| public Token getStop() { | ||
| - return getParserRuleContext().getStop(); | ||
| + return getTransformer().getStop(); | ||
| } | ||
| /** | ||
| * Allows subclasses to retrieve the payload. | ||
| * | ||
| * @return The original (unwrapped) payload. | ||
| */ | ||
| - protected ParserRuleContext getParserRuleContext() { | ||
| + public ParserRuleContext getParserRuleContext() { | ||
| return this.ctx; | ||
| } | ||
| /** | ||
| - * Sets the payload. | ||
| + * Sets the payload to the transformation class. | ||
| * | ||
| * @param ctx The original (unwrapped) payload. | ||
| */ | ||
| private void setParserRuleContext( ParserRuleContext ctx ) { | ||
| this.ctx = ctx; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Creates a new instance of the transformer. | ||
| + */ | ||
| + private ParserRuleContext createTransformer() { | ||
| + try { | ||
| + return getTransformerConstructor().newInstance( this ); | ||
| + } | ||
| + catch( Exception e ) { | ||
| + return getParserRuleContext(); | ||
| + } | ||
| + } | ||
| + | ||
| + private Constructor<ParserRuleContext> getTransformerConstructor() | ||
| + throws ClassNotFoundException, NoSuchMethodException { | ||
| + return getTransformerClass().getConstructor( Payload.class ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns the class name of the transformer to instantiate. | ||
| + * | ||
| + * @return A non-null, fully qualified Java class name. | ||
| + */ | ||
| + private String getTransformerName() { | ||
| + return String.format( "%s.%s", | ||
| + getTreePackageName(), | ||
| + getParserRuleContextClassName() ); | ||
| + } | ||
| + | ||
| + @SuppressWarnings( "unchecked" ) | ||
| + private Class<ParserRuleContext> getTransformerClass() | ||
| + throws ClassNotFoundException { | ||
| + return (Class<ParserRuleContext>)Class.forName( getTransformerName() ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Lazily initialize the transformer. This is required because the | ||
| + * transformer isn't known when this payload is instantiated. Technically, | ||
| + * the transformer could be assigned when the tree is set, but lazy | ||
| + * initialization is cleaner. (That is, no instantiation happens until | ||
| + * the object is needed.) | ||
| + */ | ||
| + private ParserRuleContext getTransformer() { | ||
| + ParserRuleContext transformer = this.transformer; | ||
| + | ||
| + if( transformer == null ) { | ||
| + setTransformer( transformer = createTransformer() ); | ||
| + } | ||
| + | ||
| + return transformer; | ||
| + } | ||
| + | ||
| + private void setTransformer( ParserRuleContext ctx ) { | ||
| + this.transformer = ctx; | ||
| } | ||
| public void setTree( Tree<Payload> tree ) { | ||
| this.tree = tree; | ||
| } | ||
| public Tree<Payload> getTree() { | ||
| return this.tree; | ||
| + } | ||
| + | ||
| + private Class getTreeClass() { | ||
| + return getTree().getClass(); | ||
| + } | ||
| + | ||
| + private Package getTreePackage() { | ||
| + return getTreeClass().getPackage(); | ||
| + } | ||
| + | ||
| + private String getTreePackageName() { | ||
| + return getTreePackage().getName(); | ||
| + } | ||
| + | ||
| + private Class getParserRuleContextClass() { | ||
| + return getParserRuleContext().getClass(); | ||
| + } | ||
| + | ||
| + private String getParserRuleContextClassName() { | ||
| + return getParserRuleContextClass().getSimpleName(); | ||
| } | ||
| } |
| Tree<T> root = this; | ||
| - // Traverse until there are no more parents. | ||
| + // Traverse until there are no more parents, which should be the root. | ||
| while( root.getParent() != null ) { | ||
| root = root.getParent(); |
| -package com.whitemagicsoftware.rxm.tree.xml; | ||
| - | ||
| -import com.whitemagicsoftware.rxm.grammar.QueryParser; | ||
| -import com.whitemagicsoftware.rxm.tree.Payload; | ||
| -import com.whitemagicsoftware.rxm.tree.Token; | ||
| -import com.whitemagicsoftware.rxm.tree.Tree; | ||
| - | ||
| -import org.antlr.v4.runtime.ParserRuleContext; | ||
| - | ||
| -/** | ||
| - * Represents a wrapper class for ParserRuleContext. This class is marked | ||
| - * as abstract because only its subclasses should be instantiated. | ||
| - */ | ||
| -public abstract class ASTParserRuleContext { | ||
| - private ParserRuleContext payload; | ||
| - private Tree<Payload> tree; | ||
| - | ||
| - protected ASTParserRuleContext( Payload payload ) { | ||
| - this.payload = payload; | ||
| - this.tree = payload.getTree(); | ||
| - } | ||
| - | ||
| - protected ParserRuleContext getParserRuleContext() { | ||
| - return this.payload; | ||
| - } | ||
| - | ||
| - /** | ||
| - * Formats the start of the XMLELEMENT call. | ||
| - * | ||
| - * @param name The name assigned to the element. | ||
| - * | ||
| - * @return The text used for SQL/XML XMLELEMENT calls. | ||
| - */ | ||
| - protected String startElement( String name ) { | ||
| - return String.format( "XMLELEMENT( NAME \"%s\"", name ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Formats the start of the XMLATTRIBUTES call. | ||
| - * | ||
| - * @param name The name assigned to the attribute. | ||
| - * | ||
| - * @return The text used for SQL/XML XMLATTRIBUTES calls. | ||
| - */ | ||
| - protected String startAttributes( String name ) { | ||
| - return String.format( "XMLATTRIBUTES( %s AS ", name ); | ||
| - } | ||
| - | ||
| - protected Tree<Payload> getTree() { | ||
| - return this.tree; | ||
| - } | ||
| - | ||
| - /** | ||
| - * Closes the current payload transformation. | ||
| - */ | ||
| - public Token getStart() { | ||
| - return new Token( "(" ); | ||
| - } | ||
| - | ||
| - /** | ||
| - * Closes the current payload transformation. | ||
| - */ | ||
| - public Token getStop() { | ||
| - return new Token( ")" ); | ||
| - } | ||
| -} | ||
| - | ||
| * Transforms <code>table > @attribute</code>. | ||
| */ | ||
| -public class AttributeMapContext extends ASTParserRuleContext { | ||
| +public class AttributeMapContext extends PayloadParserRuleContext { | ||
| public AttributeMapContext( Payload ctx ) { | ||
| super( ctx ); |
| * Transforms <code>column > path</code>. | ||
| */ | ||
| -public class ColumnMapContext extends ASTParserRuleContext { | ||
| +public class ColumnMapContext extends PayloadParserRuleContext { | ||
| public ColumnMapContext( Payload ctx ) { | ||
| super( ctx ); |
| +package com.whitemagicsoftware.rxm.tree.xml; | ||
| + | ||
| +import com.whitemagicsoftware.rxm.grammar.QueryParser; | ||
| +import com.whitemagicsoftware.rxm.tree.Payload; | ||
| +import com.whitemagicsoftware.rxm.tree.Token; | ||
| +import com.whitemagicsoftware.rxm.tree.Tree; | ||
| + | ||
| +import org.antlr.v4.runtime.ParserRuleContext; | ||
| + | ||
| +/** | ||
| + * Represents a wrapper class for ParserRuleContext. This class is marked | ||
| + * as abstract because only its subclasses should be instantiated. | ||
| + */ | ||
| +public abstract class PayloadParserRuleContext extends ParserRuleContext { | ||
| + private ParserRuleContext payload; | ||
| + private Tree<Payload> tree; | ||
| + | ||
| + protected PayloadParserRuleContext( Payload payload ) { | ||
| + this.payload = payload.getParserRuleContext(); | ||
| + this.tree = payload.getTree(); | ||
| + } | ||
| + | ||
| + protected ParserRuleContext getParserRuleContext() { | ||
| + return this.payload; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Formats the start of the XMLELEMENT call. | ||
| + * | ||
| + * @param name The name assigned to the element. | ||
| + * | ||
| + * @return The text used for SQL/XML XMLELEMENT calls. | ||
| + */ | ||
| + protected String startElement( String name ) { | ||
| + return String.format( "XMLELEMENT( NAME \"%s\"", name ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Formats the start of the XMLATTRIBUTES call. | ||
| + * | ||
| + * @param name The name assigned to the attribute. | ||
| + * | ||
| + * @return The text used for SQL/XML XMLATTRIBUTES calls. | ||
| + */ | ||
| + protected String startAttributes( String name ) { | ||
| + return String.format( "XMLATTRIBUTES( %s AS ", name ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Returns the context tree that provides subclasses the ability to | ||
| + * determine their database entity context. This allows subclasses | ||
| + * to use the correct entity alias as defined by the <b>rxm</b>. | ||
| + */ | ||
| + protected Tree<Payload> getTree() { | ||
| + return this.tree; | ||
| + } | ||
| + | ||
| + /** | ||
| + * Closes the current payload transformation. Subclasses must override | ||
| + * this to provide the correct opening SQL/XML expression. | ||
| + */ | ||
| + @Override | ||
| + public Token getStart() { | ||
| + return new Token( "(" ); | ||
| + } | ||
| + | ||
| + /** | ||
| + * Closes the current payload transformation. Subclasses may override | ||
| + * this to provide a custom closing SQL/XML expression. | ||
| + */ | ||
| + @Override | ||
| + public Token getStop() { | ||
| + return new Token( ")" ); | ||
| + } | ||
| +} | ||
| + | ||
| * Transforms <code>root > element</code>. | ||
| */ | ||
| -public class RootContext extends ASTParserRuleContext { | ||
| +public class RootContext extends PayloadParserRuleContext { | ||
| public RootContext( Payload ctx ) { | ||
| super( ctx ); |
| * Transforms <code>table > path</code>. | ||
| */ | ||
| -public class TableMapContext extends ASTParserRuleContext { | ||
| +public class TableMapContext extends PayloadParserRuleContext { | ||
| public TableMapContext( Payload ctx ) { | ||
| super( ctx ); |
| Delta | 188 lines added, 83 lines removed, 105-line increase |
|---|