You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@turbine.apache.org by tv...@apache.org on 2016/01/15 13:58:53 UTC

svn commit: r1724793 - in /turbine/core/trunk/src: changes/changes.xml java/org/apache/turbine/annotation/AnnotationProcessor.java test/org/apache/turbine/annotation/ test/org/apache/turbine/annotation/AnnotationProcessorTest.java

Author: tv
Date: Fri Jan 15 12:58:53 2016
New Revision: 1724793

URL: http://svn.apache.org/viewvc?rev=1724793&view=rev
Log:
Add annotation support for configuration values
Improve performance of AnnotationProcessor by caching annotations. 
Add performance test.

Added:
    turbine/core/trunk/src/test/org/apache/turbine/annotation/
    turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java   (with props)
Modified:
    turbine/core/trunk/src/changes/changes.xml
    turbine/core/trunk/src/java/org/apache/turbine/annotation/AnnotationProcessor.java

Modified: turbine/core/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/turbine/core/trunk/src/changes/changes.xml?rev=1724793&r1=1724792&r2=1724793&view=diff
==============================================================================
--- turbine/core/trunk/src/changes/changes.xml (original)
+++ turbine/core/trunk/src/changes/changes.xml Fri Jan 15 12:58:53 2016
@@ -25,6 +25,12 @@
 
   <body>
     <release version="4.0" date="in Subversion">
+      <action type="add" dev="tv">
+        Add annotation support for configuration values
+      </action>
+      <action type="update" dev="tv">
+        Improve performance of AnnotationProcessor by caching annotations. Add performance test.
+      </action>
       <action type="update" dev="tv">
         Replace synchronized array in TurbinePipeline with CopyOnWriteList (20% faster). Add performance test.
       </action>

Modified: turbine/core/trunk/src/java/org/apache/turbine/annotation/AnnotationProcessor.java
URL: http://svn.apache.org/viewvc/turbine/core/trunk/src/java/org/apache/turbine/annotation/AnnotationProcessor.java?rev=1724793&r1=1724792&r2=1724793&view=diff
==============================================================================
--- turbine/core/trunk/src/java/org/apache/turbine/annotation/AnnotationProcessor.java (original)
+++ turbine/core/trunk/src/java/org/apache/turbine/annotation/AnnotationProcessor.java Fri Jan 15 12:58:53 2016
@@ -21,7 +21,11 @@ package org.apache.turbine.annotation;
  */
 
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.lang.StringUtils;
@@ -46,6 +50,12 @@ public class AnnotationProcessor
     /** Logging */
     private static Log log = LogFactory.getLog(AnnotationProcessor.class);
 
+    /** Annotation cache */
+    private static ConcurrentMap<String, Annotation[]> annotationCache = new ConcurrentHashMap<String, Annotation[]>();
+
+    /** Lock for initialization of cache entry */
+    private static ReentrantLock lock = new ReentrantLock();
+
     /**
      * Search for annotated fields of the object and provide them with the
      * appropriate TurbineService
@@ -55,8 +65,9 @@ public class AnnotationProcessor
      */
     public static void process(Object object) throws TurbineException
     {
-        ServiceManager manager = TurbineServices.getInstance();
-        AssemblerBrokerService assembler = (AssemblerBrokerService)manager.getService(AssemblerBrokerService.SERVICE_NAME);
+        ServiceManager manager = null;
+        Configuration config = null;
+        AssemblerBrokerService assembler = null;
         Class<?> clazz = object.getClass();
 
         while (clazz != null)
@@ -65,17 +76,56 @@ public class AnnotationProcessor
 
             for (Field field : fields)
             {
-                if (field.isAnnotationPresent(TurbineService.class))
-                {
-                    injectTurbineService(object, manager, field);
-                }
-                else if (field.isAnnotationPresent(TurbineConfiguration.class))
+                String key = field.toString();
+                Annotation[] annotations = annotationCache.get(key);
+                if (annotations == null)
                 {
-                    injectTurbineConfiguration(object, field);
+                    lock.lock();
+
+                    try
+                    {
+                        // Double check
+                        annotations = annotationCache.get(key);
+
+                        if (annotations == null)
+                        {
+                            annotations = field.getDeclaredAnnotations();
+                            annotationCache.put(key, annotations);
+                        }
+                    }
+                    finally
+                    {
+                        lock.unlock();
+                    }
                 }
-                else if (field.isAnnotationPresent(TurbineLoader.class))
+
+                for (Annotation a : annotations)
                 {
-                    injectTurbineLoader(object, assembler, field);
+                    if (a instanceof TurbineService)
+                    {
+                        if (manager == null)
+                        {
+                            manager = TurbineServices.getInstance();
+                        }
+                        injectTurbineService(object, manager, field, (TurbineService) a);
+                    }
+                    else if (a instanceof TurbineConfiguration)
+                    {
+                        if (config == null)
+                        {
+                            config = Turbine.getConfiguration();
+                        }
+                        injectTurbineConfiguration(object, config, field, (TurbineConfiguration) a);
+                    }
+                    else if (a instanceof TurbineLoader)
+                    {
+                        if (assembler == null)
+                        {
+                            assembler = (AssemblerBrokerService) TurbineServices.getInstance().
+                                getService(AssemblerBrokerService.SERVICE_NAME);
+                        }
+                        injectTurbineLoader(object, assembler, field, (TurbineLoader) a);
+                    }
                 }
             }
 
@@ -89,13 +139,13 @@ public class AnnotationProcessor
      * @param object the object to process
      * @param assembler AssemblerBrokerService, provides the loader
      * @param field the field
+     * @param annotation the value of the annotation
      *
      * @throws TurbineException if loader cannot be set
      */
-    private static void injectTurbineLoader(Object object, AssemblerBrokerService assembler, Field field) throws TurbineException
+    private static void injectTurbineLoader(Object object, AssemblerBrokerService assembler, Field field, TurbineLoader annotation) throws TurbineException
     {
-        TurbineLoader la = field.getAnnotation(TurbineLoader.class);
-        Loader<?> loader = assembler.getLoader(la.value());
+        Loader<?> loader = assembler.getLoader(annotation.value());
         field.setAccessible(true);
 
         try
@@ -123,35 +173,137 @@ public class AnnotationProcessor
      * Inject Turbine configuration into field of object
      *
      * @param object the object to process
+     * @param conf the configuration to use
      * @param field the field
+     * @param annotation the value of the annotation
      *
      * @throws TurbineException if configuration cannot be set
      */
-    private static void injectTurbineConfiguration(Object object, Field field) throws TurbineException
+    private static void injectTurbineConfiguration(Object object, Configuration conf, Field field, TurbineConfiguration annotation) throws TurbineException
     {
-        TurbineConfiguration ca = field.getAnnotation(TurbineConfiguration.class);
-        Configuration conf = null;
-
-        // Check for annotation value
-        if (StringUtils.isNotEmpty(ca.value()))
-        {
-            conf = Turbine.getConfiguration().subset(ca.value());
-        }
-        else
-        {
-            conf = Turbine.getConfiguration();
-        }
-
-        field.setAccessible(true);
+        Class<?> type = field.getType();
+        String key = annotation.value();
 
         try
         {
-            if (log.isDebugEnabled())
+            if (Configuration.class.isAssignableFrom(type))
             {
-                log.debug("Injection of " + conf + " into object " + object);
+                // Check for annotation value
+                if (StringUtils.isNotEmpty(key))
+                {
+                    conf = conf.subset(key);
+                }
+
+                if (log.isDebugEnabled())
+                {
+                    log.debug("Injection of " + conf + " into object " + object);
+                }
+
+                field.setAccessible(true);
+                field.set(object, conf);
             }
+            else if (conf.containsKey(key))
+            {
+                if ( String.class.isAssignableFrom( type ) )
+                {
+                    String value = conf.getString(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.set(object, value);
+                }
+                else if ( Integer.TYPE.isAssignableFrom( type ) )
+                {
+                    int value = conf.getInt(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
 
-            field.set(object, conf);
+                    field.setAccessible(true);
+                    field.setInt(object, value);
+                }
+                else if ( Long.TYPE.isAssignableFrom( type ) )
+                {
+                    long value = conf.getLong(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setLong(object, value);
+                }
+                else if ( Short.TYPE.isAssignableFrom( type ) )
+                {
+                    short value = conf.getShort(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setShort(object, value);
+                }
+                else if ( Long.TYPE.isAssignableFrom( type ) )
+                {
+                    long value = conf.getLong(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setLong(object, value);
+                }
+                else if ( Float.TYPE.isAssignableFrom( type ) )
+                {
+                    float value = conf.getFloat(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setFloat(object, value);
+                }
+                else if ( Double.TYPE.isAssignableFrom( type ) )
+                {
+                    double value = conf.getDouble(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setDouble(object, value);
+                }
+                else if ( Byte.TYPE.isAssignableFrom( type ) )
+                {
+                    byte value = conf.getByte(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setByte(object, value);
+                }
+                else if ( Boolean.TYPE.isAssignableFrom( type ) )
+                {
+                    boolean value = conf.getBoolean(key);
+                    if (log.isDebugEnabled())
+                    {
+                        log.debug("Injection of " + value + " into object " + object);
+                    }
+
+                    field.setAccessible(true);
+                    field.setBoolean(object, value);
+                }
+            }
         }
         catch (IllegalArgumentException e)
         {
@@ -171,17 +323,17 @@ public class AnnotationProcessor
      * @param object the object to process
      * @param manager the service manager
      * @param field the field
+     * @param annotation the value of the annotation
      *
      * @throws TurbineException if service is not available
      */
-    private static void injectTurbineService(Object object, ServiceManager manager, Field field) throws TurbineException
+    private static void injectTurbineService(Object object, ServiceManager manager, Field field, TurbineService annotation) throws TurbineException
     {
-        TurbineService sa = field.getAnnotation(TurbineService.class);
         String serviceName = null;
         // Check for annotation value
-        if (StringUtils.isNotEmpty(sa.value()))
+        if (StringUtils.isNotEmpty(annotation.value()))
         {
-            serviceName = sa.value();
+            serviceName = annotation.value();
         }
         // Check for fields SERVICE_NAME and ROLE
         else

Added: turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java
URL: http://svn.apache.org/viewvc/turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java?rev=1724793&view=auto
==============================================================================
--- turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java (added)
+++ turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java Fri Jan 15 12:58:53 2016
@@ -0,0 +1,120 @@
+package org.apache.turbine.annotation;
+
+/*
+ * 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.fulcrum.factory.FactoryService;
+import org.apache.turbine.modules.Screen;
+import org.apache.turbine.modules.ScreenLoader;
+import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService;
+import org.apache.turbine.util.TurbineConfig;
+import org.apache.turbine.util.TurbineException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests the various annotations
+ *
+ * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
+ */
+public class AnnotationProcessorTest
+{
+    private static TurbineConfig tc;
+
+    @TurbineConfiguration
+    private Configuration completeConfiguration = null;
+
+    @TurbineConfiguration("serverdata.default")
+    private Configuration serverdataDefaultConfiguration = null;
+
+    @TurbineConfiguration("module.cache")
+    private boolean moduleCache = true;
+
+    @TurbineConfiguration("action.cache.size")
+    private int actionCacheSize = 0;
+
+    @TurbineConfiguration("template.homepage")
+    private String templateHomepage;
+
+    @TurbineConfiguration("does.not.exist")
+    private long notModified = 1;
+
+    @TurbineLoader(Screen.class)
+    private ScreenLoader screenLoader;
+
+    @TurbineService
+    private AssemblerBrokerService asb;
+
+    @TurbineService
+    private FactoryService factory;
+
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        tc = new TurbineConfig(".", "/conf/test/CompleteTurbineResources.properties");
+        tc.initialize();
+    }
+
+    @AfterClass
+    public static void destroy()
+        throws Exception
+    {
+        tc.dispose();
+    }
+
+    @Test
+    public void testProcess() throws TurbineException
+    {
+        AnnotationProcessor.process(this);
+
+        assertNotNull(completeConfiguration);
+        assertFalse(completeConfiguration.getBoolean("module.cache", true));
+
+        assertNotNull(serverdataDefaultConfiguration);
+        assertEquals(80, serverdataDefaultConfiguration.getInt("serverPort"));
+
+        assertFalse(moduleCache);
+        assertEquals(20, actionCacheSize);
+        assertEquals("Index.vm", templateHomepage);
+        assertEquals(1, notModified);
+
+        assertNotNull(screenLoader);
+        assertNotNull(asb);
+        assertNotNull(factory);
+    }
+
+    @Test
+    public void testProcessingPerformance() throws TurbineException
+    {
+        long startTime = System.currentTimeMillis();
+
+        for (int i = 0; i < 100000; i++)
+        {
+            AnnotationProcessor.process(this);
+        }
+
+        System.out.println(System.currentTimeMillis() - startTime);
+    }
+}

Propchange: turbine/core/trunk/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain