<block name="block-name" class="tes.TestBlock">
<proxy>
<interceptor class="test.TestInterceptor"/>
</proxy>
</block>It also adds support for block factories. In assemble.xml
<factory name="test-factory" class="test.Factory"/>
<block name="block-name"
factory="test-factory" impl="factory-specific-impl"/>Old block definition is supported as well.
There is a number of outstanding @todo items but most of them are of cosmetic nature (proper package names, proper exception classes and missing javadoc). One real issue is configuration of loggers for block factories -- now logs go into assembler's logger.
Could somebody who is in charge review the patch and comment on whether it will or will not be incorporated into the source code? Thank you.
Peter Donald wrote:
On Tue, 20 Aug 2002 23:13, Igor Fedorenko wrote:
Peter Donald wrote:
On Tue, 20 Aug 2002 00:59, Igor Fedorenko wrote:
Not exactly. Soap does not have to be java, so getting "all remote interfaces" of none-java service would be tricky. Of course, one could write a factory that is smart enough to map soap urls into java interfaces, but this sounds like hiding problems instead of solving them.
If that is the case you could still use the same interface with a slight modification
<block name="my-block-remote" impl="resource:/my/soap/descriptor.xml" factory="org.apache.avalon.factorys.SoapFactory"> </block>
In fact, I cheat here -- encode service definition into "impl".
So, lets say you've almost ;-) convinced me. I am going to implement this as well as invocation interceptors and will post a patch sometime later this week.
kool!
-- Igor Fedorenko Think smart. Think automated. Think Dynamics. www.thinkdynamics.com
Index: java/org/apache/avalon/phoenix/AbstractBlockFactory.java
===================================================================
RCS file: java/org/apache/avalon/phoenix/AbstractBlockFactory.java
diff -N java/org/apache/avalon/phoenix/AbstractBlockFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/AbstractBlockFactory.java 22 Aug 2002
18:56:08 -0000
@@ -0,0 +1,100 @@
+package org.apache.avalon.phoenix;
+
+import java.net.URL;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.phoenix.metainfo.BlockInfo;
+import org.apache.avalon.phoenix.tools.assembler.Assembler;
+import org.apache.avalon.phoenix.tools.configuration.ConfigurationBuilder;
+import org.apache.avalon.phoenix.tools.infobuilder.BlockInfoBuilder;
+
+/**
+ * @todo description
+ * @todo find a better package and do not forget to move messages!
+ *
+ * @author ifedorenko
+ */
+public abstract class AbstractBlockFactory extends AbstractLogEnabled
+ implements BlockFactory
+{
+ private static final Resources REZ =
+ ResourceManager.getPackageResources( Assembler.class );
+
+ private final BlockInfoBuilder m_builder = new BlockInfoBuilder();
+
+ public void enableLogging(Logger logger) {
+ super.enableLogging( logger );
+ m_builder.enableLogging( logger );
+ }
+
+ /**
+ * Get a BlockInfo for Block with specified name and classname.
+ * The BlockInfo may be loaded from the specified cache otherwise it must
be
+ * loaded from specified ClassLoader.
+ *
+ * @param name the name of Block
+ * @param classname the name of Blocks class
+ * @return the BlockInfo for specified block
+ * @throws AssemblyException if an error occurs
+ */
+ public BlockInfo getBlockInfo( final String name,
+ final String classname,
+ final ClassLoader classLoader,
+ final Configuration block )
+ throws ConfigurationException
+ {
+ final String resourceName = classname.replace( '.', '/' ) + ".xinfo";
+
+ final String notice = REZ.getString( "loading-blockinfo", resourceName
);
+ getLogger().debug( notice );
+
+ final URL resource = classLoader.getResource( resourceName );
+ if( null == resource )
+ {
+ final String message = REZ.getString( "blockinfo-missing", name,
resourceName );
+ throw new ConfigurationException( message );
+ }
+
+ try
+ {
+ final Configuration info = ConfigurationBuilder.build(
resource.toString() );
+
+ return m_builder.build( classname, info, block );
+ }
+ catch( final Exception e )
+ {
+ final String message =
+ REZ.getString( "blockinfo-nocreate", name, resourceName,
e.getMessage() );
+ throw new ConfigurationException( message, e );
+ }
+ }
+
+ /**
+ * @todo description
+ */
+ public String getConfigurationSchemaURL( final String name,
+ final String classname,
+ final ClassLoader classLoader )
+ throws ConfigurationException
+ {
+ final String resourceName = classname.replace( '.', '/' ) +
"-schema.xml";
+
+ final URL resource = classLoader.getResource( resourceName );
+ if( null == resource )
+ {
+
+ throw new ConfigurationException( REZ.getString(
"deploy.error.config.schema.missing",
+ name,
+ resourceName ) );
+ }
+ else
+ {
+ return resource.toString();
+ }
+ }
+}
Index: java/org/apache/avalon/phoenix/AstractChainedInvocable.java
===================================================================
RCS file: java/org/apache/avalon/phoenix/AstractChainedInvocable.java
diff -N java/org/apache/avalon/phoenix/AstractChainedInvocable.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/AstractChainedInvocable.java 22 Aug 2002
18:56:08 -0000
@@ -0,0 +1,83 @@
+package org.apache.avalon.phoenix;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+
+/**
+ * Subclasses of <code>AstractChainedInvocable</code> form chain of
+ * block invocation interceptors.
+ *
+ * <p>The idea is to be able to extend block's behaviour without changing
+ * block's code. One of usages of such interceptors would be
+ * <code>SecurityInterceptor</code> which verifies if a caller is allowed to
+ * perform requested operation on a block.</p>
+ *
+ * @author ifedorenko
+ */
+public abstract class AstractChainedInvocable extends AbstractLogEnabled
+ implements InvocationHandler
+{
+
+ private transient Object m_object;
+
+ private InvocationHandler m_chained;
+
+ public final void setObject( Object object )
+ {
+ m_object = object;
+ }
+
+ public final void setChained( InvocationHandler chained )
+ {
+ m_chained = chained;
+ }
+
+ /**
+ * @see java.lang.reflect.InvocationHandler#invoke(Object, Method,
Object[])
+ */
+ public Object invoke( final Object proxy,
+ final Method method,
+ final Object[] args )
+ throws Throwable
+ {
+ return ( m_chained != null )
+ ? m_chained.invoke( proxy, method, args )
+ : invokeObject( proxy, method, args );
+ }
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ private Object invokeObject( final Object proxy,
+ final Method method,
+ final Object[] args )
+ throws Throwable
+ {
+ if( null != m_object )
+ {
+ try
+ {
+ return method.invoke( m_object, args );
+ }
+ catch( final InvocationTargetException ite )
+ {
+ throw ite.getTargetException();
+ }
+ }
+ else
+ {
+ throw new IllegalStateException( "Using a stale object reference "
+ + "to call a disposed Block." );
+ }
+ }
+}
Index: java/org/apache/avalon/phoenix/BlockFactory.java
===================================================================
RCS file: java/org/apache/avalon/phoenix/BlockFactory.java
diff -N java/org/apache/avalon/phoenix/BlockFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/BlockFactory.java 22 Aug 2002 18:56:08
-0000
@@ -0,0 +1,42 @@
+package org.apache.avalon.phoenix;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.phoenix.metainfo.BlockInfo;
+
+/**
+ * @todo description
+ * @todo make sure that ConfigurationException is appropriate here
+ *
+ * @author ifedorenko
+ */
+public interface BlockFactory {
+
+ /**
+ * Get a BlockInfo for Block with specified name and classname.
+ * The BlockInfo may be loaded from the specified cache otherwise it must
be
+ * loaded from specified ClassLoader.
+ *
+ * @param name the name of Block
+ * @param impl
+ * @return the BlockInfo for specified block
+ * @throws ConfigurationException if an error occurs
+ */
+ public BlockInfo getBlockInfo( final String name,
+ final String impl,
+ final ClassLoader classLoader,
+ final Configuration block )
+ throws ConfigurationException;
+
+
+ public String getConfigurationSchemaURL( final String name,
+ final String impl,
+ final ClassLoader classLoader )
+ throws ConfigurationException;
+
+ /**
+ * @todo description
+ */
+ public Object createBlock( String impl, final ClassLoader classLoader )
+ throws ConfigurationException;
+}
Index: java/org/apache/avalon/phoenix/Invocable.java
===================================================================
RCS file: java/org/apache/avalon/phoenix/Invocable.java
diff -N java/org/apache/avalon/phoenix/Invocable.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/Invocable.java 22 Aug 2002 18:56:08
-0000
@@ -0,0 +1,26 @@
+package org.apache.avalon.phoenix;
+
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * Implementation of this interface indicates to phoenix that block's
+ * service methods should be called using reflection.
+ *
+ * <p>Blocks that implement this interface can be used as generic proxies
+ * to services available remotely. For example, one can develop
+ * <code>RemoteSoapService</code> block that can connect to any remote soap
+ * service.</p>
+ *
+ * <p><code>Invocable</code> interface can be used to implement late binding
+ * to remote services (i.e. establish remote connection when needed, not when
+ * a block is created).</p>
+ *
+ * <p><code>Invocable</code> and <code>ProxyProvider</code> are mutually
+ * exclusive.</p>
+ *
+ * @author ifedorenko
+ */
+public interface Invocable extends InvocationHandler
+{
+
+}
Index: java/org/apache/avalon/phoenix/ProxyProvider.java
===================================================================
RCS file: java/org/apache/avalon/phoenix/ProxyProvider.java
diff -N java/org/apache/avalon/phoenix/ProxyProvider.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/ProxyProvider.java 22 Aug 2002 18:56:08
-0000
@@ -0,0 +1,25 @@
+package org.apache.avalon.phoenix;
+
+/**
+ * Implementation of this interface indicates to phoenix that block's
+ * service methods should be called using proxy object provided by the block.
+ *
+ * <p>Blocks that implement this interface can be used as generic proxies
+ * to services available remotely. For example, one can develop
+ * <code>RemoteSoapService</code> block that can connect to any remote soap
+ * service.</p>
+ *
+ * <p><code>Invocable</code> and <code>ProxyProvider</code> are mutually
+ * exclusive.</p>
+ *
+ * @author ifedorenko
+ */
+public interface ProxyProvider
+{
+ /**
+ * Returns an object that implements block's service interface(s).
+ *
+ * @throws Exception if an object cannot be created
+ */
+ public Object getProxy() throws Exception;
+}
Index: java/org/apache/avalon/phoenix/components/application/BlockEntry.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/BlockEntry.java,v
retrieving revision 1.20
diff -u -r1.20 BlockEntry.java
--- java/org/apache/avalon/phoenix/components/application/BlockEntry.java
18 Aug 2002 08:23:33 -0000 1.20
+++ java/org/apache/avalon/phoenix/components/application/BlockEntry.java
22 Aug 2002 18:56:09 -0000
@@ -7,8 +7,14 @@
*/
package org.apache.avalon.phoenix.components.application;
+import java.lang.reflect.Proxy;
+
+import org.apache.avalon.framework.logger.LogEnabled;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.phoenix.*;
import org.apache.avalon.phoenix.metadata.BlockMetaData;
import org.apache.avalon.phoenix.metainfo.BlockInfo;
+import org.apache.avalon.phoenix.metainfo.InvocationInterceptorDescriptor;
import org.apache.avalon.phoenix.metainfo.ServiceDescriptor;
/**
@@ -20,6 +26,8 @@
{
private Object m_object;
+ private Object m_serviceObject;
+
private BlockMetaData m_blockMetaData;
private BlockInvocationHandler m_invocationHandler;
@@ -45,15 +53,22 @@
return m_object;
}
- public synchronized void setObject( final Object object )
+ public synchronized void setObject( final Object object,
+ final BlockResourceProvider
blockAccessor )
+ throws Exception
{
invalidate();
if( null != object && ! getMetaData().isDisableProxy() )
{
+ final ClassLoader classLoader = object.getClass().getClassLoader();
final BlockInfo blockInfo = getMetaData().getBlockInfo();
final Class[] interfaces = getServiceClasses( object,
blockInfo.getServices() );
- m_invocationHandler = new BlockInvocationHandler( object,
interfaces );
+ m_serviceObject = getServiceObject( classLoader, interfaces,
object );
+ m_invocationHandler = buildInvocationChain( classLoader,
+ interfaces,
+ m_serviceObject,
+ blockAccessor );
}
m_object = object;
}
@@ -62,7 +77,7 @@
{
if ( getMetaData().isDisableProxy() )
{
- return m_object;
+ return m_serviceObject;
}
else
{
@@ -77,6 +92,27 @@
}
}
+ /**
+ * Returns object that implements block's service interfaces
+ */
+ private Object getServiceObject( final ClassLoader classLoader,
+ final Class[] interfaces,
+ final Object object )
+ throws Exception
+ {
+ if( object instanceof ProxyProvider )
+ {
+ return ((ProxyProvider)object).getProxy();
+ }
+ else if( object instanceof Invocable )
+ {
+ return Proxy.newProxyInstance( classLoader,
+ interfaces,
+ (Invocable)object );
+ }
+ return object;
+ }
+
protected synchronized void invalidate()
{
if( null != m_invocationHandler )
@@ -85,6 +121,46 @@
m_invocationHandler = null;
}
m_object = null;
+ m_serviceObject = null;
+ }
+
+ private BlockInvocationHandler buildInvocationChain(
+ final ClassLoader classLoader,
+ final Class[] interfaces,
+ final Object object,
+ final BlockResourceProvider blockAccessor )
+ throws Exception
+ {
+ InvocationInterceptorDescriptor[] invocationHandles =
+ m_blockMetaData.getBlockInfo().getInvocationInterceptors();
+ BlockInvocationHandler head = new BlockInvocationHandler( classLoader,
interfaces);
+ AstractChainedInvocable tail = head;
+ for( int i = 0; i < invocationHandles.length; i++ )
+ {
+ final AstractChainedInvocable chained = buildChainedInvocable(
classLoader,
+
invocationHandles[ i ] );
+ tail.setChained(chained);
+ tail = chained;
+
+ if( chained instanceof LogEnabled )
+ {
+ final Logger logger = blockAccessor.createLogger(this);
+ ((LogEnabled) chained).enableLogging(logger);
+ }
+ }
+ tail.setObject( object );
+ return head;
+ }
+
+ private AstractChainedInvocable buildChainedInvocable(
+ final ClassLoader classLoader,
+ final InvocationInterceptorDescriptor description )
+ throws Exception
+ {
+ Class clazz = classLoader.loadClass( description.getClassname() );
+ AstractChainedInvocable interceptor =
+ (AstractChainedInvocable) clazz.newInstance();
+ return interceptor;
}
private Class[] getServiceClasses( final Object block, final
ServiceDescriptor[] services )
Index:
java/org/apache/avalon/phoenix/components/application/BlockInvocationHandler.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/BlockInvocationHandler.java,v
retrieving revision 1.8
diff -u -r1.8 BlockInvocationHandler.java
---
java/org/apache/avalon/phoenix/components/application/BlockInvocationHandler.java
6 Aug 2002 11:57:39 -0000 1.8
+++
java/org/apache/avalon/phoenix/components/application/BlockInvocationHandler.java
22 Aug 2002 18:56:09 -0000
@@ -7,11 +7,10 @@
*/
package org.apache.avalon.phoenix.components.application;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import org.apache.avalon.phoenix.*;
+
/**
* This makes a dynamic proxy for an object. The object can be represented
* by one, some or all of it's interfaces.
@@ -29,11 +28,8 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Paul Hammant</a>
* @version CVS $Revision: 1.8 $ $Date: 2002/08/06 11:57:39 $
*/
-final class BlockInvocationHandler
- implements InvocationHandler
+final class BlockInvocationHandler extends AstractChainedInvocable
{
- private transient Object m_object;
-
private transient Object m_proxy;
/**
@@ -42,11 +38,10 @@
* @param object the underlying object
* @param interfaces the interfaces to proxy
*/
- protected BlockInvocationHandler( final Object object, final Class[]
interfaces )
+ protected BlockInvocationHandler( final ClassLoader classLoader,
+ final Class[] interfaces )
{
- final ClassLoader classLoader = object.getClass().getClassLoader();
-
- m_object = object;
+ super();
m_proxy = Proxy.newProxyInstance( classLoader, interfaces, this );
}
@@ -56,7 +51,7 @@
*/
public void invalidate()
{
- m_object = null;
+ setObject( null );
m_proxy = null;
}
@@ -68,38 +63,5 @@
public Object getProxy()
{
return m_proxy;
- }
-
- /**
- * Invoke the specified method on underlying object.
- * This is called by proxy object.
- *
- * @param proxy the proxy object
- * @param method the method invoked on proxy object
- * @param args the arguments supplied to method
- * @return the return value of method
- * @throws Throwable if an error occurs
- */
- public Object invoke( final Object proxy,
- final Method method,
- final Object[] args )
- throws Throwable
- {
- if( null != m_object )
- {
- try
- {
- return method.invoke( m_object, args );
- }
- catch( final InvocationTargetException ite )
- {
- throw ite.getTargetException();
- }
- }
- else
- {
- throw new IllegalStateException( "Using a stale object reference "
- + "to call a disposed Block." );
- }
}
}
Index:
java/org/apache/avalon/phoenix/components/application/BlockResourceProvider.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/BlockResourceProvider.java,v
retrieving revision 1.4
diff -u -r1.4 BlockResourceProvider.java
---
java/org/apache/avalon/phoenix/components/application/BlockResourceProvider.java
6 Aug 2002 11:57:39 -0000 1.4
+++
java/org/apache/avalon/phoenix/components/application/BlockResourceProvider.java
22 Aug 2002 18:56:09 -0000
@@ -20,6 +20,7 @@
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.DefaultServiceManager;
import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.phoenix.BlockFactory;
import org.apache.avalon.phoenix.interfaces.Application;
import org.apache.avalon.phoenix.interfaces.ApplicationContext;
import org.apache.avalon.phoenix.metadata.BlockMetaData;
@@ -78,11 +79,10 @@
public Object createObject( final Object entry )
throws Exception
{
- final BlockMetaData metaData = getMetaDataFor( entry );
- final ClassLoader classLoader = m_context.getClassLoader();
- String classname =
metaData.getBlockInfo().getBlockDescriptor().getClassname();
- final Class clazz = classLoader.loadClass( classname );
- return clazz.newInstance();
+ final BlockEntry blockEntry = (BlockEntry)entry;
+ final BlockFactory blockFactory =
blockEntry.getMetaData().getBlockFactory();
+ final String impl = blockEntry.getMetaData().getBlockImpl();
+ return blockFactory.createBlock( impl, m_context.getClassLoader() );
}
/**
Index:
java/org/apache/avalon/phoenix/components/application/DefaultApplication.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/application/DefaultApplication.java,v
retrieving revision 1.35
diff -u -r1.35 DefaultApplication.java
---
java/org/apache/avalon/phoenix/components/application/DefaultApplication.java
7 Aug 2002 03:00:00 -0000 1.35
+++
java/org/apache/avalon/phoenix/components/application/DefaultApplication.java
22 Aug 2002 18:56:09 -0000
@@ -486,7 +486,7 @@
entry.getMetaData(),
block );
- entry.setObject( block );
+ entry.setObject( block, m_blockAccessor );
m_listenerSupport.fireBlockAddedEvent( entry );
}
@@ -519,7 +519,14 @@
}
finally
{
- entry.setObject( null );
+ try
+ {
+ entry.setObject( null, m_blockAccessor );
+ }
+ catch( Exception e )
+ {
+ getLogger().error( e.getMessage(), e );
+ }
}
}
Index: java/org/apache/avalon/phoenix/components/deployer/DefaultDeployer.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/components/deployer/DefaultDeployer.java,v
retrieving revision 1.50
diff -u -r1.50 DefaultDeployer.java
--- java/org/apache/avalon/phoenix/components/deployer/DefaultDeployer.java
6 Aug 2002 11:57:40 -0000 1.50
+++ java/org/apache/avalon/phoenix/components/deployer/DefaultDeployer.java
22 Aug 2002 18:56:09 -0000
@@ -29,6 +29,7 @@
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.phoenix.BlockFactory;
import org.apache.avalon.phoenix.components.deployer.installer.Installation;
import
org.apache.avalon.phoenix.components.deployer.installer.InstallationException;
import org.apache.avalon.phoenix.components.deployer.installer.Installer;
@@ -381,6 +382,7 @@
{
final String name = blocks[ i ].getName();
final BlockDescriptor descriptor = blocks[ i
].getBlockInfo().getBlockDescriptor();
+ final BlockFactory factory = blocks[ i ].getBlockFactory();
final String type = descriptor.getSchemaType();
if( null != type )
@@ -388,9 +390,9 @@
m_validator.addSchema( metaData.getName(),
name,
type,
- getConfigurationSchemaURL( name,
-
descriptor.getClassname(),
-
classLoader )
+ factory.getConfigurationSchemaURL(
name,
+
descriptor.getImpl(),
+
classLoader )
);
}
}
@@ -409,27 +411,6 @@
}
throw new DeploymentException( message, e );
- }
- }
-
- private String getConfigurationSchemaURL( final String name,
- final String classname,
- final ClassLoader classLoader )
- throws DeploymentException
- {
- final String resourceName = classname.replace( '.', '/' ) +
"-schema.xml";
-
- final URL resource = classLoader.getResource( resourceName );
- if( null == resource )
- {
-
- throw new DeploymentException( REZ.getString(
"deploy.error.config.schema.missing",
- name,
- resourceName ) );
- }
- else
- {
- return resource.toString();
}
}
Index: java/org/apache/avalon/phoenix/metadata/BlockMetaData.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/metadata/BlockMetaData.java,v
retrieving revision 1.13
diff -u -r1.13 BlockMetaData.java
--- java/org/apache/avalon/phoenix/metadata/BlockMetaData.java 18 Aug 2002
08:23:33 -0000 1.13
+++ java/org/apache/avalon/phoenix/metadata/BlockMetaData.java 22 Aug 2002
18:56:08 -0000
@@ -7,6 +7,7 @@
*/
package org.apache.avalon.phoenix.metadata;
+import org.apache.avalon.phoenix.BlockFactory;
import org.apache.avalon.phoenix.metainfo.BlockInfo;
/**
@@ -20,17 +21,25 @@
private final DependencyMetaData[] m_dependencies;
+ private final BlockFactory m_factory;
+
+ private final boolean m_defaultFactory;
+
private final boolean m_disableProxy;
private final BlockInfo m_blockInfo;
public BlockMetaData( final String name,
final DependencyMetaData[] dependencies,
- final boolean disableProxy,
+ final BlockFactory factory,
+ final boolean defaultFactory,
+ final boolean disableProxy,
final BlockInfo blockInfo )
{
m_name = name;
m_dependencies = dependencies;
+ m_factory = factory;
+ m_defaultFactory = defaultFactory;
m_disableProxy = disableProxy;
m_blockInfo = blockInfo;
}
@@ -40,9 +49,9 @@
return m_name;
}
- public String getClassname()
+ public String getBlockImpl()
{
- return getBlockInfo().getBlockDescriptor().getClassname();
+ return getBlockInfo().getBlockDescriptor().getImpl();
}
public BlockInfo getBlockInfo()
@@ -71,5 +80,13 @@
public boolean isDisableProxy()
{
return m_disableProxy;
+ }
+
+ public BlockFactory getBlockFactory() {
+ return m_factory;
+ }
+
+ public boolean isDefaultBlockFactory() {
+ return m_defaultFactory;
}
}
Index: java/org/apache/avalon/phoenix/metadata/SarMetaData.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/metadata/SarMetaData.java,v
retrieving revision 1.9
diff -u -r1.9 SarMetaData.java
--- java/org/apache/avalon/phoenix/metadata/SarMetaData.java 6 Aug 2002
11:57:41 -0000 1.9
+++ java/org/apache/avalon/phoenix/metadata/SarMetaData.java 22 Aug 2002
18:56:08 -0000
@@ -8,6 +8,10 @@
package org.apache.avalon.phoenix.metadata;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.phoenix.BlockFactory;
/**
* MetaData for the application.
@@ -16,23 +20,27 @@
*/
public class SarMetaData
{
- private String m_name;
+ private final String m_name;
+
+ private final File m_homeDirectory;
- private File m_homeDirectory;
+ private final BlockMetaData[] m_blocks;
- private BlockMetaData[] m_blocks;
+ private final Map m_blockFactories;
- private BlockListenerMetaData[] m_listeners;
+ private final BlockListenerMetaData[] m_listeners;
public SarMetaData( final String name,
final File homeDirectory,
final BlockMetaData[] blocks,
- final BlockListenerMetaData[] listeners )
+ final BlockListenerMetaData[] listeners,
+ final Map blockFactories )
{
m_name = name;
m_homeDirectory = homeDirectory;
m_blocks = blocks;
m_listeners = listeners;
+ m_blockFactories = new HashMap( blockFactories );
}
public String getName()
@@ -53,5 +61,10 @@
public BlockListenerMetaData[] getListeners()
{
return m_listeners;
+ }
+
+ public BlockFactory getBlockFactory( final String name )
+ {
+ return (BlockFactory)m_blockFactories.get( name );
}
}
Index: java/org/apache/avalon/phoenix/metainfo/BlockDescriptor.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/metainfo/BlockDescriptor.java,v
retrieving revision 1.10
diff -u -r1.10 BlockDescriptor.java
--- java/org/apache/avalon/phoenix/metainfo/BlockDescriptor.java 6 Aug
2002 11:57:41 -0000 1.10
+++ java/org/apache/avalon/phoenix/metainfo/BlockDescriptor.java 22 Aug
2002 18:56:08 -0000
@@ -22,19 +22,19 @@
*/
private final String m_name;
- private final String m_classname;
+ private final String m_impl;
private final Version m_version;
private final String m_schemaType;
public BlockDescriptor( final String name,
- final String classname,
+ final String impl,
final String schemaType,
final Version version )
{
m_name = name;
- m_classname = classname;
+ m_impl = impl;
m_version = version;
m_schemaType = schemaType;
}
@@ -54,9 +54,9 @@
*
* @return the Class Name of block
*/
- public String getClassname()
+ public String getImpl()
{
- return m_classname;
+ return m_impl;
}
/**
Index: java/org/apache/avalon/phoenix/metainfo/BlockInfo.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/metainfo/BlockInfo.java,v
retrieving revision 1.15
diff -u -r1.15 BlockInfo.java
--- java/org/apache/avalon/phoenix/metainfo/BlockInfo.java 6 Aug 2002
11:57:41 -0000 1.15
+++ java/org/apache/avalon/phoenix/metainfo/BlockInfo.java 22 Aug 2002
18:56:08 -0000
@@ -26,18 +26,22 @@
private final DependencyDescriptor[] m_dependencies;
+ private final InvocationInterceptorDescriptor[] m_invocationInterceptors;
+
/**
* Basic constructor that takes as parameters all parts.
*/
public BlockInfo( final BlockDescriptor descriptor,
final ServiceDescriptor[] services,
final ServiceDescriptor[] managementAccessPoints,
- final DependencyDescriptor[] dependencies )
+ final DependencyDescriptor[] dependencies,
+ final InvocationInterceptorDescriptor[]
invocationHandles )
{
m_descriptor = descriptor;
m_services = services;
m_managementAccessPoints = managementAccessPoints;
m_dependencies = dependencies;
+ m_invocationInterceptors = invocationHandles;
}
/**
@@ -99,5 +103,15 @@
}
return null;
+ }
+
+ /**
+ * Returns an array of invocation interceptors configured for that Block.
+ *
+ * @return an array of InvocationInterceptorDescriptor
+ */
+ public InvocationInterceptorDescriptor[] getInvocationInterceptors()
+ {
+ return m_invocationInterceptors;
}
}
Index:
java/org/apache/avalon/phoenix/metainfo/InvocationInterceptorDescriptor.java
===================================================================
RCS file:
java/org/apache/avalon/phoenix/metainfo/InvocationInterceptorDescriptor.java
diff -N
java/org/apache/avalon/phoenix/metainfo/InvocationInterceptorDescriptor.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++
java/org/apache/avalon/phoenix/metainfo/InvocationInterceptorDescriptor.java
22 Aug 2002 18:56:08 -0000
@@ -0,0 +1,21 @@
+package org.apache.avalon.phoenix.metainfo;
+
+/**
+ * @todo description
+ *
+ * @author ifedorenko
+ */
+public class InvocationInterceptorDescriptor {
+
+ private final String m_classname;
+
+ public InvocationInterceptorDescriptor( final String classname )
+ {
+ m_classname = classname;
+ }
+
+ public String getClassname()
+ {
+ return m_classname;
+ }
+}
Index: java/org/apache/avalon/phoenix/tools/assembler/Assembler.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/assembler/Assembler.java,v
retrieving revision 1.19
diff -u -r1.19 Assembler.java
--- java/org/apache/avalon/phoenix/tools/assembler/Assembler.java 18 Aug
2002 08:23:34 -0000 1.19
+++ java/org/apache/avalon/phoenix/tools/assembler/Assembler.java 22 Aug
2002 18:56:08 -0000
@@ -8,20 +8,23 @@
package org.apache.avalon.phoenix.tools.assembler;
import java.io.File;
-import java.net.URL;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.phoenix.BlockFactory;
import org.apache.avalon.phoenix.metadata.BlockListenerMetaData;
import org.apache.avalon.phoenix.metadata.BlockMetaData;
import org.apache.avalon.phoenix.metadata.DependencyMetaData;
import org.apache.avalon.phoenix.metadata.SarMetaData;
import org.apache.avalon.phoenix.metainfo.BlockInfo;
-import org.apache.avalon.phoenix.tools.configuration.ConfigurationBuilder;
import org.apache.avalon.phoenix.tools.infobuilder.BlockInfoBuilder;
/**
@@ -70,13 +73,78 @@
final ClassLoader classLoader )
throws AssemblyException
{
+ final Configuration[] factoryConfig = assembly.getChildren( "factory"
);
+ final Map factories = buildFactories( factoryConfig, classLoader );
+
final Configuration[] blockConfig = assembly.getChildren( "block" );
- final BlockMetaData[] blocks = buildBlocks( blockConfig, classLoader );
+ final BlockMetaData[] blocks = buildBlocks( blockConfig, factories,
classLoader );
final Configuration[] listenerConfig = assembly.getChildren(
"listener" );
final BlockListenerMetaData[] listeners = buildBlockListeners(
listenerConfig );
- return new SarMetaData( name, directory, blocks, listeners );
+ return new SarMetaData( name, directory, blocks, listeners, factories
);
+ }
+
+ /**
+ * Create a map of <code>BlockFactory</code> objects to represent
+ * the <factory .../> sections in <code>assembly.xml</code>.
+ *
+ * @param factories the list of Configuration objects for factories
+ * @return the Map name => BlockFactory
+ * @throws AssemblyException if an error occurs
+ */
+ private Map buildFactories( final Configuration[] factories,
+ final ClassLoader classLoader )
+ throws AssemblyException
+ {
+ final Map factoryMap = new HashMap();
+ final DefaultBlockFactory defaultFactory = new DefaultBlockFactory();
+ defaultFactory.enableLogging(getLogger()); // @todo proper logging
+ factoryMap.put( null, defaultFactory );
+ for( int i = 0; i < factories.length; i++ )
+ {
+ final Configuration factory = factories [ i ];
+ try {
+ final String name = factory.getAttribute( "name" ); // @todo
verify factory name?
+ final String classname = factory.getAttribute( "class" );
+ if( factoryMap.containsKey( name ) )
+ {
+ final String message =
+ REZ.getString( "duplicated-factory", name,
factory.getLocation() );
+ throw new AssemblyException( message );
+ }
+ factoryMap.put( name, buildFactory( name, classname,
classLoader ) );
+ } catch (ConfigurationException e) {
+ final String message =
+ REZ.getString( "factory-entry-malformed",
factory.getLocation(), e.getMessage() );
+ throw new AssemblyException( message, e );
+ }
+ }
+
+ return factoryMap;
+ }
+
+ private BlockFactory buildFactory( final String name,
+ final String classname,
+ final ClassLoader classLoader )
+ throws AssemblyException
+ {
+ try
+ {
+ Class clazz = classLoader.loadClass(classname);
+ BlockFactory factory = (BlockFactory)clazz.newInstance();
+ if( factory instanceof LogEnabled )
+ {
+ ((LogEnabled)factory).enableLogging(getLogger()); // @todo
proper logging
+ }
+ return factory;
+ }
+ catch( Exception e )
+ {
+ final String message =
+ REZ.getString( "factorycreate-error", name, classname,
e.getMessage() );
+ throw new AssemblyException( message, e );
+ }
}
/**
@@ -88,6 +156,7 @@
* @throws AssemblyException if an error occurs
*/
private BlockMetaData[] buildBlocks( final Configuration[] blocks,
+ final Map factories,
final ClassLoader classLoader )
throws AssemblyException
{
@@ -95,7 +164,7 @@
for( int i = 0; i < blocks.length; i++ )
{
final BlockMetaData blockMetaData =
- buildBlock( blocks[ i ], classLoader );
+ buildBlock( blocks[ i ], factories, classLoader );
blockSet.add( blockMetaData );
}
@@ -111,70 +180,52 @@
* @throws AssemblyException if an error occurs
*/
private BlockMetaData buildBlock( final Configuration block,
+ final Map factories,
final ClassLoader classLoader )
throws AssemblyException
{
try
{
final String name = block.getAttribute( "name" );
- final String classname = block.getAttribute( "class" );
+ final String classname = block.getAttribute( "class", null );
+ final String impl = block.getAttribute( "impl", null );
+ final String factory = block.getAttribute( "factory", null );
final Configuration[] provides = block.getChildren( "provide" );
final Configuration proxy = block.getChild( "proxy" );
+ // @todo should disableProxy be moved to BlockInfo?
final boolean disableProxy =
proxy.getAttributeAsBoolean( "disable", false );
- final DependencyMetaData[] roles = buildDependencyMetaDatas(
provides );
- final BlockInfo info = getBlockInfo( name, classname, classLoader
);
-
-
- return new BlockMetaData( name, roles, disableProxy, info );
+ // lets check if class/impl/factory combination is valid
+ if( (classname != null && factory == null && impl == null)
+ || (classname == null && factory != null && impl !=
null) ) {
+ final DependencyMetaData[] roles = buildDependencyMetaDatas(
provides );
+ final BlockFactory blockFactory = (BlockFactory)factories.get(
factory );
+ final String theImpl = ( factory == null )? classname: impl;
+ final BlockInfo info = blockFactory.getBlockInfo( name,
+ theImpl,
+ classLoader,
+ block );
+
+ return new BlockMetaData( name,
+ roles,
+ blockFactory,
+ factory == null,
+ disableProxy,
+ info );
+ }
+ else
+ {
+ final String message =
+ REZ.getString( "class-impl-factory-invalid", classname,
impl, factory );
+ throw new AssemblyException( message );
+ }
}
catch( final ConfigurationException ce )
{
final String message =
REZ.getString( "block-entry-malformed", block.getLocation(),
ce.getMessage() );
throw new AssemblyException( message );
- }
- }
-
- /**
- * Get a BlockInfo for Block with specified name and classname.
- * The BlockInfo may be loaded from the specified cache otherwise it must
be
- * loaded from specified ClassLoader.
- *
- * @param name the name of Block
- * @param classname the name of Blocks class
- * @return the BlockInfo for specified block
- * @throws AssemblyException if an error occurs
- */
- private BlockInfo getBlockInfo( final String name,
- final String classname,
- final ClassLoader classLoader )
- throws AssemblyException
- {
- final String resourceName = classname.replace( '.', '/' ) + ".xinfo";
-
- final String notice = REZ.getString( "loading-blockinfo", resourceName
);
- getLogger().debug( notice );
-
- final URL resource = classLoader.getResource( resourceName );
- if( null == resource )
- {
- final String message = REZ.getString( "blockinfo-missing", name,
resourceName );
- throw new AssemblyException( message );
- }
-
- try
- {
- final Configuration info = ConfigurationBuilder.build(
resource.toString() );
-
- return m_builder.build( classname, info );
- }
- catch( final Exception e )
- {
- final String message =
- REZ.getString( "blockinfo-nocreate", name, resourceName,
e.getMessage() );
- throw new AssemblyException( message, e );
}
}
Index: java/org/apache/avalon/phoenix/tools/assembler/DefaultBlockFactory.java
===================================================================
RCS file:
java/org/apache/avalon/phoenix/tools/assembler/DefaultBlockFactory.java
diff -N java/org/apache/avalon/phoenix/tools/assembler/DefaultBlockFactory.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/org/apache/avalon/phoenix/tools/assembler/DefaultBlockFactory.java
22 Aug 2002 18:56:08 -0000
@@ -0,0 +1,29 @@
+package org.apache.avalon.phoenix.tools.assembler;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.phoenix.AbstractBlockFactory;
+
+/**
+ * @todo description
+ *
+ * @author ifedorenko
+ */
+public class DefaultBlockFactory extends AbstractBlockFactory
+{
+ private static final Resources REZ =
+ ResourceManager.getPackageResources( Assembler.class );
+
+ public Object createBlock( String impl, final ClassLoader classLoader )
+ throws ConfigurationException
+ {
+ try {
+ final Class clazz = classLoader.loadClass( impl );
+ return clazz.newInstance();
+ } catch (Exception e) {
+ final String message = REZ.getString( "blockcreate-error", impl,
e.getMessage() );
+ throw new ConfigurationException( message, e );
+ }
+ }
+}
Index: java/org/apache/avalon/phoenix/tools/assembler/Resources.properties
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/assembler/Resources.properties,v
retrieving revision 1.3
diff -u -r1.3 Resources.properties
--- java/org/apache/avalon/phoenix/tools/assembler/Resources.properties 15 May
2002 12:25:33 -0000 1.3
+++ java/org/apache/avalon/phoenix/tools/assembler/Resources.properties 22 Aug
2002 18:56:08 -0000
@@ -3,3 +3,9 @@
blockinfo-nocreate=Failed to create BlockInfo for Block named "{0}" from
resource "{1}" (Reason: {2}).
loading-blockinfo=Creating BlockInfo from {0}.
blockinfo-missing=Unable to create BlockInfo as are unable to locate resource
"{1}".
+class-impl-factory-invalid=Block can have either class or factory/impl
specified. (class="{0}", factory="{1}", impl="{2}").
+blockcreate-error=Unable to instantiate block from {0}. (Reason: {2}).
+factorycreate-error=Unable to instantiate block factory {1} {0}. (Reason: {2}).
+factory-entry-malformed=Malformed factory entry in assembly.xml at "{0}".
(Reason: {1}).
+deploy.error.config.schema.missing=Unable to load configuration schema for
block "{0}" from "{1}"
+duplicated-factory=Duplicate definition of a factory with name {0} found at
{1}.
Index: java/org/apache/avalon/phoenix/tools/infobuilder/BlockInfoBuilder.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/infobuilder/BlockInfoBuilder.java,v
retrieving revision 1.23
diff -u -r1.23 BlockInfoBuilder.java
--- java/org/apache/avalon/phoenix/tools/infobuilder/BlockInfoBuilder.java
17 Aug 2002 02:34:44 -0000 1.23
+++ java/org/apache/avalon/phoenix/tools/infobuilder/BlockInfoBuilder.java
22 Aug 2002 18:56:08 -0000
@@ -16,6 +16,7 @@
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.phoenix.metainfo.BlockDescriptor;
import org.apache.avalon.phoenix.metainfo.BlockInfo;
+import org.apache.avalon.phoenix.metainfo.InvocationInterceptorDescriptor;
import org.apache.avalon.phoenix.metainfo.DependencyDescriptor;
import org.apache.avalon.phoenix.metainfo.ServiceDescriptor;
@@ -42,7 +43,9 @@
* @return the created BlockInfo
* @throws ConfigurationException if an error occurs
*/
- public BlockInfo build( final String classname, final Configuration info )
+ public BlockInfo build( final String classname,
+ final Configuration info,
+ final Configuration block )
throws Exception
{
if( getLogger().isDebugEnabled() )
@@ -65,16 +68,66 @@
configuration = info.getChild( "block" );
final BlockDescriptor descriptor = buildBlockDescriptor( classname,
configuration );
+ configuration = block.getChild( "proxy" );
+ final InvocationInterceptorDescriptor[] interceptors =
buildChainedInvocableDescriptors( configuration );
+
if( getLogger().isDebugEnabled() )
{
final String message = REZ.getString( "blockinfo-created",
classname,
new Integer( services.length
),
- new Integer(
dependencies.length ) );
+ new Integer(
dependencies.length ),
+ new Integer(
interceptors.length ) );
getLogger().debug( message );
}
- return new BlockInfo( descriptor, services, management, dependencies );
+ return new BlockInfo( descriptor, services, management, dependencies,
interceptors );
+ }
+
+ /**
+ * A utility method to build an array of
<code>InvocationInterceptorDescriptor</code>
+ * objects from specified configuraiton.
+ *
+ * @param configuration the interceptors configuration
+ * @return the created InvocationInterceptorDescriptor
+ * @throws ConfigurationException if an error occurs
+ */
+ private InvocationInterceptorDescriptor[]
buildChainedInvocableDescriptors( Configuration configuration )
+ throws ConfigurationException
+ {
+ final boolean proxyDisabled =
configuration.getAttributeAsBoolean("disable", false);
+ final Configuration[] elements = configuration.getChildren(
"interceptor" );
+ if( proxyDisabled && elements.length > 0 )
+ {
+ final String message =
+ REZ.getString( "interceptors-without-proxy",
configuration.getLocation() );
+ throw new ConfigurationException( message );
+ }
+ final ArrayList interceptors = new ArrayList();
+
+ for( int i = 0; i < elements.length; i++ )
+ {
+ final InvocationInterceptorDescriptor interceptor =
buildInterceptor( elements[ i ] );
+ interceptors.add( interceptor );
+ }
+
+ return (InvocationInterceptorDescriptor[])interceptors.toArray( new
InvocationInterceptorDescriptor[ 0 ] );
+ }
+
+ /**
+ * A utility method to build a <code>InvocationInterceptorDescriptor</code>
+ * object from specified configuraiton.
+ *
+ * @param dependency the dependency configuration
+ * @return the created DependencyDescriptor
+ * @throws ConfigurationException if an error occurs
+ */
+ private InvocationInterceptorDescriptor buildInterceptor( final
Configuration interceptor )
+ throws ConfigurationException
+ {
+ String classname = interceptor.getAttribute( "class" );
+
+ return new InvocationInterceptorDescriptor( classname );
}
/**
Index: java/org/apache/avalon/phoenix/tools/infobuilder/Resources.properties
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/infobuilder/Resources.properties,v
retrieving revision 1.5
diff -u -r1.5 Resources.properties
--- java/org/apache/avalon/phoenix/tools/infobuilder/Resources.properties
17 Aug 2002 02:34:44 -0000 1.5
+++ java/org/apache/avalon/phoenix/tools/infobuilder/Resources.properties
22 Aug 2002 18:56:08 -0000
@@ -1,5 +1,6 @@
-blockinfo-created=Constructed BlockInfo object for class {0}. BlockInfo
contains {1} services and {2} dependencies.
+blockinfo-created=Constructed BlockInfo object for class {0}. BlockInfo
contains {1} services, {2} dependencies and {3} invocation interceptors.
missing-block=Warning: Unspecified <block/> section in BlockInfo for class {0}.
redundent-role=Warning: BlockInfo for class {0} redundently specifies role
name "{1}" in dependency when it is identical to the name of service. It is
recomended that the <role/> section be elided.
creating-blockinfo=Creating a BlockInfo for class "{0}".
-deprecated-management-declaration=The BlockInfo for "{0}" uses the deprecated
mechanism to declare management services. It is recomended you replace
<management> with <management-access-points>.
\ No newline at end of file
+deprecated-management-declaration=The BlockInfo for "{0}" uses the deprecated
mechanism to declare management services. It is recomended you replace
<management> with <management-access-points>.
+interceptors-without-proxy=Block invocation interceptors cannot be used if
block proxy is disabled. ({0}).
Index: java/org/apache/avalon/phoenix/tools/verifier/Resources.properties
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/verifier/Resources.properties,v
retrieving revision 1.12
diff -u -r1.12 Resources.properties
--- java/org/apache/avalon/phoenix/tools/verifier/Resources.properties 23 Jun
2002 22:19:24 -0000 1.12
+++ java/org/apache/avalon/phoenix/tools/verifier/Resources.properties 22 Aug
2002 18:56:08 -0000
@@ -13,6 +13,8 @@
invalid-listener-name=The Listener name "{0}" is invalid. Valid names contain
only letters, digits and the '-' & '.' characters.
invalid-sar-name=The Sar name "{0}" is invalid. Valid names contain only
letters, digits and the '-' & '.' characters.
dependency-circular=Block named "{0}" has a circular dependency via path: {1}.
+bad-interceptor-class=Unable to load invocation interceptor class "{1}" for
Block named "{0}". (Reason: {2}).
+interceptor-noimpl-invocable=ChainedInvocable interface is not implemented by
class "{1}" designated for invocation interceptor for Block named "{0}".
verify-unique-names=Verifying that the name specified for Blocks and
BlockListeners are unique.
verify-valid-names=Verifying that the name specified for Blocks and
BlockListeners are valid.
@@ -21,6 +23,7 @@
verify-nocircular-dependencies=Verifying that there are no circular
dependencies between Blocks.
verify-block-type=Verifying that the specified Blocks have valid types.
verify-listener-type=Verifying that the specified BlockListeners have valid
types.
+verify-interceptor-type=Verifying that the specified invocation interceptors
have valid types.
verifier.service-isa-lifecycle.error=The Block named "{0}" (implementation
class "{1}"), implements a service "{2}" which extends a Lifecycle interface
"{3}". This violates the expected usage patterns.
verifier.implements-block.error=The Block named "{0}" (implementation class
"{1}"), implements Block interface. The Block interface has been deprecated and
should no longer be used.
Index: java/org/apache/avalon/phoenix/tools/verifier/SarVerifier.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon-phoenix/src/java/org/apache/avalon/phoenix/tools/verifier/SarVerifier.java,v
retrieving revision 1.26
diff -u -r1.26 SarVerifier.java
--- java/org/apache/avalon/phoenix/tools/verifier/SarVerifier.java 6 Aug
2002 11:57:42 -0000 1.26
+++ java/org/apache/avalon/phoenix/tools/verifier/SarVerifier.java 22 Aug
2002 18:56:08 -0000
@@ -21,6 +21,7 @@
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.phoenix.AstractChainedInvocable;
import org.apache.avalon.phoenix.Block;
import org.apache.avalon.phoenix.BlockListener;
import org.apache.avalon.phoenix.metadata.BlockListenerMetaData;
@@ -29,6 +30,7 @@
import org.apache.avalon.phoenix.metadata.SarMetaData;
import org.apache.avalon.phoenix.metainfo.BlockInfo;
import org.apache.avalon.phoenix.metainfo.DependencyDescriptor;
+import org.apache.avalon.phoenix.metainfo.InvocationInterceptorDescriptor;
import org.apache.avalon.phoenix.metainfo.ServiceDescriptor;
import org.apache.excalibur.containerkit.verifier.ComponentVerifier;
import org.apache.excalibur.containerkit.verifier.VerifyException;
@@ -128,6 +130,10 @@
message = REZ.getString( "verify-listener-type" );
getLogger().info( message );
verifyListenersType( listeners, classLoader );
+
+ message = REZ.getString( "verify-interceptor-type" );
+ getLogger().info( message );
+ verifyInterceptorsType( blocks, classLoader );
}
/**
@@ -360,50 +366,52 @@
throws VerifyException
{
final String name = block.getName();
- final String classname = block.getClassname();
- Class clazz = null;
- try
- {
- clazz = classLoader.loadClass( classname );
- }
- catch( final Exception e )
- {
- final String message = REZ.getString( "bad-block-class",
- name,
- classname,
- e.getMessage() );
- throw new VerifyException( message );
- }
-
- final Class[] interfaces =
- getServiceClasses( name,
- block.getBlockInfo().getServices(),
- classLoader );
-
- verifyAvalonComponent( name, clazz, interfaces );
-
- for( int i = 0; i < interfaces.length; i++ )
+ if( block.isDefaultBlockFactory() )
{
- if( !interfaces[ i ].isAssignableFrom( clazz ) )
+ final String classname = block.getBlockImpl();
+ Class clazz = null;
+ try
+ {
+ clazz = classLoader.loadClass( classname );
+ }
+ catch( final Exception e )
{
- final String message = REZ.getString( "block-noimpl-service",
+ final String message = REZ.getString( "bad-block-class",
name,
classname,
- interfaces[ i
].getName() );
+ e.getMessage() );
throw new VerifyException( message );
}
- }
- if( Block.class.isAssignableFrom( clazz ) )
- {
- final String message =
- REZ.getString( "verifier.implements-block.error",
- name,
- classname );
- getLogger().error( message );
- System.err.println( message );
- }
+ final Class[] interfaces =
+ getServiceClasses( name,
+ block.getBlockInfo().getServices(),
+ classLoader );
+
+ verifyAvalonComponent( name, clazz, interfaces );
+
+ for( int i = 0; i < interfaces.length; i++ )
+ {
+ if( !interfaces[ i ].isAssignableFrom( clazz ) )
+ {
+ final String message = REZ.getString(
"block-noimpl-service",
+ name,
+ classname,
+ interfaces[ i
].getName() );
+ throw new VerifyException( message );
+ }
+ }
+ if( Block.class.isAssignableFrom( clazz ) )
+ {
+ final String message =
+ REZ.getString( "verifier.implements-block.error",
+ name,
+ classname );
+ getLogger().error( message );
+ System.err.println( message );
+ }
+ }
}
/**
@@ -477,6 +485,65 @@
final String message = REZ.getString( "listener-noimpl-listener",
listener.getName(),
listener.getClassname() );
+ throw new VerifyException( message );
+ }
+ }
+
+ /**
+ * Verfiy that all interceptors subclasses of
<code>AstractChainedInvocable</code>.
+ *
+ * @param blocks
+ * @param classLoader
+ * @throws VerifyException if an error occurs
+ */
+ private void verifyInterceptorsType( final BlockMetaData[] blocks,
+ final ClassLoader classLoader )
+ throws VerifyException
+ {
+ for( int i = 0; i < blocks.length; i++ )
+ {
+ final BlockMetaData block = blocks[ i ];
+ final InvocationInterceptorDescriptor[] interceptors =
+ block.getBlockInfo().getInvocationInterceptors();
+ for( int j = 0; j < interceptors.length; j++ )
+ {
+ verifyInterceptorType( block, interceptors[ j ], classLoader );
+ }
+ }
+ }
+
+ /**
+ * Verfiy that specified invocation interceptor class subclass of
+ * <code>AstractChainedInvocable</code>.
+ *
+ * @param listener the BlockListenerMetaData object for the listener
+ * @throws VerifyException if an error occurs
+ */
+ private void verifyInterceptorType( final BlockMetaData block,
+ final InvocationInterceptorDescriptor
interceptor,
+ final ClassLoader classLoader )
+ throws VerifyException
+ {
+ Class clazz = null;
+ try
+ {
+ clazz = classLoader.loadClass( interceptor.getClassname() );
+ }
+ catch( final Exception e )
+ {
+ final String message =
+ REZ.getString( "bad-interceptor-class",
+ block.getName(),
+ interceptor.getClassname(),
+ e.getMessage() );
+ throw new VerifyException( message, e );
+ }
+
+ if( !AstractChainedInvocable.class.isAssignableFrom( clazz ) )
+ {
+ final String message = REZ.getString(
"interceptor-noimpl-invocable",
+ block.getName(),
+ interceptor.getClassname() );
throw new VerifyException( message );
}
}
Index: schema/assembly.dtd
===================================================================
RCS file: /home/cvspublic/jakarta-avalon-phoenix/src/schema/assembly.dtd,v
retrieving revision 1.4
diff -u -r1.4 assembly.dtd
--- schema/assembly.dtd 18 Aug 2002 08:23:34 -0000 1.4
+++ schema/assembly.dtd 22 Aug 2002 18:56:09 -0000
@@ -22,7 +22,7 @@
block a block that exists in the application
block-listener a listener that exists in the application
-->
-<!ELEMENT assembly (block|block-listener|listener)*>
+<!ELEMENT assembly (block|block-listener|listener|factory)*>
<!ATTLIST assembly id ID #IMPLIED
xmlns CDATA #FIXED
"http://jakarta.apache.org/phoenix/assembly_1_0.dtd" >
@@ -31,15 +31,22 @@
The element defines:
name the name of a block
-class the class of block instance
+class the class of block instance.
+ cannot be used with none-default factory
+factory the name of the block factory.
+ optional, default factory will be used if not specified
+impl factory specific description of the implementation of the
block.
+ default factory expects the classname of block instance
provide declare that particular blocks that will provide
the block with particular services
proxy TODO:description
-->
<!ELEMENT block (provide*,proxy?)>
- <!ATTLIST block class CDATA #REQUIRED>
<!ATTLIST block name CDATA #REQUIRED>
+ <!ATTLIST block class CDATA #IMPLIED>
+ <!ATTLIST block factory CDATA #IMPLIED>
+ <!ATTLIST block impl CDATA #IMPLIED>
<!--
The provide element declares that a specific service is provided to the block
@@ -57,8 +64,26 @@
disable TODO:description
-->
-<!ELEMENT proxy EMPTY>
+<!ELEMENT proxy (interceptor*)>
<!ATTLIST proxy disable CDATA #REQUIRED>
+
+<!--
+TODO:description
+
+class the class of block invocation interceptor
+-->
+<!ELEMENT interceptor EMPTY>
+ <!ATTLIST interceptor class CDATA #REQUIRED>
+
+<!--
+TODO: description
+
+name the name of the factory
+class the class of the factory instance
+-->
+<!ELEMENT factory EMPTY>
+ <!ATTLIST factory name CDATA #REQUIRED>
+ <!ATTLIST factory class CDATA #REQUIRED>
<!--
The block element declares a listener exists in the application.
Index: script/run.bat
===================================================================
RCS file: /home/cvspublic/jakarta-avalon-phoenix/src/script/run.bat,v
retrieving revision 1.7
diff -u -r1.7 run.bat
--- script/run.bat 21 Apr 2002 21:03:55 -0000 1.7
+++ script/run.bat 22 Aug 2002 18:56:08 -0000
@@ -82,7 +82,10 @@
rem thus breaking Phoenix
rem
+rem uncomment to get debug
+rem set DEBUG=-Xdebug
-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
+
rem Kicking the tires and lighting the fires!!!
-"%PHOENIX_JAVACMD%" "-Djava.ext.dirs=%PHOENIX_HOME%\lib"
"-Dphoenix.home=%PHOENIX_HOME%"
"-Djava.security.policy=jar:file:%PHOENIX_HOME%/bin/phoenix-loader.jar!/META-INF/java.policy"
%PHOENIX_JVM_OPTS% %PHOENIX_SECURE% -jar
"%PHOENIX_HOME%\bin\phoenix-loader.jar" %1 %2 %3 %4 %5 %6 %7 %8 %9
+"%PHOENIX_JAVACMD%" %DEBUG% "-Djava.ext.dirs=%PHOENIX_HOME%\lib"
"-Dphoenix.home=%PHOENIX_HOME%"
"-Djava.security.policy=jar:file:%PHOENIX_HOME%/bin/phoenix-loader.jar!/META-INF/java.policy"
%PHOENIX_JVM_OPTS% %PHOENIX_SECURE% -jar
"%PHOENIX_HOME%\bin\phoenix-loader.jar" %1 %2 %3 %4 %5 %6 %7 %8 %9
:end-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
