notify-dpml AT lists.ibiblio.org
Subject: DPML Notify
List archive
r948 - in trunk/main: metro metro/part/api/src/main/net/dpml/part/local metro/part/test metro/part/test/etc metro/part/test/etc/test metro/part/test/src/test/net/dpml/test/part metro/runtime/src/main/net/dpml/metro/runtime transit/core/src/main/net/dpml/transit transit/core/src/main/net/dpml/transit/util
- From: mcconnell at BerliOS <mcconnell AT mail.berlios.de>
- To: notify-dpml AT lists.ibiblio.org
- Subject: r948 - in trunk/main: metro metro/part/api/src/main/net/dpml/part/local metro/part/test metro/part/test/etc metro/part/test/etc/test metro/part/test/src/test/net/dpml/test/part metro/runtime/src/main/net/dpml/metro/runtime transit/core/src/main/net/dpml/transit transit/core/src/main/net/dpml/transit/util
- Date: Mon, 23 Jan 2006 01:57:15 +0100
Author: mcconnell
Date: 2006-01-23 01:56:47 +0100 (Mon, 23 Jan 2006)
New Revision: 948
Added:
trunk/main/metro/part/api/src/main/net/dpml/part/local/InitialContext.java
trunk/main/metro/part/api/src/main/net/dpml/part/local/LocalEventProducer.java
trunk/main/metro/part/test/etc/
trunk/main/metro/part/test/etc/test/
trunk/main/metro/part/test/etc/test/logging.properties
Modified:
trunk/main/metro/module.xml
trunk/main/metro/part/api/src/main/net/dpml/part/local/ControllerContextListener.java
trunk/main/metro/part/api/src/main/net/dpml/part/local/PartManager.java
trunk/main/metro/part/test/src/test/net/dpml/test/part/PartLoadingTestCase.java
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionContext.java
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionController.java
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/UnicastEventSource.java
trunk/main/transit/core/src/main/net/dpml/transit/DefaultCacheModel.java
trunk/main/transit/core/src/main/net/dpml/transit/DefaultLayoutRegistryModel.java
trunk/main/transit/core/src/main/net/dpml/transit/util/ConfigurationHandler.java
Log:
updates to the controller to create an initial context through which disposal
may be trigger in a protected fashion - also includes updates to transit to
improve logging information during disposal process
Modified: trunk/main/metro/module.xml
===================================================================
--- trunk/main/metro/module.xml 2006-01-22 22:56:27 UTC (rev 947)
+++ trunk/main/metro/module.xml 2006-01-23 00:56:47 UTC (rev 948)
@@ -68,6 +68,9 @@
<types>
<type id="jar"/>
</types>
+ <properties>
+ <property name="project.test.fork" value="true"/>
+ </properties>
<dependencies scope="build">
<include key="dpml-metro-tools"/>
</dependencies>
Modified:
trunk/main/metro/part/api/src/main/net/dpml/part/local/ControllerContextListener.java
===================================================================
---
trunk/main/metro/part/api/src/main/net/dpml/part/local/ControllerContextListener.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/part/api/src/main/net/dpml/part/local/ControllerContextListener.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -42,5 +42,10 @@
* @param event the change event
*/
void tempDirectoryChanged( ControllerContextEvent event );
-
+
+ /**
+ * Notify listeners of the disposal of the controller.
+ * @param event the context event
+ */
+ void controllerDisposal( ControllerContextEvent event );
}
Added:
trunk/main/metro/part/api/src/main/net/dpml/part/local/InitialContext.java
===================================================================
---
trunk/main/metro/part/api/src/main/net/dpml/part/local/InitialContext.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/part/api/src/main/net/dpml/part/local/InitialContext.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2005 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.part.local;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.util.EventObject;
+import java.util.EventListener;
+
+import net.dpml.part.Disposable;
+
+import net.dpml.transit.Logger;
+import net.dpml.transit.Transit;
+import net.dpml.transit.Repository;
+import net.dpml.transit.monitor.LoggingAdapter;
+
+/**
+ * The CompositionControllerContext class wraps a ContentModel and supplies
convinience
+ * operations that translate ContentModel properties and events to type-safe
values used
+ * in the conposition controller.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class InitialContext extends LocalEventProducer
+ implements ControllerContext, Disposable
+{
+
//----------------------------------------------------------------------------
+ // static
+
//----------------------------------------------------------------------------
+
+ /**
+ * Construct a controller.
+ * @param context the controller context
+ * @return the controller
+ */
+ public static Controller newController( final ControllerContext context )
+ {
+ if( null == context )
+ {
+ throw new NullPointerException( "context" );
+ }
+ try
+ {
+ URI uri = getControllerURI();
+ ClassLoader classloader = InitialContext.class.getClassLoader();
+ Repository repository = Transit.getInstance().getRepository();
+ Class c = repository.getPluginClass( classloader, uri );
+ Constructor constructor = c.getConstructor( new
Class[]{ControllerContext.class} );
+ Controller controller = (Controller) constructor.newInstance(
new Object[]{context} );
+ return controller;
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Internal error while attempting to establish the default part
handler.";
+ throw new RuntimeException( error, e );
+ }
+ }
+
+ private static URI getControllerURI() throws Exception
+ {
+ String spec =
+ System.getProperty(
+ "dpml.part.controller.uri",
+ "@PART-HANDLER-URI@" );
+ return new URI( spec );
+ }
+
+
//----------------------------------------------------------------------------
+ // state
+
//----------------------------------------------------------------------------
+
+ /**
+ * Working directory.
+ */
+ private File m_work;
+
+ /**
+ * Temp directory.
+ */
+ private File m_temp;
+
+ /**
+ * The assigned logging channel.
+ */
+ private Logger m_logger;
+
+
//----------------------------------------------------------------------------
+ // constructor
+
//----------------------------------------------------------------------------
+
+ /**
+ * Creation of a new <tt>CompositionContext</tt>.
+ * @param logger the assigned logging channel
+ */
+ public InitialContext()
+ {
+ this( new LoggingAdapter( "metro" ), null, null );
+ }
+
+ /**
+ * Creation of a new <tt>CompositionContext</tt>.
+ * @param logger the assigned logging channel
+ */
+ public InitialContext( Logger logger )
+ {
+ this( logger, null, null );
+ }
+
+ /**
+ * Creation of a new <tt>CompositionContext</tt>.
+ * @param logger the assigned logging channel
+ * @param work the working directory
+ * @param temp the temporary directory
+ */
+ public InitialContext( Logger logger, File work, File temp )
+ {
+ super( new LoggingAdapter( "metro.context" ) );
+
+ m_logger = logger;
+
+ if( null == work )
+ {
+ String path = System.getProperty( "user.dir" );
+ m_work = new File( path );
+ }
+ else
+ {
+ m_work = work;
+ }
+
+ if( null == temp )
+ {
+ String path = System.getProperty( "java.io.tmpdir" );
+ m_temp = new File( path );
+ }
+ else
+ {
+ m_temp = temp;
+ }
+ }
+
+
//----------------------------------------------------------------------------
+ // Disposable
+
//----------------------------------------------------------------------------
+
+ /**
+ * Initiate disposal.
+ */
+ public void dispose()
+ {
+ m_logger.debug( "context disposal" );
+ ControllerDisposalEvent event = new ControllerDisposalEvent( this );
+ enqueueEvent( event, false );
+ super.dispose();
+ }
+
+
//----------------------------------------------------------------------------
+ // ControllerContext
+
//----------------------------------------------------------------------------
+
+ /**
+ * Return the assigned logging channel
+ * @return the logging channel
+ */
+ public Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ /**
+ * Return the root working directory.
+ *
+ * @return directory representing the root of the working directory
hierachy
+ */
+ public File getWorkingDirectory()
+ {
+ synchronized( getLock() )
+ {
+ return m_work;
+ }
+ }
+
+ /**
+ * Set the root working directory.
+ *
+ * @param dir the root of the working directory hierachy
+ */
+ public void setWorkingDirectory( File dir )
+ {
+ synchronized( getLock() )
+ {
+ m_work = dir;
+ }
+ }
+
+ /**
+ * Return the root temporary directory.
+ *
+ * @return directory representing the root of the temporary directory
hierachy.
+ */
+ public File getTempDirectory()
+ {
+ synchronized( getLock() )
+ {
+ return m_temp;
+ }
+ }
+
+ /**
+ * Add the supplied controller context listener to the controller
context. A
+ * controller implementation should not maintain strong references to
supplied
+ * listeners.
+ *
+ * @param listener the controller context listener to add
+ */
+ public void addControllerContextListener( ControllerContextListener
listener )
+ {
+ addListener( listener );
+ }
+
+ /**
+ * Remove the supplied controller context listener from the controller
context.
+ *
+ * @param listener the controller context listener to remove
+ */
+ public void removeControllerContextListener( ControllerContextListener
listener )
+ {
+ removeListener( listener );
+ }
+
+
//----------------------------------------------------------------------------
+ // impl
+
//----------------------------------------------------------------------------
+
+ /**
+ * Process a context related event.
+ * @param event the event to process
+ */
+ protected void processEvent( EventObject event )
+ {
+ if( event instanceof WorkingDirectoryChangeEvent )
+ {
+ processWorkingDirectoryChangeEvent(
(WorkingDirectoryChangeEvent) event );
+ }
+ else if( event instanceof TempDirectoryChangeEvent )
+ {
+ processTempDirectoryChangeEvent( (TempDirectoryChangeEvent)
event );
+ }
+ else if( event instanceof ControllerDisposalEvent )
+ {
+ processControllerDisposalEvent( (ControllerDisposalEvent) event
);
+ }
+ }
+
+ private void processWorkingDirectoryChangeEvent(
WorkingDirectoryChangeEvent event )
+ {
+ EventListener[] listeners = super.listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener eventListener = listeners[i];
+ if( eventListener instanceof ControllerContextListener )
+ {
+ ControllerContextListener listener =
(ControllerContextListener) eventListener;
+ try
+ {
+ listener.workingDirectoryChanged( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "ControllerContextListener working dir change
notification error.";
+ getLogger().error( error, e );
+ }
+ }
+ }
+ }
+
+ private void processTempDirectoryChangeEvent( TempDirectoryChangeEvent
event )
+ {
+ EventListener[] listeners = super.listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener eventListener = listeners[i];
+ if( eventListener instanceof ControllerContextListener )
+ {
+ ControllerContextListener listener =
(ControllerContextListener) eventListener;
+ try
+ {
+ listener.tempDirectoryChanged( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "ControllerContextListener temp dir change
notification error.";
+ getLogger().error( error, e );
+ }
+ }
+ }
+ }
+
+ private void processControllerDisposalEvent( ControllerDisposalEvent
event )
+ {
+ EventListener[] listeners = super.listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener eventListener = listeners[i];
+ if( eventListener instanceof ControllerContextListener )
+ {
+ ControllerContextListener listener =
(ControllerContextListener) eventListener;
+ try
+ {
+ listener.controllerDisposal( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "ControllerContextListener disposal notification
error.";
+ getLogger().error( error, e );
+ }
+ }
+ }
+ }
+
+
//----------------------------------------------------------------------------
+ // static (private)
+
//----------------------------------------------------------------------------
+
+ /**
+ * Working directory change event impl.
+ */
+ private static class WorkingDirectoryChangeEvent extends
ControllerContextEvent
+ {
+ public WorkingDirectoryChangeEvent(
+ ControllerContext source, File oldDir, File newDir )
+ {
+ super( source, oldDir, newDir );
+ }
+ }
+
+ /**
+ * Temp directory change event impl.
+ */
+ private static class TempDirectoryChangeEvent extends
ControllerContextEvent
+ {
+ public TempDirectoryChangeEvent(
+ ControllerContext source, File oldDir, File newDir )
+ {
+ super( source, oldDir, newDir );
+ }
+ }
+
+ /**
+ * Disposal event.
+ */
+ private static class ControllerDisposalEvent extends
ControllerContextEvent
+ {
+ public ControllerDisposalEvent( ControllerContext source )
+ {
+ super( source, null, null );
+ }
+ }
+
+}
Added:
trunk/main/metro/part/api/src/main/net/dpml/part/local/LocalEventProducer.java
===================================================================
---
trunk/main/metro/part/api/src/main/net/dpml/part/local/LocalEventProducer.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/part/api/src/main/net/dpml/part/local/LocalEventProducer.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005 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.part.local;
+
+import java.util.EventObject;
+import java.util.EventListener;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.HashMap;
+
+import net.dpml.transit.Logger;
+import net.dpml.transit.util.ExceptionHelper;
+
+/**
+ * A abstract base class that established an event queue and handles event
dispatch
+ * operations for listeners declared in a class extending this base class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+abstract class LocalEventProducer
+{
+ private Map m_listeners = new HashMap();
+
+ private Logger m_logger;
+
+ /**
+ * Internal synchronization lock.
+ */
+ private final Object m_lock = new Object();
+
+ LocalEventProducer( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ protected Object getLock()
+ {
+ return m_lock;
+ }
+
+ void dispose()
+ {
+ m_logger.debug( "context event channel disposal" );
+ synchronized( getLock() )
+ {
+ if( null != m_EVENT_DISPATCH_THREAD )
+ {
+ m_EVENT_DISPATCH_THREAD.dispose();
+ }
+ }
+ }
+
+ /**
+ * Abstract operation to be implemented by classes extending this base
class.
+ * An implementation is reposible for the posting of the event to
associated
+ * listeners. Event posting will be executed under a separate thread to
the
+ * thread that initiated the event post.
+ *
+ * @param event the event to process
+ */
+ protected abstract void processEvent( EventObject event );
+
+ /**
+ * Add a listener to the set of listeners handled by this producer.
+ * @param listener the event listener
+ */
+ protected void addListener( EventListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+ synchronized( m_lock )
+ {
+ m_logger.debug( "adding context listener" );
+ m_listeners.put( listener, null );
+ }
+ startEventDispatchThread( m_logger );
+ }
+
+ /**
+ * Remove a listener to the set of listeners handled by this producer.
+ * @param listener the event listener
+ */
+ protected void removeListener( EventListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+ synchronized( m_lock )
+ {
+ m_logger.debug( "removing context listener" );
+ m_listeners.remove( listener );
+ }
+ }
+
+ /**
+ * Queue of pending notification events. When an event for which
+ * there are one or more listeners occurs, it is placed on this queue
+ * and the queue is notified. A background thread waits on this queue
+ * and delivers the events. This decouples event delivery from
+ * the application concern, greatly simplifying locking and reducing
+ * opportunity for deadlock.
+ */
+ private static final List EVENT_QUEUE = new LinkedList();
+
+ /**
+ * A single background thread ("the event notification thread") monitors
+ * the event queue and delivers events that are placed on the queue.
+ */
+ /**
+ * A single background thread ("the event notification thread") monitors
+ * the event queue and delivers events that are placed on the queue.
+ */
+ private static class EventDispatchThread extends Thread
+ {
+ private boolean m_continue = true;
+ private final Logger m_logger;
+
+ EventDispatchThread( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ void dispose()
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ m_logger.debug( "terminating event dispatch thread" );
+ m_continue = false;
+ EVENT_QUEUE.notify();
+ }
+ }
+
+ public void run()
+ {
+ while( m_continue )
+ {
+ // Wait on EVENT_QUEUE till an event is present
+ EventObject event = null;
+ synchronized( EVENT_QUEUE )
+ {
+ try
+ {
+ while( m_continue && EVENT_QUEUE.isEmpty() )
+ {
+ EVENT_QUEUE.wait();
+ }
+ if ( !m_continue )
+ {
+ break;
+ }
+ Object object = EVENT_QUEUE.remove( 0 );
+ try
+ {
+ event = (EventObject) object;
+ }
+ catch( ClassCastException cce )
+ {
+ final String error =
+ "Unexpected class cast exception while
processing an event."
+ + "\nEvent: " + object;
+ throw new IllegalStateException( error );
+ }
+ }
+ catch( InterruptedException e )
+ {
+ return;
+ }
+ }
+
+ Object source = event.getSource();
+ if( source instanceof LocalEventProducer )
+ {
+ LocalEventProducer producer = (LocalEventProducer)
source;
+ try
+ {
+ producer.processEvent( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while processing event."
+ + "\nEvent: " + event
+ + "\nSource: " + this;
+ m_logger.warn( error, e );
+ }
+ }
+ else
+ {
+ final String error =
+ "Event source is not an instance of "
+ + LocalEventProducer.class.getName();
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+ }
+
+ private static EventDispatchThread m_EVENT_DISPATCH_THREAD = null;
+
+ /**
+ * This method starts the event dispatch thread the first time it
+ * is called. The event dispatch thread will be started only
+ * if someone registers a listener.
+ */
+ private static synchronized void startEventDispatchThread( Logger logger
)
+ {
+ if( m_EVENT_DISPATCH_THREAD == null )
+ {
+ m_EVENT_DISPATCH_THREAD = new EventDispatchThread( logger );
+ m_EVENT_DISPATCH_THREAD.setDaemon( true );
+ m_EVENT_DISPATCH_THREAD.start();
+ }
+ }
+
+ /**
+ * Return this node's preference/node change listeners. Even though
+ * we're using a copy-on-write lists, we use synchronized accessors to
+ * ensure information transmission from the writing thread to the
+ * reading thread.
+ */
+ protected EventListener[] listeners()
+ {
+ synchronized( m_lock )
+ {
+ return (EventListener[]) m_listeners.keySet().toArray( new
EventListener[0] );
+ }
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ */
+ protected void enqueueEvent( EventObject event )
+ {
+ enqueueEvent( event, true );
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ */
+ protected void enqueueEvent( EventObject event, boolean asynchronouse )
+ {
+ if( m_listeners.size() != 0 )
+ {
+ if( asynchronouse )
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ EVENT_QUEUE.add( event );
+ EVENT_QUEUE.notify();
+ }
+ }
+ else
+ {
+ processEvent( event );
+ }
+ }
+ }
+}
Modified:
trunk/main/metro/part/api/src/main/net/dpml/part/local/PartManager.java
===================================================================
--- trunk/main/metro/part/api/src/main/net/dpml/part/local/PartManager.java
2006-01-22 22:56:27 UTC (rev 947)
+++ trunk/main/metro/part/api/src/main/net/dpml/part/local/PartManager.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -73,6 +73,36 @@
}
}
+ /**
+ * Construct a controller.
+ * @param context the controller context
+ * @return the controller
+ */
+ public static Controller newController( final ControllerContext context )
+ {
+ if( null == context )
+ {
+ throw new NullPointerException( "context" );
+ }
+ try
+ {
+ long now = new Date().getTime();
+ ClassLoader classloader = PartManager.class.getClassLoader();
+ URI uri = getControllerURI();
+ Repository repository = Transit.getInstance().getRepository();
+ Class c = repository.getPluginClass( classloader, uri );
+ Constructor constructor = c.getConstructor( new
Class[]{ControllerContext.class} );
+ Controller controller = (Controller) constructor.newInstance(
new Object[]{context} );
+ return controller;
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Internal error while attempting to establish the default part
handler.";
+ throw new RuntimeException( error, e );
+ }
+ }
+
private final Logger m_logger;
private final Controller m_handler;
Added: trunk/main/metro/part/test/etc/test/logging.properties
===================================================================
--- trunk/main/metro/part/test/etc/test/logging.properties 2006-01-22
22:56:27 UTC (rev 947)
+++ trunk/main/metro/part/test/etc/test/logging.properties 2006-01-23
00:56:47 UTC (rev 948)
@@ -0,0 +1,3 @@
+.level=FINE
+sun.rmi.level=INFO
+sun.rmi.transport.tcp.level=INFO
Modified:
trunk/main/metro/part/test/src/test/net/dpml/test/part/PartLoadingTestCase.java
===================================================================
---
trunk/main/metro/part/test/src/test/net/dpml/test/part/PartLoadingTestCase.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/part/test/src/test/net/dpml/test/part/PartLoadingTestCase.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -20,12 +20,17 @@
import java.io.File;
import java.net.URI;
+import java.util.logging.Logger;
import junit.framework.TestCase;
import net.dpml.part.Directive;
import net.dpml.part.local.Controller;
+import net.dpml.part.local.InitialContext;
+import net.dpml.transit.DefaultTransitModel;
+import net.dpml.transit.Transit;
+
/**
* Testcase validating part loading from a uri.
*
@@ -34,8 +39,6 @@
*/
public class PartLoadingTestCase extends TestCase
{
- private static final Controller CONTROLLER = Controller.STANDARD;
-
private URI m_uri;
/**
@@ -47,16 +50,49 @@
final String path = "test.part";
final File test = new File( System.getProperty( "project.test.dir" )
);
m_uri = new File( test, path ).toURI();
+ final File config = new File( test, "logging.properties" );
+ final String spec = config.toURI().toASCIIString();
}
-
+
/**
* Test part loading via a controller.
* @exception Exception if an error occurs
*/
public void testPartLoading() throws Exception
{
- Directive directive = CONTROLLER.loadDirective( m_uri );
+ Logger.global.info( "commencing test." );
+
+ // initialize transit
+
+ DefaultTransitModel model = DefaultTransitModel.getDefaultModel();
+ Transit.getInstance( model );
+
+ // initialize the controller
+
+ InitialContext context = new InitialContext();
+ Controller controller = InitialContext.newController( context );
+
+ // do stuff
+
+ Directive directive = controller.loadDirective( m_uri );
String classname = directive.getClass().getName();
assertEquals( "directive-classname",
"net.dpml.metro.data.ComponentDirective", classname );
+
+ // shutdown controller and transit
+
+ context.dispose();
+ model.dispose();
+
+ Logger.global.info( "test complete." );
}
+
+ static
+ {
+ System.setProperty(
+ "java.util.logging.config.class",
+ "net.dpml.transit.util.ConfigurationHandler" );
+ System.setProperty(
+ "dpml.logging.config",
+ "file:" + System.getProperty( "project.test.dir" ) +
"/logging.properties" );
+ }
}
Modified:
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionContext.java
===================================================================
---
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionContext.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionContext.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -22,6 +22,7 @@
import java.util.EventObject;
import java.util.EventListener;
+import net.dpml.part.Disposable;
import net.dpml.part.local.ControllerContext;
import net.dpml.part.local.ControllerContextListener;
import net.dpml.part.local.ControllerContextEvent;
@@ -36,7 +37,8 @@
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class CompositionContext extends LocalWeakEventProducer implements
ControllerContext
+public class CompositionContext extends LocalWeakEventProducer
+ implements ControllerContext, Disposable
{
//----------------------------------------------------------------------------
// state
@@ -109,6 +111,14 @@
}
//----------------------------------------------------------------------------
+ // Disposable
+
//----------------------------------------------------------------------------
+
+ public void dispose()
+ {
+ }
+
+
//----------------------------------------------------------------------------
// ControllerContext
//----------------------------------------------------------------------------
@@ -200,6 +210,10 @@
{
processTempDirectoryChangeEvent( (TempDirectoryChangeEvent)
event );
}
+ else if( event instanceof ControllerDisposalEvent )
+ {
+ processControllerDisposalEvent( (ControllerDisposalEvent) event
);
+ }
else
{
super.processEvent( event );
@@ -252,6 +266,29 @@
}
}
+ private void processControllerDisposalEvent( ControllerDisposalEvent
event )
+ {
+ EventListener[] listeners = super.listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener eventListener = listeners[i];
+ if( eventListener instanceof ControllerContextListener )
+ {
+ ControllerContextListener listener =
(ControllerContextListener) eventListener;
+ try
+ {
+ listener.controllerDisposal( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "ControllerContextListener disposal notification
error.";
+ getLogger().error( error, e );
+ }
+ }
+ }
+ }
+
//----------------------------------------------------------------------------
// static (private)
//----------------------------------------------------------------------------
@@ -280,4 +317,15 @@
}
}
+ /**
+ * Disposal event.
+ */
+ private static class ControllerDisposalEvent extends
ControllerContextEvent
+ {
+ public ControllerDisposalEvent( ControllerContext source )
+ {
+ super( source, null, null );
+ }
+ }
+
}
Modified:
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionController.java
===================================================================
---
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionController.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/CompositionController.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -31,9 +31,6 @@
import net.dpml.metro.data.ComponentDirective;
import net.dpml.metro.model.ComponentModel;
-import net.dpml.part.local.ControllerContext;
-import net.dpml.part.remote.Model;
-import net.dpml.part.remote.Component;
import net.dpml.part.local.Controller;
import net.dpml.part.ControlException;
import net.dpml.part.DelegationException;
@@ -41,6 +38,11 @@
import net.dpml.part.Part;
import net.dpml.part.PartBuilder;
import net.dpml.part.PartHeader;
+import net.dpml.part.local.ControllerContext;
+import net.dpml.part.local.ControllerContextListener;
+import net.dpml.part.local.ControllerContextEvent;
+import net.dpml.part.remote.Model;
+import net.dpml.part.remote.Component;
import net.dpml.transit.Repository;
import net.dpml.transit.Transit;
@@ -56,7 +58,7 @@
public class CompositionController implements Controller
{
//--------------------------------------------------------------------
- // state
+ // immutable state
//--------------------------------------------------------------------
private final Logger m_logger;
@@ -66,6 +68,12 @@
private final Repository m_loader;
//--------------------------------------------------------------------
+ // mutable state
+ //--------------------------------------------------------------------
+
+ private boolean m_disposed = false;
+
+ //--------------------------------------------------------------------
// constructor
//--------------------------------------------------------------------
@@ -92,9 +100,13 @@
m_context = context;
m_logger = new StandardLogger( context.getLogger() );
+
+ m_context.addControllerContextListener(
+ new InternalControllerContextListener( this ) );
m_loader = Transit.getInstance().getRepository();
m_logger.debug( "controller: " + CONTROLLER_URI );
m_controller = new ComponentController( m_logger, this );
+ startEventDispatchThread();
}
//--------------------------------------------------------------------
@@ -342,6 +354,17 @@
throw new ControllerNotFoundException( CONTROLLER_URI, uri, e );
}
}
+
+ void dispose()
+ {
+ getLogger().info( "initating controller disposal" );
+ m_disposed = true;
+ }
+
+ boolean isDisposed()
+ {
+ return m_disposed;
+ }
/**
* Static URI of this controller.
@@ -405,18 +428,28 @@
*/
private static class EventDispatchThread extends Thread
{
+ private final CompositionController m_controller;
+ private final Logger m_logger;
+
+ EventDispatchThread( CompositionController controller, Logger logger
)
+ {
+ m_controller = controller;
+ m_logger = logger;
+ m_logger.debug( "starting event dispatch thread" );
+ }
+
public void run()
{
- while( true )
+ while( !m_controller.isDisposed() )
{
// Wait on EVENT_QUEUE till an event is present
EventObject event = null;
synchronized( EVENT_QUEUE )
{
- try
+ try
{
while( EVENT_QUEUE.isEmpty() )
- {
+ {
EVENT_QUEUE.wait();
}
Object object = EVENT_QUEUE.remove( 0 );
@@ -465,23 +498,64 @@
throw new IllegalStateException( error );
}
}
+
+ m_logger.info( "Controller event queue terminating." );
}
}
- private static Thread m_EVENT_DISPATCH_THREAD = null;
+ private EventDispatchThread m_EVENT_DISPATCH_THREAD = null;
/**
* This method starts the event dispatch thread the first time it
* is called. The event dispatch thread will be started only
* if someone registers a listener.
*/
- static synchronized void startEventDispatchThread()
+ private synchronized void startEventDispatchThread()
{
- if( m_EVENT_DISPATCH_THREAD == null )
+ if( m_EVENT_DISPATCH_THREAD == null )
{
- m_EVENT_DISPATCH_THREAD = new EventDispatchThread();
+ Logger logger = getLogger();
+ m_EVENT_DISPATCH_THREAD = new EventDispatchThread( this, logger
);
m_EVENT_DISPATCH_THREAD.setDaemon( true );
m_EVENT_DISPATCH_THREAD.start();
}
}
+
+ private class InternalControllerContextListener implements
ControllerContextListener
+ {
+ private final CompositionController m_controller;
+
+ public InternalControllerContextListener( final
CompositionController controller )
+ {
+ m_controller = controller;
+ }
+
+ /**
+ * Notify the listener that the working directory has changed.
+ *
+ * @param event the change event
+ */
+ public void workingDirectoryChanged( ControllerContextEvent event )
+ {
+ }
+
+ /**
+ * Notify the listener that the temporary directory has changed.
+ *
+ * @param event the change event
+ */
+ public void tempDirectoryChanged( ControllerContextEvent event )
+ {
+ }
+
+ /**
+ * Notify listeners of the disposal of the controller.
+ * @param event the context event
+ */
+ public void controllerDisposal( ControllerContextEvent event )
+ {
+ System.out.println( "# DISPOSAL EVENT" );
+ m_controller.dispose();
+ }
+ }
}
Modified:
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/UnicastEventSource.java
===================================================================
---
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/UnicastEventSource.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/metro/runtime/src/main/net/dpml/metro/runtime/UnicastEventSource.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -91,7 +91,6 @@
System.arraycopy( old, 0, m_listeners, 0, old.length );
m_listeners[old.length] = listener;
}
- CompositionController.startEventDispatchThread();
}
/**
Modified:
trunk/main/transit/core/src/main/net/dpml/transit/DefaultCacheModel.java
===================================================================
--- trunk/main/transit/core/src/main/net/dpml/transit/DefaultCacheModel.java
2006-01-22 22:56:27 UTC (rev 947)
+++ trunk/main/transit/core/src/main/net/dpml/transit/DefaultCacheModel.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -100,7 +100,7 @@
try
{
- Logger log = logger.getChildLogger( "registry" );
+ Logger log = logger.getChildLogger( "layout" );
LayoutDirective[] layouts = directive.getLayoutDirectives();
m_registry = new DefaultLayoutRegistryModel( log, layouts );
String layout = directive.getCacheLayout();
Modified:
trunk/main/transit/core/src/main/net/dpml/transit/DefaultLayoutRegistryModel.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/DefaultLayoutRegistryModel.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/transit/core/src/main/net/dpml/transit/DefaultLayoutRegistryModel.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -70,13 +70,19 @@
// add the standard layouts
LayoutModel modern =
- new StandardLayoutModel( logger, "modern", "Modern",
ModernLayout.class.getName() );
+ new StandardLayoutModel(
+ logger.getChildLogger( "modern" ),
+ "modern", "Modern", ModernLayout.class.getName() );
addLayoutModel( modern, false );
LayoutModel classic =
- new StandardLayoutModel( logger, "classic", "Classic",
ClassicLayout.class.getName() );
+ new StandardLayoutModel(
+ logger.getChildLogger( "classic" ),
+ "classic", "Classic", ClassicLayout.class.getName() );
addLayoutModel( classic, false );
LayoutModel eclipse =
- new StandardLayoutModel( logger, "eclipse", "Eclipse",
EclipseLayout.class.getName() );
+ new StandardLayoutModel(
+ logger.getChildLogger( "eclipse" ),
+ "eclipse", "Eclipse", EclipseLayout.class.getName() );
addLayoutModel( eclipse, false );
// add the custom layouts
Modified:
trunk/main/transit/core/src/main/net/dpml/transit/util/ConfigurationHandler.java
===================================================================
---
trunk/main/transit/core/src/main/net/dpml/transit/util/ConfigurationHandler.java
2006-01-22 22:56:27 UTC (rev 947)
+++
trunk/main/transit/core/src/main/net/dpml/transit/util/ConfigurationHandler.java
2006-01-23 00:56:47 UTC (rev 948)
@@ -49,7 +49,13 @@
{
String group = System.getProperty( "dpml.logging.category", "root" );
- String level = System.getProperty( "dpml.logging.level", "INFO"
).toUpperCase();
+ String level =
+ System.getProperty(
+ "dpml.logging.level",
+ System.getProperty(
+ ".level",
+ "INFO" )
+ ).toUpperCase();
Properties properties = new Properties();
- r948 - in trunk/main: metro metro/part/api/src/main/net/dpml/part/local metro/part/test metro/part/test/etc metro/part/test/etc/test metro/part/test/src/test/net/dpml/test/part metro/runtime/src/main/net/dpml/metro/runtime transit/core/src/main/net/dpml/transit transit/core/src/main/net/dpml/transit/util, mcconnell at BerliOS, 01/22/2006
Archive powered by MHonArc 2.6.24.