package org.jcon.util.msg;

import org.jcon.util.PropMapStd;
import java.io.Serializable;
import java.util.Hashtable;
import java.util.Vector;

/**
 * A reusable packet of data originally designed to be
 * used in an event router. It may be used in a wide
 * variety of ways, such as events, data exchange, config
 * properties, result sets, etc. Primarily designed for events.
 *
 * Note eventName must be unique for all using the same
 * event router. When coding names ALWAYS copy and paste
 * eventName from the source.
 *
 * Due to String interning, do NOT use new String("Name")
 * to create event names. This will cause Hashtable to fail.
 *
 * This doesn't extend EventObject so there is no source.
 * This is deliberate, since if the event listener uses the
 * source for anything tight coupling is introduced. If the
 * need arises to pass the source, use a property or change
 * the design.
 *
 * @author Jack Harich
 */
public class Message extends PropMapStd {

//------------ Private Fields ---------------------------
protected String eventName = null;

//------------ Initialization ---------------------------
/**
 * For constructing a named event. The @param name is
 * interned so that clients can use "==" instead of "equals()"
 * when comparing the Message name to a literal  String.
 * The use of "==" is faster, more concise and more consist.
 */
public Message(String eventName) {
    setName(eventName);
}
public Message() {
}
//---------- Superclass Overrides ------------------------
// There is somewhat of a convention here...
public String toString() {
    return "Message: [eventName=" + eventName + "] " + properties;
}
/**
 * Performs a shallow copy.
 */
// Per Steve A. this doesn't strictly adhere to clone()
public synchronized Object clone() {
    Message message = new Message(eventName.intern());
    message.properties = (Hashtable)this.properties.clone();
    return message;
}
//---------- Public Methods ------------------------------
/**
 * Returns null if no name.
 */
public String getName() {
    return eventName;
}
/**
 * An event name should usually not be changed once set. This method
 * is provided for those rare cases where needed.
 */
public void setName(String eventName) {
    this.eventName = eventName.trim().intern();
}
/**
 * Performs a shallow copy and names the new Message.
 */
public synchronized Object clone(String eventName) {
    Message message = new Message(eventName);
    message.properties = (Hashtable)this.properties.clone();
    return message;
}
/**
 * A non-static method that sends this Message to all the
 * MessageListeners in the Vector. This convenience method
 * calls the other version of send() to do the work. This
 * method is designed to allow Message sources to concisely
 * and consistently send the Message event.
 */
public void send(Vector listeners, Object messageSource) {
    send(this, listeners, messageSource);
}
/**
 * A static method that sends the Message to all the
 * MessageListeners in the Vector. It first makes a copy
 * of the Vector while locking the source Object, thus
 * guarenteeing that all listeners will be notified.
 */
public static void send(Message message,
        Vector listeners, Object messageSource) {
    Vector list;
    synchronized(messageSource) {
        list = (Vector)listeners.clone();
    }
    for (int i = 0; i < list.size(); i++) {
        MessageListener listener =
            (MessageListener)list.elementAt(i);
        listener.processMessage(message);
    }
}
//---------- Private Methods -----------------------------
// (none)

} // End class