001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.station.server; 020 021 import java.util.EventObject; 022 import java.util.EventListener; 023 import java.rmi.server.UnicastRemoteObject; 024 import java.rmi.RemoteException; 025 026 import net.dpml.util.Logger; 027 028 029 /** 030 * A abstract base class that established an event queue and handles event dispatch 031 * operations for listeners declared in a class extending this base class. 032 * 033 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 034 * @version 1.0.5 035 */ 036 public abstract class UnicastEventSource extends UnicastRemoteObject 037 { 038 /** 039 * Registered event listeners. 040 */ 041 private EventListener[] m_listeners = new EventListener[0]; 042 043 private Logger m_logger; 044 045 /** 046 * Internal synchronization lock. 047 */ 048 private final Object m_lock = new Object(); 049 050 /** 051 * Creation of a new event producer. 052 * @param logger the logging channel 053 * @exception RemoteException if a remote exception occurs 054 */ 055 public UnicastEventSource( Logger logger ) throws RemoteException 056 { 057 super(); 058 059 m_logger = logger; 060 } 061 062 /** 063 * Return the assigned logging channel. 064 * @return the logging channel 065 */ 066 protected Logger getLogger() 067 { 068 return m_logger; 069 } 070 071 /** 072 * Abstract operation to be implemented by classes extending this base class. 073 * An implementation is reposible for the posting of the event to associated 074 * listeners. Event posting will be executed under a separate thread to the 075 * thread that initiated the event post. 076 * 077 * @param event the event to process 078 */ 079 protected abstract void processEvent( EventObject event ); 080 081 /** 082 * Add a listener to the set of listeners handled by this producer. 083 * @param listener the event listener 084 */ 085 protected void addListener( EventListener listener ) 086 { 087 if( null == listener ) 088 { 089 throw new NullPointerException( "listener" ); 090 } 091 092 synchronized( m_lock ) 093 { 094 Object[] old = m_listeners; 095 m_listeners = new EventListener[ old.length + 1 ]; 096 System.arraycopy( old, 0, m_listeners, 0, old.length ); 097 m_listeners[old.length] = listener; 098 } 099 } 100 101 /** 102 * Remove a listener to the set of listeners handled by this producer. 103 * @param listener the event listener 104 */ 105 protected void removeListener( EventListener listener ) 106 { 107 if( null == listener ) 108 { 109 throw new NullPointerException( "listener" ); 110 } 111 112 synchronized( m_lock ) 113 { 114 if( m_listeners.length == 0 ) 115 { 116 throw new IllegalArgumentException( "Listener not registered." ); 117 } 118 // create the copy 119 EventListener[] replacement = new EventListener[ m_listeners.length - 1 ]; 120 // copy listeners from 0 up to the listener being removed 121 int i=0; 122 while( i < replacement.length && m_listeners[i] != listener ) 123 { 124 replacement[i] = m_listeners[i++]; 125 } 126 // check that the listener has been located 127 if( i == replacement.length && m_listeners[i] != listener ) 128 { 129 throw new IllegalArgumentException( "Listener not registered." ); 130 } 131 // complete the copy operation 132 while( i < replacement.length ) 133 { 134 replacement[i] = m_listeners[++i]; 135 } 136 // commit the copy 137 m_listeners = replacement; 138 } 139 } 140 141 /** 142 * Return this node's preference/node change listeners. Even though 143 * we're using a copy-on-write lists, we use synchronized accessors to 144 * ensure information transmission from the writing thread to the 145 * reading thread. 146 * @return the event listener array 147 */ 148 protected EventListener[] listeners() 149 { 150 synchronized( m_lock ) 151 { 152 return m_listeners; 153 } 154 } 155 156 /** 157 * Enqueue an event for delivery to registered 158 * listeners unless there are no registered 159 * listeners. 160 * @param event the event to enqueue 161 */ 162 protected void enqueueEvent( EventObject event ) 163 { 164 if( m_listeners.length != 0 ) 165 { 166 RemoteStation.enqueueEvent( event ); 167 } 168 } 169 }