Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2460 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/event composition/control/src/main/net/dpml/composition/model composition/testing/test/src/main/net/dpml/test/state parts/src/main/net/dpml/parts/state

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: r2460 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/event composition/control/src/main/net/dpml/composition/model composition/testing/test/src/main/net/dpml/test/state parts/src/main/net/dpml/parts/state
  • Date: Wed, 04 May 2005 21:06:37 -0400

Author: mcconnell AT dpml.net
Date: Wed May 4 21:06:34 2005
New Revision: 2460

Added:

development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityListener.java

development/main/metro/composition/control/src/main/net/dpml/composition/event/EventProducer.java
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/ComponentController.java

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

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

development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityEvent.java

development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java

development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
development/main/metro/parts/src/main/net/dpml/parts/state/StateEvent.java

development/main/metro/parts/src/main/net/dpml/parts/state/StateListener.java
Log:
Add a proper event queue and dispatch mechanism.

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
Wed May 4 21:06:34 2005
@@ -24,9 +24,12 @@
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;

+import net.dpml.composition.event.AvailabilityEvent;
+import net.dpml.composition.event.AvailabilityListener;
import net.dpml.composition.model.ComponentEntry;

import net.dpml.parts.control.Disposable;
+import net.dpml.parts.state.ResourceUnavailableException;

/**
* The ApplianceInvocationHandler class represents an instance of a
component.
@@ -37,13 +40,14 @@
* @version $Id: ApplianceInvocationHandler.java 2106 2005-03-21 18:46:10Z
mcconnell AT dpml.net $
*/
final class ApplianceInvocationHandler
- implements InvocationHandler, Disposable
+ implements InvocationHandler, Disposable, AvailabilityListener
{
//-------------------------------------------------------------------
// state
//-------------------------------------------------------------------

private final ComponentEntry m_component;
+ private boolean m_available = true;
private boolean m_disposed = false;

//-------------------------------------------------------------------
@@ -60,6 +64,16 @@
{
assertNotNull( component, "component" );
m_component = component;
+ m_component.addAvailabilityListener( this );
+ }
+
+ //-------------------------------------------------------------------
+ // AvailabilityListener
+ //-------------------------------------------------------------------
+
+ public void availabilityChanged( AvailabilityEvent event )
+ {
+ m_available = event.isAvailable();
}

//-------------------------------------------------------------------
@@ -84,6 +98,19 @@
throw new IllegalStateException( "destroyed" );
}

+ // check if our availability flag has bene set to FALSE
+
+ if( false == m_available )
+ {
+ final String error =
+ "Component is not currently available."
+ + "\nComponent URI: " + m_component.getURI()
+ + "\nClass: " +
m_component.getModel().getDeploymentClass().getName();
+ throw new ResourceUnavailableException( error );
+ }
+
+ // otherwise lets' go with an optomistic attitude
+
try
{
Object instance = m_component.resolve( false );
@@ -109,6 +136,7 @@
if( !m_disposed )
{
m_disposed = true;
+ m_component.removeAvailabilityListener( this );
m_component.release( this );
}
}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
Wed May 4 21:06:34 2005
@@ -193,9 +193,9 @@
else
{
final String error =
- "Unsupported component implementation class."
+ "Unsupported component model implementation class."
+ "\nComponent: " + component.getURI()
- + "\nClass: " + component.getClass().getName()
+ + "\nModel Class: " + component.getClass().getName()
+ "\nMethod: initialize/1";
throw new IllegalArgumentException( error );
}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionClassLoader.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionClassLoader.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/CompositionClassLoader.java
Wed May 4 21:06:34 2005
@@ -146,6 +146,11 @@
buffer.append( "\n" );
}

+ protected void finalize()
+ {
+System.out.println( "## CLASSLOADER finalization: " + m_partition );
+ }
+
//--------------------------------------------------------------------
// static utilities
//--------------------------------------------------------------------

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
Wed May 4 21:06:34 2005
@@ -28,6 +28,7 @@

import net.dpml.composition.model.ComponentEntry;
import net.dpml.composition.model.CompositionModel;
+import net.dpml.composition.event.AvailabilityListener;

import net.dpml.system.SystemContext;

@@ -119,10 +120,16 @@
{
if( args.length > 0 )
{
- if( "addObserver".equals( name ) )
+ if( "addAvailabilityListener".equals( name ) )
{
- Observer observer = (Observer) args[0];
- getComponentEntry().addObserver( observer );
+ AvailabilityListener listener =
(AvailabilityListener) args[0];
+ getComponentEntry().addAvailabilityListener(
listener );
+ return null;
+ }
+ else if( "removeAvailabilityListener".equals( name ) )
+ {
+ AvailabilityListener listener =
(AvailabilityListener) args[0];
+ getComponentEntry().removeAvailabilityListener(
listener );
return null;
}
else if( "addStateListener".equals( name ) )
@@ -131,6 +138,12 @@
getComponentEntry().addStateListener( listener );
return null;
}
+ else if( "removeStateListener".equals( name ) )
+ {
+ StateListener listener = (StateListener) args[0];
+ getComponentEntry().removeStateListener( listener );
+ return null;
+ }
else
{
throw new NoSuchMethodException( name );

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityEvent.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityEvent.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityEvent.java
Wed May 4 21:06:34 2005
@@ -30,7 +30,7 @@

/**
* Creation of a new availability event.
- * @param src the subject object
+ * @param src the component model
* @param available if TRUE the object is available otherwise
* the object is no longer available and consuming systems should
* release any reference to the source and this event

Added:
development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityListener.java
==============================================================================
--- (empty file)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/event/AvailabilityListener.java
Wed May 4 21:06:34 2005
@@ -0,0 +1,33 @@
+/*
+ * 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.composition.event;
+
+import java.util.EventListener;
+
+/**
+ *
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Revision: 1.2 $ $Date: 2004/03/17 10:30:09 $
+ */
+public interface AvailabilityListener extends EventListener
+{
+ void availabilityChanged( AvailabilityEvent event );
+}
+

Added:
development/main/metro/composition/control/src/main/net/dpml/composition/event/EventProducer.java
==============================================================================
--- (empty file)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/event/EventProducer.java
Wed May 4 21:06:34 2005
@@ -0,0 +1,240 @@
+/*
+ * 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.composition.event;
+
+import java.util.EventObject;
+import java.util.EventListener;
+import java.util.List;
+import java.util.LinkedList;
+
+import net.dpml.transit.adapter.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.
+ */
+public abstract class EventProducer
+{
+ /**
+ * Registered event listeners.
+ */
+ private EventListener[] m_listeners = new EventListener[0];
+
+ /**
+ * Internal synchronization lock.
+ */
+ protected final Object m_lock = new Object();
+
+ /**
+ * 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 EventProducer )
+ {
+ EventProducer producer = (EventProducer) 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 " +
EventProducer.class.getName();
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+ }
+
+ private static Thread 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( EVENT_DISPATCH_THREAD == null )
+ {
+ EVENT_DISPATCH_THREAD = new EventDispatchThread();
+ EVENT_DISPATCH_THREAD.setDaemon( true );
+ 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 m_listeners;
+ }
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ */
+ protected void enqueueEvent( EventObject event )
+ {
+ if( m_listeners.length != 0 )
+ {
+ synchronized( EVENT_QUEUE )
+ {
+ EVENT_QUEUE.add( event );
+ EVENT_QUEUE.notify();
+ }
+ }
+ }
+}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
Wed May 4 21:06:34 2005
@@ -24,6 +24,8 @@
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.EventObject;
+import java.util.EventListener;
import java.util.Hashtable;
import java.util.Map;
import java.util.Observable;
@@ -37,11 +39,12 @@
import net.dpml.activity.Executable;
import net.dpml.activity.Startable;

-
import net.dpml.composition.control.ComponentController;
import net.dpml.composition.control.CompositionController;
import net.dpml.composition.state.DefaultState;
import net.dpml.composition.event.AvailabilityEvent;
+import net.dpml.composition.event.AvailabilityListener;
+import net.dpml.composition.event.EventProducer;

import net.dpml.parts.control.Identifiable;
import net.dpml.parts.control.LifecycleException;
@@ -63,7 +66,7 @@
* @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 ComponentEntry extends Observable implements Entry, Component
+public class ComponentEntry extends EventProducer implements Entry, Component
{
private final Map m_proxies = new WeakHashMap();

@@ -80,7 +83,6 @@
private transient Object m_instance;

private final Object m_owner; // not sure if this is needed
- private final Vector m_listeners = new Vector(); // overlaps with
Observable

private boolean m_disposed = false;

@@ -122,6 +124,65 @@
m_state = m_graph;
}

+ public void addAvailabilityListener( AvailabilityListener listener )
+ {
+ super.addListener( listener );
+ }
+
+ public void removeAvailabilityListener( AvailabilityListener listener )
+ {
+ super.removeListener( listener );
+ }
+
+ public void addStateListener( StateListener listener )
+ {
+ super.addListener( listener );
+ }
+
+ public void removeStateListener( StateListener listener )
+ {
+ super.removeListener( listener );
+ }
+
+ protected void processEvent( EventObject event )
+ {
+ if( event instanceof AvailabilityEvent )
+ {
+ AvailabilityEvent e = (AvailabilityEvent) event;
+ EventListener[] listeners = listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener listener = listeners[i];
+ if( listener instanceof AvailabilityListener )
+ {
+ AvailabilityListener availabilityListener =
(AvailabilityListener) listener;
+ availabilityListener.availabilityChanged( e );
+ }
+ }
+ }
+ else if( event instanceof StateEvent )
+ {
+ StateEvent e = (StateEvent) event;
+ EventListener[] listeners = listeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ EventListener listener = listeners[i];
+ if( listener instanceof StateListener )
+ {
+ StateListener stateListener = (StateListener) listener;
+ stateListener.stateChanged( e );
+ }
+ }
+ }
+ else
+ {
+ final String error =
+ "Event type not supported."
+ + "\nEvent Class: " + event.getClass().getName();
+ m_monitor.warn( error );
+ }
+ }
+
public Manager getManager()
{
return m_manager;
@@ -197,8 +258,8 @@
public void setInitialized( boolean flag )
{
m_initialized = flag;
- AvailabilityEvent event = new AvailabilityEvent( m_instance, true );
- notifyObservers( event );
+ AvailabilityEvent event = new AvailabilityEvent( this, flag );
+ super.enqueueEvent( event );
}

public Object getLocalInstance()
@@ -211,11 +272,6 @@
m_instance = instance;
}

- public void addStateListener( StateListener listener )
- {
- m_listeners.add( listener );
- }
-
/**
* Utility operation to apply a state change. If the supplied state is
* differnet from the current state the current state will be updated to
@@ -238,22 +294,9 @@
getMonitor().debug( message );
}

- StateEvent event = new StateEvent( m_instance, m_state, state );
+ StateEvent event = new StateEvent( this, m_state, state );
m_state = state;
- setChanged();
- ChangeEvent change = new ChangeEvent( this );
- notifyObservers( change );
- fireStateEvent( event );
- }
- }
-
- private void fireStateEvent( StateEvent event )
- {
- StateListener[] listeners = (StateListener[]) m_listeners.toArray(
new StateListener[0] );
- for( int i=0; i<listeners.length; i++ )
- {
- StateListener listener = listeners[i];
- listener.stateChanged( event );
+ super.enqueueEvent( event );
}
}

@@ -399,6 +442,7 @@
{
return;
}
+
synchronized( m_proxies )
{
m_disposed = true;
@@ -438,10 +482,10 @@
synchronized( m_proxies )
{
m_proxies.remove( proxy );
- if( m_proxies.isEmpty() )
- {
- dispose();
- }
+ //if( m_proxies.isEmpty() )
+ //{
+ // dispose();
+ //}
}
}


Modified:
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
==============================================================================
---
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
(original)
+++
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
Wed May 4 21:06:34 2005
@@ -29,14 +29,14 @@

import net.dpml.composition.state.DefaultState;

-import net.dpml.activity.Executable;
+import net.dpml.activity.Startable;

/**
* Demonstration of a component that manages the state of a contained part.
*
* @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
*/
-public class ManagingContainer implements Executable
+public class ManagingContainer implements Startable
{
//------------------------------------------------------------------
// static
@@ -72,13 +72,19 @@
// implementation
//------------------------------------------------------------------

- public void execute() throws Exception
+ public void start() throws Exception
{
Parts parts = getParts();
Component component = parts.getTestComponent();
component.initialize();
component.apply( "start" );
component.execute( "audit" );
+ }
+
+ public void stop() throws Exception
+ {
+ Parts parts = getParts();
+ Component component = parts.getTestComponent();
component.terminate();
}


Modified:
development/main/metro/parts/src/main/net/dpml/parts/state/StateEvent.java
==============================================================================
---
development/main/metro/parts/src/main/net/dpml/parts/state/StateEvent.java
(original)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/StateEvent.java
Wed May 4 21:06:34 2005
@@ -34,13 +34,13 @@
/**
* Construct a new <code>StateEvent</code>.
*
- * @param instance the source component instance
+ * @param instance the source compoent model
* @param from the originating state
* @param to the new current state
*/
- public StateEvent( final Object instance, State from, State to )
+ public StateEvent( final Object model, State from, State to )
{
- super( instance );
+ super( model );
m_from = from;
m_to = to;
}

Modified:
development/main/metro/parts/src/main/net/dpml/parts/state/StateListener.java
==============================================================================
---
development/main/metro/parts/src/main/net/dpml/parts/state/StateListener.java
(original)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/StateListener.java
Wed May 4 21:06:34 2005
@@ -18,12 +18,14 @@

package net.dpml.parts.state;

+import java.util.EventListener;
+
/**
* Exception thrown when a recursive termination sequence is encountered.
*
* @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
*/
-public interface StateListener
+public interface StateListener extends EventListener
{
/**
* Notify the listener of a state change.



  • svn commit: r2460 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/event composition/control/src/main/net/dpml/composition/model composition/testing/test/src/main/net/dpml/test/state parts/src/main/net/dpml/parts/state, mcconnell, 05/04/2005

Archive powered by MHonArc 2.6.24.

Top of Page