Author: tfischer
Date: Wed Sep  3 19:26:19 2014
New Revision: 1622323

URL: http://svn.apache.org/r1622323
Log:
TORQUE-324 allow access to parent element in generator via ..

Added:
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePathPointer.java
Modified:
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/ControllerState.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/ApplyAction.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/TraverseAllAction.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/ModelPropertyPointer.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodeIterator.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodePointer.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePath.java
    
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/SourcePathTest.java

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
 Wed Sep  3 19:26:19 2014
@@ -54,8 +54,10 @@ import org.apache.torque.generator.outle
 import org.apache.torque.generator.processor.string.StringProcessor;
 import org.apache.torque.generator.source.PostprocessorDefinition;
 import org.apache.torque.generator.source.Source;
+import org.apache.torque.generator.source.SourceElement;
 import org.apache.torque.generator.source.SourceException;
 import org.apache.torque.generator.source.SourcePath;
+import org.apache.torque.generator.source.SourcePathPointer;
 import org.apache.torque.generator.source.SourceProcessConfiguration;
 import org.apache.torque.generator.source.SourceProvider;
 import org.apache.torque.generator.source.SourceTransformerDefinition;
@@ -334,7 +336,9 @@ public class Controller
         final String startElementsPath
                 = sourceProcessConfiguration.getStartElementsPath();
 
-        final Iterator<?> iterator = SourcePath.iterate(
+        final Iterator<SourcePathPointer> iterator = SourcePath.iteratePointer(
+                null,
+                null,
                 modelRoot,
                 startElementsPath);
         if (!iterator.hasNext())
@@ -344,7 +348,27 @@ public class Controller
         }
         while (iterator.hasNext())
         {
-            final Object model = iterator.next();
+            final SourcePathPointer pointer = iterator.next();
+            final Object model = pointer.getValue();
+            String path = pointer.getPath();
+            if (model instanceof SourceElement)
+            {
+                // remove root node from path because the root node
+                // is no part of the xpath for sourceElements
+                if (path.startsWith("/"))
+                {
+                    int slashIndex = path.indexOf('/', 1);
+                    if (slashIndex != -1)
+                    {
+                        path = path.substring(slashIndex + 1);
+                    }
+                    else
+                    {
+                        path = "/";
+                    }
+                }
+            }
+            controllerState.setModel(model, path);
             processModel(
                     model,
                     output,
@@ -453,7 +477,6 @@ public class Controller
                     + "of output file "
                     + output);
         }
-        controllerState.setModel(model);
         log.debug("Processing new model " + model);
 
         ExistingTargetStrategy existingTargetStrategy = null;

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/ControllerState.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/ControllerState.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/ControllerState.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/ControllerState.java
 Wed Sep  3 19:26:19 2014
@@ -23,6 +23,7 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.torque.generator.configuration.UnitConfiguration;
 import org.apache.torque.generator.configuration.controller.OutletReference;
 import org.apache.torque.generator.configuration.controller.Output;
@@ -32,6 +33,7 @@ import org.apache.torque.generator.optio
 import org.apache.torque.generator.outlet.Outlet;
 import org.apache.torque.generator.qname.Namespace;
 import org.apache.torque.generator.qname.QualifiedName;
+import org.apache.torque.generator.source.SourceElement;
 import org.apache.torque.generator.source.SourceProvider;
 import org.apache.torque.generator.variable.VariableStore;
 
@@ -67,6 +69,11 @@ public class ControllerState
     private Object model;
 
     /**
+     * The path from the model root to the current model.
+     */
+    private String pathToModel = "/";
+
+    /**
      * The generation unit which is currently processed.
      */
     private UnitConfiguration unitConfiguration;
@@ -213,11 +220,68 @@ public class ControllerState
      * Sets the current source model object.
      *
      * @param sourceElement the new current source model object, or null
-     *        to remove the current source mdoel object.
+     *        to remove the current source model object.
+     * @param newPathToModel the path from root
+     *        to the new model, or null to leave the path unchanged.
      */
-    public void setModel(final Object model)
+    public void setModel(final Object model, String newPathToModel)
     {
         this.model = model;
+        if (newPathToModel != null)
+        {
+            if (model instanceof SourceElement)
+            {
+                // In source element, the root node precedes the path.
+                // For a correct relative path, the root node
+                // of the relative path must be removed.
+                if (newPathToModel.startsWith("/"))
+                {
+                    int slashIndex = newPathToModel.indexOf('/', 1);
+                    if (slashIndex != -1)
+                    {
+                        newPathToModel = newPathToModel.substring(slashIndex + 
1);
+                    }
+                    else
+                    {
+                        newPathToModel = "/";
+                    }
+                }
+            }
+
+            if (StringUtils.isEmpty(newPathToModel))
+            {
+                this.pathToModel = "/";
+            }
+            else
+            {
+                this.pathToModel = newPathToModel;
+            }
+        }
+    }
+
+    /**
+     * Returns the path from the model root to the current model.
+     *
+     * @return the path from the model root to the current model, not null.
+     */
+    public String getPathToModel()
+    {
+        return pathToModel;
+    }
+
+    /**
+     * Sets the path from the model root to the current model.
+     *
+     * @param pathToModel the path from the model root to the current model,
+     *        not null.
+     */
+    public void setPathToModel(final String pathToModel)
+    {
+        if (pathToModel == null)
+        {
+            throw new NullPointerException("pathToModel must not be null");
+        }
+        this.pathToModel = pathToModel;
     }
 
     /**

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/ApplyAction.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/ApplyAction.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/ApplyAction.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/ApplyAction.java
 Wed Sep  3 19:26:19 2014
@@ -29,6 +29,7 @@ import org.apache.torque.generator.outle
 import org.apache.torque.generator.qname.Namespace;
 import org.apache.torque.generator.qname.QualifiedName;
 import org.apache.torque.generator.source.SourcePath;
+import org.apache.torque.generator.source.SourcePathPointer;
 
 /**
  * Applies an outlet to the matching element.
@@ -61,7 +62,7 @@ public class ApplyAction implements Merg
      *        matches the given path, true if an error should be thrown in
      *        such a case. null means true.
      */
-    public ApplyAction(String path, String outletName, Boolean acceptNotSet)
+    public ApplyAction(final String path, final String outletName, final 
Boolean acceptNotSet)
     {
         if (path == null)
         {
@@ -89,7 +90,7 @@ public class ApplyAction implements Merg
      * The output of the outlet is appended to the output.
      * ${...} Tokens are replaced within outletName and path.
      */
-    public OutletResult execute(ControllerState controllerState)
+    public OutletResult execute(final ControllerState controllerState)
         throws GeneratorException
     {
         TokenReplacer tokenReplacer = new TokenReplacer(controllerState);
@@ -108,10 +109,15 @@ public class ApplyAction implements Merg
         }
 
         Object model = controllerState.getModel();
+        String pathToModel = controllerState.getPathToModel();
         String detokenizedPath = tokenReplacer.process(path);
 
-        Iterator<?> selectedObjectsIt
-                = SourcePath.iterate(model, detokenizedPath);
+        Iterator<SourcePathPointer> selectedObjectsIt
+            = SourcePath.iteratePointer(
+                controllerState.getModelRoot(),
+                pathToModel,
+                model,
+                detokenizedPath);
         if (!selectedObjectsIt.hasNext())
         {
             if (!acceptNotSet)
@@ -124,7 +130,8 @@ public class ApplyAction implements Merg
             }
             return new OutletResult("");
         }
-        Object selectedObject = selectedObjectsIt.next();
+        SourcePathPointer pointer = selectedObjectsIt.next();
+        Object selectedObject = pointer.getValue();
         if (selectedObjectsIt.hasNext())
         {
             throw new GeneratorException(
@@ -133,11 +140,13 @@ public class ApplyAction implements Merg
                         + " contains more than one element");
         }
 
-        controllerState.setModel(selectedObject);
+        String oldPathToModel = controllerState.getPathToModel();
+        controllerState.setModel(selectedObject, pointer.getPath());
         outlet.beforeExecute(controllerState);
         OutletResult result = outlet.execute(controllerState);
         outlet.afterExecute(controllerState);
-        controllerState.setModel(model);
+        controllerState.setModel(model, null);
+        controllerState.setPathToModel(oldPathToModel);
         return result;
     }
 
@@ -167,7 +176,7 @@ public class ApplyAction implements Merg
     }
 
     @Override
-    public boolean equals(Object obj)
+    public boolean equals(final Object obj)
     {
         if (this == obj)
         {

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/TraverseAllAction.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/TraverseAllAction.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/TraverseAllAction.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/action/TraverseAllAction.java
 Wed Sep  3 19:26:19 2014
@@ -32,6 +32,7 @@ import org.apache.torque.generator.outle
 import org.apache.torque.generator.qname.Namespace;
 import org.apache.torque.generator.qname.QualifiedName;
 import org.apache.torque.generator.source.SourcePath;
+import org.apache.torque.generator.source.SourcePathPointer;
 
 /**
  * Traverses all matching elements, and applies a outlet to each matching
@@ -124,10 +125,12 @@ public class TraverseAllAction implement
                 = tokenReplacer.process(elementsToTraverseName);
 
         final Object currentModel = controllerState.getModel();
-        final Iterator<?> toTraverseIt
-                = SourcePath.iterate(
-                        currentModel,
-                        detokenizedElementToTraverseName);
+        final Iterator<SourcePathPointer> toTraverseIt
+            = SourcePath.iteratePointer(
+                controllerState.getModelRoot(),
+                controllerState.getPathToModel(),
+                currentModel,
+                detokenizedElementToTraverseName);
         if (!acceptEmpty && toTraverseIt.hasNext())
         {
             throw new GeneratorException(
@@ -136,17 +139,23 @@ public class TraverseAllAction implement
                         + " does not exist and acceptEmpty was set to false");
         }
 
-        final List<OutletResult> resultList
-                = new ArrayList<OutletResult>();
+        final List<OutletResult> resultList = new ArrayList<OutletResult>();
+        String oldPathToModel = controllerState.getPathToModel();
         while (toTraverseIt.hasNext())
         {
-            final Object model = toTraverseIt.next();
-            controllerState.setModel(model);
+            final SourcePathPointer pointer = toTraverseIt.next();
+            final Object model = pointer.getValue();
+            String path = pointer.getPath();
+            controllerState.setModel(
+                    model,
+                    path);
             outlet.beforeExecute(controllerState);
             resultList.add(outlet.execute(controllerState));
             outlet.afterExecute(controllerState);
+            controllerState.setPathToModel(oldPathToModel);
         }
-        controllerState.setModel(currentModel);
+        controllerState.setModel(currentModel, null);
+
         if (resultList.isEmpty())
         {
             return new OutletResult("");

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/ModelPropertyPointer.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/ModelPropertyPointer.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/ModelPropertyPointer.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/ModelPropertyPointer.java
 Wed Sep  3 19:26:19 2014
@@ -108,7 +108,7 @@ public class ModelPropertyPointer extend
         {
             return 0;
         }
-        return getPropertyDescriptors().length;
+        return getPropertyNames().length;
     }
 
     /**
@@ -255,7 +255,7 @@ public class ModelPropertyPointer extend
     @Override
     protected boolean isActualProperty()
     {
-        return getPropertyDescriptor() != null;
+        return getPropertyDescriptor() != null || getField() != null;
     }
 
     @Override

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodeIterator.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodeIterator.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodeIterator.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodeIterator.java
 Wed Sep  3 19:26:19 2014
@@ -81,7 +81,13 @@ public class SourceElementNodeIterator i
         {
             setPosition(1);
         }
-        return child == null ? null : new SourceElementNodePointer(parent, 
child);
+        if (child != null)
+        {
+            NodePointer result = new SourceElementNodePointer(parent, child);
+            result.setIndex(position - 1);
+            return result;
+        }
+        return null;
     }
 
     public int getPosition()

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodePointer.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodePointer.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodePointer.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourceElementNodePointer.java
 Wed Sep  3 19:26:19 2014
@@ -70,13 +70,22 @@ public class SourceElementNodePointer ex
     @Override
     public boolean isCollection()
     {
-        return false;
+        return true;
     }
 
     @Override
     public int getLength()
     {
-        return 1;
+        // get parent in path, which is not necessarily
+        // the primary parent of the source element
+        NodePointer parentPointer = getParent();
+        if (parentPointer == null)
+        {
+            return 1;
+        }
+        SourceElement parentInPath
+                = ((SourceElement) getParent().getBaseValue());
+        return parentInPath.getChildren(sourceElement.getName()).size();
     }
 
     @Override
@@ -184,7 +193,7 @@ public class SourceElementNodePointer ex
         {
             if (((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_NODE)
             {
-                    return true;
+                return true;
             }
             return false;
         }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePath.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePath.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePath.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePath.java
 Wed Sep  3 19:26:19 2014
@@ -20,7 +20,6 @@ package org.apache.torque.generator.sour
  */
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -29,6 +28,8 @@ import java.util.Set;
 import java.util.StringTokenizer;
 
 import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.JXPathException;
+import org.apache.commons.jxpath.Pointer;
 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
 import org.apache.torque.generator.GeneratorException;
 
@@ -302,7 +303,14 @@ public final class SourcePath
     /**
      * Gets the elements which can be reached from the start element by a given
      * path.
+     * If the model root is null, only objects which are children of base
+     * can be retrieved.
      *
+     * @param root the model root, or null if no model root exists
+     *        (in the latter case, no elements only reachable via base's parent
+     *        can be accessed)
+     * @param pathToBase the path from root to base, must be not null
+     *        if root is not null, is disregarded if root is null.
      * @param base the base object, not null.
      * @param path the path to use, or null (which refers base).
      *
@@ -310,7 +318,11 @@ public final class SourcePath
      *
      * @see <a href="http://www.w3.org/TR/xpath#axes";>xpath axes</a>
      */
-    public static Iterator<?> iterate(final Object base, final String path)
+    public static Iterator<SourcePathPointer> iteratePointer(
+            final Object root,
+            String pathToBase,
+            final Object base,
+            String path)
     {
         if (base == null)
         {
@@ -318,14 +330,70 @@ public final class SourcePath
         }
         if (path == null)
         {
-            return Arrays.asList(new Object[] {base}).iterator();
+            path = ".";
         }
 
-        final JXPathContext context = JXPathContext.newContext(base);
+        final JXPathContext context;
+        if (root != null)
+        {
+            final JXPathContext rootContext = JXPathContext.newContext(root);
+            if (root instanceof SourceElement)
+            {
+                // In source element, the root node precedes the path.
+                // For a correct relative path, the root node
+                // of the relative path must be removed.
+                if (pathToBase.startsWith("/"))
+                {
+                    int slashIndex = pathToBase.indexOf('/', 1);
+                    if (slashIndex != -1)
+                    {
+                        pathToBase = pathToBase.substring(slashIndex + 1);
+                    }
+                    else
+                    {
+                        pathToBase = "/";
+                    }
+                }
+            }
+
+            try
+            {
+                context = rootContext.getRelativeContext(
+                        rootContext.getPointer(pathToBase));
+            }
+            catch (JXPathException e)
+            {
+                throw new IllegalArgumentException(
+                        "The pathToBase " + pathToBase
+                            + " is not found in root " + root,
+                        e);
+            }
+
+            Object pathValue = context.getValue(".");
+            if (pathValue != base)
+            {
+                throw new IllegalArgumentException(
+                    "The pathToBase " + pathToBase
+                        + " does not evaluate to base " + base
+                        + " from root " + root);
+            }
+            // seems to be a bug in realtiveContext . evaluation in JXPath
+            if (".".equals(path))
+            {
+                return new SourcePathPointerIterator(
+                        JXPathContext.newContext(root)
+                            .iteratePointers(pathToBase));
+            }
+        }
+        else
+        {
+            context = JXPathContext.newContext(base);
+        }
         context.setLenient(true);
 
-        final Iterator<?> iterator = context.iterate(path);
-        return iterator;
+
+        final Iterator<?> jxpathPointerIterator = 
context.iteratePointers(path);
+        return new SourcePathPointerIterator(jxpathPointerIterator);
     }
 
     /**
@@ -454,6 +522,11 @@ public final class SourcePath
      * Gets a single source element which can be reached from the start element
      * by a given path.
      *
+     * @param root the model root, or null if no model root exists
+     *        (in the latter case, no elements only reachable via base's parent
+     *        can be accessed)
+     * @param pathToBase the path from root to base, must be not null
+     *        if root is not null, is disregarded if root is null.
      * @param sourceElement the start element, not null.
      * @param path the path to use, not null.
      * @param acceptEmpty whether no match is an error(acceptEmpty=false)
@@ -467,12 +540,15 @@ public final class SourcePath
      * @see <a href="http://www.w3.org/TR/xpath#axes";>xpath axes</a>
      */
     public static Object getObject(
+            final SourceElement root,
+            final String pathToBase,
             final SourceElement sourceElement,
             final String path,
             final boolean acceptEmpty)
         throws GeneratorException
     {
-        final Iterator<?> sourceElementIt = iterate(sourceElement, path);
+        final Iterator<SourcePathPointer> sourceElementIt
+                = iteratePointer(root, pathToBase, sourceElement, path);
         if (!sourceElementIt.hasNext())
         {
             if (acceptEmpty)
@@ -488,7 +564,7 @@ public final class SourcePath
                         + sourceElement.getName());
             }
         }
-        final Object result = sourceElementIt.next();
+        final SourcePathPointer sourcePathPointer = sourceElementIt.next();
         if (sourceElementIt.hasNext())
         {
             throw new GeneratorException(
@@ -497,7 +573,7 @@ public final class SourcePath
                     + " selects more than a single element on source element "
                     + sourceElement.getName());
         }
-        return result;
+        return sourcePathPointer.getValue();
     }
 
     /**
@@ -602,4 +678,48 @@ public final class SourcePath
         alreadyProcessed.add(parent);
         getParentPath(parent, alreadyProcessed, result);
     }
+
+    /**
+     * An iterator of SourcePathPointers wrapping a Iterator of jxpath 
pointers.
+     */
+    private static final class SourcePathPointerIterator
+            implements Iterator<SourcePathPointer>
+    {
+        /** The wrapped pointer, not null. */
+        private final Iterator<?> jxpathPointerIterator;
+
+        /**
+         * Constructor.
+         *
+         * @param jxpathPointerIterator the wrapped iterator, must iterate
+         *        over org.apache.commons.jxpath.Pointer elements.
+         */
+        public SourcePathPointerIterator(
+                final Iterator<?> jxpathPointerIterator)
+        {
+            if (jxpathPointerIterator == null)
+            {
+                throw new NullPointerException(
+                        "jxpathPointerIterator must not be null");
+            }
+            this.jxpathPointerIterator = jxpathPointerIterator;
+        }
+
+        public boolean hasNext()
+        {
+            return jxpathPointerIterator.hasNext();
+        }
+
+        public SourcePathPointer next()
+        {
+            Pointer pointer = (Pointer) jxpathPointerIterator.next();
+            return new SourcePathPointer(pointer.getNode(), pointer.asPath());
+        }
+
+        public void remove()
+        {
+            jxpathPointerIterator.remove();
+        }
+
+    }
 }

Added: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePathPointer.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePathPointer.java?rev=1622323&view=auto
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePathPointer.java
 (added)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/SourcePathPointer.java
 Wed Sep  3 19:26:19 2014
@@ -0,0 +1,104 @@
+package org.apache.torque.generator.source;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * A class containing the value and the path to an object in a model graph
+ */
+public class SourcePathPointer
+{
+    /** The value of the object. */
+    private final Object value;
+
+    /** The path to the object. */
+    private final String path;
+
+    public SourcePathPointer(final Object value, final String path)
+    {
+        this.value = value;
+        this.path = path;
+    }
+
+    public Object getValue()
+    {
+        return value;
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((path == null) ? 0 : path.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        SourcePathPointer other = (SourcePathPointer) obj;
+        if (path == null)
+        {
+            if (other.path != null)
+            {
+                return false;
+            }
+        }
+        else if (!path.equals(other.path))
+        {
+            return false;
+        }
+        if (value == null)
+        {
+            if (other.value != null)
+            {
+                return false;
+            }
+        }
+        else if (!value.equals(other.value))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "SourcePathPointer [value=" + value + ", path=" + path + "]";
+    }
+}

Modified: 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/SourcePathTest.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/SourcePathTest.java?rev=1622323&r1=1622322&r2=1622323&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/SourcePathTest.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/SourcePathTest.java
 Wed Sep  3 19:26:19 2014
@@ -21,6 +21,8 @@ package org.apache.torque.generator.sour
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
@@ -64,8 +66,8 @@ public class SourcePathTest
         firstLevel2.getChildren().add(secondLevelb);
 
         modelRoot = new Root();
-        modelRoot.childList.add(new Child("child1"));
-        modelRoot.childList.add(new Child("child2"));
+        modelRoot.childList.add(new Child("child1", null));
+        modelRoot.childList.add(new Child("child2", null));
         modelRoot.stringList.add("string1");
         modelRoot.stringList.add("string2");
         modelRoot.getPropertyList().add("propertyString1");
@@ -74,6 +76,8 @@ public class SourcePathTest
         modelRoot.setPropertyValue("propertyValue");
         modelRoot.setValue("setterValue");
         modelRoot.value = "fieldValue";
+        modelRoot.child = new Child("child3", new Child("subchildValue", 
null));
+
     }
 
     @Test
@@ -219,110 +223,385 @@ public class SourcePathTest
     }
 
     @Test
-    public void testIterateGetRoot()
+    public void testIteratePointerGetRoot()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(root, "/");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                root,
+                "/",
+                root,
+                "/");
         assertTrue(resultIt.hasNext());
-        assertSame(root, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(root, "/root[1]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateGetChild()
+    public void testIteratePointerGetRootBaseNull()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(root, "firstLevel1");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                root,
+                "/");
         assertTrue(resultIt.hasNext());
-        assertSame(firstLevel1, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(root, "/root[1]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateSeveralMatches()
+    public void testIteratePointerGetChildRootSameAsBase()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(root, 
"firstLevel2/secondLevel");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                root,
+                "/",
+                root,
+                "firstLevel1");
         assertTrue(resultIt.hasNext());
-        assertSame(secondLevel, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(firstLevel1, "/root[1]/firstLevel1[1]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerGetChildRootNull()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                root,
+                "firstLevel1");
         assertTrue(resultIt.hasNext());
-        assertSame(secondLevela, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(firstLevel1, "/root[1]/firstLevel1[1]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerSeveralMatches()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                root,
+                "/firstLevel2/secondLevel");
         assertTrue(resultIt.hasNext());
-        assertSame(secondLevelb, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevel,
+                        "/root[1]/firstLevel2[1]/secondLevel[1]"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevela,
+                        "/root[1]/firstLevel2[1]/secondLevel[2]"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevelb,
+                        "/root[1]/firstLevel2[1]/secondLevel[3]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerSeveralMatchesintermediateBase()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                root,
+                "/root/firstLevel2",
+                firstLevel2,
+                "secondLevel");
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevel,
+                        "/root/firstLevel2[1]/secondLevel[1]"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevela,
+                        "/root/firstLevel2[1]/secondLevel[2]"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevelb,
+                        "/root/firstLevel2[1]/secondLevel[3]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     /**
      * Test that we can iterate over path where the parent element
-     * of the mathcing elements is not the primary parent element.
+     * of the matching elements is not the primary parent element.
      */
     @Test
-    public void testIterateNotDefaultParent()
+    public void testIteratePointerNotDefaultParent()
     {
         firstLevel1.getChildren().add(secondLevela);
         firstLevel1.getChildren().add(secondLevel);
-        final Iterator<?> resultIt = SourcePath.iterate(root, 
"firstLevel1/secondLevel");
-        assertTrue(resultIt.hasNext());
-        assertSame(secondLevela, resultIt.next());
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                root,
+                "firstLevel1/secondLevel");
         assertTrue(resultIt.hasNext());
-        assertSame(secondLevel, resultIt.next());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevela,
+                        "/root[1]/firstLevel1[1]/secondLevel[1]"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        secondLevel,
+                        "/root[1]/firstLevel1[1]/secondLevel[2]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    /**
+     * Test that we can iterate over the parent element.
+     */
+    @Test
+    public void testIteratePointerGetParent()
+    {
+        firstLevel1.getChildren().add(secondLevela);
+        firstLevel1.getChildren().add(secondLevel);
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                root,
+                "firstLevel1/secondLevel[2]",
+                secondLevel,
+                "..");
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(
+                        firstLevel1,
+                        "/root/firstLevel1[1]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelStringField()
+    public void testIteratePointerModelStringSelf()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, 
"fieldValue");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                root,
+                ".");
         assertTrue(resultIt.hasNext());
-        assertEquals("fieldValue", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    root,
+                    "/root[1]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelStringGetter()
+    public void testIteratePointerModelStringField()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, 
"propertyValue");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                modelRoot,
+                "/",
+                modelRoot,
+                "fieldValue");
         assertTrue(resultIt.hasNext());
-        assertEquals("propertyValue", resultIt.next());
+        assertEquals(
+            new SourcePathPointer(
+                "fieldValue",
+                "/fieldValue"),
+            resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelStringFieldAndGetter()
+    public void testIteratePointerModelStringFieldRootNull()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, "value");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "fieldValue");
         assertTrue(resultIt.hasNext());
-        assertEquals("setterValue", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "fieldValue",
+                    "/fieldValue"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelListField()
+    public void testIteratePointerModelStringGetter()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, 
"stringList");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "propertyValue");
         assertTrue(resultIt.hasNext());
-        assertEquals("string1", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "propertyValue",
+                    "/propertyValue"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelStringFieldAndGetter()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "value");
         assertTrue(resultIt.hasNext());
-        assertEquals("string2", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "setterValue",
+                    "/value"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelListProperty()
+    public void testIteratePointerModelListField()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, 
"propertyList");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "stringList");
         assertTrue(resultIt.hasNext());
-        assertEquals("propertyString1", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "string1",
+                    "/stringList[1]"),
+                resultIt.next());
         assertTrue(resultIt.hasNext());
-        assertEquals("propertyString2", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "string2",
+                    "/stringList[2]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelListDotWithBaseField()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                modelRoot,
+                "/childList[1]",
+                modelRoot.childList.get(0),
+                ".");
+        assertTrue(resultIt.hasNext());
+        assertEquals(
+                new SourcePathPointer(
+                    modelRoot.childList.get(0),
+                    "/childList[1]"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
     @Test
-    public void testIterateModelListChainedAttribute()
+    public void testIteratePointerModelListProperty()
     {
-        final Iterator<?> resultIt = SourcePath.iterate(modelRoot, 
"childList/value");
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "propertyList");
+        assertTrue(resultIt.hasNext());
+        assertEquals(
+                new SourcePathPointer(
+                    "propertyString1",
+                    "/propertyList[1]"),
+                resultIt.next());
         assertTrue(resultIt.hasNext());
-        assertEquals("child1", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "propertyString2",
+                    "/propertyList[2]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelListPropertyWithIndex()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "propertyList[2]");
         assertTrue(resultIt.hasNext());
-        assertEquals("child2", resultIt.next());
+        assertEquals(
+                new SourcePathPointer(
+                    "propertyString2",
+                    "/propertyList[2]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelListChainedAttribute()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "childList/value");
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer("child1", "/childList[1]/value"),
+                resultIt.next());
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer("child2", "/childList[2]/value"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelPublicListWithIndex()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                null,
+                null,
+                modelRoot,
+                "/childList[1]");
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer(modelRoot.childList.get(0), 
"/childList[1]"),
+                resultIt.next());
+        assertFalse(resultIt.hasNext());
+    }
+
+    @Test
+    public void testIteratePointerModelListChainedAttributeIntermediateBase()
+    {
+        final Iterator<SourcePathPointer> resultIt = SourcePath.iteratePointer(
+                modelRoot,
+                "child",
+                modelRoot.child,
+                "/child/subchild/value");
+        assertTrue(resultIt.hasNext());
+        assertSamePointer(
+                new SourcePathPointer("subchildValue", 
"/child/subchild/value"),
+                resultIt.next());
         assertFalse(resultIt.hasNext());
     }
 
@@ -342,6 +621,8 @@ public class SourcePathTest
 
         private String propertyValue;
 
+        private Child child;
+
         public List<String> getPropertyList()
         {
             return propertyList;
@@ -366,15 +647,44 @@ public class SourcePathTest
         {
             this.setterValue = v;
         }
+
+        public Child getChild()
+        {
+            return child;
+        }
+
+        public void setChild(final Child child)
+        {
+            this.child = child;
+        }
     }
 
     public static class Child
     {
-        public Child(final String value)
+        public Child(final String value, final Child subchild)
         {
             this.value = value;
+            this.subchild = subchild;
         }
 
         public String value;
+
+        public Child subchild;
+    }
+
+    public static void assertSamePointer(
+            final SourcePathPointer expected,
+            final SourcePathPointer actual)
+    {
+        if (expected == null)
+        {
+            assertNull(actual);
+        }
+        else
+        {
+            assertNotNull(actual);
+            assertSame(expected.getValue(), actual.getValue());
+            assertEquals(expected.getPath(), actual.getPath());
+        }
     }
 }



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

Reply via email to