You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hivemind.apache.org by hl...@apache.org on 2004/08/15 17:41:57 UTC

cvs commit: jakarta-hivemind/framework/src/test/hivemind/test/services/impl CountFactory.java MethodFilter.java FilterLoggingInterceptor.java

hlship      2004/08/15 08:41:57

  Modified:    framework/src/test/hivemind/test/services TestServices.java
               framework/src/java/org/apache/hivemind/service/impl
                        LoggingInterceptorFactory.java
               framework/src/test/hivemind/test/services/impl
                        CountFactory.java
  Added:       framework/src/java/org/apache/hivemind/service/impl
                        LoggingUtils.java
  Removed:     framework/src/test/hivemind/test/services
                        InterceptorParameters.xml
               framework/src/java/org/apache/hivemind/service/impl
                        AbstractLoggingInterceptor.java
                        AbstractServiceInterceptorFactory.java
               framework/src/test/hivemind/test/services/impl
                        MethodFilter.java FilterLoggingInterceptor.java
  Log:
  Refactor LoggingInterceptor to allow reuse of logging methods.
  Remove AbstractInterceptorFactory and roll methods back into LoggingInterceptor.
  
  Revision  Changes    Path
  1.21      +0 -22     jakarta-hivemind/framework/src/test/hivemind/test/services/TestServices.java
  
  Index: TestServices.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestServices.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- TestServices.java	3 Aug 2004 14:02:11 -0000	1.20
  +++ TestServices.java	15 Aug 2004 15:41:57 -0000	1.21
  @@ -343,27 +343,5 @@
           assertLoggedMessage("END returnArrayType() [(java.lang.String[]){alpha, beta}]");
       }
   
  -    public void testInterceptorParameters() throws Exception
  -    {
  -        Registry r = buildFrameworkRegistry("InterceptorParameters.xml");
  -
  -        interceptLogging("hivemind.test.services.Bedrock");
  -
  -        Bedrock b = (Bedrock) r.getService("hivemind.test.services.Bedrock", Bedrock.class);
  -
  -        b.fred();
  -        b.barney();
  -        b.wilma();
  -
  -        // Only fred and wilma should be logged.
  -
  -        assertLoggedMessages(
  -            new String[] {
  -                "Creating SingletonProxy for service hivemind.test.services.Bedrock",
  -                "Constructing core service implementation for service hivemind.test.services.Bedrock",
  -                "Applying interceptor factory hivemind.test.services.FilterLoggingInterceptor",
  -                "BEGIN fred()",
  -                "BEGIN wilma()" });
  -    }
   
   }
  
  
  
  1.7       +156 -42   jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/LoggingInterceptorFactory.java
  
  Index: LoggingInterceptorFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/LoggingInterceptorFactory.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- LoggingInterceptorFactory.java	25 Jun 2004 20:20:04 -0000	1.6
  +++ LoggingInterceptorFactory.java	15 Aug 2004 15:41:57 -0000	1.7
  @@ -17,16 +17,22 @@
   import java.lang.reflect.Constructor;
   import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
  +import java.util.HashMap;
   import java.util.Iterator;
   import java.util.List;
  +import java.util.Map;
   
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
  +import org.apache.hivemind.ApplicationRuntimeException;
   import org.apache.hivemind.InterceptorStack;
  +import org.apache.hivemind.ServiceInterceptorFactory;
  +import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.methodmatch.MethodMatcher;
   import org.apache.hivemind.service.BodyBuilder;
   import org.apache.hivemind.service.ClassFab;
   import org.apache.hivemind.service.ClassFabUtils;
  +import org.apache.hivemind.service.ClassFactory;
   import org.apache.hivemind.service.MethodContribution;
   import org.apache.hivemind.service.MethodFab;
   import org.apache.hivemind.service.MethodSignature;
  @@ -46,44 +52,22 @@
    *
    * @author Howard Lewis Ship
    */
  -public class LoggingInterceptorFactory extends AbstractServiceInterceptorFactory
  +public class LoggingInterceptorFactory implements ServiceInterceptorFactory
   {
  -    protected void createInfrastructure(InterceptorStack stack, ClassFab classFab, List parameters)
  -    {
  -        Class topClass = stack.peek().getClass();
  -
  -        classFab.addField("_inner", topClass);
  -
  -        classFab.addConstructor(
  -            new Class[] { Log.class, topClass },
  -            null,
  -            "{ super($1); _inner = $2; }");
  -    }
  -
  -    protected Object instantiateInterceptor(
  -        InterceptorStack stack,
  -        Class interceptorClass,
  -        List parameters)
  -        throws Exception
  -    {
  -        Object stackTop = stack.peek();
  -
  -        Log log = LogFactory.getLog(stack.getServiceExtensionPointId());
  -
  -        Constructor c = interceptorClass.getConstructors()[0];
  -
  -        return c.newInstance(new Object[] { log, stackTop });
  -    }
  -
  +    private Map _cachedClasses = new HashMap();
  +    private ClassFactory _factory;
  +    private String _serviceId;
  +
  +	/**
  +	 * Creates a method that delegates to the _inner object; this is used for
  +	 * methods that are not logged.
  +	 */
       private void addPassThruMethodImplementation(ClassFab classFab, MethodSignature sig)
       {
           BodyBuilder builder = new BodyBuilder();
           builder.begin();
   
  -        if (sig.getReturnType() != void.class)
  -            builder.add("return ");
  -
  -        builder.add("_inner.");
  +        builder.add("return ($r) _inner.");
           builder.add(sig.getName());
           builder.addln("($$);");
   
  @@ -102,10 +86,10 @@
           BodyBuilder builder = new BodyBuilder();
   
           builder.begin();
  -        builder.addln("boolean debug = _isDebugEnabled();");
  +        builder.addln("boolean debug = _log.isDebugEnabled();");
   
           builder.addln("if (debug)");
  -        builder.add("  _logEntry(");
  +        builder.add("  org.apache.hivemind.service.impl.LoggingUtils.entry(_log, ");
           builder.addQuoted(methodName);
           builder.addln(", $args);");
   
  @@ -122,14 +106,14 @@
           if (isVoid)
           {
               builder.addln("if (debug)");
  -            builder.add("  _logVoidExit(");
  +            builder.add("  org.apache.hivemind.service.impl.LoggingUtils.voidExit(_log, ");
               builder.addQuoted(methodName);
               builder.addln(");");
           }
           else
           {
               builder.addln("if (debug)");
  -            builder.add("  _logExit(");
  +            builder.add("  org.apache.hivemind.service.impl.LoggingUtils.exit(_log, ");
               builder.addQuoted(methodName);
               builder.addln(", ($w)result);");
               builder.addln("return result;");
  @@ -142,7 +126,7 @@
           builder.clear();
   
           builder.begin();
  -        builder.add("_logException(");
  +        builder.add("org.apache.hivemind.service.impl.LoggingUtils.exception(_log, ");
           builder.addQuoted(methodName);
           builder.addln(", $e);");
           builder.addln("throw $e;");
  @@ -165,11 +149,6 @@
           methodFab.addCatch(RuntimeException.class, body);
       }
   
  -    protected Class getInterceptorSuperclass()
  -    {
  -        return AbstractLoggingInterceptor.class;
  -    }
  -
       protected void addServiceMethods(InterceptorStack stack, ClassFab fab, List parameters)
       {
           boolean toString = false;
  @@ -194,6 +173,22 @@
               addToStringMethod(stack, fab);
       }
   
  +    /**
  +     * Creates a toString() method that identify the interceptor service id,
  +     * the intercepted service id, and the service interface class name).
  +     */
  +    protected void addToStringMethod(InterceptorStack stack, ClassFab fab)
  +    {
  +        ClassFabUtils.addToStringMethod(
  +            fab,
  +            "<LoggingInterceptor for "
  +                + stack.getServiceExtensionPointId()
  +                + "("
  +                + stack.getServiceInterface().getName()
  +                + ")>");
  +
  +    }
  +
       private MethodMatcher buildMethodMatcher(List parameters)
       {
           MethodMatcher result = null;
  @@ -212,6 +207,98 @@
           return result;
       }
   
  +    private Class constructInterceptorClass(InterceptorStack stack, List parameters)
  +    {
  +        Class serviceInterfaceClass = stack.getServiceInterface();
  +        Module module = stack.getServiceModule();
  +
  +        String name = ClassFabUtils.generateClassName("Interceptor");
  +
  +        ClassFab classFab = _factory.newClass(name, Object.class, module);
  +
  +        classFab.addInterface(serviceInterfaceClass);
  +
  +        createInfrastructure(stack, classFab);
  +
  +        addServiceMethods(stack, classFab, parameters);
  +
  +        return classFab.createClass();
  +    }
  +
  +    private void createInfrastructure(InterceptorStack stack, ClassFab classFab)
  +    {
  +        Class topClass = stack.peek().getClass();
  +
  +        classFab.addField("_log", Log.class);
  +        
  +        // This is very important: since we know the instance of the top object (the next
  +        // object in the pipeline for this service), we can build the instance variable
  +        // and constructor to use the exact class rather than the service interface.
  +        // That's more efficient at runtime, lowering the cost of using interceptors.
  +        // One of the reasons I prefer Javassist over JDK Proxies.
  +        
  +        classFab.addField("_inner", topClass);
  +
  +        classFab.addConstructor(
  +            new Class[] { Log.class, topClass },
  +            null,
  +            "{ _log = $1; _inner = $2; }");
  +    }
  +
  +    /**
  +     * Creates the interceptor.
  +     * The class that is created is cached; if an interceptor is requested
  +     * for the same extension point, then the previously constructed class
  +     * is reused (this can happen with the threaded service model, for example,
  +     * when a thread-local service implementation is created for different threads).
  +     */
  +    public void createInterceptor(
  +        InterceptorStack stack,
  +        Module contributingModule,
  +        List parameters)
  +    {
  +        Class serviceInterfaceClass = stack.getServiceInterface();
  +        Class interceptorClass = getInterceptorClass(stack, parameters);
  +
  +        try
  +        {
  +            Object interceptor = instantiateInterceptor(stack, interceptorClass);
  +
  +            stack.push(interceptor);
  +        }
  +        catch (Exception ex)
  +        {
  +            throw new ApplicationRuntimeException(
  +                ServiceMessages.errorInstantiatingInterceptor(
  +                    _serviceId,
  +                    stack,
  +                    interceptorClass,
  +                    ex),
  +                ex);
  +        }
  +    }
  +
  +	/**
  +	 * Returns the Class for this interceptor.  In the standard service models (primitive
  +	 * and singleton) this will only be invoked once for a particular service.  Currently (this
  +	 * may change!) for threaded and pooled, this may be called frequently, so it is necessary
  +	 * to cache the Class (and make this method synchronized).
  +	 */
  +    private synchronized Class getInterceptorClass(InterceptorStack stack, List parameters)
  +    {
  +        String id = stack.getServiceExtensionPointId();
  +        Class result = (Class) _cachedClasses.get(id);
  +
  +        if (result != null)
  +            return result;
  +
  +        result = constructInterceptorClass(stack, parameters);
  +
  +        _cachedClasses.put(id, result);
  +
  +        return result;
  +    }
  +
       private boolean includeMethod(MethodMatcher matcher, MethodSignature sig)
       {
           if (matcher == null)
  @@ -220,5 +307,32 @@
           MethodContribution mc = (MethodContribution) matcher.get(sig);
   
           return mc == null || mc.getInclude();
  +    }
  +
  +    private Object instantiateInterceptor(
  +        InterceptorStack stack,
  +        Class interceptorClass)
  +        throws Exception
  +    {
  +        Object stackTop = stack.peek();
  +
  +		// TODO: Have InterceptorStack expose a method for obtaining the logger for
  +		// the service.
  +		
  +        Log log = LogFactory.getLog(stack.getServiceExtensionPointId());
  +
  +        Constructor c = interceptorClass.getConstructors()[0];
  +
  +        return c.newInstance(new Object[] { log, stackTop });
  +    }
  +
  +    public void setFactory(ClassFactory factory)
  +    {
  +        _factory = factory;
  +    }
  +
  +    public void setServiceId(String string)
  +    {
  +        _serviceId = string;
       }
   }
  
  
  
  1.1                  jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/LoggingUtils.java
  
  Index: LoggingUtils.java
  ===================================================================
  //Copyright 2004 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.hivemind.service.impl;
  
  import org.apache.commons.logging.Log;
  import org.apache.hivemind.service.ClassFabUtils;
  
  /**
   * Collection of static methods used by loggers to
   * log method entry and exit.
   *
   * @author Howard Lewis Ship
   */
  public class LoggingUtils
  {
      private static final int BUFFER_SIZE = 100;
  
      public static void entry(Log log, String methodName, Object[] args)
      {
          StringBuffer buffer = new StringBuffer(BUFFER_SIZE);
  
          buffer.append("BEGIN ");
          buffer.append(methodName);
          buffer.append("(");
  
          int count = (args == null) ? 0 : args.length;
  
          for (int i = 0; i < count; i++)
          {
              Object arg = args[i];
  
              if (i > 0)
                  buffer.append(", ");
  
              convert(buffer, arg);
          }
  
          buffer.append(")");
  
          log.debug(buffer.toString());
      }
  
      public static void exit(Log log, String methodName, Object result)
      {
          StringBuffer buffer = new StringBuffer(BUFFER_SIZE);
  
          buffer.append("END ");
          buffer.append(methodName);
          buffer.append("() [");
  
          convert(buffer, result);
  
          buffer.append("]");
  
          log.debug(buffer.toString());
      }
  
      public static void voidExit(Log log, String methodName)
      {
          StringBuffer buffer = new StringBuffer(BUFFER_SIZE);
  
          buffer.append("END ");
          buffer.append(methodName);
          buffer.append("()");
  
          log.debug(buffer.toString());
      }
  
      public static void exception(Log log, String methodName, Throwable t)
      {
          StringBuffer buffer = new StringBuffer(BUFFER_SIZE);
  
          buffer.append("EXCEPTION ");
          buffer.append(methodName);
          buffer.append("() -- ");
  
          buffer.append(t.getClass().getName());
  
          log.debug(buffer.toString(), t);
      }
  
      public static void convert(StringBuffer buffer, Object input)
      {
          if (input == null)
          {
              buffer.append("<null>");
              return;
          }
  
          // Primitive types, and non-object arrays
          // use toString().  Less than ideal for int[], etc., but
          // that's a lot of work for a rare case.
  
          if (!(input instanceof Object[]))
          {
              buffer.append(input.toString());
              return;
          }
  
          buffer.append("(");
          buffer.append(ClassFabUtils.getJavaClassName(input.getClass()));
          buffer.append("){");
  
          Object[] array = (Object[]) input;
          int count = array.length;
  
          for (int i = 0; i < count; i++)
          {
              if (i > 0)
                  buffer.append(", ");
  
              // We use convert() again, because it could be a multi-dimensional array
              // (god help us) where each element must be converted.
              convert(buffer, array[i]);
          }
  
          buffer.append("}");
      }
  }
  
  
  1.6       +41 -12    jakarta-hivemind/framework/src/test/hivemind/test/services/impl/CountFactory.java
  
  Index: CountFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/impl/CountFactory.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- CountFactory.java	17 Jun 2004 15:16:12 -0000	1.5
  +++ CountFactory.java	15 Aug 2004 15:41:57 -0000	1.6
  @@ -14,12 +14,20 @@
   
   package hivemind.test.services.impl;
   
  +import java.lang.reflect.InvocationHandler;
  +import java.lang.reflect.InvocationTargetException;
  +import java.lang.reflect.Method;
   import java.lang.reflect.Modifier;
  +import java.lang.reflect.Proxy;
  +import java.util.List;
   
  +import org.apache.hivemind.InterceptorStack;
  +import org.apache.hivemind.ServiceInterceptorFactory;
  +import org.apache.hivemind.impl.ProxyUtils;
  +import org.apache.hivemind.internal.Module;
   import org.apache.hivemind.service.BodyBuilder;
   import org.apache.hivemind.service.ClassFab;
   import org.apache.hivemind.service.MethodSignature;
  -import org.apache.hivemind.service.impl.AbstractServiceInterceptorFactory;
   
   /**
    * Simple factory that uses dynamic proxies to count the number of times
  @@ -27,7 +35,7 @@
    *
    * @author Howard Lewis Ship
    */
  -public class CountFactory extends AbstractServiceInterceptorFactory
  +public class CountFactory implements ServiceInterceptorFactory
   {
       private static int _count = 0;
   
  @@ -46,20 +54,41 @@
           _count++;
       }
   
  -    protected void addServiceMethodImplementation(ClassFab classFab, MethodSignature sig)
  +    private class CountHandler implements InvocationHandler
       {
  -        BodyBuilder builder = new BodyBuilder();
  +        private Object _inner;
   
  -        builder.begin();
  -        builder.addln("hivemind.test.services.impl.CountFactory#incrementCount();");
  +        CountHandler(Object inner)
  +        {
  +            _inner = inner;
  +        }
  +
  +        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  +        {
  +            try
  +            {
  +                incrementCount();
  +
  +                return method.invoke(_inner, args);
  +            }
  +            catch (InvocationTargetException ex)
  +            {
  +                throw ex.getTargetException();
  +            }
  +        }
   
  -        builder.add("return ($r) _inner.");
  -        builder.add(sig.getName());
  -        builder.add("($$);");
  +    }
  +
  +    public void createInterceptor(InterceptorStack stack, Module invokingModule, List parameters)
  +    {
  +        InvocationHandler countHandler = new CountHandler(stack.peek());
   
  -        builder.end();
  +        Object proxy =
  +            Proxy.newProxyInstance(
  +                invokingModule.getClassResolver().getClassLoader(),
  +                new Class[] { stack.getServiceInterface()},
  +                countHandler);
   
  -        classFab.addMethod(Modifier.PUBLIC, sig, builder.toString());
  +        stack.push(proxy);
       }
  -
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-cvs-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-cvs-help@jakarta.apache.org