Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2208 - in development/main/metro: . automation/control/src/main/net/dpml/automation/control automation/control/src/main/net/dpml/automation/model composition/builder/src/main/net/dpml/composition/builder composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/models composition/testing/acme composition/testing/acme/src/main/net/dpml/composition/testing composition/testing/classic composition/testing/unit composition/testing/unit/src/test/net/dpml/composition/testing composition/unit/src/main/net/dpml/composition/unit meta/api/src/main/net/dpml/meta/info

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: mcconnell AT dpml.net
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: svn commit: r2208 - in development/main/metro: . automation/control/src/main/net/dpml/automation/control automation/control/src/main/net/dpml/automation/model composition/builder/src/main/net/dpml/composition/builder composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/models composition/testing/acme composition/testing/acme/src/main/net/dpml/composition/testing composition/testing/classic composition/testing/unit composition/testing/unit/src/test/net/dpml/composition/testing composition/unit/src/main/net/dpml/composition/unit meta/api/src/main/net/dpml/meta/info
  • Date: Tue, 05 Apr 2005 05:01:08 -0400

Author: mcconnell AT dpml.net
Date: Tue Apr 5 05:01:04 2005
New Revision: 2208

Added:

development/main/metro/composition/control/src/main/net/dpml/composition/control/Holder.java

development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/AcmeContainer.java

development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/AcmeContainerTestCase.java
Removed:

development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/CompositeGizmo.java
development/main/metro/composition/testing/classic/
Modified:

development/main/metro/automation/control/src/main/net/dpml/automation/control/Controller.java

development/main/metro/automation/control/src/main/net/dpml/automation/control/Monitor.java

development/main/metro/automation/control/src/main/net/dpml/automation/control/SystemManager.java

development/main/metro/automation/control/src/main/net/dpml/automation/model/Model.java

development/main/metro/composition/builder/src/main/net/dpml/composition/builder/TypeBuilderTask.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/ApplianceInvocationHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionController.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionManager.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/ConsoleMonitor.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/ContextInvocationHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/DefaultMonitor.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/LifecycleHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/LifestyleHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/PartsInvocationHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/models/StandardComponentModel.java
development/main/metro/composition/testing/acme/build.xml

development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultGizmo.java

development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultWidget.java
development/main/metro/composition/testing/unit/build.xml

development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/SimpleTestCase.java

development/main/metro/composition/unit/src/main/net/dpml/composition/unit/CompositionHelper.java
development/main/metro/index.xml
development/main/metro/meta/api/src/main/net/dpml/meta/info/Type.java
Log:
1. add support for identifiable instances
2. improve code dealing with part descriptor keywords
3. simplfy the application invocation handler though addition of an instance
Holder
4. addition of a component helper class (used in unit testing)
5. validation of all part related functions

Modified:
development/main/metro/automation/control/src/main/net/dpml/automation/control/Controller.java
==============================================================================
---
development/main/metro/automation/control/src/main/net/dpml/automation/control/Controller.java
(original)
+++
development/main/metro/automation/control/src/main/net/dpml/automation/control/Controller.java
Tue Apr 5 05:01:04 2005
@@ -99,4 +99,11 @@
* @return the nested model or null if the model is not found
*/
Model getProvider( Model model, String path );
+
+ /**
+ * Dispose of the supplied model.
+ *
+ * @param model the model to apply disposal to
+ */
+ void dispose( Model model );
}

Modified:
development/main/metro/automation/control/src/main/net/dpml/automation/control/Monitor.java
==============================================================================
---
development/main/metro/automation/control/src/main/net/dpml/automation/control/Monitor.java
(original)
+++
development/main/metro/automation/control/src/main/net/dpml/automation/control/Monitor.java
Tue Apr 5 05:01:04 2005
@@ -27,6 +27,34 @@
public interface Monitor
{
/**
+ * Returns TRUE if debug level monitoring is enabled.
+ *
+ * @return TRUE if DEBUG level monitoring is enabled
+ */
+ boolean isDebugEnabled();
+
+ /**
+ * Returns TRUE if info level monitoring is enabled.
+ *
+ * @return TRUE if INFO level monitoring is enabled
+ */
+ boolean isInfoEnabled();
+
+ /**
+ * Returns TRUE if warn level monitoring is enabled.
+ *
+ * @return TRUE if WARN level monitoring is enabled
+ */
+ boolean isWarnEnabled();
+
+ /**
+ * Returns TRUE if error level monitoring is enabled.
+ *
+ * @return TRUE if ERROR level monitoring is enabled
+ */
+ boolean isErrorEnabled();
+
+ /**
* Log the supplied debug level message.
* @param message the message to log
*/

Modified:
development/main/metro/automation/control/src/main/net/dpml/automation/control/SystemManager.java
==============================================================================
---
development/main/metro/automation/control/src/main/net/dpml/automation/control/SystemManager.java
(original)
+++
development/main/metro/automation/control/src/main/net/dpml/automation/control/SystemManager.java
Tue Apr 5 05:01:04 2005
@@ -59,4 +59,9 @@
*/
void stop();

+ /**
+ * Dispose of the manager.
+ */
+ void dispose();
+
}

Modified:
development/main/metro/automation/control/src/main/net/dpml/automation/model/Model.java
==============================================================================
---
development/main/metro/automation/control/src/main/net/dpml/automation/model/Model.java
(original)
+++
development/main/metro/automation/control/src/main/net/dpml/automation/model/Model.java
Tue Apr 5 05:01:04 2005
@@ -39,7 +39,11 @@

Controller getController();

+ Object create() throws Exception;
+
Object resolve() throws Exception;

+ Object resolve( Object key ) throws Exception;
+
void release( Object object );
}

Modified:
development/main/metro/composition/builder/src/main/net/dpml/composition/builder/TypeBuilderTask.java
==============================================================================
---
development/main/metro/composition/builder/src/main/net/dpml/composition/builder/TypeBuilderTask.java
(original)
+++
development/main/metro/composition/builder/src/main/net/dpml/composition/builder/TypeBuilderTask.java
Tue Apr 5 05:01:04 2005
@@ -571,9 +571,9 @@
{
String name = method.getName();
validateNoExceptions( method );
- if( name.startsWith( "get" ) )
+ if( name.startsWith( PartDescriptor.GET_KEY ) )
{
- validateNoParameters( method );
+ validateAtMostOneParameter( method );
Class returnType = method.getReturnType();
validateNonNullReturnType( method, returnType );
validateNonArrayReturnType( method, returnType );
@@ -581,7 +581,7 @@
String type = returnType.getName();
return new PartDescriptor( key, type, PartDescriptor.GET );
}
- else if( name.startsWith( "create" ) )
+ else if( name.startsWith( PartDescriptor.CREATE_KEY ) )
{
validateNoParameters( method );
Class returnType = method.getReturnType();
@@ -591,7 +591,7 @@
String type = returnType.getName();
return new PartDescriptor( key, type, PartDescriptor.CREATE );
}
- else if( name.startsWith( "release" ) )
+ else if( name.startsWith( PartDescriptor.RELEASE_KEY ) )
{
if( method.getParameterTypes().length == 1 )
{
@@ -860,6 +860,19 @@
}
}

+ private void validateAtMostOneParameter( Method method ) throws
IntrospectionException
+ {
+ Class[] parameterTypes = method.getParameterTypes();
+ if( parameterTypes.length > 1 )
+ {
+ final String error =
+ "Method ["
+ + method.getName()
+ + "] declares more than one parameters.";
+ throw new IntrospectionException( error );
+ }
+ }
+
private Class loadSubjectClass( ClassLoader classloader )
{
if( null == m_classname )

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ApplianceInvocationHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ApplianceInvocationHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ApplianceInvocationHandler.java
Tue Apr 5 05:01:04 2005
@@ -44,12 +44,9 @@
// state
//-------------------------------------------------------------------

- private final StandardComponentModel m_model;
- private final LifestyleHandler m_handler;
- private final Object m_key;
- private final Object m_instance;
-
+ private final Holder m_holder;
private boolean m_disposed = false;
+ private Object m_instance;

//-------------------------------------------------------------------
// constructor
@@ -58,40 +55,14 @@
/**
* Create a proxy invocation handler.
*
- * @param appliance the runtime appliance
- * @param logger the assigned logging channel
- */
- ApplianceInvocationHandler( LifestyleHandler handler,
StandardComponentModel model, Object key )
- throws NullPointerException, LifecycleException
- {
- assertNotNull( handler, "handler" );
- assertNotNull( model, "model" );
-
- m_handler = handler;
- m_model = model;
- m_key = key;
-
- handler.aquire( model, key );
- m_instance = model.get( key );
- }
-
- /**
- * Create a proxy invocation handler.
- *
- * @param appliance the runtime appliance
- * @param logger the assigned logging channel
+ * @param holder the instance holder
*/
- ApplianceInvocationHandler( LifestyleHandler handler,
StandardComponentModel model )
- throws NullPointerException, LifecycleException
+ ApplianceInvocationHandler( Holder holder )
+ throws Exception
{
- assertNotNull( handler, "handler" );
- assertNotNull( model, "model" );
-
- m_handler = handler;
- m_model = model;
-
- m_key = handler.aquire( model ); // <-- here and now or later on
invocation ?
- m_instance = model.get( m_key );
+ assertNotNull( holder, "holder" );
+ m_holder = holder;
+ m_instance = m_holder.getInstance();
}

//-------------------------------------------------------------------
@@ -135,16 +106,14 @@
if( !m_disposed )
{
m_disposed = true;
- m_handler.release( m_model, m_key );
+ m_instance = null;
+ m_holder.release( this );
}
}

protected void finalize() throws Throwable
{
- if( !m_disposed && ( null != m_instance ) )
- {
- dispose();
- }
+ dispose();
}

//-------------------------------------------------------------------
@@ -154,8 +123,8 @@
private Throwable handleInvocationThrowable( Throwable e )
{
final String error =
- "Delegation error raised by component ["
- + m_model
+ "Delegation error raised in ["
+ + m_holder
+ "].";

while( true )

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionController.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionController.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionController.java
Tue Apr 5 05:01:04 2005
@@ -27,6 +27,7 @@
import java.util.HashSet;
import java.util.Collections;
import java.util.WeakHashMap;
+import java.util.ArrayList;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;

@@ -83,8 +84,8 @@
m_monitor = monitor;
m_system = system;

- m_factory = new LifecycleHandler( system );
- m_handler = new LifestyleHandler( m_factory );
+ m_factory = new LifecycleHandler( monitor, system );
+ m_handler = new LifestyleHandler( monitor, m_factory );
}

//--------------------------------------------------------------------
@@ -184,7 +185,8 @@
if( model instanceof StandardComponentModel )
{
StandardComponentModel componentModel = (StandardComponentModel)
model;
- return resolveInstance( componentModel, null );
+ Holder holder = getHolder( componentModel , null );
+ return holder.newProxy();
}
else
{
@@ -202,10 +204,19 @@
*/
public Object resolve( Model model, Object key ) throws Exception
{
+ if( null == model )
+ {
+ throw new NullPointerException( "model" );
+ }
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
if( model instanceof StandardComponentModel )
{
StandardComponentModel componentModel = (StandardComponentModel)
model;
- return resolveInstance( componentModel, key );
+ Holder holder = getHolder( componentModel , key );
+ return holder.newProxy();
}
else
{
@@ -249,6 +260,51 @@
}
}

+ /**
+ * Dispose of the controller.
+ */
+ public void dispose()
+ {
+ }
+
+ /**
+ * Dispose of the supplied model.
+ *
+ * @param model the model to apply disposal to
+ */
+ public void dispose( Model model )
+ {
+ /*
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Initialting disposal of the model ["
+ + model.getQualifiedName()
+ + "].";
+ getMonitor().debug( message );
+ }
+
+ if( model instanceof StandardComponentModel )
+ {
+ StandardComponentModel cModel = (StandardComponentModel) model;
+ Object[] keys = cModel.keys();
+ for( int i=(keys.length -1); i>-1; i-- )
+ {
+ Object key = keys[i];
+ Object object = cModel.get( key );
+ if( null != object )
+ {
+ m_factory.etherialize( object );
+ }
+ }
+ }
+ else
+ {
+ model.getController().dispose( model );
+ }
+ */
+ }
+
//--------------------------------------------------------------------
// CompositionController
//--------------------------------------------------------------------
@@ -291,7 +347,7 @@
Model model, String partition, ClassLoader parent, ComponentProfile
profile )
throws DelegationException, ModelException
{
- getMonitor().info( "creating nested model using " + profile );
+ getMonitor().debug( "creating nested model using " + profile );
ClassLoader classloader = getClassLoader( partition, parent, profile
);
if( null == model )
{
@@ -320,32 +376,15 @@
return model.getPart( path );
}

- /**
- * Create and return a new instance of the component represented
- * by the supplied model using the assigned lifecycle manager.
- *
- * @param model the component model
- * @param key the identifying key (may be null)
- * @return the resolved instance
- */
- private Object resolveInstance( StandardComponentModel model, Object key
) throws Exception
- {
- InvocationHandler handler = createAppliance( model, key );
- Class subject = model.getDeploymentClass();
- ClassLoader classloader = subject.getClassLoader();
- Class[] interfaces = model.getServiceClasses();
- return Proxy.newProxyInstance( classloader, interfaces, handler );
- }
-
- private InvocationHandler createAppliance( StandardComponentModel model,
Object key ) throws LifecycleException
+ private Holder getHolder( StandardComponentModel model, Object key )
throws LifecycleException
{
if( null == key )
{
- return new ApplianceInvocationHandler( m_handler, model );
+ return m_handler.aquire( model );
}
else
{
- return new ApplianceInvocationHandler( m_handler, model, key );
+ return m_handler.aquire( model, key );
}
}


Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionManager.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionManager.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionManager.java
Tue Apr 5 05:01:04 2005
@@ -25,6 +25,7 @@
import java.util.HashSet;
import java.util.Collections;
import java.util.WeakHashMap;
+import java.util.ArrayList;

import net.dpml.automation.part.Part;

@@ -68,12 +69,17 @@
{
super( new DefaultMonitor( context.getLogger() ), context );
m_context = context;
+ setShutdownHook( this );
}

//--------------------------------------------------------------------
// SystemManager
//--------------------------------------------------------------------

+ /**
+ * Return the name of this controller.
+ * @return the controller name
+ */
public String getName()
{
return "manager";
@@ -116,15 +122,6 @@
//--------------------------------------------------------------------

/**
- * Return an array of managed parts.
- * @return the parts array
- */
- public Model[] getManagedModels()
- {
- return (Model[]) m_models.toArray( new Model[0] );
- }
-
- /**
* Install a part to the collection of parts managed by this manager.
*
* @param name the name identifying the part within the collection
@@ -138,6 +135,18 @@
return model;
}

+ /**
+ * Return an array of managed parts.
+ * @return the parts array
+ */
+ public Model[] getManagedModels()
+ {
+ return (Model[]) m_models.toArray( new Model[0] );
+ }
+
+ /**
+ * Create a listing of the models under management.
+ */
public void list()
{
getMonitor().info( "listing models in the controller" );
@@ -149,6 +158,42 @@
}
}

+ /**
+ * Dispose of the manager.
+ */
+ public void dispose()
+ {
+ //
+ // Without a shutdown-graph (pending) there is not a lot we can do.
+ // The general plan is to lock of the models, then construct a
+ // shutdown graph using existing instance references, model, and
+ // type data.
+ //
+ }
+
+ /**
+ * Create a shutdown hook that will trigger shutdown of the supplied
plugin.
+ * @param thread the application thread
+ */
+ private void setShutdownHook( final CompositionManager manager )
+ {
+ //
+ // Create a shutdown hook to trigger clean disposal of the
+ // controller
+ //
+
+ Runtime.getRuntime().addShutdownHook(
+ new Thread()
+ {
+ public void run()
+ {
+ manager.dispose();
+ System.runFinalization();
+ }
+ }
+ );
+ }
+
//--------------------------------------------------------------------
// static utilities
//--------------------------------------------------------------------

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ConsoleMonitor.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ConsoleMonitor.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ConsoleMonitor.java
Tue Apr 5 05:01:04 2005
@@ -45,6 +45,46 @@
}

/**
+ * Returns TRUE if debug level monitoring is enabled.
+ *
+ * @return TRUE if DEBUG level monitoring is enabled
+ */
+ public boolean isDebugEnabled()
+ {
+ return m_debug;
+ }
+
+ /**
+ * Returns TRUE if info level monitoring is enabled.
+ *
+ * @return TRUE if INFO level monitoring is enabled
+ */
+ public boolean isInfoEnabled()
+ {
+ return true;
+ }
+
+ /**
+ * Returns TRUE if warn level monitoring is enabled.
+ *
+ * @return TRUE if WARN level monitoring is enabled
+ */
+ public boolean isWarnEnabled()
+ {
+ return true;
+ }
+
+ /**
+ * Returns TRUE if error level monitoring is enabled.
+ *
+ * @return TRUE if ERROR level monitoring is enabled
+ */
+ public boolean isErrorEnabled()
+ {
+ return true;
+ }
+
+ /**
* Log the supplied debug level message.
* @param message the message to log
*/

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ContextInvocationHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ContextInvocationHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ContextInvocationHandler.java
Tue Apr 5 05:01:04 2005
@@ -55,20 +55,20 @@
//-------------------------------------------------------------------

/**
- * A map of context entry key name and context entry values.
+ * The system context.
*/
private final SystemContext m_system;

/**
- * A map of context entry key name and context entry values.
+ * A map of context entries published by the model and keyed by entry key.
*/
- private final Map m_map = new Hashtable();
+ private final Map m_entries = new Hashtable();

/**
* A map of the entry descriptors published by the component type
* and keyed by entry key.
*/
- private final Map m_entries = new Hashtable();
+ private final Map m_descriptors = new Hashtable();

/**
* The component model.
@@ -99,7 +99,7 @@

//
// get the set of context entries declared by the component type
- // and for for each entry determine the context entry model to
+ // and for each entry determine the context entry model to
// use for context entry value resolution
//

@@ -128,12 +128,12 @@
}
else
{
- m_entries.put( key, entry );
+ m_descriptors.put( key, entry );
if( directive instanceof ValueDirective )
{
ValueDirective value = (ValueDirective) directive;
- ValueModel m = new ValueModel( classloader, entry,
value, m_map );
- m_map.put( key, m );
+ ValueModel m = new ValueModel( classloader, entry,
value, m_entries );
+ m_entries.put( key, m );
}
else
{
@@ -181,7 +181,7 @@

String name = method.getName();
String key = getKeyFromMethod( method );
- EntryDescriptor entry = (EntryDescriptor) m_entries.get( key );
+ EntryDescriptor entry = (EntryDescriptor) m_descriptors.get( key );

if( null == entry )
{
@@ -198,7 +198,7 @@
// we have a valid key
//

- EntryModel model = (EntryModel) m_map.get( key );
+ EntryModel model = (EntryModel) m_entries.get( key );
if( null == model )
{
return returnClientSuppliedDefaultArgument( entry, args );

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/DefaultMonitor.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/DefaultMonitor.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/DefaultMonitor.java
Tue Apr 5 05:01:04 2005
@@ -38,6 +38,46 @@
}

/**
+ * Returns TRUE if debug level monitoring is enabled.
+ *
+ * @return TRUE if DEBUG level monitoring is enabled
+ */
+ public boolean isDebugEnabled()
+ {
+ return m_logger.isDebugEnabled();
+ }
+
+ /**
+ * Returns TRUE if info level monitoring is enabled.
+ *
+ * @return TRUE if INFO level monitoring is enabled
+ */
+ public boolean isInfoEnabled()
+ {
+ return m_logger.isInfoEnabled();
+ }
+
+ /**
+ * Returns TRUE if warn level monitoring is enabled.
+ *
+ * @return TRUE if WARN level monitoring is enabled
+ */
+ public boolean isWarnEnabled()
+ {
+ return m_logger.isWarnEnabled();
+ }
+
+ /**
+ * Returns TRUE if error level monitoring is enabled.
+ *
+ * @return TRUE if ERROR level monitoring is enabled
+ */
+ public boolean isErrorEnabled()
+ {
+ return m_logger.isErrorEnabled();
+ }
+
+ /**
* Log the supplied debug level message.
* @param message the message to log
*/

Added:
development/main/metro/composition/control/src/main/net/dpml/composition/control/Holder.java
==============================================================================
--- (empty file)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/Holder.java
Tue Apr 5 05:01:04 2005
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.composition.control;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.util.WeakHashMap;
+
+import net.dpml.automation.control.Monitor;
+import net.dpml.automation.control.LifecycleException;
+import net.dpml.automation.control.Monitor;
+
+import net.dpml.composition.models.StandardComponentModel;
+
+/**
+ * A lifestyle handler provides support for the aquisition and release
+ * of component instances. An implementation is responsible for the
+ * handling of new instance creation based on lifestyle policy declared
+ * in a component model.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: LifestyleManager.java 259 2004-10-30 07:24:40Z mcconnell $
+ */
+public class Holder
+{
+ private final WeakHashMap m_proxies = new WeakHashMap();
+
+ private final Object m_key;
+ private final Monitor m_monitor;
+ private final StandardComponentModel m_model;
+ private final LifecycleHandler m_factory;
+
+ private boolean m_disposed = false;
+ private Object m_instance;
+
+ public Holder( Monitor monitor, LifecycleHandler factory,
StandardComponentModel model, Object key )
+ {
+ m_monitor = monitor;
+ m_factory = factory;
+ m_model = model;
+ if( null == key )
+ {
+ m_key = new Integer( System.identityHashCode( this ) );
+ }
+ else
+ {
+ m_key = key;
+ }
+ }
+
+ public Object getKey()
+ {
+ return m_key;
+ }
+
+ public Object newProxy() throws Exception
+ {
+ synchronized( m_proxies )
+ {
+ InvocationHandler handler = new ApplianceInvocationHandler( this
);
+ Class subject = m_model.getDeploymentClass();
+ ClassLoader classloader = subject.getClassLoader();
+ Class[] interfaces = m_model.getServiceClasses();
+ Object proxy = Proxy.newProxyInstance( classloader, interfaces,
handler );
+ m_proxies.put( proxy, this );
+ return proxy;
+ }
+ }
+
+ public Object getInstance() throws Exception
+ {
+ synchronized( m_proxies )
+ {
+ if( m_disposed )
+ {
+ throw new IllegalStateException( "disposed" );
+ }
+ if( null == m_instance )
+ {
+ m_instance = m_factory.incarnate( m_model );
+ }
+ return m_instance;
+ }
+ }
+
+ public void release( Object proxy )
+ {
+ synchronized( m_proxies )
+ {
+ m_proxies.remove( proxy );
+ if( m_proxies.isEmpty() )
+ {
+ dispose();
+ }
+ }
+ }
+
+ public void dispose()
+ {
+ if( m_disposed )
+ {
+ return;
+ }
+ synchronized( m_proxies )
+ {
+ m_disposed = true;
+ Object[] proxies = (Object[]) m_proxies.keySet().toArray( new
Object[0] );
+ for( int i=0; i<proxies.length; i++ )
+ {
+ Object proxy = proxies[i];
+ Object handler = Proxy.getInvocationHandler( proxy );
+ if( handler instanceof ApplianceInvocationHandler )
+ {
+ ApplianceInvocationHandler aic =
+ (ApplianceInvocationHandler) handler;
+ aic.dispose();
+ }
+ }
+ m_proxies.clear();
+ m_model.remove( this );
+ if( null != m_instance )
+ {
+ m_factory.etherialize( m_instance );
+ m_instance = null;
+ }
+ }
+ }
+
+ public String toString()
+ {
+ return m_model.getQualifiedName() + "#" + m_key;
+ }
+
+ protected void finalize()
+ {
+ dispose();
+ }
+}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifecycleHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifecycleHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifecycleHandler.java
Tue Apr 5 05:01:04 2005
@@ -24,6 +24,7 @@
import java.lang.reflect.Proxy;

import net.dpml.automation.control.LifecycleException;
+import net.dpml.automation.control.Monitor;

import net.dpml.composition.models.StandardComponentModel;

@@ -44,10 +45,12 @@
*/
public class LifecycleHandler
{
+ private final Monitor m_monitor;
private final SystemContext m_system;

- public LifecycleHandler( SystemContext system )
+ public LifecycleHandler( Monitor monitor, SystemContext system )
{
+ m_monitor = monitor;
m_system = system;
}

@@ -59,6 +62,15 @@
*/
public Object incarnate( StandardComponentModel model ) throws
LifecycleException
{
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Initiating incarnation using the model ["
+ + model.getQualifiedName()
+ + "].";
+ getMonitor().debug( message );
+ }
+
Class subject = model.getDeploymentClass();
ClassLoader classloader = subject.getClassLoader();
Constructor constructor = getConstructor( subject );
@@ -125,7 +137,18 @@
{
return;
}
+
Class subject = object.getClass();
+
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Initiating etherialization on an instance of the class ["
+ + subject.getName()
+ + "].";
+ getMonitor().debug( message );
+ }
+
try
{
Method method = subject.getDeclaredMethod( "dispose", new
Class[0] );
@@ -233,4 +256,9 @@
throw new LifecycleException( error, e );
}
}
+
+ private Monitor getMonitor()
+ {
+ return m_monitor;
+ }
}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifestyleHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifestyleHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/LifestyleHandler.java
Tue Apr 5 05:01:04 2005
@@ -19,6 +19,7 @@
package net.dpml.composition.control;

import net.dpml.automation.control.LifecycleException;
+import net.dpml.automation.control.Monitor;

import net.dpml.composition.models.StandardComponentModel;

@@ -34,9 +35,11 @@
public class LifestyleHandler
{
private final LifecycleHandler m_handler;
+ private Monitor m_monitor;

- public LifestyleHandler( LifecycleHandler handler )
+ public LifestyleHandler( Monitor monitor, LifecycleHandler handler )
{
+ m_monitor = monitor;
m_handler = handler;
}

@@ -46,17 +49,37 @@
* @param model the model from which new or existing instances will be
resolved
* @return the key to the resolved instance
*/
- public Object aquire( StandardComponentModel model ) throws
LifecycleException
+ public Holder aquire( StandardComponentModel model ) throws
LifecycleException
{
final String lifestyle = model.getLifestylePolicy();
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Aquiring an object key for the model ["
+ + model.getQualifiedName()
+ + "] using the lifestyle ["
+ + lifestyle
+ + "].";
+ getMonitor().debug( message );
+ }
if( "request".equals( lifestyle ) || "transient".equals( lifestyle )
)
{
synchronized( model )
{
- Object object = m_handler.incarnate( model );
- Object key = new Integer( System.identityHashCode( object )
);
- model.put( key, object );
- return key;
+ Holder holder = new Holder( m_monitor, m_handler, model,
null );
+ Object key = holder.getKey();
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Established key ["
+ + model.getQualifiedName()
+ + "#"
+ + key
+ + "].";
+ getMonitor().debug( message );
+ }
+ model.put( holder );
+ return holder;
}
}
else if( "thread".equals( lifestyle ) )
@@ -67,14 +90,8 @@
{
synchronized( model )
{
- String key = "self";
- Object object = model.get( key );
- if( null == object )
- {
- object = m_handler.incarnate( model );
- model.put( key, object );
- }
- return key;
+ String key = "model";
+ return aquire( model, key );
}
}
else
@@ -96,36 +113,68 @@
* @param model the model from which new or existing instances will be
resolved
* @return the key to the resolved instance
*/
- public Object aquire( StandardComponentModel model, Object key ) throws
LifecycleException
+ public Holder aquire( StandardComponentModel model, Object key ) throws
LifecycleException
{
- Object instance = model.get( key );
- if( null == instance )
+ Holder holder = model.get( key );
+ if( null == holder )
+ {
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Initiating creation of identifiable instance ["
+ + model.getQualifiedName()
+ + "#"
+ + key
+ + "].";
+ getMonitor().debug( message );
+ }
+ holder = new Holder( m_monitor, m_handler, model, key );
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Adding holder ["
+ + model.getQualifiedName()
+ + "#"
+ + key
+ + "].";
+ getMonitor().debug( message );
+ }
+ model.put( holder );
+ }
+ else
{
- instance = m_handler.incarnate( model );
- model.put( key, instance );
+ if( getMonitor().isDebugEnabled() )
+ {
+ final String message =
+ "Using existing holder ["
+ + model.getQualifiedName()
+ + "#"
+ + key
+ + "].";
+ getMonitor().debug( message );
+ }
}
- return key;
+ return holder;
}

public void release( StandardComponentModel model, Object key )
{
final String lifestyle = model.getLifestylePolicy();
- if( "request".equals( lifestyle ) )
- {
- synchronized( model )
- {
- Object object = model.get( key );
- m_handler.etherialize( object );
- model.remove( key );
- }
- }
- else if( "thread".equals( lifestyle ) )
- {
- throw new UnsupportedOperationException( "thread" );
- }
- else if( "model".equals( lifestyle ) )
+ if( getMonitor().isDebugEnabled() )
{
- return;
+ final String message =
+ "Releasing ["
+ + model.getQualifiedName()
+ + "#"
+ + key
+ + "].";
+ getMonitor().debug( message );
}
+ model.remove( key );
+ }
+
+ private Monitor getMonitor()
+ {
+ return m_monitor;
}
}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/PartsInvocationHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/PartsInvocationHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/PartsInvocationHandler.java
Tue Apr 5 05:01:04 2005
@@ -35,7 +35,16 @@
import net.dpml.composition.models.StandardComponentModel;

/**
- * This makes a dynamic proxy for a Parts object.
+ * The parts invocation handler maps client request for 'get', 'create' and
+ * 'release' relative to keys identified by the method name. Method name
+ * to key mapping is based on a [function][key] breakout where [function]
+ * is one of the recognized semantic keyworks:
+ *
+ * <ol>
+ * <li>get - return a proxied annonomouse instance of the model identified
by key</li>
+ * <li>create - creates a non-proxies instance</li>
+ * <li>release - releases the instance</li>
+ * </ol>
*
* @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
* @version $Id: ApplianceInvocationHandler.java 2106 2005-03-21 18:46:10Z
mcconnell AT dpml.net $
@@ -48,24 +57,6 @@
//-------------------------------------------------------------------

/**
- * A map of the 'get' part descriptors published by the component type
- * and keyed by entry key.
- */
- private final Map m_getters = new Hashtable();
-
- /**
- * A map of the 'create' part descriptors published by the component type
- * and keyed by entry key.
- */
- private final Map m_creators = new Hashtable();
-
- /**
- * A map of the 'release' part descriptors published by the component type
- * and keyed by entry key.
- */
- private final Map m_releasors = new Hashtable();
-
- /**
* The component type.
*/
private final Type m_type;
@@ -89,26 +80,6 @@
{
m_model = model;
m_type = model.getType();
-
- PartDescriptor[] entries = m_type.getPartDescriptors();
- for( int i=0; i<entries.length; i++ )
- {
- PartDescriptor p = entries[i];
- String key = p.getKey();
- int semantic = p.getSemantic();
- if( PartDescriptor.GET == semantic )
- {
- m_getters.put( key, p );
- }
- else if( PartDescriptor.CREATE == semantic )
- {
- m_creators.put( key, p );
- }
- else if( PartDescriptor.RELEASE == semantic )
- {
- m_releasors.put( key, p );
- }
- }
}

//-------------------------------------------------------------------
@@ -135,25 +106,9 @@
{
return method.invoke( this, args );
}
-
- PartDescriptor descriptor = getPartDescriptor( method );
- if( null == descriptor )
- {
- final String error =
- "Illegal request for an undeclared part ["
- + descriptor.getKey()
- + "] withing the component type ["
- + m_type.getInfo().getClassname()
- + "].";
- throw new IllegalArgumentException( error );
- }
-
- //
- // we have a valid key
- //

- String key = descriptor.getKey();
- int semantic = descriptor.getSemantic();
+ int semantic = getSemantic( method );
+ String key = getKey( method, semantic );
Model m = m_model.getPart( key );
if( null == m )
{
@@ -169,7 +124,26 @@
Controller controller = m.getController();
if( PartDescriptor.GET == semantic )
{
- return controller.resolve( m );
+ if( null == args )
+ {
+ return controller.resolve( m );
+ }
+ else if( args.length == 0 )
+ {
+ return controller.resolve( m );
+ }
+ else if( args.length == 1 )
+ {
+ return controller.resolve( m, args[0] );
+ }
+ else
+ {
+ final String error =
+ "Illegal number of parameters supplied under the 'resolve'
method ["
+ + method.getName()
+ + "].";
+ throw new IllegalStateException( error );
+ }
}
else if( PartDescriptor.CREATE == semantic )
{
@@ -177,8 +151,19 @@
}
else if( PartDescriptor.RELEASE == semantic )
{
- controller.release( proxy );
- return null;
+ if( args.length == 1 )
+ {
+ controller.release( args[0] );
+ return null;
+ }
+ else
+ {
+ final String error =
+ "Illegal number of parameters supplied under the 'release'
method ["
+ + method.getName()
+ + "].";
+ throw new IllegalStateException( error );
+ }
}
else
{
@@ -190,53 +175,66 @@
}
}

- private PartDescriptor getPartDescriptor( Method method )
+ //-------------------------------------------------------------------
+ // implementation
+ //-------------------------------------------------------------------
+
+ private int getSemantic( Method method )
{
String name = method.getName();
- String key = getKeyFromMethod( method );
if( name.startsWith( PartDescriptor.GET_KEY ) )
{
- return (PartDescriptor) m_getters.get( key );
+ return PartDescriptor.GET;
}
else if( name.startsWith( PartDescriptor.CREATE_KEY ) )
{
- return (PartDescriptor) m_creators.get( key );
+ return PartDescriptor.CREATE;
}
else if( name.startsWith( PartDescriptor.RELEASE_KEY ) )
{
- return (PartDescriptor) m_releasors.get( key );
+ return PartDescriptor.RELEASE;
}
else
{
- return null;
+ final String error =
+ "Unrecognized part accessor method signature ["
+ + name
+ + "]";
+ throw new IllegalArgumentException( error );
}
}

- private String getKeyFromMethod( Method method )
+ private String getKey( Method method, int semantic )
{
String name = method.getName();
- if( name.startsWith( PartDescriptor.GET_KEY ) )
+ if( PartDescriptor.GET == semantic )
{
- return formatKey( name.substring( 3 ) );
+ return formatKey( name, 3 );
}
- else if( name.startsWith( PartDescriptor.CREATE_KEY ) )
+ else if( PartDescriptor.CREATE == semantic )
{
- return formatKey( name.substring( 6 ) );
+ return formatKey( name, 6 );
}
- else if( name.startsWith( PartDescriptor.RELEASE_KEY ) )
+ else if( PartDescriptor.RELEASE == semantic )
{
- return formatKey( name.substring( 7 ) );
+ return formatKey( name, 7 );
}
else
{
final String error =
- "Invalid method accessor ["
+ "Unrecognized part accessor method signature ["
+ name
+ "]";
throw new IllegalArgumentException( error );
}
}

+ private String formatKey( String method, int offset )
+ {
+ String string = method.substring( offset );
+ return formatKey( string );
+ }
+
private String formatKey( String key )
{
if( key.length() < 1 )
@@ -248,10 +246,6 @@
return first + remainder;
}

- //-------------------------------------------------------------------
- // implementation
- //-------------------------------------------------------------------
-
private void assertNotNull( Object object, String key )
throws NullPointerException
{

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/models/StandardComponentModel.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/models/StandardComponentModel.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/models/StandardComponentModel.java
Tue Apr 5 05:01:04 2005
@@ -35,10 +35,12 @@
import net.dpml.composition.data.DependencyDirective;
import net.dpml.composition.control.CompositionClassLoader;
import net.dpml.composition.control.CompositionController;
+import net.dpml.composition.control.Holder;

import net.dpml.meta.info.Type;
import net.dpml.meta.info.ServiceDescriptor;
import net.dpml.meta.info.DependencyDescriptor;
+import net.dpml.meta.info.PartDescriptor;

/**
* The implementation of a component model.
@@ -59,7 +61,7 @@
private final String m_name;
private final String m_lifestyle;

- private transient Map m_instances = new WeakHashMap();
+ private transient Map m_holders = new WeakHashMap();
private final Hashtable m_providers = new Hashtable();
private final Hashtable m_parts = new Hashtable();

@@ -174,11 +176,21 @@
}
}

+ public Object create() throws Exception
+ {
+ return getController().create( this );
+ }
+
public Object resolve() throws Exception
{
return getController().resolve( this );
}

+ public Object resolve( Object key ) throws Exception
+ {
+ return getController().resolve( this, key );
+ }
+
public void release( Object object )
{
getController().release( object );
@@ -261,28 +273,34 @@
return (Model) m_providers.get( key );
}

- public void put( Object key, Object instance )
+ public void put( Holder holder )
{
- synchronized( m_instances )
- {
- m_instances.put( key, instance );
- }
+ m_holders.put( holder, this );
}

- public Object get( Object key )
+ public Holder get( Object key )
{
- synchronized( m_instances )
+ Holder[] holders = (Holder[]) m_holders.keySet().toArray( new
Holder[0] );
+ for( int i=0; i<holders.length; i++ )
{
- return m_instances.get( key );
+ Holder holder = holders[i];
+ if( key.equals( holder.getKey() ) )
+ {
+ return holder;
+ }
}
+ return null;
+ }
+
+ public Holder[] list()
+ {
+ return (Holder[]) m_holders.keySet().toArray( new Holder[0] );
}

public void remove( Object key )
- {
- synchronized( m_instances )
- {
- m_instances.remove( key );
- }
+ {
+ Holder holder = get( key );
+ m_holders.remove( holder );
}

private Class loadComponentClass( ClassLoader classloader,
ComponentProfile profile )

Modified: development/main/metro/composition/testing/acme/build.xml
==============================================================================
--- development/main/metro/composition/testing/acme/build.xml (original)
+++ development/main/metro/composition/testing/acme/build.xml Tue Apr 5
05:01:04 2005
@@ -11,7 +11,7 @@
<types xmlns="plugin:dpml/composition/dpml-composition-builder">
<type class="net.dpml.composition.testing.DefaultWidget"/>
<type class="net.dpml.composition.testing.DefaultGizmo"/>
- <type class="net.dpml.composition.testing.CompositeGizmo"/>
+ <type class="net.dpml.composition.testing.AcmeContainer"/>
</types>

<!-- simple component -->
@@ -33,9 +33,7 @@
<!--
<target name="package" depends="standard.package">
<echo>Writing types</echo>
- <type-writer class="net.dpml.composition.testing.DefaultWidget"
- xmlns="plugin:dpml/composition/dpml-composition-builder"/>
- <type-writer class="net.dpml.composition.testing.DefaultGizmo"
+ <type-writer class="net.dpml.composition.testing.AcmeContainer"
xmlns="plugin:dpml/composition/dpml-composition-builder"/>
<echo>Building block</echo>
</target>

Added:
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/AcmeContainer.java
==============================================================================
--- (empty file)
+++
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/AcmeContainer.java
Tue Apr 5 05:01:04 2005
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.composition.testing;
+
+import java.io.File;
+
+import net.dpml.logging.Logger;
+
+/**
+ * A simple class composed of two parts (widget and gizmo).
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: CompositionTestCase.java 1393 2005-01-06 10:27:10Z niclas $
+ */
+public class AcmeContainer
+{
+ //------------------------------------------------------------------
+ // static
+ //------------------------------------------------------------------
+
+ public static final boolean TYPE_THREADSAFE_CAPABLE = true;
+
+ //------------------------------------------------------------------
+ // state
+ //------------------------------------------------------------------
+
+ private final Logger m_logger;
+
+ //------------------------------------------------------------------
+ // constructor
+ //------------------------------------------------------------------
+
+ /**
+ * Creation of a composite component. This implementation demonstrates
+ * access to parts within itself and invocation of service and non-service
+ * operations on its parts.
+ *
+ * @param logger the logging channel asign by the container
+ */
+ public AcmeContainer( final Logger logger, Parts parts )
+ {
+ m_logger = logger;
+ logger.info( "getting widget" );
+ Widget widget = parts.getWidget();
+
+ logger.info( "getting gizmo" );
+ Gizmo gizmo = parts.getGizmo();
+
+ logger.info( "getting gizmo impl" );
+ DefaultGizmo newGizmo = parts.createGizmo();
+
+ logger.info( "getting identified gizmo" );
+ Gizmo myGizmo = parts.getGizmo( "my-gizmo" );
+
+ logger.info( "releasing stuff" );
+ parts.releaseGizmo( gizmo );
+ parts.releaseGizmo( myGizmo );
+ parts.releaseGizmo( newGizmo );
+ parts.releaseWidget( widget );
+
+ logger.info( "done" );
+ }
+
+ //------------------------------------------------------------------
+ // implementation
+ //------------------------------------------------------------------
+
+ public void dispose()
+ {
+ m_logger.info( "disposal" );
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( this.hashCode() == other.hashCode() );
+ }
+
+ //------------------------------------------------------------------
+ // concerns
+ //------------------------------------------------------------------
+
+ public interface Parts
+ {
+ /**
+ * Return an instance of widget using the lifestyle policy
+ * declared by the widget component.
+ *
+ * @return the widget service
+ */
+ Widget getWidget();
+
+ /**
+ * Return an instance of gizmo using the lifestyle policy
+ * declared by the gizmo component.
+ *
+ * @return the gizmo service
+ */
+ Gizmo getGizmo();
+
+ /**
+ * Return an identified instance of gizmo.
+ *
+ * @param key the instance identifier
+ * @return the gizmo service
+ */
+ Gizmo getGizmo( Object key );
+
+ /**
+ * Create and return a new annonomouse instance of gizmo as a
+ * non-proxied component.
+ *
+ * @return the gizmo component
+ */
+ DefaultGizmo createGizmo();
+
+ /**
+ * Optional release of an instance of the gizmo component.
+ *
+ * @param the gizmo to release
+ */
+ void releaseGizmo( Gizmo gizmo );
+
+ /**
+ * Optional release of an instance of the widget component.
+ *
+ * @param the widget to release
+ */
+ void releaseWidget( Widget widget );
+ }
+
+}

Modified:
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultGizmo.java
==============================================================================
---
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultGizmo.java
(original)
+++
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultGizmo.java
Tue Apr 5 05:01:04 2005
@@ -31,25 +31,48 @@
// static
//------------------------------------------------------------------

+ /**
+ * Declaration to the container that this component is thread-safe.
+ */
public static final boolean TYPE_THREADSAFE_CAPABLE = true;

//------------------------------------------------------------------
+ // state
+ //------------------------------------------------------------------
+
+ /**
+ * The logging channel.
+ */
+ private final Logger m_logger;
+
+ //------------------------------------------------------------------
// constructor
//------------------------------------------------------------------

/**
- * Creation of a new widget component.
+ * Creation of a new gizmo component. Gizmo has a dependency
+ * on the widget service (declared under the Dependencies
+ * inner interface). It is also a disposable component
+ * identified by the public dispose method).
*
* @param logger the logging channel assigned by the container
* @param dependencies the requested dependencies
*/
public DefaultGizmo( Logger logger, Dependencies dependencies )
{
- logger.debug( "initializing" );
+ m_logger = logger;
Widget widget = dependencies.getWidget();
- logger.debug( "widget established");
-
widget.doWidgetTypeStuff();
+ logger.info( "ready");
+ }
+
+ //------------------------------------------------------------------
+ // implementation
+ //------------------------------------------------------------------
+
+ public void dispose()
+ {
+ m_logger.info( "disposal" );
}

//------------------------------------------------------------------

Modified:
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultWidget.java
==============================================================================
---
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultWidget.java
(original)
+++
development/main/metro/composition/testing/acme/src/main/net/dpml/composition/testing/DefaultWidget.java
Tue Apr 5 05:01:04 2005
@@ -34,46 +34,111 @@
// static
//------------------------------------------------------------------

+ /**
+ * Declaration to the container that this component is thread-safe.
+ */
public static final boolean TYPE_THREADSAFE_CAPABLE = true;

//------------------------------------------------------------------
// state
//------------------------------------------------------------------

+ /**
+ * The logging channel.
+ */
private final Logger m_logger;
+
+ /**
+ * The assigned context instance.
+ */
private final Context m_context;

+ /**
+ * A mutable name.
+ */
+ private String m_name;
+
//------------------------------------------------------------------
// constructor
//------------------------------------------------------------------

/**
- * Creation of a new widget component.
+ * Creation of a new widget component. The component is assigned
+ * a logging channel and context by the container. The context is
+ * pre-prepared by the container based on the criteria expressed in
+ * the Context inner interface.
*
- * @param logger the logging channel asign by the container
+ * @param logger the logging channel asigned by the container
+ * @param context the assign component context
*/
public DefaultWidget( final Logger logger, final Context context )
{
m_context = context;
m_logger = logger;

- String name = m_context.getName();
+ m_name = m_context.getName();
String partition = m_context.getPartition();
File work = m_context.getWorkingDirectory();
+
+ m_logger.info( "widget created" );
+ }
+
+ //------------------------------------------------------------------
+ // implementation
+ //------------------------------------------------------------------
+
+ /**
+ * Return the mutable name.
+ * @return the component name
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Return the mutable name.
+ * @return the component name
+ */
+ public void setName( String name )
+ {
+ m_name = name;
+ }
+
+ /**
+ * Disposal of the component.
+ */
+ public void dispose()
+ {
+ m_logger.info( "disposal" );
+ }
+
+ /**
+ * Test is this component instance is equal to the supplied
+ * instance. This implementation is primarily used in test cases
+ * to establish instance equality and uniquness across different
+ * proxies to the same service instance.
+ */
+ public boolean equals( Object other )
+ {
+ return ( this.hashCode() == other.hashCode() );
}

//------------------------------------------------------------------
// Widget
//------------------------------------------------------------------

+ /**
+ * Implementation of the widget service contract.
+ */
public void doWidgetTypeStuff()
{
- String foo = m_context.getFoo();
+ String name = getName();
int width = m_context.getWidth();
int height = m_context.getHeight( 5024 );

m_logger.info(
- foo
+ name
+ " established with a width of "
+ width
+ " and a height of "

Modified: development/main/metro/composition/testing/unit/build.xml
==============================================================================
--- development/main/metro/composition/testing/unit/build.xml (original)
+++ development/main/metro/composition/testing/unit/build.xml Tue Apr 5
05:01:04 2005
@@ -8,9 +8,10 @@
<target name="build" depends="standard.build">

<!-- simple component -->
- <component xmlns="plugin:dpml/composition/dpml-composition-builder"
- name="widget" class="net.dpml.composition.testing.DefaultWidget"
- dest="target/test/acme-simple.part" >
+ <component dest="target/test/acme-simple.part"
+ xmlns="plugin:dpml/composition/dpml-composition-builder"
+ class="net.dpml.composition.testing.DefaultWidget"
+ name="widget">
<context>
<entry key="foo" value="bar"/>
<entry key="width" value="12"/>
@@ -21,6 +22,30 @@
</context>
</component>

+ <!-- acme container -->
+ <component dest="target/test/acme-container.part"
+ xmlns="plugin:dpml/composition/dpml-composition-builder"
+ class="net.dpml.composition.testing.AcmeContainer"
+ name="acme">
+ <parts>
+ <component name="widget"
class="net.dpml.composition.testing.DefaultWidget">
+ <context>
+ <entry key="foo" value="bar"/>
+ <entry key="width" value="12"/>
+ <entry key="height" value="100"/>
+ <entry key="name" value="urn:metro:name"/>
+ <entry key="partition" value="urn:metro:partition"/>
+ <entry key="workingDirectory" value="acme/workspace"/>
+ </context>
+ </component>
+ <component name="gizmo"
class="net.dpml.composition.testing.DefaultGizmo">
+ <dependencies>
+ <dependency key="widget" source="widget"/>
+ </dependencies>
+ </component>
+ </parts>
+ </component>
+
</target>

</project>

Added:
development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/AcmeContainerTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/AcmeContainerTestCase.java
Tue Apr 5 05:01:04 2005
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004 Stephen J. McConnell.
+ * Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.dpml.composition.testing;
+
+import java.net.URI;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import net.dpml.automation.model.Model;
+import net.dpml.composition.unit.CompositionHelper;
+
+/**
+ * Test a simple component case.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: AbstractDescriptorTestCase.java 1556 2005-01-22 12:43:42Z
niclas $
+ */
+public class AcmeContainerTestCase extends TestCase
+{
+ private static final String PATH = "acme-container.part";
+
+ /**
+ * Test the construction of a component that contains two child components
+ * (widget and gizmo).
+ */
+ public void testResolve() throws Exception
+ {
+ CompositionHelper helper = new CompositionHelper( false );
+ URI uri = helper.toURI( PATH );
+ Model model = helper.getCompositionManager().addPart( uri );
+ Object acme = model.resolve();
+ model.release( acme );
+ helper.dispose();
+ }
+}

Modified:
development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/SimpleTestCase.java
==============================================================================
---
development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/SimpleTestCase.java
(original)
+++
development/main/metro/composition/testing/unit/src/test/net/dpml/composition/testing/SimpleTestCase.java
Tue Apr 5 05:01:04 2005
@@ -37,21 +37,83 @@
{
private static final String PATH = "acme-simple.part";

- private CompositionHelper m_helper;
+ /**
+ * Test the construction of the widget component and the invocation of
+ * an operation on the widget service interface.
+ */
+ public void testResolve() throws Exception
+ {
+ CompositionHelper helper = new CompositionHelper();
+ URI uri = helper.toURI( PATH );
+ Model model = helper.getCompositionManager().addPart( uri );
+ Widget widget = (Widget) model.resolve();
+ widget.doWidgetTypeStuff();
+ model.release( widget );
+ }

- public void setUp() throws Exception
+ /**
+ * Test the isolation of the widget.
+ */
+ public void testResolveToImplementation() throws Exception
{
- Hashtable map = new Hashtable();
- map.put( "urn:transit.debug.policy", "true" );
- m_helper = new CompositionHelper( map );
+ CompositionHelper helper = new CompositionHelper();
+ URI uri = helper.toURI( PATH );
+ Model model = helper.getCompositionManager().addPart( uri );
+ try
+ {
+ DefaultWidget widget = (DefaultWidget) model.resolve();
+ fail( "Casting to implementation class!" );
+ }
+ catch( ClassCastException e )
+ {
+ // success
+ }
}

- public void testSimple() throws Exception
+ /**
+ * Test the construction of the widget implementation and invocation
+ * of a non-service public method on the implementation class.
+ */
+ public void testCreate() throws Exception
{
- URI uri = m_helper.toURI( PATH );
- Model model = m_helper.getCompositionManager().addPart( uri );
- Widget widget = (Widget) model.resolve();
- widget.doWidgetTypeStuff();
+ CompositionHelper helper = new CompositionHelper();
+ URI uri = helper.toURI( PATH );
+ Model model = helper.getCompositionManager().addPart( uri );
+ DefaultWidget widget = (DefaultWidget) model.create();
+ String name = widget.getName();
+ assertEquals( "name", "widget", name );
+ String newName = "freight";
+ widget.setName( newName );
+ assertEquals( "name", newName, widget.getName() );
model.release( widget );
}
+
+ /**
+ * Test the construction of an identifiable widget instance. We create
+ * widgets w1 and w2 under unique ids and check that they are in fact
+ * unique. Then we create w3 using the same key as we used for w1 and
+ * check that the instances are the same (which is dependent on the
+ * implementation providing a rational equals implementation).
+ */
+ public void testResolveIdentifiable() throws Exception
+ {
+ CompositionHelper helper = new CompositionHelper();
+ URI uri = helper.toURI( PATH );
+ Model model = helper.getCompositionManager().addPart( uri );
+ Widget w1 = (Widget) model.resolve( "acme-widget-one" );
+ Widget w2 = (Widget) model.resolve( "acme-widget-two" );
+ if( w1.equals( w2 ) )
+ {
+ fail( "Widget w1 and w2 are not unique!" );
+ }
+ Widget w3 = (Widget) model.resolve( "acme-widget-one" );
+ if( !w1.equals( w3 ) )
+ {
+ System.out.println( "" + System.identityHashCode( w1 ) );
+ System.out.println( "" + System.identityHashCode( w3 ) );
+ fail( "Widget w1 and w3 are not the same!" );
+ }
+ model.release( w1 );
+ model.release( w2 );
+ }
}

Modified:
development/main/metro/composition/unit/src/main/net/dpml/composition/unit/CompositionHelper.java
==============================================================================
---
development/main/metro/composition/unit/src/main/net/dpml/composition/unit/CompositionHelper.java
(original)
+++
development/main/metro/composition/unit/src/main/net/dpml/composition/unit/CompositionHelper.java
Tue Apr 5 05:01:04 2005
@@ -100,6 +100,11 @@
this( getTestWorkingDir(), map );
}

+ public CompositionHelper( boolean debug ) throws Exception
+ {
+ this( getTestWorkingDir(), getSystemContextMap( debug ) );
+ }
+
public CompositionHelper( File base, Map map ) throws Exception
{
m_system = createSystemContext( map, base );
@@ -129,6 +134,11 @@
}
}

+ public void dispose()
+ {
+ getCompositionManager().dispose();
+ }
+
/**
* Setup the system context.
*
@@ -162,4 +172,15 @@
return null;
}
}
+
+ private static Map getSystemContextMap( boolean debug )
+ {
+ Hashtable map = new Hashtable();
+ if( debug )
+ {
+ map.put( "urn:transit.debug.policy", "true" );
+ }
+ return map;
+ }
+
}

Modified: development/main/metro/index.xml
==============================================================================
--- development/main/metro/index.xml (original)
+++ development/main/metro/index.xml Tue Apr 5 05:01:04 2005
@@ -532,25 +532,6 @@
</plugins>
</project>

- <project basedir="composition/testing/classic">
- <info>
- <group>dpml/test</group>
- <name>dpml-composition-testing-classic</name>
- <version>1.0.0</version>
- <status>SNAPSHOT</status>
- <types>
- <type>part</type>
- </types>
- </info>
- <dependencies>
- <include key="dpml-composition-testing-acme" runtime="true"/>
- <include key="dpml-metro-unit"/>
- </dependencies>
- <plugins>
- <include key="dpml-composition-builder"/>
- </plugins>
- </project>
-
<!-- Utilities -->

<project basedir="util/defaults">

Modified:
development/main/metro/meta/api/src/main/net/dpml/meta/info/Type.java
==============================================================================
--- development/main/metro/meta/api/src/main/net/dpml/meta/info/Type.java
(original)
+++ development/main/metro/meta/api/src/main/net/dpml/meta/info/Type.java
Tue Apr 5 05:01:04 2005
@@ -268,6 +268,29 @@
}

/**
+ * Retrieve a dependency with a particular role.
+ *
+ * @param key the service key
+ * @return the dependency or null if it does not exist
+ */
+ public PartDescriptor getPartDescriptor( final String key, int semantic )
+ {
+ for ( int i = 0; i < m_parts.length; i++ )
+ {
+ PartDescriptor part = m_parts[i];
+ if ( part.getKey().equals( key ) )
+ {
+ int s = part.getSemantic();
+ if( semantic == s )
+ {
+ return part;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Return a string representation of the type.
* @return the stringified type
*/



  • svn commit: r2208 - in development/main/metro: . automation/control/src/main/net/dpml/automation/control automation/control/src/main/net/dpml/automation/model composition/builder/src/main/net/dpml/composition/builder composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/models composition/testing/acme composition/testing/acme/src/main/net/dpml/composition/testing composition/testing/classic composition/testing/unit composition/testing/unit/src/test/net/dpml/composition/testing composition/unit/src/main/net/dpml/composition/unit meta/api/src/main/net/dpml/meta/info, mcconnell, 04/04/2005

Archive powered by MHonArc 2.6.24.

Top of Page