incubator-bval-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mben...@apache.org
Subject svn commit: r1002681 - in /incubator/bval/sandbox/lang3-work: bval-jsr303/src/main/java/ bval-jsr303/src/main/java/org/apache/bval/jsr303/util/ bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/ bval-jsr303d/src/test/java/org/apache/bval/jsr303...
Date Wed, 29 Sep 2010 15:35:47 GMT
Author: mbenson
Date: Wed Sep 29 15:35:46 2010
New Revision: 1002681

URL: http://svn.apache.org/viewvc?rev=1002681&view=rev
Log:
PathNavigation is more structured, handling index/key-less iterables marked as []:  thus, no wildcard sequence is needed for dynamic prototype iterables; make DynamicMetaGraphManager implementation function correctly by extracting the metabean-merging code into a standalone implementation class, then delegating dynamicMetaBeanFinder work to this.

Added:
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java   (with props)
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java   (with props)
Modified:
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/   (props changed)
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java
    incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java
    incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java

Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Sep 29 15:35:46 2010
@@ -1 +1 @@
-/incubator/bval/trunk/bval-jsr303/src/main/java:992330-992353,992401,992406,992412,992510,992648,993404-993438,996236,996240,997154
+/incubator/bval/trunk/bval-jsr303/src/main/java:992330-992353,992401,992406,992412,992510,992648,993404-993438,996236,996240,997154,1002445

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/NestedPathNavigator.java Wed Sep 29 15:35:46 2010
@@ -159,5 +159,12 @@ public class NestedPathNavigator {
             this.type = type;
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        public void handleGenericInIterable() {
+            throw new UnsupportedOperationException("Cannot navigate a ValidationContext to []");
+        }
+
     }
 }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303/src/main/java/org/apache/bval/jsr303/util/PathNavigation.java Wed Sep 29 15:35:46 2010
@@ -49,6 +49,11 @@ public class PathNavigation {
         void handleIndexOrKey(String value);
 
         /**
+         * Handle contiguous [].
+         */
+        void handleGenericInIterable();
+
+        /**
          * Return a result. Called after navigation is complete.
          * 
          * @return result
@@ -97,24 +102,28 @@ public class PathNavigation {
     public static <T> T navigateAndReturn(String propertyPath, Callback<? extends T> callback) {
         try {
             StringTokenizer tokens = new StringTokenizer(StringUtils.defaultString(propertyPath), ".[]", true);
-            while (tokens.hasMoreTokens()) {
-                String token = tokens.nextToken();
-                if (".".equals(token)) {
-                    continue;
+            TokenType state = TokenType.START;
+
+            String token = null;
+            while (state != TokenType.END) {
+                if (state == TokenType.KEY) {
+                    callback.handleIndexOrKey(token);
+                } else if (state == TokenType.PROPERTY) {
+                    callback.handleProperty(token);
                 }
 
-                if ("[".equals(token)) {
-                    String key = tokens.nextToken();
+                TokenType next;
+                if (tokens.hasMoreTokens()) {
                     token = tokens.nextToken();
-                    if (!"]".equals(token)) {
-                        throw new ValidationException("']' missing, invalid property format: " + propertyPath);
-                    }
-                    callback.handleIndexOrKey(key);
-                    continue;
+                    next = state.parseNext(token);
+                } else {
+                    next = TokenType.END;
                 }
-
-                // else, it is a property name
-                callback.handleProperty(token);
+                state.test(next);
+                if (state == TokenType.LBRACK && next == TokenType.RBRACK) {
+                    callback.handleGenericInIterable();
+                }
+                state = next;
             }
             return callback.result();
         } catch (ValidationException ex) {
@@ -124,4 +133,89 @@ public class PathNavigation {
         }
     }
 
+    private enum TokenType {
+        START("Expected property, index/key, or end of expression") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == PROPERTY || next == LBRACK || next == END;
+            }
+        },
+        PROPERTY("Expected property path separator, index/key, or end of expression") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == DOT || next == LBRACK || next == END;
+            }
+        },
+        LBRACK("Expected index/key or ]") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == RBRACK || next == KEY;
+            }
+
+            /**
+             * {@inheritDoc}
+             */
+            @Override
+            TokenType parseNext(String token) {
+                TokenType next = super.parseNext(token);
+                return next == PROPERTY ? KEY : next;
+            }
+        },
+        KEY("Expected ]") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == RBRACK;
+            }
+
+        },
+        RBRACK("Expected property path separator or end of expression") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == DOT || next == END;
+            }
+        },
+        DOT("Expected property after path separator") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return next == PROPERTY;
+            }
+        },
+        END("") {
+            @Override
+            boolean allowedNext(TokenType next) {
+                return false;
+            }
+        };
+
+        final String violationMessage;
+
+        /**
+         * @param violationMessage
+         * @param allowedNext
+         */
+        private TokenType(String violationMessage) {
+            this.violationMessage = violationMessage;
+        }
+
+        abstract boolean allowedNext(TokenType next);
+
+        final void test(TokenType next) {
+            if (!allowedNext(next)) {
+                throw new IllegalStateException(violationMessage);
+            }
+        }
+
+        TokenType parseNext(String token) {
+            if (".".equals(token)) {
+                return DOT;
+            }
+            if ("[".equals(token)) {
+                return LBRACK;
+            }
+            if ("]".equals(token)) {
+                return RBRACK;
+            }
+            return PROPERTY;
+        }
+    }
 }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManager.java Wed Sep 29 15:35:46 2010
@@ -75,4 +75,9 @@ public interface DynamicMetaGraphManager
      *         {@link #forRead()} results.
      */
     Interface writable();
+
+    /**
+     * Clear the dynamic metadata.
+     */
+    void clear();
 }

Added: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java?rev=1002681&view=auto
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java (added)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java Wed Sep 29 15:35:46 2010
@@ -0,0 +1,538 @@
+/*
+ *  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.
+ */
+package org.apache.bval.jsr303.dynamic;
+
+import static org.apache.bval.jsr303.dynamic.DynamicModel.copyConstraints;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.copyFeatures;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredContainer;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredProperty;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.DYNAMIC_CONSTRAINT_COLLECTION;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.META_CONTAINER;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.validation.Path;
+
+import org.apache.bval.MetaBeanFinder;
+import org.apache.bval.jsr303.AnnotationProcessor;
+import org.apache.bval.jsr303.AppendValidationToMeta;
+import org.apache.bval.jsr303.UnknownPropertyException;
+import org.apache.bval.jsr303.util.ClassHelper;
+import org.apache.bval.jsr303.util.NodeImpl;
+import org.apache.bval.jsr303.util.PathImpl;
+import org.apache.bval.jsr303.util.PathNavigation;
+import org.apache.bval.model.FeaturesCapable;
+import org.apache.bval.model.MetaBean;
+import org.apache.bval.model.MetaProperty;
+import org.apache.bval.util.AccessStrategy;
+import org.apache.bval.util.IndexedAccess;
+import org.apache.bval.util.KeyedAccess;
+import org.apache.bval.util.PropertyAccess;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.Pair;
+import org.apache.commons.lang3.reflect.TypeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link DynamicMetaGraphManager} implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+final class DynamicMetaGraphManagerImpl implements DynamicMetaGraphManager {
+    private static final Collection<Annotation> EMPTY_DYNAMIC_ANNOTATIONS = Collections.<Annotation> emptySet();
+
+    private static class FindType extends PathNavigation.CallbackProcedure {
+        Type type;
+        Class<?> rawType;
+
+        /**
+         * Create a new DynamicValidatorContext.GetRawType instance.
+         */
+        public FindType(Class<?> root) {
+            this.rawType = root;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public synchronized void handleProperty(String name) {
+            setType(new PropertyAccess(rawType, name).getJavaType());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleIndexOrKey(String value) {
+            handleGenericInIterable();
+        }
+
+        private synchronized void setType(Type type) {
+            this.rawType = TypeUtils.getRawType(type, this.type);
+            this.type = type;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleGenericInIterable() {
+            Type elementType = KeyedAccess.getJavaElementType(type);
+            if (elementType == null) {
+                elementType = IndexedAccess.getJavaElementType(type);
+            }
+            if (elementType == null) {
+                throw new UnknownPropertyException(String.format("Cannot resolve index/key type of %s", type));
+            }
+            setType(elementType);
+        }
+
+    }
+
+    /**
+     * PathNavigation callback for initial location of a property path.
+     */
+    private class NavigateOrBuildGraph implements PathNavigation.Callback<FeaturesCapable> {
+        private MetaBean metaBean;
+        private MetaProperty property;
+
+        /**
+         * Create a new SetupConstraintCallback instance.
+         *
+         * @param root
+         */
+        NavigateOrBuildGraph(MetaBean root) {
+            super();
+            this.metaBean = root;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleIndexOrKey(String value) {
+            MetaContainer<?> container = getContainer();
+            if (Integer.class.equals(container.getIdType())) {
+                @SuppressWarnings("unchecked")
+                MetaContainer<Integer> collection = (MetaContainer<Integer>) container;
+                metaBean = collection.getElement(Integer.valueOf(value));
+            } else if (Object.class.equals(container.getIdType())) {
+                @SuppressWarnings("unchecked")
+                MetaContainer<Object> map = (MetaContainer<Object>) container;
+                metaBean = map.getElement(value);
+            } else {
+                throw new IllegalStateException(String.format("Don't know how to handle container id type %s",
+                    container.getIdType()));
+            }
+            property = null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleGenericInIterable() {
+            metaBean = getContainer().getPrototype();
+            property = null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleProperty(String name) {
+            if (property != null) {
+                metaBean = property.getMetaBean();
+            }
+            property = getRequiredProperty(metaBean, name);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public FeaturesCapable result() {
+            return property == null ? metaBean : property;
+        }
+
+        private MetaContainer<?> getContainer() {
+            return getRequiredContainer(property == null ? metaBean : property);
+        }
+    }
+
+    final ThreadLocal<DynamicValidationState> currentValidationState = new ThreadLocal<DynamicValidationState>();
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private final DynamicMetaGraphManager.Interface writable = new DynamicMetaGraphManager.Interface() {
+
+        /**
+         * {@inheritDoc}
+         */
+        public MetaBean getMetaBean(Class<?> type) {
+            MetaBean result;
+            if (dynamicBeanInfo.containsKey(type)) {
+                result = dynamicBeanInfo.get(type);
+            } else {
+                result = new MetaBean();
+                result.setBeanClass(type);
+                MetaBean faster = dynamicBeanInfo.putIfAbsent(type, result);
+                if (faster != null) {
+                    return faster;
+                }
+            }
+            return result;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public <T extends FeaturesCapable> T getMeta(Class<?> type, String propertyPath) {
+            MetaBean root = getMetaBean(type);
+            @SuppressWarnings("unchecked")
+            T result = (T) PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(root));
+            return result;
+        }
+    };
+
+    private final DynamicMetaGraphManager.Interface readOnly = new DynamicMetaGraphManager.Interface() {
+        /**
+         * {@inheritDoc}
+         */
+        public MetaBean getMetaBean(Class<?> type) {
+            final MetaBean initial = metaBeanFinder.findForClass(type);
+            MetaBean result = initial;
+
+            final PathImpl path;
+            final Object rootBean;
+            final MetaBean rootMetaBean;
+
+            DynamicValidationState validationState = currentValidationState.get();
+            if (validationState == null) {
+                path = PathImpl.create(null);
+                rootBean = null;
+                rootMetaBean = initial;
+            } else {
+                rootMetaBean = validationState.getRootMetaBean();
+                path = validationState.getPropertyPath();
+                rootBean = validationState.getRootBean();
+            }
+            try {
+                /*
+                 * For each step of the path, we need to know whether the bean
+                 * we are looking for matches a mapped property, so we build a
+                 * stack of path/bean pairs. We use a stack so that when we
+                 * process, the longest path goes last and therefore wins over
+                 * short paths: the rationale here is that the longer path is
+                 * more specific thus more likely to be rooted at more important
+                 * part of your domain model.
+                 */
+                Deque<Pair<? extends PathImpl, Class<?>>> pathStack =
+                    buildPathStack(path, rootBean, rootMetaBean.getBeanClass());
+
+                while (!pathStack.isEmpty()) {
+                    Pair<? extends PathImpl, Class<?>> pair = pathStack.pop();
+                    List<MetaBean> dynamicInfo = getAssignableDynamicInfo(pair.right);
+
+                    PathImpl relativePath = pair.left;
+                    for (MetaBean root : dynamicInfo) {
+                        MetaBean leaf = findLeaf(root, relativePath);
+                        if (leaf == null) {
+                            continue;
+                        }
+                        if (result == initial) {
+                            result = initial.copy();
+                        }
+
+                        // copy bean + property features and constraints:
+                        copyFeatures(result, leaf);
+                        copyConstraints(result, leaf);
+
+                        for (MetaProperty sourceProperty : leaf.getProperties()) {
+                            MetaProperty targetProperty = getRequiredProperty(result, sourceProperty.getName());
+                            copyFeatures(targetProperty, sourceProperty);
+                            copyConstraints(targetProperty, sourceProperty);
+                        }
+
+                    }
+                }
+
+                if (result == initial) {
+                    return result;
+                }
+                // now the dynamic constraints should FINALLY be fully
+                // populated:
+
+                {
+                    Collection<Annotation> constraints =
+                        result.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS);
+                    for (Annotation constraint : constraints) {
+                        annotationProcessor.processAnnotation(constraint, result.getBeanClass(),
+                            new AppendValidationToMeta(result));
+                    }
+                }
+                for (MetaProperty property : result.getProperties()) {
+                    String propertyName = property.getName();
+                    Collection<Annotation> constraints =
+                        property.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS);
+                    for (Annotation constraint : constraints) {
+                        annotationProcessor.processAnnotation(constraint, property, result.getBeanClass(),
+                            new PropertyAccess(result.getBeanClass(), propertyName), new AppendValidationToMeta(
+                                property));
+                    }
+                }
+
+            } catch (Exception e) {
+                StringBuilder msg =
+                    new StringBuilder("Encountered error applying dynamic constraints for type ")
+                        .append(type.getName());
+                if (!path.isRootPath()) {
+                    msg.append(": path ").append(path);
+                }
+                log.error(msg.toString(), e);
+            }
+            return result;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @SuppressWarnings("unchecked")
+        public <T extends FeaturesCapable> T getMeta(Class<?> type, String propertyPath) {
+            MetaBean rootMetaBean = metaBeanFinder.findForClass(type);
+
+            PathImpl path = PathImpl.createPathFromString(propertyPath);
+            String propertyName;
+            NodeImpl leafNode = path.getLeafNode();
+            if (!leafNode.isInIterable()) {
+            	propertyName = leafNode.getName();
+            	path.removeLeafNode();
+            } else {
+                propertyName = null;
+            }
+            FindType findType = new FindType(type);
+            PathNavigation.navigate(path.toString(), findType);
+            Class<?> beanType = findType.rawType;
+
+            FeaturesCapable result;
+            try {
+                currentValidationState.set(new DynamicValidationStateBean(null, rootMetaBean, path));
+                result = getMetaBean(beanType);
+                if (propertyName != null) {
+                    result = ((MetaBean) result).getProperty(propertyName);
+                    if (result == null) {
+                        // build from its metabean
+
+                        findType = new FindType(beanType);
+                        PathNavigation.navigateAndReturn(propertyName, findType);
+                        MetaProperty prop = new MetaProperty();
+                        prop.setName(propertyName);
+                        prop.setParentMetaBean((MetaBean) result);
+                        prop.setType(findType.type);
+
+                        // replace the propertyName, but I doubt it matters
+                        path.addNode(new NodeImpl(propertyName));
+                        MetaBean metaBean = getMetaBean(prop.getTypeClass());
+                        prop.setMetaBean(metaBean);
+                        result = prop;
+                    }
+                }
+                return (T) result;
+            } finally {
+                currentValidationState.remove();
+            }
+        }
+    };
+
+    private final ConcurrentMap<Class<?>, MetaBean> dynamicBeanInfo = new ConcurrentHashMap<Class<?>, MetaBean>();
+    private final AnnotationProcessor annotationProcessor;
+    private final MetaBeanFinder metaBeanFinder;
+
+    // private String wildcard = DynamicValidatorContext.DEFAULT_WILDCARD;
+
+    /**
+     * Create a new DynamicMetaGraphManagerImpl instance.
+     *
+     * @param annotationProcessor
+     * @param metaBeanFinder
+     */
+    DynamicMetaGraphManagerImpl(AnnotationProcessor annotationProcessor, MetaBeanFinder metaBeanFinder) {
+        super();
+        this.annotationProcessor = annotationProcessor;
+        this.metaBeanFinder = metaBeanFinder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Interface readOnly() {
+        return readOnly;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Interface writable() {
+        return writable;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        dynamicBeanInfo.clear();
+    }
+
+    private List<MetaBean> getAssignableDynamicInfo(Class<?> type) {
+        List<Class<?>> classSequence = new ArrayList<Class<?>>();
+        ClassHelper.fillFullClassHierarchyAsList(classSequence, type);
+        List<MetaBean> result = new ArrayList<MetaBean>(classSequence.size());
+        for (Class<?> assignable : classSequence) {
+            MetaBean dynamicInfo = dynamicBeanInfo.get(assignable);
+            if (dynamicInfo != null) {
+                result.add(dynamicInfo);
+            }
+        }
+        return result;
+    }
+
+    private MetaBean findLeaf(MetaBean root, PathImpl path) {
+        if (path.isRootPath()) {
+            return root;
+        }
+        MetaBean metaBean = root;
+        MetaProperty property = null;
+
+        // iterate over the path; bail at the first null meta object:
+        for (Path.Node node : path) {
+            if (node.getName() != null) {
+                property = metaBean.getProperty(node.getName());
+                if (property == null) {
+                    return null;
+                }
+                // make sure the source (dynamic) properties know how to
+                // cascade so that when/if they copy over the target will
+                // cascade them as well:
+                annotationProcessor.addAccessStrategy(property,
+                    new PropertyAccess(metaBean.getBeanClass(), node.getName()));
+
+                metaBean = property.getMetaBean();
+            }
+            if (node.isInIterable()) {
+            	FeaturesCapable tip = property == null ? metaBean : property;
+            	MetaContainer<?> container = tip.getFeature(META_CONTAINER);
+            	if (container == null) {
+            		return null;
+            	}
+            	if (container.getIdType().equals(Integer.class)) {
+            		@SuppressWarnings("unchecked")
+            		MetaContainer<Integer> coll = (MetaContainer<Integer>) container;
+            		metaBean = coll.getMergedElement(node.getIndex());
+            	} else {
+            		@SuppressWarnings("unchecked")
+            		MetaContainer<Object> map = (MetaContainer<Object>) container;
+            		metaBean = map.getMergedElement(node.getKey());
+            	}
+            	property = null;
+            }
+        }
+        return metaBean;
+    }
+
+    /*
+     * build a stack of pairs of path + metabean representing each object in the
+     * currently known path, i.e. what we're trying to complete the bean for
+     */
+    private static Deque<Pair<? extends PathImpl, Class<?>>> buildPathStack(final PathImpl fullPath, Object rootBean,
+        Class<?> rootType) {
+        // get a list of Nodes we can play with:
+        LinkedList<Path.Node> nodes = new LinkedList<Path.Node>();
+        Iterator<Path.Node> fullNodes = fullPath.iterator();
+        while (fullNodes.hasNext()) {
+            nodes.add(fullNodes.next());
+        }
+
+        Deque<Pair<? extends PathImpl, Class<?>>> stack = new ArrayDeque<Pair<? extends PathImpl, Class<?>>>();
+
+        Class<?> rawType = rootType;
+        Type type = rawType;
+        Object bean = rootBean;
+
+        while (true) {
+            PathImpl path = buildPath(nodes);
+            stack.push(Pair.<PathImpl, Class<?>> of(path, rawType));
+            if (path.isRootPath()) {
+                break;
+            }
+            // handle the property:
+            Path.Node node = nodes.remove(0);
+            if (node.getName() != null) {
+                PropertyAccess access = new PropertyAccess(rawType, node.getName());
+                if (bean != null) {
+                    bean = access.get(bean);
+                }
+                rawType = TypeUtils.getRawType(access.getJavaType(), type);
+                type = access.getJavaType();
+                if (node.isInIterable()) {
+                	//substitute a nameless indexed property node and repeat the loop:
+                	NodeImpl sub = new NodeImpl(null);
+                	sub.setInIterable(true);
+                	if (IndexedAccess.getJavaElementType(type) != null) {
+                		sub.setIndex(node.getIndex());
+                	} else if (KeyedAccess.getJavaElementType(type) != null) {
+                		sub.setKey(node.getKey());
+                	}
+                	nodes.add(0, sub);
+                	continue;
+                }
+            }
+            if (node.isInIterable()) {
+                AccessStrategy access;
+                if (IndexedAccess.getJavaElementType(type) != null) {
+                    access =
+                        new IndexedAccess(type, ObjectUtils.defaultIfNull(node.getIndex(), Integer.valueOf(-1))
+                            .intValue());
+                } else if (KeyedAccess.getJavaElementType(type) != null) {
+                    access = new KeyedAccess(type, node.getKey());
+                } else {
+                    throw new UnknownPropertyException(String.format("%s in %s", node, path));
+                }
+                if (bean != null) {
+                    bean = access.get(bean);
+                }
+                rawType = TypeUtils.getRawType(access.getJavaType(), type);
+                type = access.getJavaType();
+            }
+        }
+        return stack;
+    }
+
+    private static PathImpl buildPath(Iterable<? extends Path.Node> nodes) {
+        PathImpl result = PathImpl.create(null);
+        for (Path.Node node : nodes) {
+            result.addNode(node);
+        }
+        return result;
+    }
+
+}

Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicModel.java Wed Sep 29 15:35:46 2010
@@ -20,6 +20,7 @@ import static org.apache.bval.jsr303.dyn
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -116,23 +117,23 @@ public class DynamicModel {
     /**
      * Get or create a MetaContainer for the specified property.
      * 
-     * @param property
+     * @param meta
      * @return MetaContainer
      * @throws IllegalArgumentException
      *             if the property doesn't seem to refer to a container
      */
-    public static MetaContainer<?> getRequiredContainer(MetaProperty property) {
-        MetaContainer<?> result = property.getFeature(META_CONTAINER);
+    public static MetaContainer<?> getRequiredContainer(FeaturesCapable meta) {
+        MetaContainer<?> result = meta.getFeature(META_CONTAINER);
+        Type type = meta instanceof MetaProperty ? ((MetaProperty) meta).getType() : ((MetaBean) meta).getBeanClass();
         if (result == null) {
-            if (KeyedAccess.getJavaElementType(property.getType()) != null) {
-                result = new MetaMap(property);
-            } else if (IndexedAccess.getJavaElementType(property.getType()) != null) {
-                result = new MetaCollection(property);
+            if (KeyedAccess.getJavaElementType(type) != null) {
+                result = new MetaMap(type);
+            } else if (IndexedAccess.getJavaElementType(type) != null) {
+                result = new MetaCollection(type);
             } else {
-                throw new IllegalArgumentException("don't know how to make a container of " + property + " of "
-                    + property.getParentMetaBean());
+                throw new IllegalArgumentException(String.format("don't know how to make a container of %s", meta));
             }
-            property.putFeature(META_CONTAINER, result);
+            meta.putFeature(META_CONTAINER, result);
         }
         return result;
     }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/DynamicValidatorContext.java Wed Sep 29 15:35:46 2010
@@ -16,28 +16,11 @@
  */
 package org.apache.bval.jsr303.dynamic;
 
-import static org.apache.bval.jsr303.dynamic.DynamicModel.copyConstraints;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.copyFeatures;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredContainer;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredDynamicConstraints;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.getRequiredProperty;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.DYNAMIC_CONSTRAINT_COLLECTION;
-import static org.apache.bval.jsr303.dynamic.DynamicModel.Features.META_CONTAINER;
+import static org.apache.bval.jsr303.dynamic.DynamicModel.*;
 
 import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 
-import javax.validation.Path;
 import javax.validation.Validator;
 import javax.validation.ValidatorContext;
 
@@ -46,384 +29,70 @@ import org.apache.bval.MetaBeanFinder;
 import org.apache.bval.MetaBeanManager;
 import org.apache.bval.jsr303.AnnotationProcessor;
 import org.apache.bval.jsr303.ApacheFactoryContext;
-import org.apache.bval.jsr303.AppendValidationToMeta;
-import org.apache.bval.jsr303.UnknownPropertyException;
-import org.apache.bval.jsr303.util.ClassHelper;
-import org.apache.bval.jsr303.util.PathImpl;
-import org.apache.bval.jsr303.util.PathNavigation;
 import org.apache.bval.model.FeaturesCapable;
 import org.apache.bval.model.MetaBean;
-import org.apache.bval.model.MetaProperty;
-import org.apache.bval.util.AccessStrategy;
-import org.apache.bval.util.IndexedAccess;
-import org.apache.bval.util.KeyedAccess;
-import org.apache.bval.util.PropertyAccess;
-import org.apache.commons.lang3.Pair;
-import org.apache.commons.lang3.reflect.TypeUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * {@link ValidatorContext} implementation supporting context-bound dynamic
  * constraints.
- * 
+ *
  * @version $Rev$ $Date$
  */
 public class DynamicValidatorContext extends ApacheFactoryContext implements DynamicMetaGraphManager {
-    /**
-     * Default means of signifying "any" as a match for a bracketed index/key in
-     * a path.
-     */
-    public static final String DEFAULT_WILDCARD = "*";
-
-    private static final Collection<Annotation> EMPTY_DYNAMIC_ANNOTATIONS = Collections.<Annotation> emptySet();
-
-    private class GetRawType implements PathNavigation.Callback<Class<?>> {
-        private Type type;
-        private Class<?> rawType;
 
-        /**
-         * Create a new DynamicValidatorContext.GetRawType instance.
-         */
-        public GetRawType(Class<?> root) {
-            this.rawType = root;
-        }
+    private class DynamicMetaBeanFinder extends MetaBeanManager {
 
-        /**
-         * {@inheritDoc}
-         */
-        public synchronized void handleProperty(String name) {
-            setType(new PropertyAccess(rawType, name).getJavaType());
-        }
+        final MetaBeanFinder staticFinder = new MetaBeanFinder() {
 
-        /**
-         * {@inheritDoc}
-         */
-        public void handleIndexOrKey(String value) {
-            Type elementType = KeyedAccess.getJavaElementType(type);
-            if (elementType == null) {
-                elementType = IndexedAccess.getJavaElementType(type);
+            public MetaBean findForId(String beanInfoId) {
+                return DynamicMetaBeanFinder.this.findForId(beanInfoId);
             }
-            if (elementType == null) {
-                throw new UnknownPropertyException(String.format(
-                    "Cannot resolve index/key %s in property path expression", value));
-            }
-            setType(elementType);
-        }
-
-        private synchronized void setType(Type type) {
-            this.rawType = TypeUtils.getRawType(type, this.type);
-            this.type = type;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Class<?> result() {
-            return rawType;
-        }
-
-    }
 
-    /**
-     * PathNavigation callback for initial location of a property path.
-     */
-    private class NavigateOrBuildGraph implements PathNavigation.Callback<FeaturesCapable> {
-        private MetaBean metaBean;
-        private MetaProperty property;
+            public MetaBean findForClass(Class<?> clazz) {
+                return findStatic(clazz);
+            }
+        };
 
-        /**
-         * Create a new SetupConstraintCallback instance.
-         * 
-         * @param root
-         */
-        NavigateOrBuildGraph(MetaBean root) {
-            super();
-            this.metaBean = root;
-        }
+        final DynamicMetaGraphManagerImpl metaGraphManager;
 
         /**
-         * {@inheritDoc}
+         * Create a new DynamicValidatorContext.DynamicMetaBeanFinder instance.
          */
-        public void handleIndexOrKey(String value) {
-            if (property == null) {
-                throw new IllegalStateException(
-                    "Bean validation doesn't handle property paths that lead with indexes... does it?");
-            }
-            MetaContainer<?> container = getRequiredContainer(property);
-            if (wildcard.equals(value)) {
-                metaBean = container.getPrototype();
-            } else if (Integer.class.equals(container.getIdType())) {
-                @SuppressWarnings("unchecked")
-                MetaContainer<Integer> collection = (MetaContainer<Integer>) container;
-                metaBean = collection.getElement(Integer.valueOf(value));
-            } else if (Object.class.equals(container.getIdType())) {
-                @SuppressWarnings("unchecked")
-                MetaContainer<Object> map = (MetaContainer<Object>) container;
-                metaBean = map.getElement(value);
-            } else {
-                throw new IllegalStateException(String.format("Don't know how to handle container id type %s",
-                    container.getIdType()));
-            }
-            property = null;
+        public DynamicMetaBeanFinder(MetaBeanBuilder builder) {
+            super(builder);
+            this.metaGraphManager =
+                new DynamicMetaGraphManagerImpl(new AnnotationProcessor(DynamicValidatorContext.this), staticFinder);
         }
 
-        /**
-         * {@inheritDoc}
-         */
-        public void handleProperty(String name) {
-            if (property != null) {
-                metaBean = property.getMetaBean();
-            }
-            property = getRequiredProperty(metaBean, name);
+        private MetaBean findStatic(Class<?> clazz) {
+            return super.findForClass(clazz);
         }
 
         /**
          * {@inheritDoc}
          */
-        public FeaturesCapable result() {
-            return property == null ? metaBean : property;
-        }
-
-    }
-
-    private class DynamicMetaBeanFinder extends MetaBeanManager {
-
-        /**
-         * Create a new DynamicValidatorContext.DynamicMetaBeanFinder instance.
-         */
-        DynamicMetaBeanFinder(MetaBeanBuilder builder) {
-            super(builder);
+        public MetaBean findForClass(final Class<?> clazz) {
+            return metaGraphManager.readOnly().getMetaBean(clazz);
         }
 
         /**
          * {@inheritDoc}
          */
-        public MetaBean findForClass(final Class<?> clazz) {
-            final MetaBean initial = super.findForClass(clazz);
-            MetaBean result = initial;
-
-            final PathImpl path;
-            final Object rootBean;
-            final MetaBean rootMetaBean;
-
-            DynamicValidationState validationState = currentValidationState.get();
-            if (validationState == null) {
-                path = PathImpl.create(null);
-                rootBean = null;
-                rootMetaBean = initial;
-            } else {
-                rootMetaBean = validationState.getRootMetaBean();
-                path = validationState.getPropertyPath();
-                rootBean = validationState.getRootBean();
-            }
-            try {
-                /*
-                 * For each step of the path, we need to know whether the bean
-                 * we are looking for matches a mapped property, so we build a
-                 * stack of path/bean pairs. We use a stack so that when we
-                 * process, the longest path goes last and therefore wins over
-                 * short paths: the rationale here is that the longer path is
-                 * more specific thus more likely to be rooted at more important
-                 * part of your domain model.
-                 */
-                Deque<Pair<? extends PathImpl, Class<?>>> pathStack =
-                    buildPathStack(path, rootBean, rootMetaBean.getBeanClass());
-
-                while (!pathStack.isEmpty()) {
-                    Pair<? extends PathImpl, Class<?>> pair = pathStack.pop();
-                    List<MetaBean> dynamicInfo = getAssignableDynamicInfo(pair.right);
-
-                    PathImpl relativePath = pair.left;
-                    for (MetaBean root : dynamicInfo) {
-                        MetaBean leaf = findLeaf(root, relativePath);
-                        if (leaf == null) {
-                            continue;
-                        }
-                        if (result == initial) {
-                            result = initial.copy();
-                        }
-
-                        // copy bean + property features and constraints:
-                        copyFeatures(result, leaf);
-                        copyConstraints(result, leaf);
-
-                        for (MetaProperty sourceProperty : leaf.getProperties()) {
-                            MetaProperty targetProperty = getRequiredProperty(result, sourceProperty.getName());
-                            copyFeatures(targetProperty, sourceProperty);
-                            copyConstraints(targetProperty, sourceProperty);
-                        }
-
-                    }
-                }
-
-                if (result == initial) {
-                    return result;
-                }
-                // now the dynamic constraints should FINALLY be fully
-                // populated:
-
-                {
-                    Collection<Annotation> constraints =
-                        result.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS);
-                    for (Annotation constraint : constraints) {
-                        annotationProcessor.processAnnotation(constraint, result.getBeanClass(),
-                            new AppendValidationToMeta(result));
-                    }
-                }
-                for (MetaProperty property : result.getProperties()) {
-                    String propertyName = property.getName();
-                    Collection<Annotation> constraints =
-                        property.getFeature(DYNAMIC_CONSTRAINT_COLLECTION, EMPTY_DYNAMIC_ANNOTATIONS);
-                    for (Annotation constraint : constraints) {
-                        annotationProcessor.processAnnotation(constraint, property, result.getBeanClass(),
-                            new PropertyAccess(result.getBeanClass(), propertyName), new AppendValidationToMeta(
-                                property));
-                    }
-                }
-
-            } catch (Exception e) {
-                StringBuilder msg =
-                    new StringBuilder("Encountered error applying dynamic constraints for type ").append(clazz
-                        .getName());
-                if (!path.isRootPath()) {
-                    msg.append(": path ").append(path);
-                }
-                log.error(msg.toString(), e);
-            }
-            return result;
-        }
-    }
-
-    private List<MetaBean> getAssignableDynamicInfo(Class<?> type) {
-        List<Class<?>> classSequence = new ArrayList<Class<?>>();
-        ClassHelper.fillFullClassHierarchyAsList(classSequence, type);
-        List<MetaBean> result = new ArrayList<MetaBean>(classSequence.size());
-        for (Class<?> assignable : classSequence) {
-            MetaBean dynamicInfo = dynamicBeanInfo.get(assignable);
-            if (dynamicInfo != null) {
-                result.add(dynamicInfo);
-            }
-        }
-        return result;
-    }
-
-    /*
-     * build a stack of pairs of path + metabean representing each object in the
-     * currently known path, i.e. what we're trying to complete the bean for
-     */
-    private Deque<Pair<? extends PathImpl, Class<?>>> buildPathStack(final PathImpl fullPath, Object rootBean,
-        Class<?> rootType) {
-        // get a list of Nodes we can play with:
-        LinkedList<Path.Node> nodes = new LinkedList<Path.Node>();
-        Iterator<Path.Node> fullNodes = fullPath.iterator();
-        while (fullNodes.hasNext()) {
-            nodes.add(fullNodes.next());
+        public MetaBean findForId(String beanInfoId) {
+            return super.findForId(beanInfoId);
         }
-
-        Deque<Pair<? extends PathImpl, Class<?>>> stack = new ArrayDeque<Pair<? extends PathImpl, Class<?>>>();
-
-        PathImpl path = fullPath;
-        Class<?> rawType = rootType;
-        Type type = rawType;
-        Object bean = rootBean;
-
-        while (true) {
-            stack.push(Pair.<PathImpl, Class<?>> of(path, rawType));
-            if (path.isRootPath()) {
-                break;
-            }
-            // handle the property:
-            Path.Node node = nodes.remove(0);
-            {
-                PropertyAccess access = new PropertyAccess(rawType, node.getName());
-                if (bean != null) {
-                    bean = access.get(bean);
-                }
-                rawType = TypeUtils.getRawType(access.getJavaType(), type);
-                type = access.getJavaType();
-            }
-            if (node.isInIterable()) {
-                AccessStrategy access;
-                if (node.getIndex() != null) {
-                    access = new IndexedAccess(type, node.getIndex());
-                } else {
-                    access = new KeyedAccess(type, node.getKey());
-                }
-                if (bean != null) {
-                    bean = access.get(bean);
-                }
-                rawType = TypeUtils.getRawType(access.getJavaType(), type);
-                type = access.getJavaType();
-            }
-
-            // rebuild relative path from remaining nodes:
-            path = buildPath(nodes);
-        }
-        return stack;
     }
 
-    private MetaBean findLeaf(MetaBean root, PathImpl path) {
-        if (path.isRootPath()) {
-            return root;
-        }
-        MetaBean result = root;
-        // iterate over the path; bail at the first null meta object:
-        for (Path.Node node : path) {
-            MetaProperty sourceProperty = result.getProperty(node.getName());
-            if (sourceProperty == null) {
-                return null;
-            }
-            if (node.isInIterable()) {
-                if (sourceProperty.getFeature(META_CONTAINER) == null) {
-                    return null;
-                }
-                if (node.getIndex() != null) {
-                    MetaContainer<Integer> collection = sourceProperty.getFeature(META_CONTAINER);
-                    result = collection.getMergedElement(node.getIndex());
-                } else {
-                    // assume there must be a key
-                    MetaContainer<Object> map = sourceProperty.getFeature(META_CONTAINER);
-                    result = map.getMergedElement(node.getKey());
-                }
-            } else {
-                result = sourceProperty.getMetaBean();
-            }
-            // make sure the source (dynamic) properties know how to
-            // cascade so that when/if they copy over the target will
-            // cascade them as well:
-            annotationProcessor.addAccessStrategy(sourceProperty, new PropertyAccess(sourceProperty.getParentMetaBean()
-                .getBeanClass(), sourceProperty.getName()));
-        }
-        return result;
-    }
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-    private final ThreadLocal<DynamicValidationState> currentValidationState =
-        new ThreadLocal<DynamicValidationState>();
-
-    private final AnnotationProcessor annotationProcessor = new AnnotationProcessor(this);
-    private final ConcurrentMap<Class<?>, MetaBean> dynamicBeanInfo = new ConcurrentHashMap<Class<?>, MetaBean>();
-    private String wildcard = DEFAULT_WILDCARD;
+    private final DynamicMetaGraphManagerImpl metaGraphManager;
 
     /**
      * Create a new {@link DynamicValidatorContext} instance.
-     * 
+     *
      * @param validatorFactory
      */
     public DynamicValidatorContext(DynamicValidatorFactory validatorFactory) {
         super(validatorFactory);
-    }
-
-    /**
-     * Set the wildcard string in use for dynamically constrained properties.
-     * 
-     * @param wildcard
-     * @return <code>this</code> following the chained invocation pattern
-     */
-    public DynamicValidatorContext wildcard(String wildcard) {
-        this.wildcard = wildcard;
-        return this;
+        this.metaGraphManager = ((DynamicMetaBeanFinder) getMetaBeanFinder()).metaGraphManager;
     }
 
     /**
@@ -436,7 +105,7 @@ public class DynamicValidatorContext ext
 
     /**
      * Constrain a bean type at the class level.
-     * 
+     *
      * @param beanType
      * @param constraintCollectionManipulator
      * @return <code>this</code> following the chained invocation pattern
@@ -448,106 +117,38 @@ public class DynamicValidatorContext ext
 
     /**
      * Constrain a property path relative to a root bean type.
-     * 
+     *
      * @param beanType
      * @param propertyPath
      * @param constraintCollectionManipulator
      * @return <code>this</code> following the chained invocation pattern
      */
     public DynamicValidatorContext constrain(Class<?> beanType, String propertyPath, Annotation constraint) {
-        MetaBean metaBean = writable().getMetaBean(beanType);
-        FeaturesCapable meta = PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(metaBean));
+        FeaturesCapable meta = writable().getMeta(beanType, propertyPath);
         Collection<Annotation> constraints = getRequiredDynamicConstraints(meta);
         ConstraintAppender.FACTORY.constraintAppender(constraint).append(constraint, constraints);
         return this;
     }
 
     /**
-     * Clear dynamic constraints for this context.
+     * {@inheritDoc}
      */
-    public void clearDynamicConstraints() {
-        dynamicBeanInfo.clear();
+    public DynamicMetaGraphManager.Interface writable() {
+        return metaGraphManager.writable();
     }
 
     /**
      * {@inheritDoc}
      */
-    public DynamicMetaGraphManager.Interface writable() {
-        return new DynamicMetaGraphManager.Interface() {
-
-            /**
-             * {@inheritDoc}
-             */
-            public MetaBean getMetaBean(Class<?> type) {
-                MetaBean result;
-                if (dynamicBeanInfo.containsKey(type)) {
-                    result = dynamicBeanInfo.get(type);
-                } else {
-                    result = new MetaBean();
-                    result.setBeanClass(type);
-                    MetaBean faster = dynamicBeanInfo.putIfAbsent(type, result);
-                    if (faster != null) {
-                        return faster;
-                    }
-                }
-                return result;
-            }
-
-            /**
-             * {@inheritDoc}
-             */
-            public <T extends FeaturesCapable> T getMeta(Class<?> type, String propertyPath) {
-                MetaBean root = getMetaBean(type);
-                @SuppressWarnings("unchecked")
-                T result = (T) PathNavigation.navigateAndReturn(propertyPath, new NavigateOrBuildGraph(root));
-                return result;
-            }
-        };
+    public DynamicMetaGraphManager.Interface readOnly() {
+        return metaGraphManager.readOnly();
     }
 
     /**
      * {@inheritDoc}
      */
-    public DynamicMetaGraphManager.Interface readOnly() {
-        return new DynamicMetaGraphManager.Interface() {
-
-            /**
-             * {@inheritDoc}
-             */
-            public MetaBean getMetaBean(Class<?> type) {
-                return getMetaBeanFinder().findForClass(type);
-            }
-
-            /**
-             * {@inheritDoc}
-             */
-            @SuppressWarnings("unchecked")
-            public <T extends FeaturesCapable> T getMeta(Class<?> type, String propertyPath) {
-                MetaBean rootMetaBean = DynamicValidatorContext.this.writable().getMetaBean(type);
-                PathImpl path = PathImpl.createPathFromString(propertyPath);
-                // trim off simple leaf property if applicable:
-                String simplePropertyName;
-                if (path.isRootPath() || path.getLeafNode().isInIterable()) {
-                    simplePropertyName = null;
-                } else {
-                    simplePropertyName = path.getLeafNode().getName();
-                    path = path.getPathWithoutLeafNode();
-                }
-                Class<?> beanClass = PathNavigation.navigateAndReturn(path.toString(), new GetRawType(type));
-
-                FeaturesCapable meta;
-                try {
-                    register(new DynamicValidationStateBean(null, rootMetaBean, path));
-                    meta = getMetaBeanFinder().findForClass(beanClass);
-                } finally {
-                    clearValidationState();
-                }
-                if (simplePropertyName != null) {
-                    meta = ((MetaBean) meta).getProperty(simplePropertyName);
-                }
-                return (T) meta;
-            }
-        };
+    public void clear() {
+        metaGraphManager.clear();
     }
 
     /**
@@ -562,26 +163,19 @@ public class DynamicValidatorContext ext
      * Register a {@link DynamicValidationState} instance to the current thread.
      * Etiquette requires the caller to clear the instance when no longer
      * needed.
-     * 
+     *
      * @param validationState
      * @see #clearValidationState()
      */
     void register(DynamicValidationState validationState) {
-        currentValidationState.set(validationState);
+        metaGraphManager.currentValidationState.set(validationState);
     }
 
     /**
      * Clear the registered {@link DynamicValidationState}.
      */
     void clearValidationState() {
-        currentValidationState.remove();
+        metaGraphManager.currentValidationState.remove();
     }
 
-    private static PathImpl buildPath(Iterable<? extends Path.Node> nodes) {
-        PathImpl result = PathImpl.create(null);
-        for (Path.Node node : nodes) {
-            result.addNode(node);
-        }
-        return result;
-    }
 }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaCollection.java Wed Sep 29 15:35:46 2010
@@ -18,7 +18,6 @@ package org.apache.bval.jsr303.dynamic;
 
 import java.lang.reflect.Type;
 
-import org.apache.bval.model.MetaProperty;
 import org.apache.bval.util.IndexedAccess;
 
 /**
@@ -33,15 +32,15 @@ public class MetaCollection extends Meta
      *
      * @param parent
      */
-    public MetaCollection(MetaProperty parent) {
-        super(Integer.class, parent);
+    public MetaCollection(Type type) {
+        super(Integer.class, type);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    protected Type getElementType(MetaProperty parent) {
-        return IndexedAccess.getJavaElementType(parent.getType());
+    protected Type getElementType(Type type) {
+        return IndexedAccess.getJavaElementType(type);
     }
 }

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaContainer.java Wed Sep 29 15:35:46 2010
@@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHa
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.bval.model.MetaBean;
-import org.apache.bval.model.MetaProperty;
 import org.apache.commons.lang3.reflect.TypeUtils;
 
 /**
@@ -42,19 +41,19 @@ public abstract class MetaContainer<K> {
      * Create a new MetaContainer instance.
      * @param parent
      */
-    protected MetaContainer(Class<K> idType, MetaProperty parent) {
+    protected MetaContainer(Class<K> idType, Type type) {
         this.idType = idType;
-        this.elementType = getElementType(parent);
+        this.elementType = getElementType(type);
         prototype = new MetaBean();
-        prototype.setBeanClass(TypeUtils.getRawType(elementType, parent.getType()));
+        prototype.setBeanClass(TypeUtils.getRawType(elementType, type));
     }
 
     /**
-     * Get the raw element type of this {@link MetaContainer} given its parent.
-     * @param parent
-     * @return
+     * Get the element type of a container of type <code>type</code>.
+     * @param type
+     * @return Type
      */
-    protected abstract Type getElementType(MetaProperty parent);
+    protected abstract Type getElementType(Type type);
 
     /**
      * @return the idType
@@ -92,6 +91,9 @@ public abstract class MetaContainer<K> {
      * @return MetaBean
      */
     public MetaBean getElement(K id) {
+        if (id == null) {
+            return getPrototype();
+        }
         MetaBean result = elements.get(id);
         if (result == null) {
             result = new MetaBean();
@@ -114,7 +116,9 @@ public abstract class MetaContainer<K> {
     public MetaBean getMergedElement(K id) {
         MetaBean result = new MetaBean();
         copy(result, prototype);
-        copy(result, elements.get(id));
+        if (id != null) {
+            copy(result, elements.get(id));
+        }
         return result;
     }
 

Modified: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java?rev=1002681&r1=1002680&r2=1002681&view=diff
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java (original)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/main/java/org/apache/bval/jsr303/dynamic/MetaMap.java Wed Sep 29 15:35:46 2010
@@ -18,7 +18,6 @@ package org.apache.bval.jsr303.dynamic;
 
 import java.lang.reflect.Type;
 
-import org.apache.bval.model.MetaProperty;
 import org.apache.bval.util.KeyedAccess;
 
 /**
@@ -33,15 +32,15 @@ public class MetaMap extends MetaContain
      *
      * @param parent
      */
-    public MetaMap(MetaProperty parent) {
-        super(Object.class, parent);
+    public MetaMap(Type type) {
+        super(Object.class, type);
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    protected Type getElementType(MetaProperty parent) {
-        return KeyedAccess.getJavaElementType(parent.getType());
+    protected Type getElementType(Type type) {
+        return KeyedAccess.getJavaElementType(type);
     }
 }

Added: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java?rev=1002681&view=auto
==============================================================================
--- incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java (added)
+++ incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java Wed Sep 29 15:35:46 2010
@@ -0,0 +1,81 @@
+/*
+ *  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.
+ */
+package org.apache.bval.jsr303.dynamic;
+
+import static org.junit.Assert.*;
+
+import javax.validation.Validation;
+
+import org.apache.bval.jsr303.ApacheValidationProvider;
+import org.apache.bval.jsr303.ApacheValidatorConfiguration;
+import org.apache.bval.jsr303.dynamic.DynamicMetaGraphManager;
+import org.apache.bval.jsr303.dynamic.DynamicValidatorContext;
+import org.apache.bval.jsr303.dynamic.DynamicValidatorFactory;
+import org.apache.bval.jsr303.example.Book;
+import org.apache.bval.model.MetaBean;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the {@link DynamicMetaGraphManager} implementation of
+ * {@link DynamicValidatorContext}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class DynamicMetaGraphManagerTest {
+
+    private DynamicMetaGraphManager metaGraphManager;
+
+    @Before
+    public void setup() {
+        metaGraphManager =
+            Validation
+                .byProvider(ApacheValidationProvider.class)
+                .configure()
+                .addProperty(ApacheValidatorConfiguration.Properties.VALIDATOR_FACTORY_CLASSNAME,
+                    DynamicValidatorFactory.class.getName())
+                .addProperty(ApacheValidatorConfiguration.Properties.ENABLE_INTROSPECTOR, Boolean.TRUE.toString())
+                .buildValidatorFactory().unwrap(DynamicValidatorFactory.class).usingContext();
+    }
+
+    @Test
+    public void testGetMetaBean() {
+        assertNotNull(metaGraphManager.writable().getMetaBean(Book.class));
+        assertNotNull(metaGraphManager.readOnly().getMetaBean(Book.class));
+    }
+
+    @Test
+    public void testGetRootMeta() {
+        MetaBean metaBean = metaGraphManager.writable().getMeta(Book.class, "");
+        assertNotNull(metaBean);
+        metaBean = metaGraphManager.readOnly().getMeta(Book.class, "");
+        assertNotNull(metaBean);
+    }
+
+    @Test
+    public void testGetImmediateProperty() {
+        assertNotNull(metaGraphManager.writable().getMeta(Book.class, "title"));
+        assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "title"));
+    }
+
+    @Test
+    public void testGetNestedProperty() {
+        assertNotNull(metaGraphManager.writable().getMeta(Book.class, "author.addresses[].city"));
+        assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "author.addresses[].city"));
+        assertNotNull(metaGraphManager.readOnly().getMeta(Book.class, "author.addresses[0].city"));
+    }
+}

Propchange: incubator/bval/sandbox/lang3-work/bval-jsr303d/src/test/java/org/apache/bval/jsr303/dynamic/DynamicMetaGraphManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message