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