Return-Path: Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 54364 invoked by uid 500); 22 Sep 2003 20:05:50 -0000 Received: (qmail 54357 invoked from network); 22 Sep 2003 20:05:50 -0000 Received: from unknown (HELO minotaur.apache.org) (209.237.227.194) by daedalus.apache.org with SMTP; 22 Sep 2003 20:05:50 -0000 Received: (qmail 23132 invoked by uid 1616); 22 Sep 2003 20:06:00 -0000 Date: 22 Sep 2003 20:06:00 -0000 Message-ID: <20030922200600.23131.qmail@minotaur.apache.org> From: hlship@apache.org To: jakarta-commons-sandbox-cvs@apache.org Subject: cvs commit: jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/rules TestClassTranslator.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N hlship 2003/09/22 13:06:00 Modified: hivemind/framework/src/java/org/apache/commons/hivemind/impl DefaultClassResolver.java DeferredServiceExtensionPointImpl.java RegistryBuilder.java ConfigurationImpl.java ServiceInterceptorContributionImpl.java ThreadedServiceExtensionPointImpl.java hivemind/framework/src/test/hivemind/test/services TestServices.java TestThreadedModel.java hivemind/framework/src/test/hivemind/test/parse TestDescriptorParser.java TestToString.java hivemind/framework/src/java/org/apache/commons/hivemind/parse ModuleDescriptor.java hivemind/framework/src/test/hivemind/test TestMisc.java hivemind/framework/src/test/hivemind/test/rules TestClassTranslator.java Added: hivemind/framework/src/java/org/apache/commons/hivemind/impl ProxyBuilder.java SingletonServiceExtensionPointImpl.java AbstractServiceExtensionPoint.java Removed: hivemind/framework/src/java/org/apache/commons/hivemind/impl ServiceExtensionPointImpl.java Log: Refactor the three service point implementations. Split out most code-generation logic into new class, ProxyBuilder. Change the implementation of the deferred service model to use a pair of proxies (to avoid the need for synchronization). Remove some unused imports. Revision Changes Path 1.2 +1 -2 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/DefaultClassResolver.java Index: DefaultClassResolver.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/DefaultClassResolver.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DefaultClassResolver.java 16 Sep 2003 18:51:07 -0000 1.1 +++ DefaultClassResolver.java 22 Sep 2003 20:05:59 -0000 1.2 @@ -58,7 +58,6 @@ package org.apache.commons.hivemind.impl; import java.net.URL; -import java.util.Map; import org.apache.commons.hivemind.ApplicationRuntimeException; import org.apache.commons.hivemind.ClassResolver; 1.2 +91 -127 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/DeferredServiceExtensionPointImpl.java Index: DeferredServiceExtensionPointImpl.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/DeferredServiceExtensionPointImpl.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DeferredServiceExtensionPointImpl.java 16 Sep 2003 18:51:07 -0000 1.1 +++ DeferredServiceExtensionPointImpl.java 22 Sep 2003 20:05:59 -0000 1.2 @@ -58,26 +58,21 @@ package org.apache.commons.hivemind.impl; import java.lang.reflect.Constructor; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.hivemind.ApplicationRuntimeException; -import org.apache.commons.hivemind.HiveMind; -import org.apache.commons.hivemind.Registry; import org.apache.commons.hivemind.service.BodyBuilder; import org.apache.commons.hivemind.service.ClassFab; -import org.apache.commons.hivemind.service.ClassFabUtils; -import org.apache.commons.hivemind.service.ClassFactory; /** - * Subclass of {@link org.apache.commons.hivemind.impl.ServiceExtensionPointImpl} + * Subclass of {@link org.apache.commons.hivemind.impl.SingletonServiceExtensionPointImpl} * which supports creation of a deferred service proxy (deferring the actual * construction of the service until absolutely necessary). * * @author Howard Lewis Ship * @version $Id$ */ -public class DeferredServiceExtensionPointImpl extends ServiceExtensionPointImpl +public class DeferredServiceExtensionPointImpl extends AbstractServiceExtensionPoint { /** * Name of a method in the deferred proxy that is used to obtain @@ -86,37 +81,25 @@ protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service"; private Object _serviceProxy; + private Object _constructedService; - /** - * Invokes {@link ServiceExtensionPointImpl#constructServiceImplementation()} - * and clears the deferred proxy. This method is, itself, invoked - * by the deferred proxy. - * - */ - public Object constructServiceImplementation() + public synchronized Object getService() { - Object result = super.constructServiceImplementation(); + if (_constructedService != null) + return _constructedService; - // After succesfully constructing the service implementation, - // we don't need the proxy any more. - - _serviceProxy = null; - - return result; + return getServiceProxy(); } /** - * Returns the constructed service if it exists; otherwise, - * returns a deferred proxy for the service. + * This is invoked by the proxy to create the actual implementation. */ - protected synchronized Object getService() + public synchronized Object getServiceImplementation() { - Object result = super.getService(); - - if (result == null) - result = getServiceProxy(); + if (_constructedService == null) + _constructedService = constructServiceImplementation(); - return result; + return _constructedService; } /** @@ -127,7 +110,7 @@ protected Object getServiceProxy() { if (_serviceProxy == null) - _serviceProxy = createServiceProxyClass(); + _serviceProxy = createDeferredProxy(); return _serviceProxy; } @@ -135,7 +118,7 @@ /** * Creates a proxy class for the service and then constructs the class itself. */ - private Object createServiceProxyClass() + private Object createDeferredProxy() { checkBuilding(); @@ -143,11 +126,28 @@ { setBuilding(true); + // Create the outer proxy, the one visible to client code (including + // other services). It is dependent on an inner proxy. + Class proxyClass = createDeferredProxyClass(); + + // Create the inner proxy, whose job is to replace itself + // when the first service method is invoked. + + Class innerProxyClass = createInnerProxyClass(proxyClass); + + // Create the outer proxy. + + Object result = proxyClass.newInstance(); + + // The inner proxy's construct invokes a method on the + // outer proxy to connect the two. + + Constructor c = innerProxyClass.getConstructor(new Class[] { proxyClass, getClass()}); - Constructor c = proxyClass.getConstructor(new Class[] { getClass()}); + c.newInstance(new Object[] { result, this }); - return c.newInstance(new Object[] { this }); + return result; } catch (Exception ex) { @@ -168,123 +168,87 @@ */ private Class createDeferredProxyClass() { - Registry registry = getModule().getRegistry(); + ProxyBuilder builder = new ProxyBuilder("DeferredProxy", this); - ClassFactory factory = - (ClassFactory) registry.getService("hivemind.ClassFactory", ClassFactory.class); - - String className = ClassFabUtils.generateClassName("Proxy"); - - ClassFab classFab = factory.newClass(className, Object.class, getModule()); + ClassFab classFab = builder.getClassFab(); Class serviceInterface = getServiceInterface(); + + // This will initally be the inner proxy, then switch over to the + // service implementation. + + classFab.addField("_inner", serviceInterface); - classFab.addInterface(serviceInterface); - - addConstructor(classFab); - - addServiceAccessor(classFab, serviceInterface); + classFab.addMethod( + Modifier.PUBLIC | Modifier.SYNCHRONIZED | Modifier.FINAL, + "_setInner", + Void.TYPE, + new Class[] { serviceInterface }, + null, + "{ _inner = $1; }"); - addServiceMethods(classFab, serviceInterface); + builder.addServiceMethods("_inner"); return classFab.createClass(); } - /** - * Adds a field, _serviceExtensionPoint, whose type - * matches this class, and a constructor which sets - * the field. - */ - protected void addConstructor(ClassFab classFab) + private Class createInnerProxyClass(Class deferredProxyClass) { + Class serviceInterface = getServiceInterface(); + ProxyBuilder builder = new ProxyBuilder("InnerProxy", this); + + ClassFab classFab = builder.getClassFab(); + + classFab.addField("_deferredProxy", deferredProxyClass); + classFab.addField("_service", serviceInterface); classFab.addField("_serviceExtensionPoint", getClass()); + BodyBuilder body = new BodyBuilder(); + + // The constructor remembers the outer proxy and registers itself + // with the outer proxy. + + body.begin(); + body.addln("super();"); + body.addln("_deferredProxy = $1;"); + body.addln("_serviceExtensionPoint = $2;"); + body.addln("_deferredProxy._setInner(this);"); + body.end(); + classFab.addConstructor( - new Class[] { getClass()}, + new Class[] { deferredProxyClass, getClass()}, null, - "{ super(); _serviceExtensionPoint = $1; }"); - } + body.toString()); - /** - * Defines a instance variable, _service, of the right type; the created - * method (private, final, synchronized) lazily obtains a value for _service by - * invoking {@link #constructServiceImplementation()}. - */ - protected void addServiceAccessor(ClassFab classFab, Class serviceInterface) - { - classFab.addField("_service", serviceInterface); + // Method _service() will look up the service implementation, + // then update the deferred proxy to go directly to the + // service implementation, bypassing itself! + + body.clear(); + body.begin(); + body.add("if (_service == null)"); + body.begin(); + body.add("_service = ("); + body.add(serviceInterface.getName()); + body.addln(") _serviceExtensionPoint.getServiceImplementation();"); - BodyBuilder builder = new BodyBuilder(); + body.add("_deferredProxy._setInner(_service);"); + body.end(); - builder.begin(); - builder.addln("if (_service == null)"); - builder.begin(); - builder.add("_service = ("); - builder.add(serviceInterface.getName()); - builder.addln(") _serviceExtensionPoint.constructServiceImplementation();"); - builder.end(); - builder.add("return _service;"); - builder.end(); + body.add("return _service;"); + body.end(); classFab.addMethod( - Modifier.PRIVATE | Modifier.SYNCHRONIZED | Modifier.FINAL, - SERVICE_ACCESSOR_METHOD_NAME, + Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED, + "_service", serviceInterface, null, null, - builder.toString()); - } - - /** - * Adds service methods, and a toString() method as well. - * - */ - private void addServiceMethods(ClassFab classFab, Class serviceInterface) - { - boolean toString = false; - - Method[] methods = serviceInterface.getMethods(); - - BodyBuilder builder = new BodyBuilder(); - - for (int i = 0; i < methods.length; i++) - { - Method m = methods[i]; + body.toString()); - String methodName = m.getName(); + builder.addServiceMethods("_service()"); - builder.clear(); - - builder.begin(); - - builder.add("return ($r) "); - builder.add(SERVICE_ACCESSOR_METHOD_NAME); - builder.add("()."); - builder.add(methodName); - builder.add("($$);"); - - builder.end(); - - classFab.addMethod( - Modifier.PUBLIC | Modifier.FINAL, - methodName, - m.getReturnType(), - m.getParameterTypes(), - m.getExceptionTypes(), - builder.toString()); - - toString |= ClassFabUtils.isToString(m); - } - - if (!toString) - createToString(classFab, serviceInterface); - } - - private void createToString(ClassFab classFab, Class serviceInterface) - { - ClassFabUtils.addToStringMethod( - classFab, - ""); + return classFab.createClass(); } } 1.4 +17 -15 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/RegistryBuilder.java Index: RegistryBuilder.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/RegistryBuilder.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- RegistryBuilder.java 18 Sep 2003 20:08:59 -0000 1.3 +++ RegistryBuilder.java 22 Sep 2003 20:05:59 -0000 1.4 @@ -75,8 +75,8 @@ import org.apache.commons.hivemind.Occurances; import org.apache.commons.hivemind.Registry; import org.apache.commons.hivemind.Resource; -import org.apache.commons.hivemind.parse.ContributionDescriptor; import org.apache.commons.hivemind.parse.ConfigurationPointDescriptor; +import org.apache.commons.hivemind.parse.ContributionDescriptor; import org.apache.commons.hivemind.parse.DescriptorParser; import org.apache.commons.hivemind.parse.ImplementationDescriptor; import org.apache.commons.hivemind.parse.InstanceBuilder; @@ -132,7 +132,7 @@ private Map _modules = new HashMap(); /** - * Map of {@link ServiceExtensionPointImpl} (or subclass) keyed on fully qualified id. + * Map of {@link SingletonServiceExtensionPointImpl} (or subclass) keyed on fully qualified id. */ private Map _servicePoints = new HashMap(); @@ -326,7 +326,7 @@ // whether the service is create-on-first-reference // or create-on-first-use (deferred). - ServiceExtensionPointImpl point = null; + AbstractServiceExtensionPoint point = null; ServiceModel model = sd.getModel(); @@ -336,7 +336,7 @@ if (model == ServiceModel.THREADED) point = new ThreadedServiceExtensionPointImpl(); else - point = new ServiceExtensionPointImpl(); + point = new SingletonServiceExtensionPointImpl(); point.setExtensionPointId(pointId); point.setLocation(sd.getLocation()); @@ -388,7 +388,10 @@ } } - private void addContributionElements(Module sourceModule, ConfigurationPointImpl point, List elements) + private void addContributionElements( + Module sourceModule, + ConfigurationPointImpl point, + List elements) { if (size(elements) == 0) return; @@ -589,7 +592,8 @@ if (LOG.isDebugEnabled()) LOG.debug("Adding " + builder + " to service extension point " + pointId); - ServiceExtensionPointImpl sep = (ServiceExtensionPointImpl) _servicePoints.get(pointId); + AbstractServiceExtensionPoint sep = + (AbstractServiceExtensionPoint) _servicePoints.get(pointId); if (sep == null) { @@ -616,15 +620,13 @@ sep.setServiceConstructor(builder.createConstructor(sep, sourceModule)); } - private void addInterceptor( - ModuleImpl sourceModule, - String pointId, - InterceptorDescriptor id) + private void addInterceptor(ModuleImpl sourceModule, String pointId, InterceptorDescriptor id) { if (LOG.isDebugEnabled()) LOG.debug("Adding " + id + " to service extension point " + pointId); - ServiceExtensionPointImpl sep = (ServiceExtensionPointImpl) _servicePoints.get(pointId); + AbstractServiceExtensionPoint sep = + (AbstractServiceExtensionPoint) _servicePoints.get(pointId); if (sep == null) { @@ -659,7 +661,7 @@ Iterator i = _servicePoints.values().iterator(); while (i.hasNext()) { - ServiceExtensionPointImpl point = (ServiceExtensionPointImpl) i.next(); + AbstractServiceExtensionPoint point = (AbstractServiceExtensionPoint) i.next(); if (point.getServiceConstructor() != null) continue; @@ -747,9 +749,9 @@ { ClassResolver resolver = new DefaultClassResolver(); RegistryBuilder builder = new RegistryBuilder(); - + builder.processModules(resolver); - + return builder.constructRegistry(Locale.getDefault()); } 1.2 +1 -2 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ConfigurationImpl.java Index: ConfigurationImpl.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ConfigurationImpl.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ConfigurationImpl.java 18 Sep 2003 19:00:58 -0000 1.1 +++ ConfigurationImpl.java 22 Sep 2003 20:05:59 -0000 1.2 @@ -61,7 +61,6 @@ import java.util.Collections; import java.util.List; -import org.apache.commons.hivemind.Element; import org.apache.commons.hivemind.Configuration; import org.apache.commons.hivemind.Module; 1.2 +1 -2 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ServiceInterceptorContributionImpl.java Index: ServiceInterceptorContributionImpl.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ServiceInterceptorContributionImpl.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ServiceInterceptorContributionImpl.java 16 Sep 2003 18:51:07 -0000 1.1 +++ ServiceInterceptorContributionImpl.java 22 Sep 2003 20:06:00 -0000 1.2 @@ -64,7 +64,6 @@ import org.apache.commons.hivemind.Module; import org.apache.commons.hivemind.Registry; import org.apache.commons.hivemind.ServiceExtensionPoint; -import org.apache.commons.hivemind.ServiceImplementationFactory; import org.apache.commons.hivemind.ServiceInterceptorContribution; import org.apache.commons.hivemind.ServiceInterceptorFactory; import org.apache.commons.hivemind.schema.Schema; 1.2 +98 -8 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ThreadedServiceExtensionPointImpl.java Index: ThreadedServiceExtensionPointImpl.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ThreadedServiceExtensionPointImpl.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ThreadedServiceExtensionPointImpl.java 16 Sep 2003 18:51:07 -0000 1.1 +++ ThreadedServiceExtensionPointImpl.java 22 Sep 2003 20:06:00 -0000 1.2 @@ -57,10 +57,10 @@ package org.apache.commons.hivemind.impl; +import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; +import org.apache.commons.hivemind.ApplicationRuntimeException; import org.apache.commons.hivemind.Registry; import org.apache.commons.hivemind.service.BodyBuilder; import org.apache.commons.hivemind.service.ClassFab; @@ -78,15 +78,22 @@ * @author Howard Lewis Ship * @version $Id$ */ -public class ThreadedServiceExtensionPointImpl extends DeferredServiceExtensionPointImpl +public class ThreadedServiceExtensionPointImpl extends AbstractServiceExtensionPoint { + /** + * Name of a method in the deferred proxy that is used to obtain + * the constructed service. + */ + protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service"; + + private Object _constructedService; + private Object _serviceProxy; private ThreadEventNotifier _notifier; class CleanupListener implements ThreadCleanupListener { public void threadDidCleanup() { - _notifier.removeThreadCleanupListener(this); discardActiveService(); @@ -107,21 +114,100 @@ } /** + * Returns the proxy, creating it if necessary. + * + */ + + protected Object getServiceProxy() + { + if (_serviceProxy == null) + _serviceProxy = createServiceProxy(); + + return _serviceProxy; + } + + /** + * Creates a proxy class for the service and then constructs the class itself. + */ + private Object createServiceProxy() + { + checkBuilding(); + + try + { + setBuilding(true); + + Class proxyClass = createDeferredProxyClass(); + + Constructor c = proxyClass.getConstructor(new Class[] { getClass()}); + + return c.newInstance(new Object[] { this }); + } + catch (Exception ex) + { + throw new ApplicationRuntimeException(ex); + } + finally + { + setBuilding(false); + } + + } + + /** + * Creates a class that implements the service interface. Implements + * a private synchronized method, _service(), that constructs the service + * as needed, and has each service interface method re-invoke on _service(). + * Adds a toString() method if the service interface does not define toString(). + */ + private Class createDeferredProxyClass() + { + ProxyBuilder builder = new ProxyBuilder("ThreadedProxy", this); + + ClassFab classFab = builder.getClassFab(); + + addConstructor(classFab); + + addServiceAccessor(classFab); + + builder.addServiceMethods(SERVICE_ACCESSOR_METHOD_NAME + "()"); + + return classFab.createClass(); + } + + /** + * Adds a field, _serviceExtensionPoint, whose type + * matches this class, and a constructor which sets + * the field. + */ + protected void addConstructor(ClassFab classFab) + { + classFab.addField("_serviceExtensionPoint", getClass()); + + classFab.addConstructor( + new Class[] { getClass()}, + null, + "{ super(); _serviceExtensionPoint = $1; }"); + } + + /** * Here's the difference between a threaded service mode (this class) and a merely * deferred one. The {@link DeferredServiceExtensionPointImpl} implementation * gets the actual service implementation in the generated method. Here we * construct a method that always goes through the service extension point's * {@link #obtainServiceImplementation()}. */ - protected void addServiceAccessor(ClassFab classFab, Class serviceInterface) + protected void addServiceAccessor(ClassFab classFab) { + Class serviceInterface = getServiceInterface(); + classFab.addField(SERVICE_ACCESSOR_METHOD_NAME, serviceInterface); BodyBuilder builder = new BodyBuilder(); builder.add("return ("); builder.add(serviceInterface.getName()); - builder.add(") _serviceExtensionPoint.obtainServiceImplementation();"); + builder.add(") _serviceExtensionPoint.getServiceImplementation();"); classFab.addMethod( Modifier.PRIVATE | Modifier.FINAL, @@ -137,7 +223,7 @@ * the active service impl for this thread, * constructing it as necessary. */ - public synchronized Object obtainServiceImplementation() + public synchronized Object getServiceImplementation() { if (_activeService == null) _activeService = new ThreadLocal(); @@ -152,6 +238,10 @@ private Object constructServiceForCurrentThread() { + // Note: don't call constructServiceImplementation since that discards the + // service instance constructor and interceptor contributions; we need + // to be able to build new instances of the service again and again. + Object result = constructNewServiceImplementation(); if (_notifier == null) 1.1 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/ProxyBuilder.java Index: ProxyBuilder.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.hivemind.impl; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.hivemind.Module; import org.apache.commons.hivemind.Registry; import org.apache.commons.hivemind.ServiceExtensionPoint; import org.apache.commons.hivemind.service.BodyBuilder; import org.apache.commons.hivemind.service.ClassFab; import org.apache.commons.hivemind.service.ClassFabUtils; import org.apache.commons.hivemind.service.ClassFactory; /** * Class used to assist service extension points in creating proxies. * * @author Howard Lewis Ship * @version $Id: ProxyBuilder.java,v 1.1 2003/09/22 20:05:59 hlship Exp $ */ public class ProxyBuilder { private ServiceExtensionPoint _point; private Class _serviceInterface; private ClassFab _classFab; private String _type; ProxyBuilder(String type, ServiceExtensionPoint point) { _point = point; _type = type; _serviceInterface = point.getServiceInterface(); Module module = point.getModule(); Registry registry = module.getRegistry(); ClassFactory factory = (ClassFactory) registry.getService("hivemind.ClassFactory", ClassFactory.class); _classFab = factory.newClass(ClassFabUtils.generateClassName(type), Object.class, module); _classFab.addInterface(_serviceInterface); } public ClassFab getClassFab() { return _classFab; } /** * Creates the service methods for the class. * @parameter indirection the name of a variable, or a method invocation snippet, * used to redirect the invocation on the proxy to the actual service implementation. */ public void addServiceMethods(String indirection) { BodyBuilder builder = new BodyBuilder(); boolean toString = false; Method[] methods = _serviceInterface.getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; String methodName = m.getName(); builder.clear(); builder.begin(); builder.add("return ($r) "); builder.add(indirection); builder.add("."); builder.add(methodName); builder.addln("($$);"); builder.end(); _classFab.addMethod( Modifier.PUBLIC, methodName, m.getReturnType(), m.getParameterTypes(), m.getExceptionTypes(), builder.toString()); toString |= ClassFabUtils.isToString(m); } if (!toString) ClassFabUtils.addToStringMethod( _classFab, "<" + _type + " for " + _point.getExtensionPointId() + "(" + _serviceInterface.getName() + ")>"); } } 1.1 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/SingletonServiceExtensionPointImpl.java Index: SingletonServiceExtensionPointImpl.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.hivemind.impl; /** * Implementation of {@link org.apache.commons.hivemind.ServiceExtensionPoint}. * * @author Howard Lewis Ship * @version $Id: SingletonServiceExtensionPointImpl.java,v 1.1 2003/09/22 20:05:59 hlship Exp $ */ public class SingletonServiceExtensionPointImpl extends AbstractServiceExtensionPoint { private Object _constructedService; /** * Constructs the service (the first time this is invoked) * and returns it. */ protected synchronized Object getService() { if (_constructedService == null) _constructedService = constructServiceImplementation(); return _constructedService; } } 1.1 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/impl/AbstractServiceExtensionPoint.java Index: AbstractServiceExtensionPoint.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * */ package org.apache.commons.hivemind.impl; import java.util.ArrayList; import java.util.List; import org.apache.commons.hivemind.ApplicationRuntimeException; import org.apache.commons.hivemind.ClassResolver; import org.apache.commons.hivemind.HiveMind; import org.apache.commons.hivemind.Initializable; import org.apache.commons.hivemind.ServiceExtensionPoint; import org.apache.commons.hivemind.ServiceImplementationConstructor; import org.apache.commons.hivemind.ServiceInterceptorContribution; import org.apache.commons.hivemind.schema.Schema; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Abstract implementation of {@link org.apache.commons.hivemind.ServiceExtensionPoint} * that provides most of the machinery for creating new services ... subclasses * implement different service models; the service models determine when the * service is actually constructed. * * @author Howard Lewis Ship * @version $Id: AbstractServiceExtensionPoint.java,v 1.1 2003/09/22 20:06:00 hlship Exp $ */ public abstract class AbstractServiceExtensionPoint extends AbstractExtensionPoint implements ServiceExtensionPoint { private static final Log LOG = LogFactory.getLog(AbstractServiceExtensionPoint.class); private String _serviceInterfaceName; private boolean _building; private Class _serviceInterface; private ServiceImplementationConstructor _serviceConstructor; private List _interceptorContributions; private boolean _interceptorsSorted; private Schema _parametersSchema; protected void extendDescription(ToStringBuilder builder) { builder.append("serviceInterfaceName", _serviceInterfaceName); builder.append("factoryContribution", _serviceConstructor); builder.append("interceptorContributions", _interceptorContributions); builder.append("parametersSchema", _parametersSchema); } public void addInterceptorContribution(ServiceInterceptorContribution contribution) { if (_interceptorContributions == null) _interceptorContributions = new ArrayList(); _interceptorContributions.add(contribution); } public String getServiceInterfaceName() { return _serviceInterfaceName; } public synchronized Class getServiceInterface() { if (_serviceInterface == null) _serviceInterface = lookupServiceInterface(); return _serviceInterface; } private Class lookupServiceInterface() { ClassResolver resolver = getModule().getClassResolver(); Class result = null; try { result = resolver.findClass(_serviceInterfaceName); } catch (Exception ex) { throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.bad-interface", _serviceInterfaceName, getExtensionPointId()), getLocation(), ex); } if (!result.isInterface()) throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.interface-required", _serviceInterfaceName, getExtensionPointId()), getLocation(), null); return result; } public void setServiceConstructor(ServiceImplementationConstructor contribution) { _serviceConstructor = contribution; } public void setServiceInterfaceName(String string) { _serviceInterfaceName = string; } public void setParametersSchema(Schema schema) { _parametersSchema = schema; } public void setInterceptorContributions(List interceptorContributions) { _interceptorContributions = interceptorContributions; } protected Object addInterceptors(Object core) { if (_interceptorContributions == null || _interceptorContributions.size() == 0) return core; if (!_interceptorsSorted) { _interceptorContributions = HiveMind.sortOrderables(_interceptorContributions); _interceptorsSorted = true; } int count = _interceptorContributions.size(); InterceptorStackImpl stack = new InterceptorStackImpl(this, core); for (int i = 0; i < count; i++) { ServiceInterceptorContribution ic = (ServiceInterceptorContribution) _interceptorContributions.get(i); stack.process(ic); } // Whatever's on top is the final service. return stack.peek(); } protected void setBuilding(boolean building) { _building = building; } public Schema getParametersSchema() { return _parametersSchema; } public ServiceImplementationConstructor getServiceConstructor() { return _serviceConstructor; } /** * Checks the {@link #isBuilding() building flag}, throwing an exception * if true; this is used to detect unresolvable build cycles (which are * now very rare, since most services use deferred service model). */ protected void checkBuilding() { if (_building) throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.recursive-service-build", getExtensionPointId())); } /** * Constructs the core service implementation (by invoking the * {@link ServiceImplementationConstructor}), and checks * that the result is non-null and assignable * to the service interface. */ protected Object constructCoreServiceImplementation() { Class serviceType = getServiceInterface(); ServiceImplementationConstructor constructor = getServiceConstructor(); Object result = constructor.constructCoreServiceImplementation(); if (result == null) throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.factory-returned-null", getExtensionPointId()), constructor.getLocation(), null); if (!serviceType.isAssignableFrom(result.getClass())) throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.factory-wrong-interface", getExtensionPointId(), result, serviceType.getName()), constructor.getLocation(), null); return result; } /** * Invoked after the service has been constructed to utilize * the {@link Initializable} call back interface, if the * core implementation implements it. */ protected void initializeCoreServiceImplementation(Object core, Object intercepted) { if (core instanceof Initializable) { Initializable initializeCore = (Initializable) core; initializeCore.initializeService(intercepted); } } /** * Constructs the service implementation; this is invoked * from {@link #getService(Class)} and from the generated * deferrable proxy. Primarily, invokes * {@link #constructNewServiceImplementation()} from * within a block that checks for recursive builds. */ protected Object constructServiceImplementation() { checkBuilding(); Object result = null; try { setBuilding(true); result = constructNewServiceImplementation(); // After succesfully building, we don't need // some of the definition stuff again. setServiceConstructor(null); setInterceptorContributions(null); } finally { setBuilding(false); } return result; } /** * Constructs a new implementation of the service, starting with * a core implementation, then adding any interceptors. */ protected Object constructNewServiceImplementation() { try { if (LOG.isDebugEnabled()) LOG.debug("Constructing core instance for service " + getExtensionPointId()); Object core = constructCoreServiceImplementation(); Object intercepted = addInterceptors(core); initializeCoreServiceImplementation(core, intercepted); return intercepted; } catch (Exception ex) { throw new ApplicationRuntimeException( HiveMind.format( "ServiceExtensionPoint.unable-to-construct-service", getExtensionPointId(), ex.getMessage()), ex); } } /** * Invoked by {@link #getService(Class)} to get a service implementation or proxy. * Implemented in subclasses to return either the actual service, or some form of * service proxy, depending on the servce model and the state of the extension point. * */ protected abstract Object getService(); public Object getService(Class serviceInterface) { Object result = getService(); if (!serviceInterface.isAssignableFrom(result.getClass())) { throw new ApplicationRuntimeException( HiveMind.format( "BaseModule.service-wrong-interface", getExtensionPointId(), serviceInterface.getName(), getServiceInterfaceName()), getLocation(), null); } return result; } } 1.4 +2 -2 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestServices.java Index: TestServices.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestServices.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestServices.java 19 Sep 2003 22:10:58 -0000 1.3 +++ TestServices.java 22 Sep 2003 20:06:00 -0000 1.4 @@ -121,7 +121,7 @@ CountFactory.reset(); assertEquals( - "", + "", s.toString()); assertEquals(7, s.add(4, 3)); 1.3 +1 -3 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestThreadedModel.java Index: TestThreadedModel.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/services/TestThreadedModel.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- TestThreadedModel.java 19 Sep 2003 18:25:19 -0000 1.2 +++ TestThreadedModel.java 22 Sep 2003 20:06:00 -0000 1.3 @@ -57,8 +57,6 @@ package hivemind.test.services; -import java.util.List; - import hivemind.test.FrameworkTestCase; import org.apache.commons.hivemind.Registry; @@ -116,7 +114,7 @@ assertNull(h.getValue()); assertEquals( - "", + "", h.toString()); assertLoggedMessages( 1.4 +2 -3 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/parse/TestDescriptorParser.java Index: TestDescriptorParser.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/parse/TestDescriptorParser.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestDescriptorParser.java 19 Sep 2003 18:25:20 -0000 1.3 +++ TestDescriptorParser.java 22 Sep 2003 20:06:00 -0000 1.4 @@ -69,10 +69,9 @@ import org.apache.commons.hivemind.Attribute; import org.apache.commons.hivemind.Element; import org.apache.commons.hivemind.Occurances; -import org.apache.commons.hivemind.parse.ContributionDescriptor; import org.apache.commons.hivemind.parse.ConfigurationPointDescriptor; +import org.apache.commons.hivemind.parse.ContributionDescriptor; import org.apache.commons.hivemind.parse.CreateInstanceDescriptor; -import org.apache.commons.hivemind.parse.DescriptorParser; import org.apache.commons.hivemind.parse.ImplementationDescriptor; import org.apache.commons.hivemind.parse.InterceptorDescriptor; import org.apache.commons.hivemind.parse.ModuleDescriptor; 1.4 +8 -9 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/parse/TestToString.java Index: TestToString.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/parse/TestToString.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestToString.java 19 Sep 2003 18:25:20 -0000 1.3 +++ TestToString.java 22 Sep 2003 20:06:00 -0000 1.4 @@ -61,23 +61,22 @@ import java.util.Locale; -import org.apache.commons.hivemind.ConfigurationPoint; import org.apache.commons.hivemind.Location; import org.apache.commons.hivemind.Module; import org.apache.commons.hivemind.ServiceExtensionPoint; import org.apache.commons.hivemind.impl.AttributeImpl; -import org.apache.commons.hivemind.impl.InterceptorStackImpl; -import org.apache.commons.hivemind.impl.ModuleImpl; -import org.apache.commons.hivemind.impl.ElementImpl; import org.apache.commons.hivemind.impl.ConfigurationImpl; import org.apache.commons.hivemind.impl.ConfigurationPointImpl; +import org.apache.commons.hivemind.impl.ElementImpl; +import org.apache.commons.hivemind.impl.InterceptorStackImpl; +import org.apache.commons.hivemind.impl.ModuleImpl; import org.apache.commons.hivemind.impl.RegistryImpl; -import org.apache.commons.hivemind.impl.ServiceExtensionPointImpl; import org.apache.commons.hivemind.impl.ServiceInterceptorContributionImpl; +import org.apache.commons.hivemind.impl.SingletonServiceExtensionPointImpl; +import org.apache.commons.hivemind.parse.ConfigurationPointDescriptor; +import org.apache.commons.hivemind.parse.ContributionDescriptor; import org.apache.commons.hivemind.parse.CreateInstanceDescriptor; import org.apache.commons.hivemind.parse.ImplementationDescriptor; -import org.apache.commons.hivemind.parse.ContributionDescriptor; -import org.apache.commons.hivemind.parse.ConfigurationPointDescriptor; import org.apache.commons.hivemind.parse.InterceptorDescriptor; import org.apache.commons.hivemind.parse.InvokeFactoryDescriptor; import org.apache.commons.hivemind.parse.ModuleDescriptor; @@ -150,7 +149,7 @@ new ElementImpl().toString(); new AttributeImpl("foo", "bar").toString(); new ServiceInterceptorContributionImpl().toString(); - new ServiceExtensionPointImpl().toString(); + new SingletonServiceExtensionPointImpl().toString(); new InterceptorStackImpl(new MockServiceExtensionPoint(), null).toString(); } } 1.3 +1 -3 jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/parse/ModuleDescriptor.java Index: ModuleDescriptor.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/java/org/apache/commons/hivemind/parse/ModuleDescriptor.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ModuleDescriptor.java 18 Sep 2003 19:01:00 -0000 1.2 +++ ModuleDescriptor.java 22 Sep 2003 20:06:00 -0000 1.3 @@ -58,10 +58,8 @@ package org.apache.commons.hivemind.parse; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import org.apache.commons.hivemind.HiveMind; import org.apache.commons.hivemind.impl.BaseLocatable; import org.apache.commons.lang.builder.ToStringBuilder; 1.5 +3 -3 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/TestMisc.java Index: TestMisc.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/TestMisc.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- TestMisc.java 19 Sep 2003 22:10:59 -0000 1.4 +++ TestMisc.java 22 Sep 2003 20:06:00 -0000 1.5 @@ -73,7 +73,7 @@ import org.apache.commons.hivemind.impl.CreateClassServiceConstructor; import org.apache.commons.hivemind.impl.InvokeFactoryServiceConstructor; import org.apache.commons.hivemind.impl.ModuleImpl; -import org.apache.commons.hivemind.impl.ServiceExtensionPointImpl; +import org.apache.commons.hivemind.impl.SingletonServiceExtensionPointImpl; import org.apache.commons.hivemind.impl.SystemPropertiesSymbolSource; /** @@ -172,7 +172,7 @@ public void testInvokeFactoryServiceConstructorAccessors() { Module m = new ModuleImpl(); - ServiceExtensionPoint sep = new ServiceExtensionPointImpl(); + ServiceExtensionPoint sep = new SingletonServiceExtensionPointImpl(); List p = new ArrayList(); InvokeFactoryServiceConstructor c = new InvokeFactoryServiceConstructor(); 1.4 +1 -2 jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/rules/TestClassTranslator.java Index: TestClassTranslator.java =================================================================== RCS file: /home/cvs/jakarta-commons-sandbox/hivemind/framework/src/test/hivemind/test/rules/TestClassTranslator.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- TestClassTranslator.java 19 Sep 2003 18:25:19 -0000 1.3 +++ TestClassTranslator.java 22 Sep 2003 20:06:00 -0000 1.4 @@ -68,7 +68,6 @@ import org.apache.commons.hivemind.impl.LocationImpl; import org.apache.commons.hivemind.schema.SchemaProcessor; import org.apache.commons.hivemind.schema.rules.ClassTranslator; -import org.apache.commons.hivemind.schema.rules.RuleUtils; /** * Fill in some gaps in