You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hivemind.apache.org by ah...@apache.org on 2006/09/18 23:29:43 UTC
svn commit: r447572 - in /hivemind/branches/branch-2-0-annot:
framework/src/java/org/apache/hivemind/impl/
xml/src/test/hivemind/test/config/
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));