hlship 2004/06/12 11:43:41
Modified: library/src/java/org/apache/hivemind/lib/impl
EJBProxyFactory.java
DefaultImplementationBuilderImpl.java
framework/src/java/org/apache/hivemind/impl
ProxyBuilder.java ProxyUtils.java
library/src/test/org/apache/hivemind/lib/pipeline
TestFilterMethodAnalyzer.java
framework/src/java/org/apache/hivemind/service/impl
ClassFabImpl.java ServiceStrings.properties
LoggingInterceptorFactory.java ServiceMessages.java
MethodFabImpl.java
framework/src/java/org/apache/hivemind/service
MethodFab.java ClassFabUtils.java ClassFab.java
framework/src/test/hivemind/test/services TestClassFab.java
TestMethodSignature.java
framework/src/java/org/apache/hivemind/impl/servicemodel
SingletonServiceModel.java
library/src/java/org/apache/hivemind/lib/pipeline
FilterMethodAnalyzer.java BridgeBuilder.java
PipelineMessages.java
framework/src/test/hivemind/test/services/impl
CountFactory.java FilterLoggingInterceptor.java
Added: framework/src/java/org/apache/hivemind/service
MethodSignature.java
Removed: framework/src/java/org/apache/hivemind/service/impl
MethodSignature.java
Log:
Make use of the MethodSignature class as a parameter to ClassFab.addMethod().
Move MethodSignature from service.impl to service.
Add extend() to MethodFab to allow additional code to bre written into
fabricated methods.
Revision Changes Path
1.5 +8 -15
jakarta-hivemind/library/src/java/org/apache/hivemind/lib/impl/EJBProxyFactory.java
Index: EJBProxyFactory.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/java/org/apache/hivemind/lib/impl/EJBProxyFactory.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- EJBProxyFactory.java 9 Jun 2004 14:57:15 -0000 1.4
+++ EJBProxyFactory.java 12 Jun 2004 18:43:41 -0000 1.5
@@ -26,6 +26,7 @@
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.ClassFactory;
+import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.hivemind.ServiceImplementationFactory;
@@ -98,10 +99,7 @@
{
classFab.addMethod(
Modifier.PROTECTED,
- "_clearCachedReferences",
- Void.TYPE,
- null,
- null,
+ new MethodSignature(void.class, "_clearCachedReferences", null,
null),
"_remote = null;");
}
@@ -142,10 +140,11 @@
classFab.addMethod(
Modifier.SYNCHRONIZED + Modifier.PRIVATE,
- "_lookupRemote",
- remoteInterface,
- null,
- new Class[] { RemoteException.class },
+ new MethodSignature(
+ remoteInterface,
+ "_lookupRemote",
+ null,
+ new Class[] { RemoteException.class }),
builder.toString());
}
@@ -217,13 +216,7 @@
builder.end(); // while
builder.end();
- classFab.addMethod(
- Modifier.PUBLIC,
- methodName,
- m.getReturnType(),
- m.getParameterTypes(),
- m.getExceptionTypes(),
- builder.toString());
+ classFab.addMethod(Modifier.PUBLIC, new MethodSignature(m),
builder.toString());
}
private void addToStringMethod(
1.3 +2 -7
jakarta-hivemind/library/src/java/org/apache/hivemind/lib/impl/DefaultImplementationBuilderImpl.java
Index: DefaultImplementationBuilderImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/java/org/apache/hivemind/lib/impl/DefaultImplementationBuilderImpl.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- DefaultImplementationBuilderImpl.java 9 Jun 2004 14:57:15 -0000
1.2
+++ DefaultImplementationBuilderImpl.java 12 Jun 2004 18:43:41 -0000
1.3
@@ -27,6 +27,7 @@
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.ClassFactory;
+import org.apache.hivemind.service.MethodSignature;
/**
* Implemenation of [EMAIL PROTECTED]
org.apache.hivemind.lib.DefaultImplementationBuilder}.
@@ -129,13 +130,7 @@
body.append(" }");
- cf.addMethod(
- Modifier.PUBLIC,
- m.getName(),
- returnType,
- m.getParameterTypes(),
- m.getExceptionTypes(),
- body.toString());
+ cf.addMethod(Modifier.PUBLIC, new MethodSignature(m),
body.toString());
}
public void setClassFactory(ClassFactory factory)
1.4 +6 -13
jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java
Index: ProxyBuilder.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ProxyBuilder.java 18 May 2004 15:34:00 -0000 1.3
+++ ProxyBuilder.java 12 Jun 2004 18:43:41 -0000 1.4
@@ -17,13 +17,13 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import org.apache.hivemind.Registry;
import org.apache.hivemind.internal.Module;
import org.apache.hivemind.internal.ServicePoint;
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.MethodSignature;
/**
* Class used to assist service extension points in creating proxies.
@@ -77,25 +77,18 @@
Method[] methods = _serviceInterface.getMethods();
for (int i = 0; i < methods.length; i++)
{
- Method m = methods[i];
- String methodName = m.getName();
-
+ Method m = methods[i];
+
builder.clear();
builder.begin();
builder.add("return ($r) ");
builder.add(indirection);
builder.add(".");
- builder.add(methodName);
+ builder.add(m.getName());
builder.addln("($$);");
builder.end();
- _classFab.addMethod(
- Modifier.PUBLIC,
- methodName,
- m.getReturnType(),
- m.getParameterTypes(),
- m.getExceptionTypes(),
- builder.toString());
+ _classFab.addMethod(Modifier.PUBLIC, new MethodSignature(m),
builder.toString());
toString |= ClassFabUtils.isToString(m);
}
1.6 +7 -12
jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ProxyUtils.java
Index: ProxyUtils.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/ProxyUtils.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ProxyUtils.java 18 May 2004 15:34:00 -0000 1.5
+++ ProxyUtils.java 12 Jun 2004 18:43:41 -0000 1.6
@@ -17,13 +17,14 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
-import org.apache.hivemind.*;
import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.ShutdownCoordinator;
import org.apache.hivemind.events.RegistryShutdownListener;
-import org.apache.hivemind.internal.ServicePoint;
import org.apache.hivemind.internal.ServiceModel;
+import org.apache.hivemind.internal.ServicePoint;
import org.apache.hivemind.service.BodyBuilder;
import org.apache.hivemind.service.ClassFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* Contains some common code used to create proxies that defer to a service
model method
@@ -68,7 +69,7 @@
try
{
- Constructor c = proxyClass.getConstructor(new Class[] {
serviceModel.getClass() });
+ Constructor c = proxyClass.getConstructor(new Class[] {
serviceModel.getClass()});
RegistryShutdownListener result =
(RegistryShutdownListener) c.newInstance(new Object[] {
serviceModel });
@@ -131,20 +132,14 @@
classFab.addMethod(
Modifier.PRIVATE | Modifier.FINAL,
- SERVICE_ACCESSOR_METHOD_NAME,
- serviceInterface,
- null,
- null,
+ new MethodSignature(serviceInterface,
SERVICE_ACCESSOR_METHOD_NAME, null, null),
builder.toString());
classFab.addInterface(RegistryShutdownListener.class);
classFab.addMethod(
Modifier.PUBLIC | Modifier.FINAL,
- "registryDidShutdown",
- Void.TYPE,
- null,
- null,
+ new MethodSignature(void.class, "registryDidShutdown", null,
null),
"{ _serviceModel = null; _shutdown = true; }");
}
}
1.2 +1 -1
jakarta-hivemind/library/src/test/org/apache/hivemind/lib/pipeline/TestFilterMethodAnalyzer.java
Index: TestFilterMethodAnalyzer.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/test/org/apache/hivemind/lib/pipeline/TestFilterMethodAnalyzer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestFilterMethodAnalyzer.java 9 Jun 2004 14:58:16 -0000 1.1
+++ TestFilterMethodAnalyzer.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -16,7 +16,7 @@
import java.lang.reflect.Method;
-import org.apache.hivemind.service.impl.MethodSignature;
+import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.test.HiveMindTestCase;
public class TestFilterMethodAnalyzer extends HiveMindTestCase
1.5 +34 -15
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ClassFabImpl.java
Index: ClassFabImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ClassFabImpl.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ClassFabImpl.java 6 Jun 2004 00:29:25 -0000 1.4
+++ ClassFabImpl.java 12 Jun 2004 18:43:41 -0000 1.5
@@ -15,18 +15,19 @@
package org.apache.hivemind.service.impl;
import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
import javassist.CannotCompileException;
-import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import org.apache.hivemind.ApplicationRuntimeException;
-import org.apache.hivemind.HiveMind;
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.MethodFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* Implementation of [EMAIL PROTECTED]
org.apache.hivemind.service.ClassFab}. Hides,
@@ -39,12 +40,25 @@
private CtClass _ctClass;
private CtClassSource _source;
+ /**
+ * Map of [EMAIL PROTECTED] MethodFab} keyed on [EMAIL PROTECTED]
MethodSignature}.
+ */
+ private Map _methods = new HashMap();
+
public ClassFabImpl(CtClassSource source, CtClass ctClass)
{
_source = source;
_ctClass = ctClass;
}
+ /**
+ * Returns the name of the class fabricated by this instance.
+ */
+ String getName()
+ {
+ return _ctClass.getName();
+ }
+
public void addInterface(Class interfaceClass)
{
CtClass ctInterfaceClass = _source.getCtClass(interfaceClass);
@@ -71,20 +85,17 @@
}
}
- public MethodFab addMethod(
- int modifiers,
- String name,
- Class returnType,
- Class[] parameterTypes,
- Class[] exceptions,
- String body)
+ public MethodFab addMethod(int modifiers, MethodSignature ms, String
body)
{
- CtClass ctReturnType = _source.getCtClass(returnType);
+ if (_methods.get(ms) != null)
+ throw new
ApplicationRuntimeException(ServiceMessages.duplicateMethodInClass(ms, this));
+
+ CtClass ctReturnType = _source.getCtClass(ms.getReturnType());
- CtClass[] ctParameters = convertClasses(parameterTypes);
- CtClass[] ctExceptions = convertClasses(exceptions);
+ CtClass[] ctParameters = convertClasses(ms.getParameterTypes());
+ CtClass[] ctExceptions = convertClasses(ms.getExceptionTypes());
- CtMethod method = new CtMethod(ctReturnType, name, ctParameters,
_ctClass);
+ CtMethod method = new CtMethod(ctReturnType, ms.getName(),
ctParameters, _ctClass);
try
{
@@ -97,14 +108,22 @@
catch (Exception ex)
{
throw new ApplicationRuntimeException(
- ServiceMessages.unableToAddMethod(name, _ctClass, ex),
+ ServiceMessages.unableToAddMethod(ms, _ctClass, ex),
ex);
}
// Return a MethodFab so the caller can add catches.
- return new MethodFabImpl(_source, method);
+ MethodFab result = new MethodFabImpl(_source, ms, method);
+ _methods.put(ms, result);
+
+ return result;
+ }
+
+ public MethodFab getMethodFab(MethodSignature ms)
+ {
+ return (MethodFab) _methods.get(ms);
}
public void addConstructor(Class[] parameterTypes, Class[] exceptions,
String body)
1.3 +2 -1
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties
Index: ServiceStrings.properties
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ServiceStrings.properties,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ServiceStrings.properties 10 Jun 2004 19:49:39 -0000 1.2
+++ ServiceStrings.properties 12 Jun 2004 18:43:41 -0000 1.3
@@ -28,4 +28,5 @@
no-event-matches={0} (at {1}) does not implement any listener interfaces
compatible with {2}.
unable-to-introspect-class=Unable to introspect {0}: {1}
unable-to-add-listener=Unable to add {0} as listener of {1} (event set {2},
at {3}): {4}
-
+duplicate-method-in-class=Attempt to redefine method {0} of class {1}.
+unable-to-extend-method=Unable to extend method {0} of class {1}: {2}
1.4 +4 -9
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.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- LoggingInterceptorFactory.java 17 May 2004 16:57:47 -0000 1.3
+++ LoggingInterceptorFactory.java 12 Jun 2004 18:43:41 -0000 1.4
@@ -29,6 +29,7 @@
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.MethodContribution;
import org.apache.hivemind.service.MethodFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* An interceptor factory that adds logging capability to a service.
@@ -97,10 +98,7 @@
classFab.addMethod(
Modifier.PUBLIC,
- methodName,
- returnType,
- parameterTypes,
- exceptions,
+ new MethodSignature(returnType, methodName, parameterTypes,
exceptions),
builder.toString());
}
@@ -154,10 +152,7 @@
MethodFab methodFab =
classFab.addMethod(
Modifier.PUBLIC,
- methodName,
- returnType,
- parameterTypes,
- exceptions,
+ new MethodSignature(returnType, methodName, parameterTypes,
exceptions),
builder.toString());
builder.clear();
1.5 +24 -2
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java
Index: ServiceMessages.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/ServiceMessages.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ServiceMessages.java 10 Jun 2004 19:49:39 -0000 1.4
+++ ServiceMessages.java 12 Jun 2004 18:43:41 -0000 1.5
@@ -25,6 +25,8 @@
import org.apache.hivemind.InterceptorStack;
import org.apache.hivemind.Location;
import org.apache.hivemind.impl.MessageFormatter;
+import org.apache.hivemind.service.ClassFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* Messages for the service.impl package.
@@ -78,11 +80,14 @@
_formatter.extractMessage(cause));
}
- public static String unableToAddMethod(String methodName, CtClass
ctClass, Throwable cause)
+ public static String unableToAddMethod(
+ MethodSignature methodSignature,
+ CtClass ctClass,
+ Throwable cause)
{
return _formatter.format(
"unable-to-add-method",
- methodName,
+ methodSignature,
ctClass.getName(),
_formatter.extractMessage(cause));
}
@@ -179,6 +184,23 @@
"unable-to-add-catch",
exceptionClass.getName(),
method.getDeclaringClass().getName(),
+ _formatter.extractMessage(cause));
+ }
+
+ public static String duplicateMethodInClass(MethodSignature ms,
ClassFabImpl cf)
+ {
+ return _formatter.format("duplicate-method-in-class", ms,
cf.getName());
+ }
+
+ public static String unableToExtendMethod(
+ MethodSignature ms,
+ String className,
+ Throwable cause)
+ {
+ return _formatter.format(
+ "unable-to-extend-method",
+ ms,
+ className,
_formatter.extractMessage(cause));
}
}
1.4 +21 -3
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/MethodFabImpl.java
Index: MethodFabImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/impl/MethodFabImpl.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MethodFabImpl.java 6 Jun 2004 00:29:25 -0000 1.3
+++ MethodFabImpl.java 12 Jun 2004 18:43:41 -0000 1.4
@@ -14,13 +14,12 @@
package org.apache.hivemind.service.impl;
-import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.apache.hivemind.ApplicationRuntimeException;
-import org.apache.hivemind.HiveMind;
import org.apache.hivemind.service.MethodFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* Implementation of [EMAIL PROTECTED]
org.apache.hivemind.service.MethodFab},
@@ -33,11 +32,13 @@
class MethodFabImpl implements MethodFab
{
private CtClassSource _source;
+ private MethodSignature _signature;
private CtMethod _method;
- public MethodFabImpl(CtClassSource source, CtMethod method)
+ public MethodFabImpl(CtClassSource source, MethodSignature signature,
CtMethod method)
{
_source = source;
+ _signature = signature;
_method = method;
}
@@ -53,6 +54,23 @@
{
throw new ApplicationRuntimeException(
ServiceMessages.unableToAddCatch(exceptionClass, _method,
ex),
+ ex);
+ }
+ }
+
+ public void extend(String body, boolean asFinally)
+ {
+ try
+ {
+ _method.insertAfter(body, asFinally);
+ }
+ catch (Exception ex)
+ {
+ throw new ApplicationRuntimeException(
+ ServiceMessages.unableToExtendMethod(
+ _signature,
+ _method.getDeclaringClass().getName(),
+ ex),
ex);
}
}
1.2 +16 -5
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/MethodFab.java
Index: MethodFab.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/MethodFab.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MethodFab.java 26 Feb 2004 23:07:49 -0000 1.1
+++ MethodFab.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -17,13 +17,24 @@
/**
* Represents a created method on a class; used to add catch handlers.
* @see org.apache.hivemind.service.ClassFab#addMethod(int, String, Class,
Class[], Class[], String)
- *
- * @version $Id$
*/
public interface MethodFab
{
- /**
- * Adds a catch to the method. The body must end with a return or
throw.
- */
+ /**
+ * Adds a catch to the method. The body must end with a return or throw.
+ * The special Javassist varaiable <code>$e</code> represents the caught
exception.
+ */
public void addCatch(Class exceptionClass, String catchBody);
+
+ /**
+ * Extends the existing method with additional code. The new body can
reference the
+ * return value generated by the existing body using the special variable
+ * <code>$_</code>, for example <code>$_ = 2 * $_</code>.
+ *
+ * @param body a block to execute after any existing code in the method
+ * @param asFinally if true, the block provided wil execute as with a
finally block (even
+ * if an exception is thrown)
+ */
+
+ public void extend(String body, boolean asFinally);
}
1.3 +8 -11
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/ClassFabUtils.java
Index: ClassFabUtils.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/ClassFabUtils.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ClassFabUtils.java 5 Jun 2004 19:09:13 -0000 1.2
+++ ClassFabUtils.java 12 Jun 2004 18:43:41 -0000 1.3
@@ -73,13 +73,13 @@
return method.getReturnType().equals(String.class);
}
- /**
- * Adds a <code>toString()</code> method to a class that returns a
fixed,
- * pre-computed value.
- *
- * @param classFab ClassFab used to construct the new class.
- * @param toStringResult fixed result to be returned by the method.
- */
+ /**
+ * Adds a <code>toString()</code> method to a class that returns a fixed,
+ * pre-computed value.
+ *
+ * @param classFab ClassFab used to construct the new class.
+ * @param toStringResult fixed result to be returned by the method.
+ */
public static void addToStringMethod(ClassFab classFab, String
toStringResult)
{
StringBuffer buffer = new StringBuffer("return ");
@@ -90,10 +90,7 @@
classFab.addMethod(
Modifier.PUBLIC,
- "toString",
- String.class,
- null,
- null,
+ new MethodSignature(String.class, "toString", null, null),
buffer.toString());
}
1.3 +38 -12
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/ClassFab.java
Index: ClassFab.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/service/ClassFab.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ClassFab.java 6 Jun 2004 00:29:25 -0000 1.2
+++ ClassFab.java 12 Jun 2004 18:43:41 -0000 1.3
@@ -17,6 +17,29 @@
/**
* Used when fabricating a new class. Represents a wrapper around
* the Javassist library.
+ *
+ * <p>
+ * The core concept of Javassist is how method bodies (as well as
constructor bodies, etc.)
+ * are specified ... as a very Java-like scripting language. The
+ * [EMAIL PROTECTED] org.apache.hivemind.service.BodyBuilder} class is
<em>very</em> useful for assembling
+ * this method bodies. Details are available at the
+ * <a href="http://jboss.org/products/javassist">Javassist home page</a>.
+ *
+ * <p>
+ * Method bodies look largely like Java. References to java classes must be
fully qualified.
+ * Several special variables are used:
+ * <ul>
+ * <li><code>$0</code> first parameter, equivalent to <code>this</code> in
Java code (and can't
+ * be used when creating a static method)
+ * <li><code>$1, $2, ...</code> actual parameters to the method
+ * <li><code>$args</code> all the parameters as an <code>Object[]</code>
+ * <li><code>$r</code> the return type of the method, typically used as
<code>return ($r) ...</code>.
+ * <code>$r</code> is valid with method that return <code>void</code>. This
also handles conversions
+ * between wrapper types and primitive types.
+ * <li><code>$w</code> conversion from primitive type to wrapper type, used
as <code>($w) foo()</code> where
+ * <code>foo()</code> returns a primitive type and a wrapper type is needed
+ * <li>
+ * </ul>
*
* @author Howard Lewis Ship
*/
@@ -37,21 +60,24 @@
/**
* Adds a method. The method is a public instance method.
* @return a method fabricator, used to add catch handlers.
- * @param modifiers - Modifiers for the method
- * @param name The name of the method to create.
- * @param returnType the return type of the method.
- * @param parameterTypes the types of each parameter, or null if the
method takes no parameters.
- * @param exceptions The types of all declared exceptions, or null if
the method throws no exceptions.
+ * @param modifiers Modifiers for the method (see [EMAIL PROTECTED]
java.lang.reflect.Modifier}).
+ * @param signature defines the name, return type, parameters and
exceptions thrown
* @param body The body of the method.
+ * @throws ApplicationRuntimeException if a method with that signature
has already
+ * been added, or if there is a Javassist compilation error
*/
- public MethodFab addMethod(
- int modifiers,
- String name,
- Class returnType,
- Class[] parameterTypes,
- Class[] exceptions,
- String body);
+ public MethodFab addMethod(int modifiers, MethodSignature signature,
String body);
+
+ /**
+ * Returns a previous defined method so that it can be further enhanced
+ * (perhaps by adding additional catches, etc.).
+ *
+ * @param signature the signature of the method previously added
+ * @return the MethodFab for that method, or null if the method has not
been added yet
+ */
+
+ public MethodFab getMethodFab(MethodSignature signature);
/**
* Adds a constructor to the class. The constructor will be public.
1.1
jakarta-hivemind/framework/src/java/org/apache/hivemind/service/MethodSignature.java
Index: MethodSignature.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;
import java.lang.reflect.Method;
/**
* A representation of a [EMAIL PROTECTED] java.lang.reflect.Method},
identifying the name,
* return type, parameter types and exception types. Actual Method objects
are tied to
* a particular class, and don't compare well with other otherwise identical
Methods from
* other classes or interface; MethodSignatures are distinct from classes and
compare well.
*
* <p>
* Because the intended purpose is to compare methods from interfaces (which
are always
* public and abstract) we don't bother to actually track the modifiers. In
addition,
* at this time, MethodSignature <em>does not distinguish between instance
and static
* methods</em>.
*
* @author Howard Lewis Ship
*/
public class MethodSignature
{
private int _hashCode = -1;
private Class _returnType;
private String _name;
private Class[] _parameterTypes;
private Class[] _exceptionTypes;
public MethodSignature(
Class returnType,
String name,
Class[] parameterTypes,
Class[] exceptionTypes)
{
_returnType = returnType;
_name = name;
_parameterTypes = parameterTypes;
_exceptionTypes = exceptionTypes;
}
public MethodSignature(Method m)
{
this(m.getReturnType(), m.getName(), m.getParameterTypes(),
m.getExceptionTypes());
}
/**
* Returns the exceptions for this method. Caution: do not modify the
returned array.
* May return null.
*/
public Class[] getExceptionTypes()
{
return _exceptionTypes;
}
public String getName()
{
return _name;
}
/**
* Returns the parameter types for this method. May return null.
Caution: do
* not modify the returned array.
*/
public Class[] getParameterTypes()
{
return _parameterTypes;
}
public Class getReturnType()
{
return _returnType;
}
public int hashCode()
{
if (_hashCode == -1)
{
_hashCode = _returnType.hashCode();
_hashCode = 31 * _hashCode + _name.hashCode();
int count = count(_parameterTypes);
for (int i = 0; i < count; i++)
_hashCode = 31 * _hashCode + _parameterTypes[i].hashCode();
count = count(_exceptionTypes);
for (int i = 0; i < count; i++)
_hashCode = 31 * _hashCode + _exceptionTypes[i].hashCode();
}
return _hashCode;
}
private static int count(Object[] array)
{
return array == null ? 0 : array.length;
}
/**
* Returns true if the other object is an instance of MethodSignature with
* identical values for return type, name, parameter types and exception
types.
*/
public boolean equals(Object o)
{
if (o == null || !(o instanceof MethodSignature))
return false;
MethodSignature ms = (MethodSignature) o;
if (_returnType != ms._returnType)
return false;
if (!_name.equals(ms._name))
return false;
if (mismatch(_parameterTypes, ms._parameterTypes))
return false;
return !mismatch(_exceptionTypes, ms._exceptionTypes);
}
private boolean mismatch(Class[] a1, Class[] a2)
{
int a1Count = count(a1);
int a2Count = count(a2);
if (a1Count != a2Count)
return true;
// Hm. What if order is important (for exceptions)? We're really
saying here that they
// were derived from the name Method.
for (int i = 0; i < a1Count; i++)
{
if (a1[i] != a2[i])
return true;
}
return false;
}
public String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append(ClassFabUtils.getJavaClassName(_returnType));
buffer.append(" ");
buffer.append(_name);
buffer.append("(");
for (int i = 0; i < count(_parameterTypes); i++)
{
if (i > 0)
buffer.append(", ");
buffer.append(ClassFabUtils.getJavaClassName(_parameterTypes[i]));
}
buffer.append(")");
for (int i = 0; i < count(_exceptionTypes); i++)
{
if (i == 0)
buffer.append(" throws ");
else
buffer.append(", ");
buffer.append(_exceptionTypes[i].getName());
}
return buffer.toString();
}
}
1.2 +117 -33
jakarta-hivemind/framework/src/test/hivemind/test/services/TestClassFab.java
Index: TestClassFab.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestClassFab.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestClassFab.java 6 Jun 2004 00:29:25 -0000 1.1
+++ TestClassFab.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -24,6 +24,7 @@
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.MethodFab;
+import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.service.impl.ClassFabImpl;
import org.apache.hivemind.service.impl.CtClassSource;
import org.apache.hivemind.test.HiveMindTestCase;
@@ -53,21 +54,15 @@
cf.addField("_stringValue", String.class);
- cf.addMethod(
- Modifier.PUBLIC,
- "setStringValue",
- void.class,
- new Class[] { String.class },
- null,
- "_stringValue = $1;");
+ MethodSignature setStringValue =
+ new MethodSignature(void.class, "setStringValue", new Class[] {
String.class }, null);
- cf.addMethod(
- Modifier.PUBLIC,
- "getStringValue",
- String.class,
- null,
- null,
- "return _stringValue;");
+ cf.addMethod(Modifier.PUBLIC, setStringValue, "_stringValue = $1;");
+
+ MethodSignature getStringValue =
+ new MethodSignature(String.class, "getStringValue", null, null);
+
+ cf.addMethod(Modifier.PUBLIC, getStringValue, "return
_stringValue;");
Class targetClass = cf.createClass();
@@ -87,13 +82,10 @@
cf.addField("_stringValue", String.class);
cf.addConstructor(new Class[] { String.class }, null, "{
_stringValue = $1; }");
- cf.addMethod(
- Modifier.PUBLIC,
- "getStringValue",
- String.class,
- null,
- null,
- "return _stringValue;");
+ MethodSignature getStringValue =
+ new MethodSignature(String.class, "getStringValue", null, null);
+
+ cf.addMethod(Modifier.PUBLIC, getStringValue, "return
_stringValue;");
Class targetClass = cf.createClass();
@@ -122,7 +114,10 @@
cf.addField("_intValue", int.class);
cf.addConstructor(new Class[] { int.class }, null, "{ _intValue =
$1; }");
- cf.addMethod(Modifier.PUBLIC, "getIntValue", int.class, null, null,
"return _intValue;");
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(int.class, "getIntValue", null, null),
+ "return _intValue;");
Class targetClass = cf.createClass();
Constructor c = targetClass.getConstructors()[0];
@@ -156,10 +151,7 @@
cf.addMethod(
Modifier.PUBLIC,
- "add",
- int.class,
- new Class[] { int.class, int.class },
- null,
+ new MethodSignature(int.class, "add", new Class[] { int.class,
int.class }, null),
"return $1 + $2;");
Class targetClass = cf.createClass();
@@ -204,11 +196,102 @@
try
{
- cf.addMethod(Modifier.PUBLIC, "run", void.class, null, null,
"fail;");
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(void.class, "run", null, null),
+ "fail;");
}
catch (ApplicationRuntimeException ex)
{
- assertExceptionSubstring(ex, "Unable to add method run to class
BadMethod");
+ assertExceptionSubstring(ex, "Unable to add method void run() to
class BadMethodBody:");
+ }
+ }
+
+ public void testGetMethodFab() throws Exception
+ {
+ ClassFab cf = newClassFab("GetMethodFab", Object.class);
+
+ MethodSignature s = new MethodSignature(void.class, "run", null,
null);
+ MethodFab mf = cf.addMethod(Modifier.PUBLIC, s, null);
+
+ assertSame(mf, cf.getMethodFab(s));
+
+ assertNull(cf.getMethodFab(new MethodSignature(void.class, "skip",
null, null)));
+ }
+
+ public void testExtendMethod() throws Exception
+ {
+ ClassFab cf = newClassFab("ExtendMethod", Object.class);
+
+ MethodFab mf =
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(int.class, "getValue", null, null),
+ "return 1;");
+
+ mf.extend("return 2 * $_;", false);
+
+ Object bean = cf.createClass().newInstance();
+
+ assertEquals(new Integer(2), PropertyUtils.read(bean, "value",
null));
+ }
+
+ public void testExtendMethodAlterReturn() throws Exception
+ {
+ ClassFab cf = newClassFab("ExtendMethodAlterReturn", Object.class);
+
+ MethodFab mf =
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(int.class, "getValue", null, null),
+ "return 2;");
+
+ mf.extend("$_ = 3 * $_;", false);
+
+ Object bean = cf.createClass().newInstance();
+
+ assertEquals(new Integer(6), PropertyUtils.read(bean, "value",
null));
+ }
+
+ public void testExtendMethodFailure() throws Exception
+ {
+ ClassFab cf = newClassFab("ExtendMethodFailure", Object.class);
+
+ MethodFab mf =
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(int.class, "getValue", null, null),
+ "return 1;");
+
+ try
+ {
+ mf.extend("$_ =", true);
+ unreachable();
+ }
+ catch (ApplicationRuntimeException ex)
+ {
+ assertExceptionSubstring(
+ ex,
+ "Unable to extend method int getValue() of class
ExtendMethodFailure:");
+ }
+ }
+
+ public void testDupeMethodAdd() throws Exception
+ {
+ ClassFab cf = newClassFab("DupeMethodAdd", Object.class);
+
+ cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "foo",
null, null), "{}");
+
+ try
+ {
+ cf.addMethod(Modifier.PUBLIC, new MethodSignature(void.class,
"foo", null, null), "{}");
+ unreachable();
+ }
+ catch (ApplicationRuntimeException ex)
+ {
+ assertEquals(
+ "Attempt to redefine method void foo() of class
DupeMethodAdd.",
+ ex.getMessage());
}
}
@@ -236,10 +319,7 @@
MethodFab mf =
cf.addMethod(
Modifier.PUBLIC,
- "fail",
- void.class,
- null,
- null,
+ new MethodSignature(void.class, "fail", null, null),
"throw new java.lang.RuntimeException(\"Ouch!\");");
mf.addCatch(RuntimeException.class, "throw new
java.io.IOException($e.getMessage());");
@@ -265,7 +345,11 @@
cf.addInterface(Runnable.class);
- MethodFab mf = cf.addMethod(Modifier.PUBLIC, "run", void.class,
null, null, "return;");
+ MethodFab mf =
+ cf.addMethod(
+ Modifier.PUBLIC,
+ new MethodSignature(void.class, "run", null, null),
+ "return;");
try
{
1.2 +12 -1
jakarta-hivemind/framework/src/test/hivemind/test/services/TestMethodSignature.java
Index: TestMethodSignature.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/TestMethodSignature.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestMethodSignature.java 9 Jun 2004 14:54:18 -0000 1.1
+++ TestMethodSignature.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -18,7 +18,7 @@
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
-import org.apache.hivemind.service.impl.MethodSignature;
+import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.test.HiveMindTestCase;
/**
@@ -63,6 +63,17 @@
assertEquals(m1.hashCode(), m2.hashCode());
assertTrue(m1.equals(m2));
+ }
+
+ public void testEqualsAndHashCodeWithNulls()
+ {
+ MethodSignature m1 = new MethodSignature(void.class, "foo", null,
null);
+ MethodSignature m2 = new MethodSignature(void.class, "foo", new
Class[0], new Class[0]);
+
+ assertEquals(m1, m2);
+ assertEquals(m2, m1);
+
+ assertEquals(m1.hashCode(), m2.hashCode());
}
public void testToString()
1.5 +7 -21
jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java
Index: SingletonServiceModel.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/java/org/apache/hivemind/impl/servicemodel/SingletonServiceModel.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- SingletonServiceModel.java 19 May 2004 02:30:53 -0000 1.4
+++ SingletonServiceModel.java 12 Jun 2004 18:43:41 -0000 1.5
@@ -24,6 +24,7 @@
import org.apache.hivemind.internal.ServicePoint;
import org.apache.hivemind.service.BodyBuilder;
import org.apache.hivemind.service.ClassFab;
+import org.apache.hivemind.service.MethodSignature;
/**
* Subclass of [EMAIL PROTECTED]
org.apache.hivemind.impl.AbstractServiceModelImpl}
@@ -138,18 +139,12 @@
classFab.addMethod(
Modifier.PUBLIC | Modifier.FINAL,
- "registryDidShutdown",
- Void.TYPE,
- null,
- null,
+ new MethodSignature(void.class, "registryDidShutdown", null,
null),
"{ _shutdown = true; }");
classFab.addMethod(
Modifier.PUBLIC | Modifier.SYNCHRONIZED | Modifier.FINAL,
- "_setInner",
- Void.TYPE,
- new Class[] { serviceInterface },
- null,
+ new MethodSignature(void.class, "_setInner", new Class[] {
serviceInterface }, null),
"{ _inner = $1; }");
BodyBuilder builder = new BodyBuilder();
@@ -165,10 +160,7 @@
classFab.addMethod(
Modifier.PRIVATE,
- "_getInner",
- serviceInterface,
- null,
- null,
+ new MethodSignature(serviceInterface, "_getInner", null, null),
builder.toString());
proxyBuilder.addServiceMethods("_getInner()");
@@ -232,10 +224,7 @@
classFab.addMethod(
Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED,
- "_service",
- serviceInterface,
- null,
- null,
+ new MethodSignature(serviceInterface, "_service", null, null),
body.toString());
builder.addServiceMethods("_service()");
@@ -251,10 +240,7 @@
classFab.addMethod(
Modifier.PUBLIC | Modifier.FINAL,
- "_instantiateServiceImplementation",
- Void.TYPE,
- null,
- null,
+ new MethodSignature(void.class,
"_instantiateServiceImplementation", null, null),
body.toString());
classFab.addInterface(SingletonInnerProxy.class);
1.2 +1 -1
jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/FilterMethodAnalyzer.java
Index: FilterMethodAnalyzer.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/FilterMethodAnalyzer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- FilterMethodAnalyzer.java 9 Jun 2004 14:58:16 -0000 1.1
+++ FilterMethodAnalyzer.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -14,7 +14,7 @@
package org.apache.hivemind.lib.pipeline;
-import org.apache.hivemind.service.impl.MethodSignature;
+import org.apache.hivemind.service.MethodSignature;
/**
* Used by [EMAIL PROTECTED]
org.apache.hivemind.lib.pipeline.PipelineAssembler}
1.2 +3 -20
jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/BridgeBuilder.java
Index: BridgeBuilder.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/BridgeBuilder.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- BridgeBuilder.java 9 Jun 2004 14:58:16 -0000 1.1
+++ BridgeBuilder.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -28,7 +28,7 @@
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.ClassFactory;
-import org.apache.hivemind.service.impl.MethodSignature;
+import org.apache.hivemind.service.MethodSignature;
/**
* Used by the [EMAIL PROTECTED]
org.apache.hivemind.lib.pipeline.PipelineAssembler}
@@ -201,18 +201,7 @@
b.addQuoted(message);
b.addln(");");
- addMethod(ms, b.toString());
- }
-
- private void addMethod(MethodSignature ms, String methodBody)
- {
- _classFab.addMethod(
- Modifier.PUBLIC,
- ms.getName(),
- ms.getReturnType(),
- ms.getParameterTypes(),
- ms.getExceptionTypes(),
- methodBody);
+ _classFab.addMethod(Modifier.PUBLIC, ms, b.toString());
}
/**
@@ -268,13 +257,7 @@
// This should work, unless the exception types turn out to not be
compatble. We still
// don't do a check on that, and not sure that Javassist does either!
- _classFab.addMethod(
- Modifier.PUBLIC,
- ms.getName(),
- ms.getReturnType(),
- ms.getParameterTypes(),
- ms.getExceptionTypes(),
- buffer.toString());
+ _classFab.addMethod(Modifier.PUBLIC, ms, buffer.toString());
}
}
1.2 +1 -1
jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/PipelineMessages.java
Index: PipelineMessages.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/library/src/java/org/apache/hivemind/lib/pipeline/PipelineMessages.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PipelineMessages.java 9 Jun 2004 14:58:16 -0000 1.1
+++ PipelineMessages.java 12 Jun 2004 18:43:41 -0000 1.2
@@ -19,7 +19,7 @@
import org.apache.hivemind.HiveMind;
import org.apache.hivemind.Location;
import org.apache.hivemind.impl.MessageFormatter;
-import org.apache.hivemind.service.impl.MethodSignature;
+import org.apache.hivemind.service.MethodSignature;
/**
* Messages for the lib.pipeline package.
1.4 +4 -6
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.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- CountFactory.java 26 Feb 2004 23:07:35 -0000 1.3
+++ CountFactory.java 12 Jun 2004 18:43:41 -0000 1.4
@@ -18,6 +18,7 @@
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;
/**
@@ -61,15 +62,12 @@
builder.add("return ($r) _inner.");
builder.add(methodName);
builder.add("($$);");
-
+
builder.end();
classFab.addMethod(
Modifier.PUBLIC,
- methodName,
- returnType,
- parameterTypes,
- exceptions,
+ new MethodSignature(returnType, methodName, parameterTypes,
exceptions),
builder.toString());
}
1.5 +8 -13
jakarta-hivemind/framework/src/test/hivemind/test/services/impl/FilterLoggingInterceptor.java
Index: FilterLoggingInterceptor.java
===================================================================
RCS file:
/home/cvs/jakarta-hivemind/framework/src/test/hivemind/test/services/impl/FilterLoggingInterceptor.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- FilterLoggingInterceptor.java 13 May 2004 11:04:48 -0000 1.4
+++ FilterLoggingInterceptor.java 12 Jun 2004 18:43:41 -0000 1.5
@@ -22,17 +22,18 @@
import java.util.List;
import java.util.Set;
+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.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.MethodSignature;
import org.apache.hivemind.service.impl.AbstractLoggingInterceptor;
-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;
/**
* Much like [EMAIL PROTECTED]
org.apache.hivemind.service.impl.LoggingInterceptorFactory},
@@ -100,13 +101,7 @@
builder.end();
- classFab.addMethod(
- Modifier.PUBLIC,
- methodName,
- m.getReturnType(),
- m.getParameterTypes(),
- m.getExceptionTypes(),
- builder.toString());
+ classFab.addMethod(Modifier.PUBLIC, new MethodSignature(m),
builder.toString());
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]