/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.cache.pojo.interceptors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.joinpoint.Invocation;
import org.jboss.aop.joinpoint.MethodInvocation;
import org.jboss.cache.pojo.PojoCacheException;

import java.lang.reflect.Method;

/**
 * @author Ben Wang
 */

public class MethodReentrancyStopperInterceptor implements Interceptor
{
   private final Log log_ = LogFactory.getLog(MethodReentrancyStopperInterceptor.class);
   private ThreadLocal<Boolean> done;
   private String methodName;

   public MethodReentrancyStopperInterceptor()
   {
      done = new ThreadLocal<Boolean>();
      done.set(false);
   }

   public void setMethodName(String mname)
   {
      methodName = mname;
   }

   public String getName()
   {
      return MethodReentrancyStopperInterceptor.class.getName() + "-" + methodName;
   }

   public Object invoke(Invocation invocation) throws Throwable
   {
      boolean wasDone = done.get();

      try
      {
         if (!wasDone)
         {
            done.set(true);
            return invocation.invokeNext();
         }
         else
         {
            //Needs adding, and will invoke target joinpoint skipping the rest of the chain
            if (log_.isDebugEnabled())
            {
               Method method = ((MethodInvocation) invocation).getMethod();
               log_.debug("Detect recursive interception. Will call the target directly: " + method.getName());
            }

            if (methodName.equals("toString"))
            {
               return invocation.getTargetObject().getClass().getName();
            }
            else if (methodName.equals("hashCode"))
            {
               return 0;
            }
            else
            {
               throw new PojoCacheException("MethodReentrancyStopperInterceptor.invoke(): unknown method name"
                                            + methodName);
            }
         }
      }
      finally
      {
         if (!wasDone)
         {
            done.set(false);
         }
      }
   }
}
