Author: simonetripodi
Date: Sat Jan  9 12:15:52 2010
New Revision: 897428

URL: http://svn.apache.org/viewvc?rev=897428&view=rev
Log:
first checkin of DigesterLoader class

Added:
    
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
   (with props)

Added: 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java?rev=897428&view=auto
==============================================================================
--- 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
 (added)
+++ 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
 Sat Jan  9 12:15:52 2010
@@ -0,0 +1,203 @@
+/*
+ * 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.commons.digester.annotations;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.RuleSet;
+import org.apache.commons.digester.annotations.reflect.MethodArgument;
+import org.apache.commons.digester.annotations.utils.AnnotationUtils;
+
+/**
+ * This class manages the creation of Digester instances analyzing target 
classes
+ * annotated with digester annotations.
+ *
+ * It avoids iterate the annotations analysis for already analyzed classes,
+ * using an in-memory LRU cache.
+ *
+ * @author Simone Tripodi (simonetripodi)
+ * @version $Id$
+ */
+public final class DigesterLoader {
+
+    /**
+     * The fixed cache size.
+     */
+    private static final int CACHE_SIZE = 255;
+
+    /**
+     * The fixed cache load facor.
+     */
+    private static final float LOAD_FACTOR = 0.75f;
+
+    /**
+     * The fixed cache capacity.
+     */
+    private static final int CACHE_CAPACITY = (int) Math.ceil(CACHE_SIZE / 
LOAD_FACTOR) + 1;
+
+    /**
+     * In-memory LRU cache that stores already analyzed classes and relative
+     * {...@link RuleSet}.
+     */
+    private static final Map<Class<?>, FromAnnotationsRuleSet> CACHED_RULESET =
+        new LinkedHashMap<Class<?>, FromAnnotationsRuleSet>(CACHE_CAPACITY, 
LOAD_FACTOR) {
+
+            private static final long serialVersionUID = 1L;
+
+            protected boolean 
removeEldestEntry(Map.Entry<Class<?>,FromAnnotationsRuleSet> eldest) {
+                return size() > CACHE_SIZE;
+            };
+    };
+
+    /**
+     * This class can't be instantiated.
+     */
+    private DigesterLoader() {
+        // do nothing
+    }
+
+    /**
+     * Creates a new digester which rules are defined by analyzing the digester
+     * annotations in the target class.
+     *
+     * @param target the class has to be analyzed.
+     * @return a new Digester instance.
+     */
+    public static Digester createDigester(final Class<?> target) {
+        Digester digester = new Digester();
+        digester.setClassLoader(target.getClassLoader());
+        addRules(target, digester);
+        return digester;
+    }
+
+    /**
+     * Add rules to an already created Digester instance, analyzing the 
digester
+     * annotations in the target class.
+     *
+     * @param target the class has to be analyzed.
+     * @param digester the Digester instance reference.
+     */
+    public static void addRules(final Class<?> target, final Digester 
digester) {
+        RuleSet ruleSet = getRuleSet(target);
+        ruleSet.addRuleInstances(digester);
+    }
+
+    /**
+     * Builds a new {...@link RuleSet} analyzing the digester annotations in 
the
+     * target class.
+     *
+     * It avoids iterate the annotations analysis for already analyzed classes,
+     * using an in-memory LRU cache.
+     *
+     * @param target the class has to be analyzed.
+     * @return a new {...@link RuleSet}.
+     */
+    public static RuleSet getRuleSet(final Class<?> target) {
+        if (CACHED_RULESET.containsKey(target)) {
+            return CACHED_RULESET.get(target);
+        }
+
+        FromAnnotationsRuleSet ruleSet = new FromAnnotationsRuleSet();
+        addRules(target, ruleSet);
+        CACHED_RULESET.put(target, ruleSet);
+
+        return ruleSet;
+    }
+
+    /**
+     * Analyzes the target class and adds the {...@link 
AnnotationRuleProvider}s to
+     * the existing {...@link FromAnnotationsRuleSet}.
+     *
+     * @param target the class has to be analyzed.
+     * @param ruleSet the RuleSet where adding the providers.
+     */
+    public static void addRules(final Class<?> target, FromAnnotationsRuleSet 
ruleSet) {
+        if (target == Object.class
+                || target.isInterface()
+                || Modifier.isAbstract(target.getModifiers())) {
+            return;
+        }
+
+        if (CACHED_RULESET.containsKey(target)) {
+            ruleSet.addRulesProviderFrom(CACHED_RULESET.get(target));
+            return;
+        }
+
+        // current analyzed class
+        handle(target, ruleSet);
+
+        // class fields
+        for (Field field : target.getDeclaredFields()) {
+            handle(field, ruleSet);
+        }
+
+        // class methods
+        for (Method method : target.getDeclaredMethods()) {
+            handle(method, ruleSet);
+
+            // method args
+            Annotation[][] parameterAnnotations = 
method.getParameterAnnotations();
+            Class<?>[] parameterTypes = method.getParameterTypes();
+            for (int i = 0; i < parameterTypes.length; i++) {
+                handle(new MethodArgument(i, parameterTypes[i], 
parameterAnnotations[i]), ruleSet);
+            }
+        }
+
+        addRules(target.getSuperclass(), ruleSet);
+    }
+
+    /**
+     * 
+     * @param element
+     */
+    private static void handle(AnnotatedElement element, 
FromAnnotationsRuleSet ruleSet) {
+        for (Annotation annotation : element.getAnnotations()) {
+            handle(annotation, element, ruleSet);
+        }
+    }
+
+    /**
+     * 
+     * @param annotation
+     * @param element
+     */
+    private static void handle(Annotation annotation, AnnotatedElement 
element, FromAnnotationsRuleSet ruleSet) {
+        Class<?> annotationType = annotation.annotationType();
+
+        // check if it is one of the @*.List annotation
+        if (annotationType.isAnnotationPresent(DigesterRuleList.class)) {
+            Annotation[] annotations = 
AnnotationUtils.getAnnotationsArrayValue(annotation);
+            if (annotations != null && annotations.length > 0) {
+                // if it is an annotations array, process them
+                for (Annotation ptr : annotations) {
+                    handle(ptr, element, ruleSet);
+                }
+            }
+        } else if (annotationType.isAnnotationPresent(DigesterRule.class)) {
+            DigesterRule digesterRule = 
annotationType.getAnnotation(DigesterRule.class);
+            // TODO add missing code
+        }
+    }
+
+}

Propchange: 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/sandbox/at-digester/trunk/src/java/org/apache/commons/digester/annotations/DigesterLoader.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to