package org.perf4j.aop;

import org.perf4j.LoggingStopWatch;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import java.lang.reflect.Method;

/**
 * This is the base class for TimingAspects that use the EJB interceptor framework.
 * Subclasses just need to implement the {@link #newStopWatch} method to use their logging framework of choice
 * (e.g. log4j or java.logging) to persist the StopWatch log message.
 *
 * @author Alex Devine
 */
public abstract class AbstractEjbTimingAspect extends AgnosticTimingAspect {
    /**
     * This is the interceptor that runs the target method, surrounding it with stop watch start and stop calls.
     *
     * @param ctx The InvocationContext will be passed in by the Java EE server.
     * @return The return value from the executed method.
     * @throws Throwable Any exceptions thrown by the executed method will bubble up.
     */
    @AroundInvoke
    public Object doPerfLogging(final InvocationContext ctx) throws Throwable {
        final Method executingMethod = ctx.getMethod();

        //need to get the Profiled annotation off the method, otherwise use a default
        Profiled profiled = (executingMethod == null) ?
                            DefaultProfiled.INSTANCE :
                            ctx.getMethod().getAnnotation(Profiled.class);
        if (profiled == null) {
            profiled = DefaultProfiled.INSTANCE;
        }

        return runProfiledMethod(
                new AbstractJoinPoint() {
                    public Object proceed() throws Throwable { return ctx.proceed(); }

                    public Object getExecutingObject() { return ctx.getTarget(); }

                    public Object[] getParameters() { return ctx.getParameters(); }

                    public String getMethodName() {
                        return (executingMethod == null) ? "null" : executingMethod.getName();
                    }
                },
                profiled,
                newStopWatch(profiled.logger(), profiled.level())
        );
    }

    /**
     * Subclasses should implement this method to return a LoggingStopWatch that should be used to time the wrapped
     * code block.
     *
     * @param loggerName The name of the logger to use for persisting StopWatch messages.
     * @param levelName  The level at which the message should be logged.
     * @return The new LoggingStopWatch.
     */
    protected abstract LoggingStopWatch newStopWatch(String loggerName, String levelName);
}

@@ -830,25 +830,25 @@
 @throws 
-Throwable
+Exception
  Any exc
@@ -995,25 +995,25 @@
  throws 
-Throwable
+Exception
  %7B%0A     
@@ -1424,24 +1424,192 @@
 %0A        %7D%0A%0A
+        //note - the EJB 3.0 Interceptor spec requires that we only throw Exception, NOT throwable, but%0A        //runProfiledMethod throws Throwable.%0A        try %7B%0A    
         retu
@@ -1630,16 +1630,20 @@
 Method(%0A
+    
         
@@ -1688,32 +1688,36 @@
                 
+  
+  
 public Object pr
@@ -1780,32 +1780,36 @@
                 
+    
 public Object ge
@@ -1868,32 +1868,36 @@
                 
+  
+  
 public Object%5B%5D 
@@ -1961,24 +1961,28 @@
             
+    
 public Strin
@@ -2021,24 +2021,28 @@
             
+  
+  
 return (exec
@@ -2120,18 +2120,24 @@
         
-%7D%0A
+    %7D%0A  
         
@@ -2148,11 +2148,17 @@
     
+  
 %7D,%0A
+    
     
@@ -2179,16 +2179,20 @@
 ofiled,%0A
+    
         
@@ -2257,18 +2257,861 @@
         
-);
+    );%0A        %7D catch (Exception e) %7B%0A            throw e;%0A        %7D catch (Error e) %7B%0A            throw e;%0A        %7D catch (Throwable t) %7B%0A            //in practice this should rarely happen, as in standard usage Throwables fall under Exception or Error.%0A            //However, by the Java spec, ONLY RuntimeExceptions and Errors are unchecked, so the compiler prevents us%0A            //from executing %22throw t%22 at this point. This seems like a poor design decision of the EJB spec, as all%0A            //interceptors that wish to call a method that throws Throwable need to do something special like this.%0A            //The best we can do here is wrap the Throwable as a RuntimeException, even though this could potentially%0A            //change the semantics from the callers point of view.%0A            throw new RuntimeException(t);%0A        %7D
 %0A    %7D%0A%0A

Fix for http://jira.codehaus.org/browse/PERFFORJ-48, EJB3 interceptor doesn't deploy under JBoss.