You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/01/26 18:33:15 UTC
svn commit: r1236308 - in /tapestry/tapestry5/trunk/tapestry-ioc/src:
main/java/org/apache/tapestry5/ioc/annotations/
main/java/org/apache/tapestry5/ioc/internal/services/
main/java/org/apache/tapestry5/ioc/services/
test/java/org/apache/tapestry5/ioc/...
Author: hlship
Date: Thu Jan 26 17:33:14 2012
New Revision: 1236308
URL: http://svn.apache.org/viewvc?rev=1236308&view=rev
Log:
TAP5-1168: Add @Operation annotation that can be used to automatically track a component or service method invocation using the OperationTracker
Added:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Operation.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OperationAdvisorImpl.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/OperationAdvisor.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationAdvisorTest.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedModule.java
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedService.java
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Operation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Operation.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Operation.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/Operation.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,39 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * Describes a method as one that should be operation tracked. Operation tracking is useful when an exception in deeply nested code occurs,
+ * as it is possible to identify (using human readable descriptions) the path to the code that failed.
+ *
+ * @see org.apache.tapestry5.ioc.OperationTracker
+ * @since 5.4
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@UseWith({AnnotationUseContext.SERVICE, AnnotationUseContext.COMPONENT, AnnotationUseContext.PAGE})
+public @interface Operation
+{
+ /**
+ * The message to pass to {@link org.apache.tapestry5.ioc.OperationTracker#invoke(String, org.apache.tapestry5.ioc.Invokable)}. If the message contains
+ * the '%' character, it is interpreted to be a {@linkplain java.util.Formatter format string}, passed the method's parameters.
+ *
+ * @see org.apache.tapestry5.ioc.services.OperationAdvisor#createAdvice(String)
+ */
+ String value();
+}
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OperationAdvisorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OperationAdvisorImpl.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OperationAdvisorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OperationAdvisorImpl.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,129 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.OperationTracker;
+import org.apache.tapestry5.ioc.annotations.Operation;
+import org.apache.tapestry5.ioc.annotations.PreventServiceDecoration;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.OperationAdvisor;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodInvocation;
+
+import java.lang.reflect.Method;
+
+@PreventServiceDecoration
+public class OperationAdvisorImpl implements OperationAdvisor
+{
+ private final OperationTracker tracker;
+
+ public OperationAdvisorImpl(OperationTracker tracker)
+ {
+ this.tracker = tracker;
+ }
+
+ private Runnable toRunnable(final MethodInvocation invocation)
+ {
+ return new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ invocation.proceed();
+ }
+ };
+ }
+
+ private class SimpleAdvice implements MethodAdvice
+ {
+ private final String description;
+
+ SimpleAdvice(String description)
+ {
+ this.description = description;
+ }
+
+ @Override
+ public void advise(MethodInvocation invocation)
+ {
+ tracker.run(description, toRunnable(invocation));
+ }
+ }
+
+ private class FormattedAdvice implements MethodAdvice
+ {
+ private final String format;
+
+ FormattedAdvice(String format)
+ {
+ this.format = format;
+ }
+
+ @Override
+ public void advise(MethodInvocation invocation)
+ {
+ Object[] parameters = extractParameters(invocation);
+
+ String description = String.format(format, parameters);
+
+ tracker.run(description, toRunnable(invocation));
+ }
+
+ private Object[] extractParameters(MethodInvocation invocation)
+ {
+ int count = invocation.getMethod().getParameterTypes().length;
+
+ Object[] result = new Object[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ result[i] = invocation.getParameter(i);
+ }
+
+ return result;
+ }
+ }
+
+ @Override
+ public void addOperationAdvice(MethodAdviceReceiver receiver)
+ {
+ for (Method m : receiver.getInterface().getMethods())
+ {
+
+ Operation annotation = receiver.getMethodAnnotation(m, Operation.class);
+
+ if (annotation != null)
+ {
+ String value = annotation.value();
+
+ receiver.adviseMethod(m, createAdvice(value));
+ }
+ }
+ }
+
+ @Override
+ public MethodAdvice createAdvice(String description)
+ {
+ assert InternalUtils.isNonBlank(description);
+
+ if (description.contains("%"))
+ {
+ return new FormattedAdvice(description);
+ }
+
+ return new SimpleAdvice(description);
+ }
+}
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/OperationAdvisor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/OperationAdvisor.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/OperationAdvisor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/OperationAdvisor.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,42 @@
+// Copyright 2012 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.plastic.MethodAdvice;
+
+/**
+ * Used from a {@linkplain org.apache.tapestry5.ioc.annotations.Advise service advice method} to identify methods with the
+ * {@link org.apache.tapestry5.ioc.annotations.Operation} annotation, and add advice for those methods. This advice should typically
+ * be provided first, or nearly first, among all advice, to maximize the benefit of tracking operations.
+ *
+ * @since 5.4
+ */
+public interface OperationAdvisor
+{
+ /**
+ * Adds {@linkplain #createAdvice advice} to methods with the {@link org.apache.tapestry5.ioc.annotations.Operation} annotation.
+ */
+ void addOperationAdvice(MethodAdviceReceiver receiver);
+
+ /**
+ * Creates advice for a method.
+ *
+ * @param description the text (or format) used to display describe the operation for the method
+ * @return method advice
+ * @see org.apache.tapestry5.ioc.annotations.Operation#value()
+ */
+ MethodAdvice createAdvice(String description);
+}
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java?rev=1236308&r1=1236307&r2=1236308&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java Thu Jan 26 17:33:14 2012
@@ -73,6 +73,7 @@ public final class TapestryIOCModule
binder.bind(ThunkCreator.class, ThunkCreatorImpl.class);
binder.bind(UpdateListenerHub.class, UpdateListenerHubImpl.class).preventReloading();
binder.bind(PeriodicExecutor.class, PeriodicExecutorImpl.class);
+ binder.bind(OperationAdvisor.class, OperationAdvisorImpl.class);
}
/**
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationAdvisorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationAdvisorTest.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationAdvisorTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationAdvisorTest.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,111 @@
+package org.apache.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.Invokable;
+import org.apache.tapestry5.ioc.LoggerSource;
+import org.apache.tapestry5.ioc.OperationTracker;
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.def.ModuleDef;
+import org.apache.tapestry5.ioc.internal.DefaultModuleDefImpl;
+import org.apache.tapestry5.ioc.internal.LoggerSourceImpl;
+import org.apache.tapestry5.ioc.internal.RegistryImpl;
+import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.test.IOCTestCase;
+import org.slf4j.Logger;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+/**
+ * Tests for the {@link OperationAdvisor} service.
+ *
+ * @since 5.4
+ */
+public class OperationAdvisorTest extends IOCTestCase
+{
+ private List<String> operations = CollectionFactory.newList();
+
+ private Registry registry;
+
+ @BeforeClass
+ public void setup()
+ {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ LoggerSource loggerSource = new LoggerSourceImpl();
+
+ Logger logger = loggerSource.getLogger(OperationAdvisorTest.class);
+ Logger proxyFactoryLogger = loggerSource.getLogger(TapestryIOCModule.class.getName() + ".PlasticProxyFactory");
+
+ PlasticProxyFactory plasticProxyFactory = new PlasticProxyFactoryImpl(classLoader, proxyFactoryLogger);
+
+ List<ModuleDef> modules = CollectionFactory.newList();
+
+ modules.add(new DefaultModuleDefImpl(TapestryIOCModule.class, logger, plasticProxyFactory));
+ modules.add(new DefaultModuleDefImpl(OperationTrackedModule.class, logger, plasticProxyFactory));
+
+ OperationTracker simpleOperationTracker = new OperationTracker()
+ {
+ @Override
+ public void run(String description, Runnable operation)
+ {
+ operations.add(description);
+
+ operation.run();
+ }
+
+ @Override
+ public <T> T invoke(String description, Invokable<T> operation)
+ {
+ operations.add(description);
+
+ return operation.invoke();
+ }
+ };
+
+ registry = new RegistryImpl(modules, plasticProxyFactory, loggerSource, simpleOperationTracker);
+ }
+
+ @AfterClass
+ public void cleanup()
+ {
+ registry.shutdown();
+
+ registry = null;
+
+ operations = null;
+ }
+
+ @Test
+ public void simple_operation_tracking()
+ {
+ OperationTrackedService service = registry.getService(OperationTrackedService.class);
+
+ service.nonOperation();
+
+ operations.clear();
+
+ service.first();
+
+ assertListsEquals(operations, "First operation");
+ }
+
+ @Test
+ public void complex_operation_tracking()
+ {
+ OperationTrackedService service = registry.getService(OperationTrackedService.class);
+
+ service.nonOperation();
+
+ operations.clear();
+
+ service.second("foo");
+
+ service.second("bar");
+
+ assertListsEquals(operations, "Second operation: foo", "Second operation: bar");
+ }
+
+
+}
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedModule.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedModule.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedModule.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,23 @@
+package org.apache.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.Match;
+import org.apache.tapestry5.ioc.annotations.Order;
+
+public class OperationTrackedModule
+{
+ public OperationTrackedService buildTestSubject(DefaultImplementationBuilder builder)
+ {
+ return builder.createDefaultImplementation(OperationTrackedService.class);
+ }
+
+ @Advise @Match("*")
+ @Order("before:*")
+ public void addOperationTracking(MethodAdviceReceiver receiver, OperationAdvisor advisor)
+ {
+ advisor.addOperationAdvice(receiver);
+ }
+
+
+}
Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedService.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedService.java?rev=1236308&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedService.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/OperationTrackedService.java Thu Jan 26 17:33:14 2012
@@ -0,0 +1,14 @@
+package org.apache.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.annotations.Operation;
+
+public interface OperationTrackedService
+{
+ @Operation("First operation")
+ void first();
+
+ @Operation("Second operation: %s")
+ void second(String name);
+
+ void nonOperation();
+}