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