notify-dpml AT lists.ibiblio.org
Subject: DPML Notify
List archive
r989 - in trunk/main/metro: exec exec/etc exec/etc/bin station/server/src/main/net/dpml/station/server
- From: mcconnell at BerliOS <mcconnell AT mail.berlios.de>
- To: notify-dpml AT lists.ibiblio.org
- Subject: r989 - in trunk/main/metro: exec exec/etc exec/etc/bin station/server/src/main/net/dpml/station/server
- Date: Sun, 29 Jan 2006 16:29:52 +0100
Author: mcconnell
Date: 2006-01-29 16:29:51 +0100 (Sun, 29 Jan 2006)
New Revision: 989
Added:
trunk/main/metro/station/server/src/main/net/dpml/station/server/UnicastEventSource.java
Removed:
trunk/main/metro/exec/etc/prefs/
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java
Modified:
trunk/main/metro/exec/build.xml
trunk/main/metro/exec/etc/bin/metro
trunk/main/metro/exec/etc/bin/metro.lap
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteApplication.java
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteStation.java
Log:
rework the shutdown procedure to resolve a locking condition
Modified: trunk/main/metro/exec/build.xml
===================================================================
--- trunk/main/metro/exec/build.xml 2006-01-29 15:29:07 UTC (rev 988)
+++ trunk/main/metro/exec/build.xml 2006-01-29 15:29:51 UTC (rev 989)
@@ -20,13 +20,6 @@
</target>
<target name="install" depends="bin,standard.install">
- <property name="prefs" location="${dpml.prefs}/dpml/metro"/>
- <mkdir dir="${prefs}"/>
- <copy toDir="${prefs}">
- <fileset dir="target/prefs">
- <include name="**/*"/>
- </fileset>
- </copy>
<copy todir="${dpml.system}" preservelastmodified="true"
overwrite="true">
<fileset dir="target">
<include name="bin/metro.lap"/>
Modified: trunk/main/metro/exec/etc/bin/metro
===================================================================
--- trunk/main/metro/exec/etc/bin/metro 2006-01-29 15:29:07 UTC (rev 988)
+++ trunk/main/metro/exec/etc/bin/metro 2006-01-29 15:29:51 UTC (rev 989)
@@ -1,13 +1,13 @@
-#!/bin/sh
-#
-
-METRO_JVM_OPTS="-Ddpml.depot.application=dpml.metro
-Ddpml.logging.config=local:properties:dpml/metro/logging"
-
-if [ "$DEPOT_JVM_OPTS" = "" ] ; then
- DEPOT_JVM_OPTS=$METRO_JVM_OPTS
-else
- DEPOT_JVM_OPTS="$METRO_JVM_OPTS $DEPOT_JVM_OPTS"
-fi
-export DEPOT_JVM_OPTS
-
-depot $*
+#!/bin/sh
+#
+
+METRO_JVM_OPTS="-Ddpml.depot.application=dpml.metro
-Ddpml.logging.config=local:properties:dpml/transit/default"
+
+if [ "$DEPOT_JVM_OPTS" = "" ] ; then
+ DEPOT_JVM_OPTS=$METRO_JVM_OPTS
+else
+ DEPOT_JVM_OPTS="$METRO_JVM_OPTS $DEPOT_JVM_OPTS"
+fi
+export DEPOT_JVM_OPTS
+
+depot $*
Modified: trunk/main/metro/exec/etc/bin/metro.lap
===================================================================
--- trunk/main/metro/exec/etc/bin/metro.lap 2006-01-29 15:29:07 UTC (rev
988)
+++ trunk/main/metro/exec/etc/bin/metro.lap 2006-01-29 15:29:51 UTC (rev
989)
@@ -7,7 +7,7 @@
-Ddpml.depot.application=dpml.metro
-Djava.protocol.handler.pkgs=net.dpml.transit
-Djava.rmi.server.RMIClassLoaderSpi=net.dpml.depot.DepotRMIClassLoaderSpi
--Ddpml.logging.config=local:properties:dpml/metro/logging
+-Ddpml.logging.config=local:properties:dpml/transit/default
janel.main.class=net.dpml.depot.Main
janel.min.java.version=1.4.0
janel.classpath.jars.dir=${env.DPML_HOME}\share\lib
Deleted:
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java
===================================================================
---
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java
2006-01-29 15:29:07 UTC (rev 988)
+++
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java
2006-01-29 15:29:51 UTC (rev 989)
@@ -1,271 +0,0 @@
-/*
- * 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.station.server;
-
-import java.util.EventObject;
-import java.util.EventListener;
-import java.util.List;
-import java.util.LinkedList;
-import java.rmi.server.UnicastRemoteObject;
-import java.rmi.RemoteException;
-
-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@
- */
-public abstract class EventChannel extends UnicastRemoteObject
-{
- /**
- * Registered event listeners.
- */
- private EventListener[] m_listeners = new EventListener[0];
-
- private Logger m_logger;
-
- /**
- * Internal synchronization lock.
- */
- private final Object m_lock = new Object();
-
- /**
- * Creation of a new event producer.
- * @param logger the logging channel
- * @exception RemoteException if a remote exception occurs
- */
- public EventChannel( Logger logger ) throws RemoteException
- {
- super();
-
- m_logger = logger;
- }
-
- /**
- * Return the assigned logging channel.
- * @return the logging channel
- */
- protected Logger getLogger()
- {
- return m_logger;
- }
-
- /**
- * 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 )
- {
- Object[] old = m_listeners;
- m_listeners = new EventListener[ old.length + 1 ];
- System.arraycopy( old, 0, m_listeners, 0, old.length );
- m_listeners[old.length] = listener;
- }
- startEventDispatchThread();
- }
-
- /**
- * 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 )
- {
- if( m_listeners.length == 0 )
- {
- throw new IllegalArgumentException( "Listener not
registered." );
- }
- // create the copy
- EventListener[] replacement = new EventListener[
m_listeners.length - 1 ];
- // copy listeners from 0 up to the listener being removed
- int i=0;
- while( i < replacement.length && m_listeners[i] != listener )
- {
- replacement[i] = m_listeners[i++];
- }
- // check that the listener has been located
- if( i == replacement.length && m_listeners[i] != listener )
- {
- throw new IllegalArgumentException( "Listener not
registered." );
- }
- // complete the copy operation
- while( i < replacement.length )
- {
- replacement[i] = m_listeners[++i];
- }
- // commit the copy
- m_listeners = replacement;
- }
- }
-
- /**
- * 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.
- */
- private static class EventDispatchThread extends Thread
- {
- public void run()
- {
- while( true )
- {
- // Wait on EVENT_QUEUE till an event is present
- EventObject event = null;
- synchronized( EVENT_QUEUE )
- {
- try
- {
- while( EVENT_QUEUE.isEmpty() )
- {
- EVENT_QUEUE.wait();
- }
- 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 EventChannel )
- {
- EventChannel producer = (EventChannel) source;
- try
- {
- producer.processEvent( event );
- }
- catch( Throwable e )
- {
- final String error =
- "Unexpected error while processing event."
- + "\nEvent: " + event
- + "\nSource: " + source;
- String msg = ExceptionHelper.packException( error,
e, true );
- System.err.println( msg );
- }
- }
- else
- {
- final String error =
- "Event source is not an instance of " +
EventChannel.class.getName();
- throw new IllegalStateException( error );
- }
- }
- }
- }
-
- private static Thread 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()
- {
- if( m_EVENT_DISPATCH_THREAD == null )
- {
- m_EVENT_DISPATCH_THREAD = new EventDispatchThread();
- 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.
- * @return the event listener array
- */
- protected EventListener[] listeners()
- {
- synchronized( m_lock )
- {
- return m_listeners;
- }
- }
-
- /**
- * Enqueue an event for delivery to registered
- * listeners unless there are no registered
- * listeners.
- * @param event the event to enqueue
- */
- protected void enqueueEvent( EventObject event )
- {
- if( m_listeners.length != 0 )
- {
- synchronized( EVENT_QUEUE )
- {
- EVENT_QUEUE.add( event );
- EVENT_QUEUE.notify();
- }
- }
- }
-}
Modified:
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteApplication.java
===================================================================
---
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteApplication.java
2006-01-29 15:29:07 UTC (rev 988)
+++
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteApplication.java
2006-01-29 15:29:51 UTC (rev 989)
@@ -54,7 +54,7 @@
* @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
* @version @PROJECT-VERSION@
*/
-public class RemoteApplication extends EventChannel implements Callback,
Application
+public class RemoteApplication extends UnicastEventSource implements
Callback, Application
{
private final Logger m_logger;
private final ApplicationDescriptor m_descriptor;
@@ -386,7 +386,7 @@
}
finally
{
- UnicastRemoteObject.unexportObject( this, true );
+ //UnicastRemoteObject.unexportObject( this, true ); // handled
in station
}
}
Modified:
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteStation.java
===================================================================
---
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteStation.java
2006-01-29 15:29:07 UTC (rev 988)
+++
trunk/main/metro/station/server/src/main/net/dpml/station/server/RemoteStation.java
2006-01-29 15:29:51 UTC (rev 989)
@@ -27,6 +27,9 @@
import java.util.Map;
import java.util.Hashtable;
import java.util.logging.LogRecord;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.EventObject;
import net.dpml.station.Application;
import net.dpml.station.Callback;
@@ -94,6 +97,7 @@
}
setShutdownHook( this );
+ startEventDispatchThread();
try
{
@@ -220,6 +224,7 @@
{
RemoteApplication application = applications[i];
application.shutdown();
+ UnicastRemoteObject.unexportObject( application, true );
}
UnicastRemoteObject.unexportObject( m_registry, true );
}
@@ -254,6 +259,7 @@
{
public void run()
{
+ RemoteStation.m_dispatch.dispose();
System.exit( 0 );
}
}
@@ -360,7 +366,140 @@
return registry;
}
}
+
+ /**
+ * 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();
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ * @param event the event to enqueue
+ */
+ static void enqueueEvent( EventObject event )
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ EVENT_QUEUE.add( event );
+ EVENT_QUEUE.notify();
+ }
+ }
+ /**
+ * 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 final Logger m_logger;
+
+ private boolean m_continue = true;
+
+ EventDispatchThread( Logger logger )
+ {
+ m_logger = logger;
+ m_logger.debug( "starting event dispatch thread" );
+ }
+
+ void dispose()
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ m_logger.debug( "stopping 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( EVENT_QUEUE.isEmpty() )
+ {
+ EVENT_QUEUE.wait();
+ }
+ 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 UnicastEventSource )
+ {
+ UnicastEventSource producer = (UnicastEventSource)
source;
+ try
+ {
+ producer.processEvent( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while processing event."
+ + "\nEvent: " + event
+ + "\nSource: " + source;
+ m_logger.warn( error, e );
+ }
+ }
+ else
+ {
+ final String error =
+ "Event source ["
+ + source.getClass().getName()
+ + "] is not an instance of " +
UnicastEventSource.class.getName();
+ throw new IllegalStateException( error );
+ }
+ }
+
+ m_logger.info( "Controller event queue terminating." );
+ }
+ }
+
+ private static EventDispatchThread m_dispatch = 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 synchronized void startEventDispatchThread()
+ {
+ if( m_dispatch == null )
+ {
+ Logger logger = getLogger().getChildLogger( "event" );
+ m_dispatch = new EventDispatchThread( logger );
+ m_dispatch.setDaemon( true );
+ m_dispatch.start();
+ }
+ }
+
/**
* Create a shutdown hook that will trigger shutdown of the supplied
plugin.
* @param station the station
Copied:
trunk/main/metro/station/server/src/main/net/dpml/station/server/UnicastEventSource.java
(from rev 980,
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java)
===================================================================
---
trunk/main/metro/station/server/src/main/net/dpml/station/server/EventChannel.java
2006-01-26 07:36:59 UTC (rev 980)
+++
trunk/main/metro/station/server/src/main/net/dpml/station/server/UnicastEventSource.java
2006-01-29 15:29:51 UTC (rev 989)
@@ -0,0 +1,172 @@
+/*
+ * 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.station.server;
+
+import java.util.EventObject;
+import java.util.EventListener;
+import java.util.List;
+import java.util.LinkedList;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.RemoteException;
+
+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@
+ */
+public abstract class UnicastEventSource extends UnicastRemoteObject
+{
+ /**
+ * Registered event listeners.
+ */
+ private EventListener[] m_listeners = new EventListener[0];
+
+ private Logger m_logger;
+
+ /**
+ * Internal synchronization lock.
+ */
+ private final Object m_lock = new Object();
+
+ /**
+ * Creation of a new event producer.
+ * @param logger the logging channel
+ * @exception RemoteException if a remote exception occurs
+ */
+ public UnicastEventSource( Logger logger ) throws RemoteException
+ {
+ super();
+
+ m_logger = logger;
+ }
+
+ /**
+ * Return the assigned logging channel.
+ * @return the logging channel
+ */
+ protected Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ /**
+ * 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 )
+ {
+ Object[] old = m_listeners;
+ m_listeners = new EventListener[ old.length + 1 ];
+ System.arraycopy( old, 0, m_listeners, 0, old.length );
+ m_listeners[old.length] = listener;
+ }
+ }
+
+ /**
+ * 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 )
+ {
+ if( m_listeners.length == 0 )
+ {
+ throw new IllegalArgumentException( "Listener not
registered." );
+ }
+ // create the copy
+ EventListener[] replacement = new EventListener[
m_listeners.length - 1 ];
+ // copy listeners from 0 up to the listener being removed
+ int i=0;
+ while( i < replacement.length && m_listeners[i] != listener )
+ {
+ replacement[i] = m_listeners[i++];
+ }
+ // check that the listener has been located
+ if( i == replacement.length && m_listeners[i] != listener )
+ {
+ throw new IllegalArgumentException( "Listener not
registered." );
+ }
+ // complete the copy operation
+ while( i < replacement.length )
+ {
+ replacement[i] = m_listeners[++i];
+ }
+ // commit the copy
+ m_listeners = replacement;
+ }
+ }
+
+ /**
+ * 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.
+ * @return the event listener array
+ */
+ protected EventListener[] listeners()
+ {
+ synchronized( m_lock )
+ {
+ return m_listeners;
+ }
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ * @param event the event to enqueue
+ */
+ protected void enqueueEvent( EventObject event )
+ {
+ if( m_listeners.length != 0 )
+ {
+ RemoteStation.enqueueEvent( event );
+ }
+ }
+}
- r989 - in trunk/main/metro: exec exec/etc exec/etc/bin station/server/src/main/net/dpml/station/server, mcconnell at BerliOS, 01/29/2006
Archive powered by MHonArc 2.6.24.