hivemind-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ahue...@apache.org
Subject svn commit: r447572 - in /hivemind/branches/branch-2-0-annot: framework/src/java/org/apache/hivemind/impl/ xml/src/test/hivemind/test/config/
Date Mon, 18 Sep 2006 21:29:43 GMT
Author: ahuegen
Date: Mon Sep 18 14:29:43 2006
New Revision: 447572

URL: http://svn.apache.org/viewvc?view=rev&rev=447572
Log:
Generate generic proxies so that all kind of configurations types support lazy construction


Modified:
    hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ConfigurationPointImpl.java
    hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java
    hivemind/branches/branch-2-0-annot/xml/src/test/hivemind/test/config/TestConfigurationPoint.java

Modified: hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ConfigurationPointImpl.java
URL: http://svn.apache.org/viewvc/hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ConfigurationPointImpl.java?view=diff&rev=447572&r1=447571&r2=447572
==============================================================================
--- hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ConfigurationPointImpl.java
(original)
+++ hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ConfigurationPointImpl.java
Mon Sep 18 14:29:43 2006
@@ -14,18 +14,26 @@
 
 package org.apache.hivemind.impl;
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.HiveMind;
 import org.apache.hivemind.Occurances;
 import org.apache.hivemind.ShutdownCoordinator;
 import org.apache.hivemind.definition.ContributionDefinition;
+import org.apache.hivemind.impl.servicemodel.SingletonInnerProxy;
 import org.apache.hivemind.internal.ConfigurationConstructor;
 import org.apache.hivemind.internal.ConfigurationPoint;
 import org.apache.hivemind.internal.Contribution;
+import org.apache.hivemind.service.BodyBuilder;
+import org.apache.hivemind.service.ClassFab;
+import org.apache.hivemind.service.InterfaceSynthesizer;
+import org.apache.hivemind.service.MethodSignature;
 import org.apache.hivemind.util.ToStringBuilder;
 
 /**
@@ -95,6 +103,14 @@
     {
         _expectedCount = occurances;
     }
+    
+    public boolean isLazy()
+    {
+        // TODO annotations: make configurable
+        // exclude ServiceModels, otherwise a cycle occurs because the proxy generation
+        // requires the {@link ClassFactory service}
+        return !getExtensionPointId().equals("hivemind.ServiceModels");
+    }
 
     /**
      * @see org.apache.hivemind.internal.ConfigurationPoint#getContainer()
@@ -104,22 +120,29 @@
         if (_container != null)
             return _container;
 
-        // TODO: implement generic proxy for all kind of containers
-//        if (_containerProxy == null)
-//        {
-//            ElementsProxyList outerProxy = new ElementsProxyList();
-//
-//            new ElementsInnerProxyList(this, outerProxy);
-//
-//            _shutdownCoordinator.addRegistryShutdownListener(outerProxy);
-//
-//            _containerProxy = outerProxy;
-//        }
-
-        return constructContainer();
+        if (isLazy()) {
+            // Configuration is lazy, so return a proxy that generates the configuration
+            // the first time a member method is called
+            if (_containerProxy == null)
+            {
+                _containerProxy = createSingletonProxy();
+            }
+            return _containerProxy;
+            
+        } else {
+            // construct the container immediately
+            _container = constructContainer();
+            return _container;
+        }
     }
 
-    synchronized Object constructContainer()
+    /**
+     * Called by the proxy responsible for lazy construction of the configuration when 
+     * the first time a method of the container proxy is called. 
+     * Generates the real configuration container object and stores it in a field.
+     * Must be public so the proxy can access it.
+     */
+    public synchronized Object constructContainer()
     {
         // It's nice to have this protection, but (unlike services), you
         // would really have to go out of your way to provoke
@@ -240,4 +263,183 @@
         _constructor = constructor;
     }
     
+    /**
+     * @return  the interface of the configuration container. if the container class is an
+     *          interface already it's returned instantly. If it is a pojo, then an interface
+     *          is generated by {@link InterfaceSynthesizer}.
+     */
+    private Class lookupContainerInterface()
+    {
+        Class declaredInterface = lookupContainerClass();
+
+        if (declaredInterface.isInterface())
+            return declaredInterface;
+
+        // Not an interface ... a class. Synthesize an interface from the class itself.
+
+        InterfaceSynthesizer is = (InterfaceSynthesizer) getModule().getService(
+                HiveMind.INTERFACE_SYNTHESIZER_SERVICE,
+                InterfaceSynthesizer.class);
+
+        return is.synthesizeInterface(declaredInterface);
+    }
+
+    /**
+     * Creates a proxy class for the service and then construct the class itself.
+     */
+    private Object createSingletonProxy()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Creating LazyConstructionProxy for configuration "
+                    + getExtensionPointId());
+
+        try
+        {
+
+            // Create the outer proxy, the one visible to client code (including
+            // other services). It is dependent on an inner proxy.
+
+            Class proxyClass = createSingletonProxyClass();
+
+            // 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() });
+
+            Object _innerProxy = (SingletonInnerProxy) c.newInstance(new Object[]
+            { result, this });
+
+            return result;
+        }
+        catch (Exception ex)
+        {
+            throw new ApplicationRuntimeException(ex);
+        }
+
+    }
+
+    /**
+     * Creates a class that implements the service interface. Implements a private synchronized
+     * method, _configuration(), that constructs the service as needed, and has each service
interface
+     * method re-invoke on _configuration(). Adds a toString() method if the service interface
does not
+     * define toString().
+     */
+    private Class createSingletonProxyClass()
+    {
+        Class configurationInterface = lookupContainerInterface();
+
+        ProxyBuilder proxyBuilder = new ProxyBuilder("LazyConstructionProxy", this, configurationInterface,
true);
+
+        ClassFab classFab = proxyBuilder.getClassFab();
+
+
+        // This will initally be the inner proxy, then switch over to the
+        // service implementation.
+
+        classFab.addField("_inner", configurationInterface);
+        classFab.addMethod(
+                Modifier.PUBLIC | Modifier.SYNCHRONIZED | Modifier.FINAL,
+                new MethodSignature(void.class, "_setInner", new Class[]
+                { configurationInterface }, null),
+                "{ _inner = $1; }");
+
+        BodyBuilder builder = new BodyBuilder();
+        builder.begin();
+
+        builder.addln("return _inner;");
+        builder.end();
+
+        classFab.addMethod(Modifier.PRIVATE, new MethodSignature(configurationInterface,
"_getInner",
+                null, null), builder.toString());
+
+        proxyBuilder.addServiceMethods("_getInner()");
+
+        return classFab.createClass();
+    }
+
+    private Class createInnerProxyClass(Class deferredProxyClass)
+    {
+        Class configurationInterface = lookupContainerInterface();
+        
+        ProxyBuilder builder = new ProxyBuilder("InnerProxy", this, configurationInterface,
false);
+
+        ClassFab classFab = builder.getClassFab();
+
+        classFab.addField("_deferredProxy", deferredProxyClass);
+        classFab.addField("_configuration", configurationInterface);
+        classFab.addField("_configurationPoint", this.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("_configurationPoint = $2;");
+        body.addln("_deferredProxy._setInner(this);");
+
+        body.end();
+
+        classFab.addConstructor(new Class[]
+        { deferredProxyClass, getClass() }, null, body.toString());
+
+        // Method _configuration() 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 (_configuration == null)");
+        body.begin();
+
+        body.add("_configuration = (");
+        body.add(configurationInterface.getName());
+        body.addln(") _configurationPoint.constructContainer();");
+
+        body.add("_deferredProxy._setInner(_configuration);");
+
+        body.end();
+
+        body.add("return _configuration;");
+
+        body.end();
+
+        classFab.addMethod(
+                Modifier.PRIVATE | Modifier.FINAL | Modifier.SYNCHRONIZED,
+                new MethodSignature(configurationInterface, "_configuration", null, null),
+                body.toString());
+
+        builder.addServiceMethods("_configuration()");
+
+        // Build the implementation of interface SingletonInnerProxy
+
+        body.clear();
+        body.begin();
+
+        body.add("_configuration();");
+
+        body.end();
+
+        classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class,
+                "_instantiateServiceImplementation", null, null), body.toString());
+
+        classFab.addInterface(SingletonInnerProxy.class);
+
+        return classFab.createClass();
+    }
+
 }

Modified: hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java
URL: http://svn.apache.org/viewvc/hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java?view=diff&rev=447572&r1=447571&r2=447572
==============================================================================
--- hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java
(original)
+++ hivemind/branches/branch-2-0-annot/framework/src/java/org/apache/hivemind/impl/ProxyBuilder.java
Mon Sep 18 14:29:43 2006
@@ -17,6 +17,7 @@
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
 
+import org.apache.hivemind.internal.ConfigurationPoint;
 import org.apache.hivemind.internal.Module;
 import org.apache.hivemind.internal.ServicePoint;
 import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
@@ -28,13 +29,13 @@
 import org.apache.hivemind.service.MethodSignature;
 
 /**
- * Class used to assist service extension points in creating proxies.
+ * Class used to assist extension points in creating proxies.
  * 
  * @author Howard Lewis Ship
  */
 public final class ProxyBuilder
 {
-    private ServicePoint _point;
+    private String _extensionPointId;
 
     private Class _serviceInterface;
 
@@ -63,13 +64,40 @@
      */
     public ProxyBuilder(String type, ServicePoint point, boolean outerProxy)
     {
-        _point = point;
+        _extensionPointId = point.getExtensionPointId();
         _type = type;
-        _serviceInterface = point.getServiceInterface();
 
-        Class declaredInterface = point.getDeclaredInterface();
+        init(point.getModule(), point.getServiceInterface(), point.getDeclaredInterface(),
+                outerProxy);
+    }
+    
+    /**
+     * Constructs a new builder. The type will be incorporated into value returned by the
+     * <code>toString()</code> method. The configuration point is used to identify
the service
+     * interface and service id.
+     * 
+     * @param type
+     *            used as part of the <code>toString()</code> method's return
value
+     * @param point
+     *            the configuration point for which this proxy is being constructed
+     * @param outerProxy
+     *            if false, then the proxy can extend the configuration points service interface
always.
+     *            If true and the service point's declared interface is actually a bean class
(not
+     *            an interface), then the proxy will be a subclass of that bean.
+     */
+    public ProxyBuilder(String type, ConfigurationPoint point, Class serviceInterface, boolean
outerProxy)
+    {
+        _extensionPointId = point.getExtensionPointId();
+        _type = type;
+
+        init(point.getModule(), serviceInterface, point.getContainerType(),
+                outerProxy);
+    }
+    
+    private void init(Module module, Class serviceInterface, Class declaredInterface, boolean
outerProxy)
+    {
+        _serviceInterface = serviceInterface;
 
-        Module module = point.getModule();
         ClassFactory factory = (ClassFactory) module.getService(
                 "hivemind.ClassFactory",
                 ClassFactory.class);
@@ -86,7 +114,7 @@
         // are serializable!
 
         if (outerProxy)
-            addSerializable(point.getExtensionPointId());
+            addSerializable(_extensionPointId);
     }
 
     /** @since 1.1 */
@@ -142,6 +170,6 @@
 
         if (!mi.getToString())
             ClassFabUtils.addToStringMethod(_classFab, "<" + _type + " for "
-                    + _point.getExtensionPointId() + "(" + _serviceInterface.getName() +
")>");
+                    + _extensionPointId + "(" + _serviceInterface.getName() + ")>");
     }
 }

Modified: hivemind/branches/branch-2-0-annot/xml/src/test/hivemind/test/config/TestConfigurationPoint.java
URL: http://svn.apache.org/viewvc/hivemind/branches/branch-2-0-annot/xml/src/test/hivemind/test/config/TestConfigurationPoint.java?view=diff&rev=447572&r1=447571&r2=447572
==============================================================================
--- hivemind/branches/branch-2-0-annot/xml/src/test/hivemind/test/config/TestConfigurationPoint.java
(original)
+++ hivemind/branches/branch-2-0-annot/xml/src/test/hivemind/test/config/TestConfigurationPoint.java
Mon Sep 18 14:29:43 2006
@@ -321,7 +321,7 @@
 
         List l = (List) r.getConfiguration("hivemind.test.config.Simple");
 
-        assertEquals("<Element List Proxy for hivemind.test.config.Simple>", l.toString());
+        assertEquals("<LazyConstructionProxy for hivemind.test.config.Simple(java.util.List)>",
l.toString());
 
         assertEquals(true, l.equals(l));
         assertEquals(false, l.equals(null));



Mime
View raw message