This is an automated email from the ASF dual-hosted git repository. gk pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/turbine-core.git
commit 2d151a0dfeaf235a4b07cc4f0f06fcc24bb66311 Author: Georg Kallidis <[email protected]> AuthorDate: Mon Dec 6 14:25:41 2021 +0100 enable method annotation for turbine services, with test, not enabled by default due to performance penalty --- .../turbine/annotation/AnnotationProcessor.java | 141 +++++++++++++++++---- .../turbine/annotation/AnnotatedMethodsTest.java | 99 +++++++++++++++ .../annotation/AnnotationProcessorTest.java | 7 + 3 files changed, 220 insertions(+), 27 deletions(-) diff --git a/src/java/org/apache/turbine/annotation/AnnotationProcessor.java b/src/java/org/apache/turbine/annotation/AnnotationProcessor.java index 7913dce..aaa384c 100644 --- a/src/java/org/apache/turbine/annotation/AnnotationProcessor.java +++ b/src/java/org/apache/turbine/annotation/AnnotationProcessor.java @@ -22,6 +22,8 @@ package org.apache.turbine.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -227,6 +229,18 @@ public class AnnotationProcessor */ public static void process(Object object) throws TurbineException { + process(object, false); + } + + /** + * Search for annotated fields and optionally of method fields of the object and inject the appropriate + * objects + * + * @param object the object + * @throws TurbineException if the objects could not be injected + */ + public static void process(Object object, Boolean hasTurbineServicesInMethodFields) throws TurbineException + { ServiceManager manager = null; Configuration config = null; AssemblerBrokerService assembler = null; @@ -270,10 +284,36 @@ public class AnnotationProcessor } } + if (hasTurbineServicesInMethodFields) { + manager = processMethods(object, manager, clazz); + } + clazz = clazz.getSuperclass(); } } + private static ServiceManager processMethods(Object object, ServiceManager manager, Class<?> clazz) throws TurbineException { + Method[] methods = clazz.getMethods(); + + for (Method method : methods) + { + Annotation[] annotations = getAnnotations(method); + for (Annotation a : annotations) + { + if (a instanceof TurbineService) + { + + if (manager == null) + { + manager = TurbineServices.getInstance(); + } + injectTurbineService(object, manager, method, (TurbineService) a); + } + } + } + return manager; + } + /** * Inject Turbine configuration into field of object * @@ -451,33 +491,7 @@ public class AnnotationProcessor else { Field[] typeFields = field.getType().getFields(); - for (Field f : typeFields) - { - if (TurbineService.SERVICE_NAME.equals(f.getName())) - { - try - { - serviceName = (String)f.get(null); - } - catch (IllegalArgumentException | IllegalAccessException e) - { - continue; - } - break; - } - else if (TurbineService.ROLE.equals(f.getName())) - { - try - { - serviceName = (String)f.get(null); - } - catch (IllegalArgumentException | IllegalAccessException e) - { - continue; - } - break; - } - } + serviceName = checkServiceOrRoleInField(serviceName, typeFields); } if (StringUtils.isEmpty(serviceName)) @@ -503,4 +517,77 @@ public class AnnotationProcessor + serviceName + " into object " + object, e); } } + + private static void injectTurbineService(Object object, ServiceManager manager, Method method, TurbineService annotation) throws TurbineException + { + String serviceName = null; + // Check for annotation value + if (StringUtils.isNotEmpty(annotation.value())) + { + serviceName = annotation.value(); + } + else + { + Class<?>[] classes = method.getParameterTypes(); + for (Class c : classes) + { + Field[] fields = c.getFields(); + // Check for fields SERVICE_NAME and ROLE + serviceName = checkServiceOrRoleInField(serviceName, fields); + } + } + + log.debug("Looking up service for injection: {} for object {}", serviceName, object); + if (StringUtils.isEmpty(serviceName)) + { + // Try interface class name + serviceName = method.getName(); + } + + Object service = manager.getService(serviceName); // throws Exception on unknown service + method.setAccessible(true); + + try + { + log.debug("Injection of {} into object {}", serviceName, object); + + Object[] paramValues = new Object[1]; + paramValues[0] = service; + method.invoke(object, paramValues); + } + catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) + { + throw new TurbineException("Could not inject service " + + serviceName + " into object " + object, e); + } + } + + private static String checkServiceOrRoleInField(String serviceName, Field[] fields) { + for (Field f : fields) + if (TurbineService.SERVICE_NAME.equals(f.getName())) + { + try + { + serviceName = (String)f.get(null); + } + catch (IllegalArgumentException | IllegalAccessException e) + { + continue; + } + break; + } + else if (TurbineService.ROLE.equals(f.getName())) + { + try + { + serviceName = (String)f.get(null); + } + catch (IllegalArgumentException | IllegalAccessException e) + { + continue; + } + break; + } + return serviceName; + } } diff --git a/src/test/org/apache/turbine/annotation/AnnotatedMethodsTest.java b/src/test/org/apache/turbine/annotation/AnnotatedMethodsTest.java new file mode 100644 index 0000000..b75d79d --- /dev/null +++ b/src/test/org/apache/turbine/annotation/AnnotatedMethodsTest.java @@ -0,0 +1,99 @@ +package org.apache.turbine.annotation; + + + +import org.apache.commons.lang3.StringUtils; +import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService; +import org.apache.turbine.services.localization.DateTimeFormatterInterface; +import org.apache.turbine.services.localization.DateTimeFormatterService; +import org.apache.turbine.services.pull.PullService; +import org.apache.turbine.services.pull.util.DateTimeFormatterTool; +import org.apache.turbine.util.TurbineConfig; +import org.apache.turbine.util.TurbineException; +import org.apache.velocity.context.Context; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.function.ThrowingConsumer; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test class for AnnotatedMethodsTest to test method fields annotation + * + */ +public class AnnotatedMethodsTest { + + private static AssemblerBrokerService asb; + private static TurbineConfig tc = null; + private static PullService pullService; + + @BeforeAll + public static void setup() + { + // required to initialize defaults + tc = new TurbineConfig( + ".", + "/conf/test/CompleteTurbineResources.properties"); + tc.initialize(); + } + + @AfterAll + public static void tearDown() + { + tc.dispose(); + } + + @TurbineService + public void setAssemblerBrokerService(AssemblerBrokerService df) + { + AnnotatedMethodsTest.asb = df; + } + + @TurbineService + public static void setPullService(PullService pullService) { + AnnotatedMethodsTest.pullService = pullService; + } + + /* + * Class under test for String format(Date, String) + */ + @Test + void testTool() throws TurbineException + { + AnnotationProcessor.process(this, true); + assertNotNull(pullService); + assertNotNull(asb); + } + + @Tag("performance") // ignore in surefire, activating seems to be still buggy ? + @Test + public void testProcessingPerformance() throws TurbineException + { + long startTime = System.currentTimeMillis(); + + for (int i = 0; i < 100000; i++) + { + AnnotationProcessor.process(this, true); + } + + System.out.println(System.currentTimeMillis() - startTime); + } + +} diff --git a/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java b/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java index 3444b8c..c69fdc3 100644 --- a/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java +++ b/src/test/org/apache/turbine/annotation/AnnotationProcessorTest.java @@ -39,6 +39,8 @@ import org.apache.turbine.annotation.AnnotationProcessor.ConditionType; import org.apache.turbine.modules.Screen; import org.apache.turbine.modules.ScreenLoader; import org.apache.turbine.services.assemblerbroker.AssemblerBrokerService; +import org.apache.turbine.services.localization.DateTimeFormatterService; +import org.apache.turbine.services.localization.DateTimeFormatterServiceTest; import org.apache.turbine.util.RunData; import org.apache.turbine.util.TurbineConfig; import org.apache.turbine.util.TurbineException; @@ -219,4 +221,9 @@ public class AnnotationProcessorTest System.out.println(System.currentTimeMillis() - startTime); } + + @TurbineService + private DateTimeFormatterService df; + + }
