Commit in hps-et-java/src/main/java/org/jlab/coda/et on MAIN
EtAttachment.java+167added 1.1
EtConstants.java+479added 1.1
EtEvent.java+216added 1.1
EtEventImpl.java+648added 1.1
EtEventSelectable.java+36added 1.1
EtJniAccess.java+250added 1.1
EtStation.java+587added 1.1
EtStationConfig.java+399added 1.1
EtStationSelection.java+41added 1.1
EtSystem.java+2700added 1.1
EtSystemOpen.java+1471added 1.1
EtSystemOpenConfig.java+804added 1.1
EtUtils.java+291added 1.1
apps/Blaster.java+280added 1.1
    /Consumer.java+267added 1.1
    /EtMonitor.java+548added 1.1
    /EvioProducer.java+314added 1.1
    /Producer.java+271added 1.1
    /StartEt.java+226added 1.1
data/AllData.java+52added 1.1
    /AttachmentData.java+214added 1.1
    /ProcessData.java+114added 1.1
    /StationData.java+347added 1.1
    /SystemData.java+398added 1.1
enums/Age.java+79added 1.1
     /DataStatus.java+80added 1.1
     /Mode.java+82added 1.1
     /Modify.java+85added 1.1
     /Priority.java+76added 1.1
exception/EtBusyException.java+38added 1.1
         /EtDeadException.java+20added 1.1
         /EtEmptyException.java+37added 1.1
         /EtException.java+36added 1.1
         /EtExistsException.java+37added 1.1
         /EtReadException.java+36added 1.1
         /EtTimeoutException.java+36added 1.1
         /EtTooManyException.java+39added 1.1
         /EtWakeUpException.java+38added 1.1
         /EtWriteException.java+36added 1.1
monitorGui/Monitor.java+2048added 1.1
          /MonitorConfiguration.java+814added 1.1
          /MonitorFonts.java+36added 1.1
          /MonitorSingleSystem.java+1826added 1.1
          /WholeNumberField.java+162added 1.1
          /monitorConfiguration.xsd+207added 1.1
system/AttachmentLocal.java+286added 1.1
      /EventList.java+595added 1.1
      /StationLocal.java+942added 1.1
      /SystemConfig.java+448added 1.1
      /SystemCreate.java+1962added 1.1
      /SystemTcpServer.java+1801added 1.1
      /SystemUdpServer.java+385added 1.1
test/EmuTest.java+330added 1.1
+23717
53 added files
move to et 12.0 as recommended by Carl Timmer

hps-et-java/src/main/java/org/jlab/coda/et
EtAttachment.java added at 1.1
diff -N EtAttachment.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtAttachment.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,167 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.io.*;
+
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class defines an ET system user's attachment to a station.
+ * Attachments can only be created by an ET system's {@link EtSystem#attach(EtStation)}
+ * method. Attachments are means of designating the
+ * ownership of events and keeping track of events.
+ *
+ * @author Carl Timmer
+ */
+public class EtAttachment {
+
+    // TODO: keep a list or set of events we currently have out?
+
+    /** Unique id number. */
+    private int id;
+
+    /** ET system the attachment is associated with. */
+    private EtSystem sys;
+
+    /** Station the attachment is associated with. */
+    private EtStation station;
+
+    /**
+     * Flag telling whether this attachment object is usable or the attachment it
+     * represents has been detached. Set by the user's ET system object.
+     */
+    private boolean usable;
+
+
+    /**
+     * Constructor for creating an attachment to a specific ET system and station.
+     * Attachments can only be created by an ET system's {@link EtSystem#attach(EtStation)}
+     * method.
+     *
+     * @param station  station object
+     * @param id       unique attachment id number
+     * @param sys      ET system object
+     */
+    EtAttachment(EtStation station, int id, EtSystem sys) {
+        this.id      = id;
+        this.sys     = sys;
+        this.station = station;
+    }
+
+
+    // Getters/Setters
+
+
+    /**
+     * Gets the object of the station attached to.
+     * @return object of station attached to
+     */
+    public EtStation getStation() {return station;}
+
+    /**
+     * Gets the id number of this attachment.
+     * @return id number of this attachment
+     */
+    public int getId() {return id;}
+
+    /**
+     * Tells if this attachment object is usable.
+     * @return <code>true</code> if attachment object is usable and <code>false
+     * </code> otherwise
+     */
+    public boolean isUsable() {return usable;}
+
+    /**
+     * Sets whether this attachment object is usable or not.
+     * @param usable <code>true</code> if this attachment object is usable and <code>false otherwise
+     */
+    void setUsable(boolean usable) {
+        this.usable = usable;
+    }
+
+    /**
+     * Sets the EtSystemUse object for using the ET system.
+     * @return the EtSystemUse object for using the ET system
+     */
+    public EtSystem getSys() {
+        return sys;
+    }
+
+    /**
+     * Gets the value of an attachment's eventsPut, eventsGet, eventsDump, or
+     * eventsMake by network communication with the ET system.
+     *
+     * @param cmd command number
+     * @return value of requested parameter
+     * @throws IOException if there are network communication problems
+     * @throws EtException if the station no longer exists
+     */
+    private long getLongValue(int cmd) throws IOException, EtException {
+        int  err;
+        long val;
+
+        synchronized (sys) {
+            sys.getOutputStream().writeInt(cmd);
+            sys.getOutputStream().writeInt(id);
+            sys.getOutputStream().flush();
+            err = sys.getInputStream().readInt();
+            val = sys.getInputStream().readLong();
+        }
+
+        if (err != EtConstants.ok) {
+            throw new EtException("this station has been revmoved from ET system");
+        }
+
+        return val;
+    }
+
+    /**
+     * Gets the number of events put into the ET system by this attachment.
+     * @return number of events put into the ET system by this attachment
+     */
+    public long getEventsPut() throws IOException, EtException {
+        return getLongValue(EtConstants.netAttPut);
+    }
+
+    /**
+     * Gets the number of events gotten from the ET system by this attachment.
+     * @return number of events gotten from the ET system by this attachment
+     */
+    public long getEventsGet() throws IOException, EtException {
+        return getLongValue(EtConstants.netAttGet);
+    }
+
+    /**
+     * Gets the number of events dumped (recycled by returning to GRAND_CENTRAL
+     * station) through this attachment.
+     *
+     * @return number of events dumped into the ET system by this attachment
+     */
+    public long getEventsDump() throws IOException, EtException {
+        return getLongValue(EtConstants.netAttDump);
+    }
+
+    /**
+     * Gets the number of new events gotten from the ET system by this attachment.
+     * @return number of new events gotten from the ET system by this attachment
+     */
+    public long getEventsMake() throws IOException, EtException {
+        return getLongValue(EtConstants.netAttMake);
+  }
+}
+
+
+

hps-et-java/src/main/java/org/jlab/coda/et
EtConstants.java added at 1.1
diff -N EtConstants.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtConstants.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,479 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+/**
+ * This class defines some useful constants which are made to be identical to those
+ * used in the C-based ET system code.
+ *
+ * @author Carl Timmer
+ */
+
+public final class EtConstants {
+
+    /** This constructor does nothing. */
+    private EtConstants() {
+    }
+
+    /** Ints representing ascii for "cMsg is cool", used to filter out portscanning software. */
+    public static final int[] magicNumbers = {0x45543269, 0x73324772, 0x72656174};
+
+    // constants from et.h
+
+    /** A convenient multicast address used for finding an ET system.
+     * @see EtSystemOpenConfig#addMulticastAddr(String)  */
+    public static final String multicastAddr       = "239.200.0.0";
+    /** Specify a local host when opening an ET system.
+     *  @see EtSystemOpenConfig#setHost(String)  */
+    public static final String hostLocal           = ".local";
+    /** Specify a remote host when opening an ET system.
+     *  @see EtSystemOpenConfig#setHost(String)  */
+    public static final String hostRemote          = ".remote";
+    /** Allow any host when opening an ET system.
+     *  @see EtSystemOpenConfig#setHost(String)  */
+    public static final String hostAnywhere        = ".anywhere";
+    /** Discover an ET system by multicasting.
+     *  @see EtSystemOpenConfig#setNetworkContactMethod(int)  */
+    public static final int    multicast           = 0;
+    /** Discover an ET system by broadcasting.
+     *  @see EtSystemOpenConfig#setNetworkContactMethod(int)  */
+    public static final int    broadcast           = 1;
+    /** Open an ET system by specifying host and port.
+     *  @see EtSystemOpenConfig#setNetworkContactMethod(int)  */
+    public static final int    direct              = 2;
+    /** Discover an ET system by broadcasting and multicasting.
+     *  @see EtSystemOpenConfig#setNetworkContactMethod(int)  */
+    public static final int    broadAndMulticast   = 3;
+    /** A default port on which to broadcast when finding an ET system. */
+    public static final int    broadcastPort       = 11111;
+    /** A default port on which to multicast when finding an ET system.
+     *  @see EtSystemOpenConfig#addMulticastAddr(String)
+     *  @see EtSystemOpenConfig#setMulticastAddrs(java.util.Collection)  */
+    public static final int    multicastPort       = 11112;
+    /** A default port on which ET system TCP server makes connections with users.
+     *  @see EtSystemOpenConfig#setTcpPort(int)  */
+    public static final int    serverPort          = 11111;
+    /** A default time-to-live value for multicasting.
+     *  @see EtSystemOpenConfig#setTTL(int)  */
+    public static final int    multicastTTL        = 32;
+    /** A default value for the number of integers associated with each event that
+     *  atations may use to select or filter that event. If this is changed, a
+     *  recompilation of ET is necessary and communication with ET systems in
+     *  which this value differs is impossible.
+     */
+    public static final int    stationSelectInts   = 6;
+    /** A limit on the length of the ET system (or file) name's length. This limit
+     *  is due to the C implementation. */
+    public static final int    fileNameLengthMax   = 101;
+
+
+    /** A policy that chooses the first ET system to respond when broadcasting
+     *  and/or multicasting to find a system anywhere or remotely.
+     *  @see EtSystemOpenConfig#setResponsePolicy(int)  */
+    public static final int    policyFirst         = 0;
+    /** A policy that chooses the first local ET system to respond when
+     *  broadcasting and/or multicasting to find a system anywhere or remotely.
+     *  If a local system does not respond, the first response is chosen.
+     *  @see EtSystemOpenConfig#setResponsePolicy(int)  */
+    public static final int    policyLocal         = 1;
+    /** A policy that throws an EtTooManyException when multiple ET systems
+     *  respond when broadcasting and/or multicasting to find an ET system
+     *  anywhere or remotely.
+     *  @see EtSystemOpenConfig#setResponsePolicy(int)  */
+    public static final int    policyError         = 2;
+
+
+    // system defaults
+
+    /** An ET system's default number of events. */
+    public static final int    defaultNumEvents    = 300;
+    /** An ET system's default event size in bytes. */
+    public static final int    defaultEventSize    = 1000;
+    /** An ET system's default maximum number of stations. */
+    public static final int    defaultStationsMax  = 20;
+    /** An ET system's default maximum number of attachments. */
+    public static final int    defaultAttsMax      = 50;
+
+    // station stuff
+
+    /** A station object's status meaning it has not been fully created yet. */
+    public static final int    stationUnused          = 0;
+    /** A station's status used in C implementations meaning the station is
+     *  currently being created. */
+    public static final int    stationCreating        = 1;
+    /** A station's status meaning it exists but has no attachments. */
+    public static final int    stationIdle            = 2;
+    /** A station's status meaning it exists and has at least one attachment. */
+    public static final int    stationActive          = 3;
+    /** A station may have multiple attachments.
+     *  @see EtStationConfig#setUserMode(int)  */
+    public static final int    stationUserMulti       = 0;
+    /** A station may only have one attachment.
+     *  @see EtStationConfig#setUserMode(int)  */
+    public static final int    stationUserSingle      = 1;
+    /** A station will not block the flow of events. Once its cue is full, the
+     *  station asks for no more events.
+     *  @see EtStationConfig#setBlockMode(int)  */
+    public static final int    stationNonBlocking     = 0;
+    /** A station accepts every event into its cue and may block the flow of
+     *  events.
+     *  @see EtStationConfig#setBlockMode(int)  */
+    public static final int    stationBlocking        = 1;
+    /** All events are placed into a station's cue with no filtering applied
+     *  (besides prescaling).
+     *  @see EtStationConfig#setSelectMode(int)  */
+    public static final int    stationSelectAll       = 1;
+    /** Events are placed into a station's cue with a predefined filtering applied
+     *  (besides prescaling).
+     *  @see EtStationConfig#setSelectMode(int)  */
+    public static final int    stationSelectMatch     = 2;
+    /** Events are placed into a station's cue with a user defined filtering
+     *  applied (besides prescaling).
+     *  @see EtStationConfig#setSelectMode(int)  */
+    public static final int    stationSelectUser      = 3;
+    /** Events are placed into the cues of a single group of parallel stations
+     *  with a round robin distribution algorithm.
+     *  @see EtStationConfig#setSelectMode(int)  */
+    public static final int    stationSelectRRobin    = 4;
+    /** Events are placed into the cues of a single group of parallel stations
+     *  in an algorithm designed to keep the cues equal in value.
+     *  @see EtStationConfig#setSelectMode(int)  */
+    public static final int    stationSelectEqualCue  = 5;
+    /** Events owned by a crashed user process are restored to the ET system in
+     *  the output list of the attachment's station.
+     *  @see EtStationConfig#setRestoreMode(int)  */
+    public static final int    stationRestoreOut      = 0;
+    /** Events owned by a crashed user process are restored to the ET system in
+     *  the input list of the attachment's station.
+     *  @see EtStationConfig#setRestoreMode(int)  */
+    public static final int    stationRestoreIn       = 1;
+    /** Events owned by a crashed user process are restored to the ET system by
+     *  putting them in GRAND_CENTRAL station (recycling them).
+     *  @see EtStationConfig#setRestoreMode(int)  */
+    public static final int    stationRestoreGC       = 2;
+    /** Events owned by a crashed user process attached to a parallel station
+     *  are restored to the ET system by redistributing them among that group
+     *  of parallel stations (recycling them). Also, if the station has no more
+     *  attachments, the events in its input list are also redistributed (unlike
+     *  in stationRestoreGC mode where these events are put in the station's output
+     *  list).
+     *  @see EtStationConfig#setRestoreMode(int)  */
+    public static final int    stationRestoreRedist   = 3;
+    /** Events flow "normally" - that is serially - through a station.
+     *  @see EtStationConfig#setFlowMode(int)  */
+    public static final int    stationSerial          = 0;
+    /** Events flow in parallel through stations in a single group.
+     *  @see EtStationConfig#setFlowMode(int)  */
+    public static final int    stationParallel        = 1;
+    /** Events flow in parallel through stations in a single group with this station
+     *  as the head of that group.
+     *  @see EtStationConfig#setFlowMode(int)  */
+    public static final int    stationParallelHead    = 2;
+
+    // station defaults
+
+    /** A default input list cue size for a nonblocking station.
+     *  @see EtStationConfig#setCue(int)  */
+    public static final int    defaultStationCue      = 10;
+    /** A default prescale value for a station.
+     *  @see EtStationConfig#setPrescale(int)  */
+    public static final int    defaultStationPrescale = 1;
+
+    // talk to C language ET systems with structures
+
+    /** C structure state value for talking to C language ET systems. */
+    public static final int    structNew           = 0;
+    /** C structure state value for talking to C language ET systems. */
+    public static final int    structOk            = 1;
+
+    /** Add station to end of linked list. */
+    public static final int    end                 = -1;
+    /** Make added station head of a new group of parallel stations. */
+    public static final int    newHead             = -2;
+
+    // Events
+
+    /** Low event priority.
+     *  @see EtEvent#setPriority(org.jlab.coda.et.enums.Priority)  */
+    public static final int    low                 = 0;
+    /** High event priority.
+     *  @see EtEvent#setPriority(org.jlab.coda.et.enums.Priority)  */
+    public static final int    high                = 1;
+    /** Parse event priority information. */
+    public static final int    priorityMask        = 0x1;
+    /** Event has been obtained with getEvents, not newEvents. */
+    public static final int    eventUsed           = 0;
+    /** Event has been obtained with newEvents, not getEvents. */
+    public static final int    eventNew            = 1;
+    /** System is event owner */
+    public static final int    system              = -1;
+
+    /** User sleeps when waiting for events to fill a station's empty input list. */
+    public static final int    sleep               = 0;
+    /** User waits for a specified time when waiting for events to fill a
+     *  station's empty input list. */
+    public static final int    timed               = 1;
+    /** User does not wait for events to fill station's empty input list, but
+     *  returns immediately. */
+    public static final int    async               = 2;
+    /** User intends to modify the event's data. */
+    public static final int    modify              = 4;
+    /** User intends to modify only the event's header information. */
+    public static final int    modifyHeader        = 8;
+    /** User wants events automatically dumped (not put) if data is not modified. */
+    public static final int    dump                = 16;
+    /** Parse event waiting information. */
+    public static final int    waitMask            = 0x3;
+
+    //public static final int    openNoWait          = 0;
+    //public static final int    openWait            = 1;
+
+    //public static final int    remote              = 0;
+    //public static final int    local               = 1;
+    //public static final int    localNoShare        = 2;
+
+    //public static final String subnetDefault       = "default";
+    //public static final String subnetAll           = "all";
+
+    /** An event's data is OK. */
+    public static final int    dataOk              = 0;
+    /** An event's data is corrupted. */
+    public static final int    dataCorrupt         = 1;
+    /** An event's data may possibly be corrupted. */
+    public static final int    dataPossiblyCorrupt = 2;
+    /** Parse data status information. */
+    public static final int    dataMask            = 0x30;
+    /** Parse data status information. */
+    public static final int    dataShift           = 4;
+
+    /** An event's data is big endian. */
+    public static final int    endianBig           = 0;
+    /** An event's data is little endian. */
+    public static final int    endianLittle        = 1;
+    /** An event's data endian is the same as the local host's. */
+    public static final int    endianLocal         = 2;
+    /** An event's data endian is opposite of the local host's. */
+    public static final int    endianNotLocal      = 3;
+    /** An event's data endian is to be switched. */
+    public static final int    endianSwitch        = 4;
+
+    /** An event's data does not need to be swapped to be the same endian as the
+     *  local host's. */
+    public static final int    noSwap              = 0;
+    /** An event's data needs to be swapped to be the same endian as the local
+     *  host's. */
+    public static final int    swap                = 1;
+
+    /** Print out no status messages. */
+    public static final int    debugNone           = 0;
+    /** Print out only severe error messages. */
+    public static final int    debugSevere         = 1;
+    /** Print out severe and normal error messages. */
+    public static final int    debugError          = 2;
+    /** Print out all error and warning messages. */
+    public static final int    debugWarn           = 3;
+    /** Print out all error, warning, and informational messages. */
+    public static final int    debugInfo           = 4;
+
+    // C language ET system error codes
+
+    /** No error. */
+    public static final int    ok                  =  0;
+    /** General error. */
+    public static final int    error               = -1;
+    /** Error specifying too many of something. */
+    public static final int    errorTooMany        = -2;
+    /** Error specifying that something already exists. */
+    public static final int    errorExists         = -3;
+    /** Error when a thread was told to wake up from a blocking read. */
+    public static final int    errorWakeUp         = -4;
+    /** Error specifying a time out. */
+    public static final int    errorTimeout        = -5;
+    /** Error specifying that a station has an empty input list. */
+    public static final int    errorEmpty          = -6;
+    /** Error specifying that a station's input list is being accessed by
+     *  another thread or process. */
+    public static final int    errorBusy           = -7;
+    /** Error specifying that the ET system is dead. */
+    public static final int    errorDead           = -8;
+    /** Error specifying problems in a network read. */
+    public static final int    errorRead           = -9;
+    /** Error specifying problems in a network write. */
+    public static final int    errorWrite          = -10;
+    /** Error not used in java ET. */
+    public static final int    errorRemote         = -11;
+    /** Error not used in java ET. */
+    public static final int    errorNoRemote       = -12;
+    /** Error when memory asked for is too big. */
+    public static final int    errorTooBig         = -13;
+    /** Error when no memory available. */
+    public static final int    errorNoMemory       = -14;
+    /** Error when argument has bad value. */
+    public static final int    errorBadArg         = -15;
+    /** Error when socket error. */
+    public static final int    errorSocket         = -16;
+    /** Error when network error. */
+    public static final int    errorNetwork        = -17;
+
+
+    // constants from private.h
+
+    
+    /**
+     * String length of dotted-decimal, ip address string
+     * Some systems - but not all - define INET_ADDRSTRLEN
+     * ("ddd.ddd.ddd.ddd\0" = 16)
+     */
+    public static final int ipAddrStrLen = 16;
+
+    /**
+     * MAXHOSTNAMELEN is defined to be 256 on Solaris and is the max length
+     * of the host name so we add one for the terminator. On Linux the
+     * situation is less clear but 257 appears to be the max (whether that
+     * includes termination is not clear).
+     * We need it to be uniform across all platforms since we transfer
+     * this info across the network. Define it to be 256 for everyone.
+     */
+    public static final int maxHostNameLen = 256;
+
+    /** Java ET systems are 32 bit since arrays can only be of size Integer.MAX_VALUE. */
+    public static final int    bit64               = 0;
+    /** Major ET version number. */
+    public static final int    version             = 12;
+    /** Minor ET version number. */
+    public static final int    minorVersion        = 0;
+    /** Maximum number of attachments to an ET system. */
+    public static final int    attachmentsMax      = 110;
+    //static final int    ipAddrStrLen        = 16;
+    //static final int    maxHostNameLen      = 256;
+
+    /** ET system was implemented in the C language. */
+    public static final int    langC               = 0;
+    /** ET system was implemented in the C++ language. */
+    public static final int    langCpp             = 1;
+    /** ET system was implemented in the Java language. */
+    public static final int    langJava            = 2;
+
+    /** Shared memory layout from C language ET system. */
+    public static final int    systemTypeC         = 1;
+    /** Shared memory layout from Java language ET system. */
+    public static final int    systemTypeJava      = 2;
+
+    /** Shared memory layout from Java language ET system. */
+    public static final int    initialSharedMemBytes = 64;
+
+    /** A mutex is not locked. Relevant only to C language ET systems. */
+    public static final int    mutexUnlocked       = 0;
+    /** A mutex is locked. Relevant only to C language ET systems. */
+    public static final int    mutexLocked         = 1;
+    /** The local UNIX operating system allows multiple processes to share POSIX
+     *  mutexes. Relevant only to C language ET systems. */
+    public static final int    mutexShare          = 0;
+    /** The local UNIX operating system does not allow multiple processes to share
+     *  POSIX mutexes. Relevant only to C language ET systems. */
+    public static final int    mutexNoShare        = 1;
+
+    //static final int    attUnused           = 0;
+    //static final int    attActive           = 1;
+    /** An attachment is not being told to wake up. */
+    public static final int    attContinue         = 0;
+    /** An attachment is being told to wake up. */
+    public static final int    attQuit             = 1;
+    /** An attachment is not blocked on a read statement. */
+    public static final int    attUnblocked        = 0;
+    /** An attachment is blocked on a read statement. */
+    public static final int    attBlocked          = 1;
+
+    // codes sent over the network to identify ET system routines to call
+    public static final int    netEvGetL        = 0;
+    public static final int    netEvsGetL       = 1;
+    public static final int    netEvPutL        = 2;
+    public static final int    netEvsPutL       = 3;
+    public static final int    netEvNewL        = 4;
+    public static final int    netEvsNewL       = 5;
+    public static final int    netEvDumpL       = 6;
+    public static final int    netEvsDumpL      = 7;
+    public static final int    netEvsNewGrpL    = 8;
+
+    public static final int    netEvGet         = 20;
+    public static final int    netEvsGet        = 21;
+    public static final int    netEvPut         = 22;
+    public static final int    netEvsPut        = 23;
+    public static final int    netEvNew         = 24;
+    public static final int    netEvsNew        = 25;
+    public static final int    netEvDump        = 26;
+    public static final int    netEvsDump       = 27;
+    public static final int    netEvsNewGrp     = 28;
+
+    public static final int    netAlive         = 40;
+    public static final int    netWait          = 41;
+    public static final int    netClose         = 42;
+    public static final int    netFClose        = 43;
+    public static final int    netWakeAtt       = 44;
+    public static final int    netWakeAll       = 45;
+
+    public static final int    netStatAtt       = 60;
+    public static final int    netStatDet       = 61;
+    public static final int    netStatCrAt      = 62;
+    public static final int    netStatRm        = 63;
+    public static final int    netStatSPos      = 64;
+    public static final int    netStatGPos      = 65;
+
+    public static final int    netStatIsAt      = 80;
+    public static final int    netStatEx        = 81;
+    public static final int    netStatSSw       = 82;
+    public static final int    netStatGSw       = 83;
+    public static final int    netStatLib       = 84;
+    public static final int    netStatFunc      = 85;
+    public static final int    netStatClass     = 86;
+
+    public static final int    netStatGAtts     = 100;
+    public static final int    netStatStatus    = 101;
+    public static final int    netStatInCnt     = 102;
+    public static final int    netStatOutCnt    = 103;
+    public static final int    netStatGBlock    = 104;
+    public static final int    netStatGUser     = 105;
+    public static final int    netStatGRestore  = 106;
+    public static final int    netStatGPre      = 107;
+    public static final int    netStatGCue      = 108;
+    public static final int    netStatGSelect   = 109;
+
+    public static final int    netStatSBlock    = 115;
+    public static final int    netStatSUser     = 116;
+    public static final int    netStatSRestore  = 117;
+    public static final int    netStatSPre      = 118;
+    public static final int    netStatSCue      = 119;
+
+    public static final int    netAttPut        = 130;
+    public static final int    netAttGet        = 131;
+    public static final int    netAttDump       = 132;
+    public static final int    netAttMake       = 133;
+
+    public static final int    netSysTmp        = 150;
+    public static final int    netSysTmpMax     = 151;
+    public static final int    netSysStat       = 152;
+    public static final int    netSysStatMax    = 153;
+    public static final int    netSysProc       = 154;
+    public static final int    netSysProcMax    = 155;
+    public static final int    netSysAtt        = 156;
+    public static final int    netSysAttMax     = 157;
+    public static final int    netSysHBeat      = 158;
+    public static final int    netSysPid        = 159;
+    public static final int    netSysGrp        = 160;
+
+    public static final int    netSysData       = 170;
+    public static final int    netSysHist       = 171;
+    public static final int    netSysGrps       = 172;
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtEvent.java added at 1.1
diff -N EtEvent.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtEvent.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,216 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import org.jlab.coda.et.exception.EtException;
+import org.jlab.coda.et.enums.Modify;
+import org.jlab.coda.et.enums.Priority;
+import org.jlab.coda.et.enums.DataStatus;
+import org.jlab.coda.et.enums.Age;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Interface used to define methods necessary to be an Event.
+ */
+public interface EtEvent {
+
+    /**
+     * Initialize an event's fields. Called for an event each time it passes
+     * through GRAND_CENTRAL station.
+     */
+    public void init();
+
+
+    // getters
+
+
+    /**
+     * Gets the event's id number.
+     * @return event's id number.
+     */
+    public int getId();
+
+    /**
+     * Gets the age of the event, either {@link Age#NEW} if a new event obtained through
+     * calling {@link EtSystem#newEvents(EtAttachment, org.jlab.coda.et.enums.Mode, int, int, int)}
+     * or {@link Age#USED} if obtained through calling
+     * {@link EtSystem#getEvents(EtAttachment, org.jlab.coda.et.enums.Mode, org.jlab.coda.et.enums.Modify, int, int)}.
+     *
+     * @return age of the event.
+     */
+    public Age getAge();
+
+    /**
+     * Gets the group the event belongs to (1, 2, ...) if ET system events are divided into groups.
+     * If not, group = 1. Used so some producers don't hog events from others.
+     *
+     * @return the group the event belongs to.
+     */
+    public int getGroup();
+
+    /**
+     * Gets the event's priority, either high {@link Priority#HIGH} or low {@link Priority#LOW}.
+     * Low priority is normal while high priority events get placed at the front of stations'
+     * input and output event lists.
+     * 
+     * @return event's priority.
+     */
+    public Priority getPriority();
+
+    /**
+     * Gets the length of the data in bytes.
+     * @return length of the data in bytes.
+     */
+    public int getLength();
+
+    /**
+     * Gets the status of the data (set by the system), which can be OK {@link DataStatus#OK},
+     * corrupted {@link DataStatus#CORRUPT}, or possibly corrupted
+     * {@link DataStatus#POSSIBLYCORRUPT}. Data is OK by default, it is never labeled
+     * as corrupt but can be labeled as possible corrupt if the process owning an
+     * event crashes and the system recovers it.
+     *
+     * @return status of the data.
+     */
+    public DataStatus getDataStatus();
+
+    /**
+     * Gets the event's modify value when receiving it over the network.
+     * This specifies whether the user wants to read the event only, will modify only
+     * the event header (everything except the data), or will modify the data and/or header.
+     * Modifying the data and/or header is {@link Modify#ANYTHING}, modifying only the header
+     * is {@link Modify#HEADER}, else the default assumed, {@link Modify#NOTHING},
+     * is that nothing is modified resulting in this event being put back into
+     * the ET system (by remote server) immediately upon being copied and that copy
+     * sent to the user.
+     *
+     * @return event's modify value.
+     */
+    public Modify getModify();
+
+    /**
+     * Gets the event's control array.
+     * This is an array of integers which can be used for any purpose by the user.
+     * 
+     * @return event's control array.
+     */
+    public int[] getControl();
+
+    /**
+     * Gets the data array which is backing the event's data buffer if there is one.
+     * Any changes to the array will be reflected in the buffer.
+     * If there is no backing data array, as is the case when a user connects
+     * to a local, C-based ET system (memory mapped buffer) then an exception
+     * is thrown.
+     *
+     * @return data array which is backing the event's data buffer
+     * @throws UnsupportedOperationException if there is no backing array
+     */
+    public byte[] getData() throws UnsupportedOperationException;
+
+    /**
+     * Gets the event's data buffer.
+     * @return event's data buffer.
+     */
+    public ByteBuffer getDataBuffer();
+
+    /**
+     * Gets the attachment id of the attachment which owns or got the event.
+     * If it's owned by the system its value is {@link EtConstants#system}.
+     *
+     * @return id of owning attachment or {@link EtConstants#system} if system owns it
+     */
+    public int getOwner();
+
+    /**
+     * Gets the event data's byte order.
+     * @return event data's byte order
+     */
+    public ByteOrder getByteOrder();
+
+    /**
+     * Gets the raw byte order data (0x04030201 or 0x01020304).
+     * @return raw byte order data (0x04030201 or 0x01020304).
+     */
+    public int getRawByteOrder();
+
+
+    // setters
+
+
+    /**
+     * Sets the event's priority, either high {@link Priority#HIGH} or low {@link Priority#LOW}.
+     * Low priority is normal while high priority events get placed at the front of stations'
+     * input and output event lists.
+     *
+     * @param pri event priority
+     */
+    public void setPriority(Priority pri);
+
+    /**
+     * Sets the event's data length in bytes.
+     *
+     * @param len data length
+     * @throws EtException if length is less than zero
+     */
+    public void setLength(int len) throws EtException;
+
+    /**
+     * Sets the event's control array by copying it into the event.
+     *
+     * @param con control array
+     * @throws EtException if control array has the wrong number of elements
+     */
+    public void setControl(int[] con) throws EtException;
+
+    /**
+     * Set the event data's byte order.
+     * @param order data's byte order
+     */
+    void setByteOrder(ByteOrder order);
+
+    /**
+     * Set the event data's byte order by using values consistent with C-based ET systems,
+     * {@link EtConstants#endianBig}, {@link EtConstants#endianLittle}, {@link EtConstants#endianLocal},
+     * {@link EtConstants#endianNotLocal}, or {@link EtConstants#endianSwitch}.
+     *
+     * @param endian endian value
+     * @throws EtException if argument is a bad value
+     */
+    void setByteOrder(int endian) throws EtException;
+
+    /**
+     * Set the event data's byte order as big with 0x04030201 or
+     * as little with 0x01020304.
+     *
+     * @param byteOrder data's byte order as big with 0x04030201 or
+     *                  as little with 0x01020304.
+     */
+    void setRawByteOrder(int byteOrder) throws EtException;
+
+
+    // miscellaneous
+
+    
+    /**
+     * Tells caller if the event data needs to be swapped in order to be the
+     * same byte order as the local JVM.
+     *
+     * @return <code>true</code> if swapping is needed, otherwise <code>false</code>
+     */
+    public boolean needToSwap();
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtEventImpl.java added at 1.1
diff -N EtEventImpl.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtEventImpl.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,648 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.enums.Age;
+import org.jlab.coda.et.enums.Priority;
+import org.jlab.coda.et.enums.DataStatus;
+import org.jlab.coda.et.enums.Modify;
+
+/**
+ * This class defines an ET event.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtEventImpl implements EtEvent {
+
+    // convenience variables
+    private static final int   numSelectInts = EtConstants.stationSelectInts;
+    private static final int[] controlInitValues = new int[numSelectInts];
+
+    /** Unique id number (place of event in C-based ET system). */
+    private int id;
+
+    /**
+     * Specifies whether the event was obtained as a new event (through
+     * {@link EtSystem#newEvents(EtAttachment, org.jlab.coda.et.enums.Mode, int, int, int)}),
+     * or as a "used" event (through
+     * {@link EtSystem#getEvents(EtAttachment, org.jlab.coda.et.enums.Mode, org.jlab.coda.et.enums.Modify, int, int)}).
+     * If the event is new, its value is {@link Age#NEW} otherwise {@link Age#USED}.
+     */
+    private Age age;
+
+    /** Group to which this event belongs (1, 2, ...) if ET system events are divided into groups.
+     *  If not, group = 1. Used so some producers don't hog events from others. */
+    private int group;
+
+    /** Event priority which is either {@link Priority#HIGH} or {@link Priority#LOW}. */
+    private Priority priority;
+
+    /**
+     * The attachment id which owns or got the event. If it's owned by the
+     * system its value is {@link EtConstants#system}.
+     */
+    private int owner;
+
+    /** Length of the valid data in bytes. */
+    private int length;
+
+    /** Size of the data buffer in bytes. */
+    private int memSize;
+
+    /**
+     * Size limit of events' data buffers in bytes. This is important to
+     * know when Java users connect to C-based ET systems. The C-based ET
+     * systems cannot allow users to increase an event's data size beyond
+     * what was originally allocated. In Java systems there is no size
+     * limit besides computer and JVM limits.
+     */
+    private int sizeLimit;
+
+    /**
+     * Status of the data. It can be ok {@link DataStatus#OK}, corrupted
+     * {@link DataStatus#CORRUPT}, or possibly corrupted
+     * {@link DataStatus#POSSIBLYCORRUPT}.
+     */
+    private DataStatus dataStatus;
+
+    /**
+     * Specifies whether the user wants to read the event only, will modify only the event header
+     * (everything except the data), or will modify the data and/or header.
+     * Modifying the data and/or header is {@link Modify#ANYTHING}, modifying only the header
+     * is {@link Modify#HEADER}, else the default assumed, {@link Modify#NOTHING},
+     * is that nothing is modified resulting in this event being put back into
+     * the ET system (by remote server) immediately upon being copied and that copy
+     * sent to the user.
+     */
+    private Modify modify;
+
+    /**
+     * An integer used to keep track of the data's byte ordering.
+     * Values can be 0x04030201 (local endian) or 0x01020304 (not local endian).
+     */
+    private int byteOrder;
+
+    /**
+     * An array of integers normally used by stations to filter events out of
+     * their input lists. It is used to control the flow of events through
+     * the ET system.
+     */
+    private int[] control;
+
+    /**
+     * This byte array backs the dataBuffer when receiving events from a Java-based
+     * ET system or from over the network. If connected to a local, C-based ET system,
+     * a MappedByteBuffer is used which has <b>no</b> backing array.
+     */
+    private byte[] data;
+
+    /** This ByteBuffer object is a wrapper for the data byte array for convenience. */
+    private ByteBuffer dataBuffer;
+
+    /** Flag specifying whether the ET system process is Java based or not. */
+    private boolean isJava;
+
+
+    
+    /**
+     * Creates an event object for users of Java-based ET systems or by the
+     * system itself. Event objects are only created once in the ET
+     * system process - when the ET system is started up.
+     *
+     * @param size size of the data array in bytes
+     */
+    public EtEventImpl(int size) {
+        memSize    = size;
+        isJava     = true;
+        data       = new byte[size];
+        control    = new int[numSelectInts];
+        dataBuffer = ByteBuffer.wrap(data);
+        init();
+    }
+
+    /**
+     * Creates an event object for ET system users when connecting to ET systems
+     * over the network. Called by
+     * {@link EtSystem#getEvents(EtAttachment, org.jlab.coda.et.enums.Mode,Modify,int,int)},
+     * and
+     * {@link EtSystem#newEvents(EtAttachment, org.jlab.coda.et.enums.Mode,boolean,int,int,int,int)}.
+     *
+     * @param size   size of the data array in bytes.
+     * @param limit  limit on the size of the data array in bytes. Only used
+     *               for C-based ET systems.
+     * @param isJava is ET system Java based?
+     * @param noBuffer forget about allocating byte array and ByteBuffer?
+     */
+    EtEventImpl(int size, int limit, boolean isJava, boolean noBuffer) {
+        memSize     = size;
+        sizeLimit   = limit;
+        this.isJava = isJava;
+        control     = new int[numSelectInts];
+        if (!noBuffer) {
+            data        = new byte[size];
+            dataBuffer  = ByteBuffer.wrap(data);
+        }
+        init();
+    }
+
+    /**
+     * Creates an event object for ET system users when connecting to local, C-based ET systems
+     * and using native methods to call et_events_get.
+     * No data array or buffer are created since we will be using shared
+     * memory and it will be taken care of later. Tons of args since it's a lot easier in
+     * JNI to call one method with lots of args then to call lots of set methods on one object.
+     *
+     * @param size      {@link #memSize}
+     * @param limit     {@link #sizeLimit}
+     * @param status    {@link #dataStatus}
+     * @param id        {@link #id}
+     * @param age       {@link #age}
+     * @param owner     {@link #owner}
+     * @param modify    {@link #modify}
+     * @param length    {@link #length}
+     * @param priority  {@link #modify}
+     * @param byteOrder {@link #byteOrder}
+     * @param control   {@link #control}
+     */
+    EtEventImpl(int size, int limit, int status, int id, int age, int owner,
+              int modify, int length, int priority, int byteOrder, int[] control) {
+
+        isJava         = false;
+        memSize        = size;
+        sizeLimit      = limit;
+        dataStatus     = DataStatus.getStatus(status);
+        this.id        = id;
+        this.age       = Age.getAge(age);
+        this.owner     = owner;
+        this.modify    = Modify.getModify(modify);
+        this.length    = length;
+        this.priority  = Priority.getPriority(priority);
+        this.byteOrder = byteOrder;
+        this.control   = control.clone();
+    }
+
+    /**
+     * Creates an event object for ET system users when connecting to local, C-based ET systems
+     * and using native methods to call et_events_get. The ByteBuffer object is created in JNI
+     * code and directly "wraps" the et data pointer from the ET event obtained through
+     * et_events_get.
+     * Tons of args since it's a lot easier in
+     * JNI to call one method with lots of args then to call lots of set methods on one object.
+     *
+     * @param size      {@link #memSize}
+     * @param limit     {@link #sizeLimit}
+     * @param status    {@link #dataStatus}
+     * @param id        {@link #id}
+     * @param age       {@link #age}
+     * @param owner     {@link #owner}
+     * @param modify    {@link #modify}
+     * @param length    {@link #length}
+     * @param priority  {@link #modify}
+     * @param byteOrder {@link #byteOrder}
+     * @param control   {@link #control}
+     * @param buffer    {@link #dataBuffer}
+     */
+    EtEventImpl(int size, int limit, int status, int id, int age, int owner,
+                int modify, int length, int priority, int byteOrder, int[] control,
+                ByteBuffer buffer) {
+
+        isJava         = false;
+        memSize        = size;
+        sizeLimit      = limit;
+        dataStatus     = DataStatus.getStatus(status);
+        this.id        = id;
+        this.age       = Age.getAge(age);
+        this.owner     = owner;
+        this.modify    = Modify.getModify(modify);
+        this.length    = length;
+        this.priority  = Priority.getPriority(priority);
+        this.byteOrder = byteOrder;
+        this.control   = control;
+        dataBuffer     = buffer;
+    }
+
+    /**
+     * Creates an event object for ET system users when connecting to local, C-based ET systems
+     * and using native methods to call et_events_new_group.
+     * No data array or buffer are created since we will be using shared
+     * memory and it will be taken care of later.
+     *
+     * @param limit {@link #sizeLimit}, {@link #memSize}
+     * @param id    {@link #id}
+     * @param owner {@link #owner}
+     */
+    EtEventImpl(int limit, int id, int owner) {
+
+        age        = Age.NEW;
+        priority   = Priority.LOW;
+        isJava     = false;
+        byteOrder  = 0x04030201;
+        length     = 0;
+        modify     = Modify.NOTHING;
+        dataStatus = DataStatus.OK;
+        control    = new int[numSelectInts];
+
+        memSize    = limit;
+        sizeLimit  = limit;
+        this.id    = id;
+        this.owner = owner;
+    }
+
+    /**
+     * Creates an event object by duplicating another.
+     *
+     * @param ev event to duplicate
+     */
+    public EtEventImpl(EtEventImpl ev) {
+        this.isJava     = ev.isJava;
+        this.memSize    = ev.memSize;
+        this.sizeLimit  = ev.sizeLimit;
+        this.dataStatus = ev.dataStatus;
+        this.id         = ev.id;
+        this.age        = ev.age;
+        this.owner      = ev.owner;
+        this.group      = ev.group;
+        this.modify     = ev.modify;
+        this.length     = ev.length;
+        this.priority   = ev.priority;
+        this.byteOrder  = ev.byteOrder;
+
+        this.control    = ev.control.clone();
+        this.data       = ev.data.clone();
+
+        this.dataBuffer = ByteBuffer.wrap(data);
+        this.dataBuffer.limit(ev.dataBuffer.limit());
+        this.dataBuffer.position(ev.dataBuffer.position());
+        // Cannot copy the mark, oh well.
+    }
+
+    /** Initialize an event's fields. Called for an event each time it passes
+     *  through GRAND_CENTRAL station. */
+    public void init() {
+        age        = Age.NEW;
+        priority   = Priority.LOW;
+        owner      = EtConstants.system;
+        length     = 0;
+        modify     = Modify.NOTHING;
+        byteOrder  = 0x04030201;
+        dataStatus = DataStatus.OK;
+        System.arraycopy(controlInitValues, 0, control, 0, numSelectInts);
+    }
+
+
+    // getters
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Age getAge() {
+        return age;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getGroup() {
+        return group;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Priority getPriority() {
+        return priority;
+    }
+
+    /**
+     * Get int value associated with Priority enum.
+     * @return int value associated with Priority enum
+     */
+    public int getPriorityValue() {
+        return priority.getValue();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getOwner() {
+        return owner;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getLength() {
+        return length;
+    }
+
+    /**
+     * Gets the size of the data buffer in bytes.
+     * @return size of the data buffer in bytes
+     */
+    public int getMemSize() {
+        return memSize;
+    }
+
+    /**
+     * Gets the size limit of the data buffer in bytes when using a C-based ET system.
+     * @return size size limit of the data buffer in bytes
+     */
+    public int getSizeLimit() {
+        return sizeLimit;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public DataStatus getDataStatus() {
+        return dataStatus;
+    }
+
+    /**
+     * Get int value associated with DataStatus enum.
+     * @return int value associated with DataStatus enum
+     */
+    public int getDataStatusValue() {
+        return dataStatus.getValue();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Modify getModify() {
+        return modify;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteOrder getByteOrder() {
+        // java is always big endian
+        return ((byteOrder == 0x04030201) ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRawByteOrder() {
+        return byteOrder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int[] getControl() {
+        return control.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public byte[] getData() throws UnsupportedOperationException {
+        return dataBuffer.array();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ByteBuffer getDataBuffer() {
+        return dataBuffer;
+    }
+
+
+    // setters
+
+
+    /**
+     * Sets the event's id number.
+     * @param id event's id number
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Sets the age of the event which is {@link Age#NEW} for new events obtained by calling
+     * {@link EtSystem#newEvents(EtAttachment, org.jlab.coda.et.enums.Mode, int, int, int)}),
+     * or {@link Age#NEW} for "used" event obtained by calling
+     * {@link EtSystem#getEvents(EtAttachment, org.jlab.coda.et.enums.Mode, org.jlab.coda.et.enums.Modify, int, int)}).
+     *
+     * @param age age of the event
+     */
+    public void setAge(Age age) {
+        this.age = age;
+    }
+
+    /**
+     * Sets the group the event belongs to: (1, 2, ...) if ET system events are divided into groups,
+     * or group = 1 if not.
+     *
+     * @param group group the event belongs to
+     */
+    public void setGroup(int group) {
+        this.group = group;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setPriority(Priority pri) {
+        priority = pri;
+    }
+
+    /**
+     * Sets the owner of the event (attachment using event or system).
+     * @param owner owner of event (attachment using event or system)
+     */
+    public void setOwner(int owner) {
+        this.owner = owner;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setLength(int len) throws EtException {
+        if (len < 0 || len > sizeLimit) {
+            throw new EtException("bad value for event data length");
+        }
+        length = len;
+    }
+
+    /**
+     * Set the length of valid data from server where sizeLimit may be 0.
+     * @param len  length of valid data
+     * @throws EtException if len is negative
+     */
+    public void setLengthFromServer(int len) throws EtException {
+        if (len < 0) {
+            throw new EtException("bad value for event data length");
+        }
+        length = len;
+    }
+
+    /**
+     * Sets the size of the data buffer in bytes.
+     * @param memSize size of the data buffer in bytes
+     */
+    public void setMemSize(int memSize) {
+        this.memSize = memSize;
+    }
+
+    /**
+     * Sets the event's data status. It can be ok {@link DataStatus#OK} which is the default,
+     * corrupted {@link DataStatus#CORRUPT} which is never used actually, or possibly corrupted
+     * {@link DataStatus#POSSIBLYCORRUPT} which occurs when a process holding the event crashes
+     * and the system recovers it.
+     *
+     * @param status data status
+     */
+    public void setDataStatus(DataStatus status) {
+        dataStatus = status;
+    }
+
+    /**
+     * Sets whether the user wants to read the event only, will modify only the event header
+     * (everything except the data), or will modify the data and/or header.
+     * Modifying the data and/or header is {@link Modify#ANYTHING}, modifying only the header
+     * is {@link Modify#HEADER}, else the default assumed, {@link Modify#NOTHING},
+     * is that nothing is modified resulting in this event being put back into
+     * the ET system (by remote server) immediately upon being copied and that copy
+     * sent to the user.
+     * 
+     * @param modify
+     */
+    public void setModify(Modify modify) {
+        this.modify = modify;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setByteOrder(int endian) throws EtException {
+        if (endian == EtConstants.endianBig) {
+            byteOrder = 0x04030201;
+        }
+        else if (endian == EtConstants.endianLittle) {
+            byteOrder = 0x01020304;
+        }
+        else if (endian == EtConstants.endianLocal) {
+            byteOrder = 0x04030201;
+        }
+        else if (endian == EtConstants.endianNotLocal) {
+            byteOrder = 0x01020304;
+        }
+        else if (endian == EtConstants.endianSwitch) {
+            byteOrder = Integer.reverseBytes(byteOrder);
+        }
+        else {
+            throw new EtException("bad value for byte order");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setByteOrder(ByteOrder order) {
+        if (order == null) return;
+        if (order == ByteOrder.BIG_ENDIAN) {
+            byteOrder = 0x04030201;
+        }
+        else {
+            byteOrder = 0x01020304;
+        }
+    }
+
+    /**
+     * [log in to unmask] This is how byte order is stored internally in
+     * this object and how it is stored in the C code.
+     *
+     * @param {@inheritDoc}
+     */
+    public void setRawByteOrder(int byteOrder) throws EtException {
+        if (byteOrder != 0x04030201 && byteOrder != 0x01020304) {
+            throw new EtException("invalid value for byteOrder arg");
+        }
+
+        this.byteOrder = byteOrder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setControl(int[] con) throws EtException {
+        if (con == null) return;
+        if (con.length != numSelectInts) {
+            throw new EtException("wrong number of elements in control array");
+        }
+        System.arraycopy(con, 0, control, 0, numSelectInts);
+    }
+
+    /**
+     * Sets the event's data without copying. The length and memSize members of
+     * the event are automatically set to the data array's length.
+     * Used only by local Java ET system in newEvents to increase data array size.
+     *
+     * @param data data array
+     */
+    public void setData(byte[] data) {
+        // In C-based ET systems, user cannot increase data size beyond
+        // what was initially allocated, but this is only used by local Java ET system.
+        if (data == null) return;
+        this.data = data;
+        length    = data.length;
+        memSize   = data.length;
+    }
+
+    /**
+     * Sets the event's data buffer (must be backed by data array).
+     * This is used when reading data from shared memory and
+     * also if remote user gets new events with the no-allocate flag
+     * set. In the latter case, the user must set the data buffer
+     * explicitly or an exception will result when trying to put the
+     * event back. In any case, using this method should only be done
+     * by the expert user.
+     *
+     * @param dataBuffer event's data buffer (must be backed by data array)
+     */
+    public void setDataBuffer(ByteBuffer dataBuffer) {
+        this.dataBuffer = dataBuffer;
+    }
+
+
+    // miscellaneous
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean needToSwap() {
+        return byteOrder != 0x04030201;
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtEventSelectable.java added at 1.1
diff -N EtEventSelectable.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtEventSelectable.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import org.jlab.coda.et.system.StationLocal;
+import org.jlab.coda.et.system.SystemCreate;
+
+/**
+ * This interface defines a method to use for custom event selection in a station.
+ *
+ * @author Carl Timmer
+ */
+
+public interface EtEventSelectable {
+
+  /**
+   * An event selection method must follow this form.
+   * @param sys the ET system object
+   * @param st the station using a user-defned selection method
+   * @param ev event being evaluated for selection
+   */
+  public boolean select(SystemCreate sys, StationLocal st, EtEvent ev);
+
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtJniAccess.java added at 1.1
diff -N EtJniAccess.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtJniAccess.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,250 @@
+package org.jlab.coda.et;
+
+import org.jlab.coda.et.exception.*;
+
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
+
+
+/**
+ * This class handles all calls to native methods which, in turn,
+ * makes calls to the C ET library routines to get, new, put, and dump events.
+ */
+class EtJniAccess {
+
+    // Load in the necessary library when this class is loaded
+    static {
+        try {
+            System.loadLibrary("et_jni");
+        }
+        catch (Error e) {
+            System.out.println("error loading libet_jni.so");
+            e.printStackTrace();
+            System.exit(-1);
+        }
+    }
+
+    /** Serialize access to classMap and creation of these objects. */
+    static ReentrantLock classLock = new ReentrantLock();
+
+    /** Store EtJniAccess objects here since we only want to create 1 object per ET system. */
+    static HashMap<String, EtJniAccess> classMap = new HashMap<String, EtJniAccess>(10);
+
+
+    /**
+     * Get an instance of this object for a particular ET system. Only one EtJniAccess object
+     * is created for a particular ET system.
+     *
+     * @param etName name of ET system to open
+     * @return object of this type to use for interaction with local, C-based ET system
+     * @throws EtException        for any failure to open ET system except timeout
+     * @throws EtTimeoutException for failure to open ET system within the specified time limit
+     */
+    static EtJniAccess getInstance(String etName) throws EtException, EtTimeoutException {
+        try {
+            classLock.lock();
+
+            // See if we've already opened the ET system being asked for, if so, return that
+            if (classMap.containsKey(etName)) {
+//System.out.println("USE ALREADY EXISTING ET JNI OBJECT for et -> " + etName);
+                EtJniAccess jni = classMap.get(etName);
+                jni.numberOpens++;
+//System.out.println("numberOpens = " + jni.numberOpens);
+                return jni;
+            }
+
+            EtJniAccess jni = new EtJniAccess();
+            jni.openLocalEtSystem(etName);
+            jni.etSystemName = etName;
+            jni.numberOpens = 1;
+//System.out.println("CREATING ET JNI OBJECT for et -> " + etName);
+//System.out.println("numberOpens = " + jni.numberOpens);
+            classMap.put(etName, jni);
+
+            return jni;
+        }
+        finally {
+            classLock.unlock();
+        }
+    }
+
+    private int numberOpens;
+
+    /** Place to store id (pointer) returned from et_open in C code. */
+    private long localEtId;
+
+    /** Store the name of the ET system. */
+    private String etSystemName;
+
+    /**
+     * Create EtJniAccess objects with the {@link #getInstance(String)} method.
+     */
+    private EtJniAccess() {}
+
+
+    /**
+     * Get the et id.
+     * @return et id
+     */
+    long getLocalEtId() {
+        return localEtId;
+    }
+
+
+    /**
+     * Set the et id. Used inside native method {@link #openLocalEtSystem(String)}.
+     * @param id et id
+     */
+    private void setLocalEtId(long id) {
+        localEtId = id;
+    }
+
+
+    /**
+     * Open a local, C-based ET system and store it's id in {@link #localEtId}.
+     * This only needs to be done once per local system even though many connections
+     * to the ET server may be desired.
+     *
+     * @param etName name of ET system to open
+     *
+     * @throws EtException        for any failure to open ET system except timeout
+     * @throws EtTimeoutException for failure to open ET system within the specified time limit
+     */
+    private native void openLocalEtSystem(String etName)
+            throws EtException, EtTimeoutException;
+
+
+    /**
+     * Close the local, C-based ET system that we previously opened.
+     */
+    void close() {
+        try {
+            classLock.lock();
+            numberOpens--;
+//System.out.println("close: numberOpens = " + numberOpens);
+            if (numberOpens < 1) {
+                classMap.remove(etSystemName);
+//System.out.println("close: really close local ET system");
+                closeLocalEtSystem(localEtId);
+            }
+        }
+        finally {
+            classLock.unlock();
+        }
+    }
+
+
+    /**
+     * Close the local, C-based ET system that we previously opened.
+     *
+     * @param etId ET system id
+     */
+    private native void closeLocalEtSystem(long etId);
+
+
+    /**
+     * Put the given array of events back into the local, C-based ET system.
+     *
+     * @param etId   ET system id
+     * @param attId  attachment id
+     * @param evs    array of events
+     * @param length number of events to be put (starting at index of 0)
+     * 
+     * @throws EtException     for variety of general errors
+     * @throws EtDeadException if ET system is dead
+     */
+    native void putEvents(long etId, int attId, EtEventImpl[] evs, int length)
+            throws EtException, EtDeadException;
+
+
+    /**
+     * Dump (dispose of) the given array of unwanted events back into the local, C-based ET system.
+     *
+     * @param etId   ET system id
+     * @param attId  attachment id
+     * @param evs    array of event objects
+     * @param length number of events to be dumped (starting at index of 0)
+     *
+     * @throws EtException for variety of general errors
+     * @throws EtDeadException if ET system is dead
+     */
+    native void dumpEvents(long etId, int attId, EtEventImpl[] evs, int length)
+            throws EtException, EtDeadException;
+
+
+    /**
+     * Get events from the local, C-based ET system.
+     *
+     * @param etId   ET system id
+     * @param attId  attachment id
+     * @param mode   if there are no events available, this parameter specifies
+     *               whether to wait for some by sleeping {@link EtConstants#sleep},
+     *               to wait for a set time {@link EtConstants#timed},
+     *               or to return immediately {@link EtConstants#async}.
+     * @param sec    the number of seconds to wait if a timed wait is specified
+     * @param nsec   the number of nanoseconds to wait if a timed wait is specified
+     * @param count  number of events desired. Size may be different from that requested.
+     *
+     * @return array of events obtained from ET system. Count may be different from that requested.
+     *
+     * @throws EtException     for variety of general errors
+     * @throws EtDeadException if ET system is dead
+     */
+    native EtEventImpl[] getEvents(long etId, int attId, int mode, int sec, int nsec, int count)
+            throws EtException, EtDeadException;
+
+
+    /**
+     * Get array of integers from the local, C-based ET system containing all information
+     * necessary to construct an array of events.
+     *
+     * @param etId   ET system id
+     * @param attId  attachment id
+     * @param mode   if there are no events available, this parameter specifies
+     *               whether to wait for some by sleeping {@link EtConstants#sleep},
+     *               to wait for a set time {@link EtConstants#timed},
+     *               or to return immediately {@link EtConstants#async}.
+     * @param sec    the number of seconds to wait if a timed wait is specified
+     * @param nsec   the number of nanoseconds to wait if a timed wait is specified
+     * @param count  number of events desired. Size may be different from that requested.
+     *
+     * @return array of events obtained from ET system. Count may be different from that requested.
+     *
+     * @throws EtException     for variety of general errors
+     * @throws EtDeadException if ET system is dead
+     */
+    native int[] getEventsInfo(long etId, int attId, int mode, int sec, int nsec, int count)
+            throws EtException, EtDeadException;
+
+
+    /**
+     * Get new (unused) events from a specified group of such events from the local, C-based ET system.
+     *
+     * @param etId   ET system id
+     * @param attId  attachment id
+     * @param mode   if there are no new events available, this parameter specifies
+     *               whether to wait for some by sleeping {@link EtConstants#sleep},
+     *               to wait for a set time {@link EtConstants#timed},
+     *               or to return immediately {@link EtConstants#async}.
+     * @param sec    the number of seconds to wait if a timed wait is specified
+     * @param nsec   the number of nanoseconds to wait if a timed wait is specified
+     * @param count  number of events desired
+     * @param size   the size in bytes of the events desired
+     * @param group  group number from which to draw new events. Some ET systems have
+     *               unused events divided into groups whose numbering starts at 1.
+     *               For ET system not so divided, all events belong to group 1.
+     *
+     * @return array of unused events obtained from ET system. Count may be different from that requested.
+     *
+     * @throws EtException        for variety of general errors
+     * @throws EtDeadException    if ET system is dead
+     * @throws EtWakeUpException  if told to stop sleeping (before timeout) while trying to get events
+     * @throws EtTimeoutException if timed out on {@link EtConstants#timed} option
+     * @throws EtEmptyException   if no events available in {@link EtConstants#async} mode
+     * @throws EtBusyException    if cannot get access to events due to activity of other
+     *                            processes when in {@link EtConstants#async} mode
+     */
+    native EtEventImpl[] newEvents(long etId, int attId, int mode, int sec, int nsec, int count, int size, int group)
+            throws EtException,        EtDeadException, EtWakeUpException,
+                   EtTimeoutException, EtBusyException, EtEmptyException;
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtStation.java added at 1.1
diff -N EtStation.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtStation.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,587 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.io.*;
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class defines a station for the ET system user.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtStation {
+
+    /** Unique id number. */
+    private int id;
+
+    /** Name of the station. */
+    private String name;
+
+    /** User's ET system object. */
+    private EtSystem sys;
+
+    /** Flag telling whether this station object is usable or the station it
+     *  represents has been removed. Set by the user's ET system object. */
+    private boolean usable;
+
+    // userMode = attachmentLimit; 0 = multiple attachments, 1 = single attachment, 2 = 2 attachments, etc...
+
+
+    /**
+     * Creates a station object. Done by the ET system object only.
+     *
+     * @param name station name
+     * @param id   station id number
+     * @param sys  user's ET system object
+     */
+    EtStation(String name, int id, EtSystem sys) {
+        this.id = id;
+        this.sys = sys;
+        this.name = name;
+    }
+
+
+    // public sets
+
+
+    /**
+     * Sets whether this station object is usable or the station it represents has been removed.
+     * @param usable <code>true</code> if station object is usable,
+     *               <code>false</code> if station it represents has been removed
+     */
+    void setUsable(boolean usable) {
+        this.usable = usable;
+    }
+
+
+    // public gets
+
+
+    /** Gets the station name.
+     * @return station name */
+    public String getName() {return name;}
+
+    /** Gets the station id.
+     * @return station id */
+    public int getId() {return id;}
+
+    /** Gets the ET system object.
+     * @return ET system object */
+    public EtSystem getSys() {return sys;}
+
+    /** Tells if this station object is usable.
+     * @return <code>true</code> if station object is usable and <code>false</code> otherwise */
+    public boolean isUsable() {return usable;}
+
+    /**
+     * Gets the station's select array used for filtering events.
+     *
+     * @return array of select integers
+     * @throws EtException
+     *     if the station has been removed or cannot be found
+     * @see EtStationConfig#select
+     */
+    public int[] getSelectWords() throws IOException, EtException {
+        if (!usable) {throw new EtException("station has been removed");}
+
+        int err;
+        int[] select = new int[EtConstants.stationSelectInts];
+
+        synchronized(sys) {
+            sys.getOutputStream().writeInt(EtConstants.netStatGSw);
+            sys.getOutputStream().writeInt(id);
+            sys.getOutputStream().flush();
+
+            err = sys.getInputStream().readInt();
+            for (int i=0; i < select.length; i++) {
+                select[i] = sys.getInputStream().readInt();
+            }
+        }
+
+        if (err != EtConstants.ok) {
+            throw new EtException("cannot find station");
+        }
+
+        return select;
+    }
+
+    /**
+     * Sets the station's select array - used for filtering events.
+     *
+     * @param select array of select integers
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed or cannot be found;
+     *                     if wrong size array, or if the station is GRAND_CENTRAL
+     * @see EtStationConfig#select
+     */
+    public void setSelectWords(int[] select) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if (select.length != EtConstants.stationSelectInts) {
+            throw new EtException("wrong number of elements in select array");
+        }
+
+        int err;
+
+        synchronized (sys) {
+            sys.getOutputStream().writeInt(EtConstants.netStatSSw);
+            sys.getOutputStream().writeInt(id);
+            for (int i = 0; i < select.length; i++) {
+                sys.getOutputStream().writeInt(select[i]);
+            }
+            sys.getOutputStream().flush();
+            err = sys.getInputStream().readInt();
+        }
+
+        if (err != EtConstants.ok) {
+            throw new EtException("this station has been removed from ET system");
+        }
+
+        return;
+    }
+
+    /**
+     * This gets "String" station parameter data over the network.
+     *
+     * @param command coded command to send to the TCP server thread.
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station cannot be found
+     */
+    private String getStringValue(int command) throws IOException, EtException {
+        byte[] buf = null;
+        String val = null;
+        int err, length = 0;
+
+        synchronized (sys) {
+            sys.getOutputStream().writeInt(command);
+            sys.getOutputStream().writeInt(id);
+            sys.getOutputStream().flush();
+            err = sys.getInputStream().readInt();
+            length = sys.getInputStream().readInt();
+
+            if (err == EtConstants.ok) {
+                buf = new byte[length];
+                sys.getInputStream().readFully(buf, 0, length);
+            }
+        }
+
+        if (err == EtConstants.ok) {
+            try {
+                val = new String(buf, 0, length - 1, "ASCII");
+            }
+            catch (UnsupportedEncodingException ex) {
+            }
+        }
+        else {
+            if (length == 0) {
+                return null;
+            }
+            throw new EtException("cannot find station");
+        }
+
+        return val;
+    }
+
+    /**
+     * Gets the name of the library containing the station's user-defined select
+     * function. This is only relevant for station's on C language ET systems.
+     *
+     * @return station's user-defined select function library
+     * @throws IOException if there are problems with network communication
+     * @throws EtException  if the station has been removed
+     * @see EtStationConfig#selectLibrary
+     */
+    public String getSelectLibrary() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getStringValue(EtConstants.netStatLib);
+    }
+
+    /**
+     * Gets the name of the station's user-defined select function.
+     * This is only relevant for station's on C language ET systems.
+     *
+     * @return station's user-defined select function
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#selectFunction
+     */
+    public String getSelectFunction() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getStringValue(EtConstants.netStatFunc);
+    }
+
+    /**
+     * Gets the name of the class containing the station's user-defined select
+     * method. This is only relevant for station's on Java language ET systems.
+     *
+     * @return station's user-defined select method class
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#selectClass
+     */
+    public String getSelectClass() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getStringValue(EtConstants.netStatClass);
+    }
+
+
+    /**
+     * This gets "integer" station parameter data over the network.
+     *
+     * @param cmd coded command to send to the TCP server thread.
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station cannot be found
+     */
+    private int getIntValue(int cmd) throws IOException, EtException {
+        int err, val = 0;
+
+        synchronized (sys) {
+            sys.getOutputStream().writeInt(cmd);
+            sys.getOutputStream().writeInt(id);
+            sys.getOutputStream().flush();
+            err = sys.getInputStream().readInt();
+            val = sys.getInputStream().readInt();
+        }
+        
+        if (err != EtConstants.ok) {
+            throw new EtException("this station has been removed from ET system");
+        }
+
+        return val;
+    }
+
+    /**
+     * This sets "integer" station parameter data over the network.
+     *
+     * @param cmd coded command to send to the TCP server thread.
+     * @param val value to set.
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station cannot be found
+     */
+    private void setIntValue(int cmd, int val) throws IOException, EtException {
+        int err;
+
+        synchronized (sys) {
+            sys.getOutputStream().writeInt(cmd);
+            sys.getOutputStream().writeInt(id);
+            sys.getOutputStream().writeInt(val);
+            sys.getOutputStream().flush();
+            err = sys.getInputStream().readInt();
+        }
+
+        if (err != EtConstants.ok) {
+            throw new EtException("this station has been removed from ET system");
+        }
+
+        return;
+  }
+
+    /**
+     * Gets the station's number of attachments.
+     *
+     * @return station's number of attachments
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     */
+    public int getNumAttachments() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGAtts);
+    }
+
+    /**
+     * Gets the station's status. It may have the values
+     * {@link EtConstants#stationUnused}, {@link EtConstants#stationCreating},
+     * {@link EtConstants#stationIdle}, and {@link EtConstants#stationActive}.
+     *
+     * @return station's status
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     */
+    public int getStatus() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatStatus);
+    }
+
+    /**
+     * Gets the number of events in the station's input list.
+     *
+     * @return number of events in the station's input list
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     */
+    public int getInputCount() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatInCnt);
+    }
+
+    /**
+     * Gets the number of events in the station's output list.
+     *
+     * @return number of events in the station's output list
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     */
+    public int getOutputCount() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatOutCnt);
+    }
+
+    /**
+     * Gets the station configuration's block mode.
+     *
+     * @return station's block mode
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#blockMode
+     */
+    public int getBlockMode() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGBlock);
+    }
+
+    /**
+     * Sets the station's block mode dynamically.
+     *
+     * @param mode block mode value
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed, bad mode value, or
+     *                     the station is GRAND_CENTRAL
+     * @see EtStationConfig#blockMode
+     */
+    public void setBlockMode(int mode) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if ((mode != EtConstants.stationBlocking) &&
+            (mode != EtConstants.stationNonBlocking)) {
+            throw new EtException("bad block mode value");
+        }
+        setIntValue(EtConstants.netStatSBlock, mode);
+        return;
+  }
+
+    /**
+     * Gets the station configuration's user mode.
+     *
+     * @return station's user mode
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#userMode
+     */
+    public int getUserMode() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGUser);
+    }
+
+    /**
+     * Sets the station's user mode dynamically.
+     *
+     * @param mode user mode value
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed, bad mode value, or
+     *                     the station is GRAND_CENTRAL
+     * @see EtStationConfig#userMode
+     */
+    public void setUserMode(int mode) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if (mode < 0) {
+            throw new EtException("bad user mode value");
+        }
+
+        setIntValue(EtConstants.netStatSUser, mode);
+        return;
+    }
+
+    /**
+     * Gets the station configuration's restore mode.
+     *
+     * @return station's restore mode
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#restoreMode
+     */
+    public int getRestoreMode() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGRestore);
+    }
+
+    /**
+     * Sets the station's restore mode dynamically.
+     *
+     * @param mode restore mode value
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed, bad mode value, or
+     *                     the station is GRAND_CENTRAL
+     * @see EtStationConfig#restoreMode
+     */
+    public void setRestoreMode(int mode) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if ((mode != EtConstants.stationRestoreOut) &&
+            (mode != EtConstants.stationRestoreIn) &&
+            (mode != EtConstants.stationRestoreGC)) {
+            throw new EtException("bad restore mode value");
+        }
+
+        setIntValue(EtConstants.netStatSRestore, mode);
+        return;
+    }
+
+    /**
+     * Gets the station configuration's select mode.
+     *
+     * @return station's select mode
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#selectMode
+     */
+    public int getSelectMode() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGSelect);
+  }
+
+    /**
+     * Gets the station configuration's cue.
+     *
+     * @return station's cue
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#cue
+     */
+    public int getCue() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGCue);
+    }
+
+    /**
+     * Sets the station's cue size dynamically.
+     *
+     * @param cue cue value
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed, bad cue value, or
+     *                     the station is GRAND_CENTRAL
+     * @see EtStationConfig#cue
+     */
+    public void setCue(int cue) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if (cue < 1) {
+            throw new EtException("bad cue value");
+        }
+
+        setIntValue(EtConstants.netStatSCue, cue);
+        return;
+    }
+
+    /**
+     * Gets the station configuration's prescale.
+     *
+     * @return station's prescale
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed
+     * @see EtStationConfig#prescale
+     */
+    public int getPrescale() throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+        return getIntValue(EtConstants.netStatGPre);
+    }
+
+    /**
+     * Sets the station's prescale dynamically.
+     *
+     * @param prescale prescale value
+     * @throws IOException if there are problems with network communication
+     * @throws EtException if the station has been removed, bad prescale value, or
+     *                     the station is GRAND_CENTRAL
+     * @see EtStationConfig#prescale
+     */
+    public void setPrescale(int prescale) throws IOException, EtException {
+        if (!usable) {
+            throw new EtException("station has been removed");
+        }
+
+        if (id == 0) {
+            throw new EtException("cannot modify GRAND_CENTRAL station");
+        }
+
+        if (prescale < 1) {
+            throw new EtException("bad prescale value");
+        }
+        
+        setIntValue(EtConstants.netStatSPre, prescale);
+        return;
+    }
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtStationConfig.java added at 1.1
diff -N EtStationConfig.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtStationConfig.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,399 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.util.*;
+import java.io.Serializable;
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class specifies a configuration used to create a new station.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtStationConfig implements Serializable {
+
+    /**
+     * Maximum number of events to store in this station's input list when the
+     * station is nonblocking. When the input list has reached this limit,
+     * additional events flowing through the ET system are passed to the next
+     * station in line.
+     */
+    private int cue;
+
+    /**
+     * A value of N means selecting 1 out of every Nth event that meets this
+     * station's selection criteria.
+     */
+    private int prescale;
+
+    /**
+     * Determine whether the station is part of a single group of stations
+     * through which events flow in parallel or is not. A value of
+     * {@link EtConstants#stationParallel} means it is a parallel station,
+     * while a value of {@link EtConstants#stationSerial} means it is not.
+     */
+    private int flowMode;
+
+    /**
+     * The maximum number of users permitted to attach to this station. A value
+     * of 0 means any number of users may attach. It may be set to
+     * {@link EtConstants#stationUserMulti} or {@link EtConstants#stationUserSingle}
+     * meaning unlimited users and a single user respectively.
+     */
+    private int userMode;
+
+    /**
+     * Determine the method of dealing with events obtained by a user through an
+     * attachment, but whose process has ended before putting the events back
+     * into the system. It may have the value {@link EtConstants#stationRestoreIn}
+     * which places the events in the station's input list,
+     * {@link EtConstants#stationRestoreOut} which places them in the output list,
+     * or {@link EtConstants#stationRestoreGC} which places them in GRAND_CENTRAL
+     * station.
+     */
+    private int restoreMode;
+
+    /**
+     * Determine whether all events will pass through the station (blocking) or
+     * whether events should fill a cue with additional events bypassing the
+     * station and going to the next (nonblocking). The permitted values are
+     * {@link EtConstants#stationBlocking} and {@link EtConstants#stationNonBlocking}.
+     */
+    private int blockMode;
+
+    /**
+     * Determine the method of filtering events for selection into the station's
+     * input list. A value of {@link EtConstants#stationSelectAll} applies no
+     * filtering, {@link EtConstants#stationSelectMatch} applies a builtin
+     * method for selection ({@link org.jlab.coda.et.system.StationLocal#select}), and
+     * {@link EtConstants#stationSelectUser} allows the user to define a selection
+     * method. If the station is part of a single group of parallel stations, a
+     * value of {@link EtConstants#stationSelectRRobin} distributes events among the
+     * parallel stations using a round robin algorithm. Similarly, if the station
+     * is part of a single group of parallel stations, a value of
+     * {@link EtConstants#stationSelectEqualCue} distributes events among the
+     * parallel stations using an algorithm to keep the cues equal to eachother.
+     */
+    private int selectMode;
+
+    /**
+     * An array of integers used in the builtin selection method and available
+     * for any tasks the user desires. Its size is set by
+     * {@link EtConstants#stationSelectInts}.
+     */
+    private int[] select;
+
+    /**
+     * Name of user-defined select function in a C library. It may be null. This
+     * is only relevant to C language ET systems.
+     */
+    private String selectFunction;
+
+    /**
+     * Name of the C library containing the user-defined select function. It may
+     * be null. This is only relevant to C language ET systems.
+     */
+    private String selectLibrary;
+
+    /**
+     * Name of the Java class containing the user-defined select method. It may
+     * be null. This is only relevant to Java language ET systems.
+     */
+    private String selectClass;
+
+
+    /**
+     * Creates a new StationConfig object with default values for everything.
+     * The default values are:
+     * cue         = {@link EtConstants#defaultStationCue},
+     * prescale    = {@link EtConstants#defaultStationPrescale},
+     * flowMode    = {@link EtConstants#stationSerial},
+     * userMode    = {@link EtConstants#stationUserMulti},
+     * restoreMode = {@link EtConstants#stationRestoreOut},
+     * blockMode   = {@link EtConstants#stationBlocking},
+     * selectMode  = {@link EtConstants#stationSelectAll}, and
+     * select      = filled with -1's
+     */
+    public EtStationConfig() {
+        cue         = EtConstants.defaultStationCue;
+        prescale    = EtConstants.defaultStationPrescale;
+        flowMode    = EtConstants.stationSerial;
+        userMode    = EtConstants.stationUserMulti;
+        restoreMode = EtConstants.stationRestoreOut;
+        blockMode   = EtConstants.stationBlocking;
+        selectMode  = EtConstants.stationSelectAll;
+        select      = new int[EtConstants.stationSelectInts];
+        Arrays.fill(select, -1);
+    }
+
+
+    /**
+     * Creates a new StationConfig object from an existing one.
+     * @param config config to copy
+     */
+    public EtStationConfig(EtStationConfig config) {
+        cue            = config.cue;
+        prescale       = config.prescale;
+        flowMode       = config.flowMode;
+        userMode       = config.userMode;
+        restoreMode    = config.restoreMode;
+        blockMode      = config.blockMode;
+        selectMode     = config.selectMode;
+        select         = (int[]) config.select.clone();
+        selectFunction = config.selectFunction;
+        selectLibrary  = config.selectLibrary;
+        selectClass    = config.selectClass;
+    }
+
+
+    /**
+     * Checks to see if station configurations are compatible when adding
+     * a parallel station to an existing group of parallel stations.
+     *
+     * @param group  station configuration of head of existing group of parallel stations
+     * @param config configuration of station seeking to be added to the group
+     */
+    public static boolean compatibleParallelConfigs(EtStationConfig group, EtStationConfig config) {
+
+        // both must be parallel stations
+        if ((group.flowMode  != EtConstants.stationParallel) ||
+            (config.flowMode != EtConstants.stationParallel))  {
+            return false;
+        }
+
+        // if group is roundrobin or equal-cue, then config must be same
+        if (((group.selectMode  == EtConstants.stationSelectRRobin) &&
+             (config.selectMode != EtConstants.stationSelectRRobin)) ||
+            ((group.selectMode  == EtConstants.stationSelectEqualCue) &&
+             (config.selectMode != EtConstants.stationSelectEqualCue))) {
+            return false;
+        }
+
+        // If group is roundrobin or equal-cue, then config's blocking & prescale must be same.
+        // BlockMode is forced to be blocking and prescale is forced to be 1
+        // in the method EtSystem.configCheck.
+        if (((group.selectMode == EtConstants.stationSelectRRobin) ||
+             (group.selectMode == EtConstants.stationSelectEqualCue)) &&
+            ((group.blockMode  != config.blockMode) ||
+             (group.prescale   != config.prescale))) {
+            return false;
+        }
+
+        // if group is NOT roundrobin or equal-cue, then config's cannot be either
+        if (((group.selectMode  != EtConstants.stationSelectRRobin) &&
+             (group.selectMode  != EtConstants.stationSelectEqualCue)) &&
+            ((config.selectMode == EtConstants.stationSelectRRobin) ||
+             (config.selectMode == EtConstants.stationSelectEqualCue))) {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    // public gets
+
+
+    /** Gets the cue size.
+     * @return cue size */
+    public int getCue() {return cue;}
+
+    /** Gets the prescale value.
+     * @return prescale value */
+    public int getPrescale() {return prescale;}
+
+    /** Gets the flow mode.
+     * @return flow mode */
+    public int getFlowMode() {return flowMode;}
+
+    /** Gets the user mode.
+     * @return user mode */
+    public int getUserMode() {return userMode;}
+
+    /** Gets the restore mode.
+     * @return restore mode */
+    public int getRestoreMode() {return restoreMode;}
+
+    /** Gets the block mode.
+     * @return block mode */
+    public int getBlockMode() {return blockMode;}
+
+    /** Gets the select mode.
+     * @return select mode */
+    public int getSelectMode() {return selectMode;}
+
+    /** Gets a copy of the select integer array.
+     * @return copy of select integer array */
+    public int[] getSelect() {return select.clone();}
+
+    /** Gets the user-defined select function name.
+     * @return selection function name */
+    public String getSelectFunction() {return selectFunction;}
+
+    /** Gets the name of the library containing the user-defined select function.
+     * @return library name */
+    public String getSelectLibrary() {return selectLibrary;}
+
+    /** Gets the name of the class containing the user-defined select method.
+     * @return class name */
+    public String getSelectClass() {return selectClass;}
+
+
+  // public sets
+
+
+    /**
+     * Sets the station's cue size.
+     *
+     * @param q cue size
+     * @throws EtException if there is a bad cue size value
+     */
+    public void setCue(int q) throws EtException {
+        if (q < 1) {
+            throw new EtException("bad cue value");
+        }
+        cue = q;
+    }
+
+    /**
+     * Sets the station's prescale value.
+     *
+     * @param pre prescale value
+     * @throws EtException if there is a bad prescale value
+     */
+    public void setPrescale(int pre) throws EtException {
+        if (pre < 1) {
+            throw new EtException("bad prescale value");
+        }
+        prescale = pre;
+    }
+
+    /**
+     * Sets the station's flow mode value.
+     *
+     * @param mode flow mode
+     * @throws EtException if there is a bad flow mode value
+     */
+    public void setFlowMode(int mode) throws EtException {
+        if ((mode != EtConstants.stationSerial) &&
+            (mode != EtConstants.stationParallel)) {
+            throw new EtException("bad flow mode value");
+        }
+        flowMode = mode;
+    }
+
+    /**
+     * Sets the station's user mode value.
+     *
+     * @param mode user mode
+     * @throws EtException if there is a bad user mode value
+     */
+    public void setUserMode(int mode) throws EtException {
+        if (mode < 0) {
+            throw new EtException("bad user mode value");
+        }
+        userMode = mode;
+    }
+
+    /**
+     * Sets the station's restore mode value.
+     *
+     * @param mode restore mode
+     * @throws EtException if there is a bad restore mode value
+     */
+    public void setRestoreMode(int mode) throws EtException {
+        if ((mode != EtConstants.stationRestoreOut) &&
+            (mode != EtConstants.stationRestoreIn) &&
+            (mode != EtConstants.stationRestoreGC) &&
+            (mode != EtConstants.stationRestoreRedist)) {
+            throw new EtException("bad restore mode value");
+        }
+        restoreMode = mode;
+    }
+
+    /**
+     * Sets the station's block mode value.
+     *
+     * @param mode block mode
+     * @throws EtException if there is a bad block mode value
+     */
+    public void setBlockMode(int mode) throws EtException {
+        if ((mode != EtConstants.stationBlocking) &&
+            (mode != EtConstants.stationNonBlocking)) {
+            throw new EtException("bad block mode value");
+        }
+        blockMode = mode;
+    }
+
+    /**
+     * Sets the station's select mode value.
+     *
+     * @param mode select mode
+     * @throws EtException if there is a bad select mode value
+     */
+    public void setSelectMode(int mode) throws EtException {
+        if ((mode != EtConstants.stationSelectAll) &&
+            (mode != EtConstants.stationSelectMatch) &&
+            (mode != EtConstants.stationSelectUser) &&
+            (mode != EtConstants.stationSelectRRobin) &&
+            (mode != EtConstants.stationSelectEqualCue)) {
+            throw new EtException("bad select mode value");
+        }
+        selectMode = mode;
+  }
+
+    /**
+     * Sets the station's select integer array.
+     *
+     * @param sel select integer array
+     * @throws EtException if there are the wrong number of elements in the array
+     */
+    public void setSelect(int[] sel) throws EtException {
+        if (sel.length != EtConstants.stationSelectInts) {
+            throw new EtException("wrong number of elements in select array");
+        }
+        select = (int[]) sel.clone();
+    }
+
+    /**
+     * Sets the station's user-defined select function.
+     *
+     * @param func name of the user-defined select function
+     */
+    public void setSelectFunction(String func) {
+        selectFunction = func;
+    }
+
+    /**
+     * Sets the library containing the user-defined select function.
+     *
+     * @param lib name of the library containg the user-defined select function
+     */
+    public void setSelectLibrary(String lib) {
+        selectLibrary = lib;
+    }
+
+    /**
+     * Sets the class containing the user-defined select method.
+     *
+     * @param sClass name of the class containg the user-defined select method
+     */
+    public void setSelectClass(String sClass) {
+        selectClass = sClass;
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtStationSelection.java added at 1.1
diff -N EtStationSelection.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtStationSelection.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import org.jlab.coda.et.system.StationLocal;
+import org.jlab.coda.et.system.SystemCreate;
+
+
+/**
+ * This class contains an example of a user-defined method used to
+ * select events for a station.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtStationSelection implements EtEventSelectable {
+
+    public EtStationSelection() {
+    }
+
+    public boolean select(SystemCreate sys, StationLocal st, EtEvent ev) {
+        if (ev.getId()%2 == 0) {
+            //System.out.println("  Select Func: accept ev.id = " + ev.id);
+            return true;
+        }
+        //System.out.println("  Select Func: reject ev.id = " + ev.id);
+        return false;
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtSystem.java added at 1.1
diff -N EtSystem.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtSystem.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,2700 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.nio.ByteOrder;
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.nio.MappedByteBuffer;
+import java.nio.ByteBuffer;
+
+import org.jlab.coda.et.data.*;
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.enums.Modify;
+import org.jlab.coda.et.enums.Mode;
+import org.jlab.coda.et.enums.Priority;
+import org.jlab.coda.et.enums.DataStatus;
+
+// TODO: if IO exception occurs, open is not set to false, must catch it and call close()
+// TODO: so open is set to false. Then try open again.
+/**
+ * This class implements an object which allows a user to interact with an ET
+ * system. It is not the ET system itself, but rather a proxy which communicates
+ * over the network or through JNI with the real ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtSystem {
+
+    /** Object to specify how to open the ET system of interest. */
+    private EtSystemOpenConfig openConfig;
+
+    /** Object used to connect to a real ET system. */
+    private EtSystemOpen sys;
+
+    /** Flag telling whether the real ET system is currently opened or not. */
+    private boolean open;
+
+    /** Debug level. */
+    private int debug;
+
+    /** Tcp socket connected to ET system's server. */
+    private Socket sock;
+
+    /** Flag specifying whether the ET system process is Java based or not. */
+    private boolean isJava;
+
+    /** Data input stream built on top of the socket's input stream (with an
+     *  intervening buffered input stream). */
+    private DataInputStream in;
+
+    /** Data output stream built on top of the socket's output stream (with an
+     *  intervening buffered output stream). */
+    private DataOutputStream out;
+
+
+
+    /**
+     * Construct a new EtSystem object.
+     *
+     * @param config EtSystemOpenConfig object to specify how to open the ET
+     *               system of interest (copy is stored & used)
+     * @param debug  debug level (e.g. {@link EtConstants#debugInfo})
+     * @throws EtException if config is null or not self-consistent
+     */
+    public EtSystem(EtSystemOpenConfig config, int debug) throws EtException {
+
+        if (config == null) {
+            throw new EtException("Invalid arg");
+        }
+
+        openConfig = new EtSystemOpenConfig(config);
+
+        if (!openConfig.selfConsistent()) {
+            throw new EtException("system open configuration is not self-consistent");
+        }
+
+        sys = new EtSystemOpen(openConfig);
+
+        if ((debug != EtConstants.debugNone)   &&
+            (debug != EtConstants.debugSevere) &&
+            (debug != EtConstants.debugError)  &&
+            (debug != EtConstants.debugWarn)   &&
+            (debug != EtConstants.debugInfo))    {
+
+            this.debug = EtConstants.debugError;
+        }
+        else {
+            this.debug = debug;
+        }
+
+        try {
+            sys.setDebug(debug);
+        }
+        catch (EtException e) { /* never happen */ }
+
+        //open();
+    }
+
+    /**
+     * Construct a new EtSystem object. Debug level set to print only errors.
+     *
+     * @param config EtSystemOpenConfig object to specify how to open the ET
+     *               system of interest (copy is stored & used)
+     * @throws EtException if config is not self-consistent
+     */
+    public EtSystem(EtSystemOpenConfig config) throws EtException {
+
+        this(config, EtConstants.debugError);
+    }
+
+    /**
+     * Construct a new EtSystem object. Not meant for general use.
+     * Use one of the other constructors.
+     *
+     * @param sys   EtSystemOpen object to specify a connection to the ET
+     *              system of interest
+     * @param debug debug level (e.g. {@link EtConstants#debugInfo})
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws UnknownHostException
+     *     if the host address(es) is(are) unknown
+     * @throws EtException
+     *     if arg is null;
+     *     if the responding ET system has the wrong name, runs a different
+     *     version of ET, or has a different value for
+     *     {@link EtConstants#stationSelectInts}
+     * @throws EtTooManyException
+     *     if there were more than one valid response when policy is set to
+     *     {@link EtConstants#policyError} and we are looking either
+     *     remotely or anywhere for the ET system.
+     */
+    public EtSystem(EtSystemOpen sys, int debug)  throws
+            IOException, EtException, EtTooManyException {
+
+        if (sys == null) {
+            throw new EtException("Invalid arg");
+        }
+
+        this.sys   = sys;
+        openConfig = sys.getConfig();
+
+        if ((debug != EtConstants.debugNone)   &&
+            (debug != EtConstants.debugSevere) &&
+            (debug != EtConstants.debugError)  &&
+            (debug != EtConstants.debugWarn)   &&
+            (debug != EtConstants.debugInfo))    {
+
+            this.debug = EtConstants.debugError;
+        }
+        else {
+            this.debug = debug;
+        }
+
+        if (sys.isConnected()) {
+            if (sys.getLanguage() == EtConstants.langJava) {isJava = true;}
+
+            // buffer communication streams for efficiency
+            sock = sys.getSocket();
+
+            if (openConfig.getTcpRecvBufSize() > 0) {
+                in = new DataInputStream(new BufferedInputStream(sock.getInputStream(), openConfig.getTcpRecvBufSize()));
+            }
+            else {
+                in = new DataInputStream( new BufferedInputStream( sock.getInputStream(), sock.getReceiveBufferSize()));
+            }
+
+            if (openConfig.getTcpSendBufSize() > 0) {
+                out  = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(), openConfig.getTcpSendBufSize()));
+            }
+            else {
+                out  = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(), sock.getSendBufferSize()));
+            }
+
+            open = true;
+        }
+        else {
+            open();
+        }
+
+    }
+
+
+    // Local getters & setters
+
+    
+    /**
+     * Get the data input stream to talk to ET system server.
+     * @return data input stream to talk to ET system server
+     */
+    public DataInputStream getInputStream() {
+        return in;
+    }
+
+    /**
+     * Get the data output stream to receive from the ET system server.
+     * @return data output stream to receive from the ET system server
+     */
+    public DataOutputStream getOutputStream() {
+        return out;
+    }
+
+    /**
+     * Gets the debug output level.
+     * @return debug output level
+     */
+    public int getDebug() {
+        return debug;
+    }
+
+    /**
+     * Sets the debug output level. Must be either {@link EtConstants#debugNone},
+     * {@link EtConstants#debugSevere}, {@link EtConstants#debugError},
+     * {@link EtConstants#debugWarn}, or {@link EtConstants#debugInfo}.
+     *
+     * @param val debug level
+     * @throws EtException if bad argument value
+     */
+    public void setDebug(int val) throws EtException {
+        if ((val != EtConstants.debugNone)   &&
+            (val != EtConstants.debugSevere) &&
+            (val != EtConstants.debugError)  &&
+            (val != EtConstants.debugWarn)   &&
+            (val != EtConstants.debugInfo)) {
+            throw new EtException("bad debug argument");
+        }
+        debug = val;
+    }
+
+    /**
+     * Gets a copy of the configuration object used to specify how to open the ET system.
+     * @return copy of the configuration object used to specify how to open the ET system.
+     */
+    public EtSystemOpenConfig getConfig() {
+        return new EtSystemOpenConfig(openConfig);
+    }
+
+
+    /**
+     * Open the ET system and set up buffered communication.
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws UnknownHostException
+     *     if the host address(es) is(are) unknown
+     * @throws EtException
+     *     if the responding ET system has the wrong name, runs a different
+     *     version of ET, or has a different value for
+     *     {@link EtConstants#stationSelectInts}
+     * @throws EtTooManyException
+     *     if there were more than one valid response when policy is set to
+     *     {@link EtConstants#policyError} and we are looking either
+     *     remotely or anywhere for the ET system.
+     */
+    synchronized public void open() throws IOException, EtException, EtTooManyException {
+
+        if (open) {
+            return;
+        }
+
+        try {
+            sys.connect();
+        }
+        catch (EtTooManyException ex) {
+            if (debug >= EtConstants.debugError) {
+                int count = 1;
+                System.out.println("The following hosts responded:");
+                for (Map.Entry<ArrayList<String>,Integer> entry : sys.getResponders().entrySet()) {
+                    System.out.println("  host #" + (count++) + " at port " + entry.getValue());
+                    ArrayList<String> addrList = entry.getKey();
+                    for (String s : addrList) {
+                        System.out.println("    " + s);
+                    }
+                    System.out.println();
+                }
+            }
+            throw ex;
+        }
+
+        if (sys.getLanguage() == EtConstants.langJava) {isJava = true;}
+
+        sock = sys.getSocket();
+
+        // buffer communication streams for efficiency
+        if (openConfig.getTcpRecvBufSize() > 0) {
+            in = new DataInputStream(new BufferedInputStream(sock.getInputStream(), openConfig.getTcpRecvBufSize()));
+        }
+        else {
+            in = new DataInputStream( new BufferedInputStream( sock.getInputStream(),  sock.getReceiveBufferSize()));
+        }
+
+        if (openConfig.getTcpSendBufSize() > 0) {
+            out  = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(), openConfig.getTcpSendBufSize()));
+        }
+        else {
+            out  = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(), sock.getSendBufferSize()));
+        }
+
+        open = true;
+    }
+
+
+    /** Close the ET system. */
+    synchronized public void close() {
+
+        if (!open) {
+            return;
+        }
+
+        // if communication with ET system fails, we've already been "closed"
+        try {
+            // Are we using JNI? If so, close the ET system it opened.
+            if (sys.isMapLocalSharedMemory()) {
+//System.out.println("   Close et sys JNI object");
+                sys.getJni().close();
+            }
+//            else {
+//System.out.println("   Do NOT close et sys JNI object since NO local shared memory");
+//            }
+
+            out.writeInt(EtConstants.netClose);  // close and forcedclose do the same thing in java
+            out.flush();
+            in.readInt();
+        }
+        catch (IOException ex) {
+            if (debug >= EtConstants.debugError) {
+                System.out.println("network communication error");
+            }
+        }
+        finally {
+            try {
+                in.close();
+                out.close();
+                sys.disconnect(); // does sock.close()
+            }
+            catch (IOException ex) { /* ignore exception */ }
+        }
+
+        open = false;
+    }
+
+
+    /**
+     * Is the ET system alive and are we connected to it?
+     *
+     *  @return <code>true</code> if the ET system is alive and we're connected to it,
+     *          otherwise  <code>false</code>
+     */
+    synchronized public boolean alive() {
+        if (!open) {
+            return false;
+        }
+
+        int alive;
+        // If ET system is NOT alive, or if ET system was killed and restarted
+        // (breaking tcp connection), we'll get a read or write error.
+        try {
+            out.writeInt(EtConstants.netAlive);
+            out.flush();
+            alive = in.readInt();
+        }
+        catch (IOException ex) {
+            if (debug >= EtConstants.debugError) {
+                System.out.println("network communication error");
+            }
+            return false;
+        }
+
+        return (alive == 1);
+    }
+
+
+    /**
+     * Wake up an attachment that is waiting to read events from a station's empty input list.
+     *
+     * @param att attachment to wake up
+     *
+     * @throws IOException
+     *      if problems with network communications
+     * @throws EtException
+     *      if arg is null;
+     *      if not connected to ET system;
+     *      if the attachment object is invalid
+     */
+    synchronized public void wakeUpAttachment(EtAttachment att) throws IOException, EtException {
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (att == null || !att.isUsable() || att.getSys() != this) {
+            throw new EtException("Invalid attachment");
+        }
+
+        out.writeInt(EtConstants.netWakeAtt);
+        out.writeInt(att.getId());
+        out.flush();
+    }
+
+
+    /**
+     * Wake up all attachments waiting to read events from a station's
+     * empty input list.
+     *
+     * @param station station whose attachments are to wake up
+     *
+     * @throws IOException
+     *      if problems with network communications
+     * @throws EtException
+     *      if arg is null;
+     *      if not connected to ET system;
+     *      if the station object is invalid
+     */
+    synchronized public void wakeUpAll(EtStation station) throws IOException, EtException {
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (station == null || !station.isUsable() || station.getSys() != this) {
+            throw new EtException("Invalid station");
+        }
+
+        out.writeInt(EtConstants.netWakeAll);
+        out.writeInt(station.getId());
+        out.flush();
+    }
+
+
+    //****************************************************
+    //                      STATIONS                     *
+    //****************************************************
+
+    
+    /**
+     * Checks a station configuration for self-consistency.
+     *
+     * @param config station configuration
+     *
+     * @throws EtException
+     *     if arg is null;
+     *     if the station configuration is not self-consistent
+     */
+    private void configCheck(EtStationConfig config) throws EtException {
+
+        if (config == null) {
+            throw new EtException("Invalid arg");
+        }
+
+        // USER mode means specifing a class
+        if ((config.getSelectMode()  == EtConstants.stationSelectUser) &&
+            (config.getSelectClass() == null)) {
+
+            throw new EtException("station config needs a select class name");
+        }
+
+        // Must be parallel, block, not prescale, and not restore to input list if rrobin or equal cue
+        if (((config.getSelectMode()  == EtConstants.stationSelectRRobin) ||
+             (config.getSelectMode()  == EtConstants.stationSelectEqualCue)) &&
+            ((config.getFlowMode()    == EtConstants.stationSerial) ||
+             (config.getBlockMode()   == EtConstants.stationNonBlocking) ||
+             (config.getRestoreMode() == EtConstants.stationRestoreIn)  ||
+             (config.getPrescale()    != 1))) {
+
+            throw new EtException("if flowMode = rrobin/equalcue, station must be parallel, nonBlocking, prescale=1, & not restoreIn");
+        }
+
+        // If redistributing restored events, must be a parallel station
+        if ((config.getRestoreMode() == EtConstants.stationRestoreRedist) &&
+            (config.getFlowMode()    != EtConstants.stationParallel)) {
+
+            throw new EtException("if restoreMode = restoreRedist, station must be parallel");
+        }
+
+        if (config.getCue() > sys.getNumEvents()) {
+            config.setCue(sys.getNumEvents());
+        }
+    }
+
+
+    /**
+     * Creates a new station placed at the end of the ordered list of stations.
+     * If the station is added to a group of parallel stations,
+     * it is placed at the end of the list of parallel stations.
+     *
+     * @param config  station configuration
+     * @param name    station name
+     *
+     * @return new station object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if not connected to ET system;
+     *     if the select method's class cannot be loaded;
+     *     if the position is less than 1 (GRAND_CENTRAL's spot);
+     *     if the name is GRAND_CENTRAL (already taken);
+     *     if the configuration's cue size is too big;
+     *     if the configuration needs a select class name
+     * @throws EtExistsException
+     *     if the station already exists but with a different configuration
+     * @throws EtTooManyException
+     *     if the maximum number of stations has been created already
+     */
+    public EtStation createStation(EtStationConfig config, String name)
+            throws IOException, EtException,
+                   EtExistsException, EtTooManyException {
+
+        return createStation(config, name, EtConstants.end, EtConstants.end);
+    }
+
+
+    /**
+     * Creates a new station at a specified position in the ordered list of
+     * stations. If the station is added to a group of parallel stations,
+     * it is placed at the end of the list of parallel stations.
+     *
+     * @param config   station configuration
+     * @param name     station name
+     * @param position position in the linked list to put the station.
+     *
+     * @return new station object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if not connected to ET system;
+     *     if the select method's class cannot be loaded;
+     *     if the position is less than 1 (GRAND_CENTRAL's spot);
+     *     if the name is GRAND_CENTRAL (already taken);
+     *     if the configuration's cue size is too big;
+     *     if the configuration needs a select class name
+     * @throws EtExistsException
+     *     if the station already exists but with a different configuration
+     * @throws EtTooManyException
+     *     if the maximum number of stations has been created already
+     */
+    public EtStation createStation(EtStationConfig config, String name, int position)
+            throws IOException, EtException,
+            EtExistsException, EtTooManyException {
+        return createStation(config, name, position, EtConstants.end);
+    }
+
+
+    /**
+     * Creates a new station at a specified position in the ordered list of
+     * stations and in a specified position in an ordered list of parallel
+     * stations if it is a parallel station.
+     *
+     * @param config     station configuration
+     * @param name       station name
+     * @param position   position in the main list to put the station.
+     * @param parallelPosition   position in the list of parallel
+     *                           stations to put the station.
+     *
+     * @return new station object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if arg is null;
+     *     if not connected to ET system;
+     *     if the select method's class cannot be loaded;
+     *     if the position is less than 1 (GRAND_CENTRAL's spot);
+     *     if the name is GRAND_CENTRAL (already taken);
+     *     if the configuration's cue size is too big;
+     *     if the configuration needs a select class name
+     * @throws EtExistsException
+     *     if the station already exists but with a different configuration
+     * @throws EtTooManyException
+     *     if the maximum number of stations has been created already
+     */
+    synchronized public EtStation createStation(EtStationConfig config, String name,
+                                              int position, int parallelPosition)
+            throws IOException, EtException,
+                   EtExistsException, EtTooManyException {
+
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (name == null || config == null) {
+            throw new EtException("Invalid arg");
+        }
+
+        // cannot create GrandCentral
+        if (name.equals("GRAND_CENTRAL")) {
+            throw new EtException("Cannot create GRAND_CENTRAL station");
+        }
+
+        // check value of position
+        if (position != EtConstants.end && position < 1) {
+            throw new EtException("Bad value for position");
+        }
+
+        // check value of parallel position
+        if ((parallelPosition != EtConstants.end) &&
+            (parallelPosition != EtConstants.newHead) &&
+            (parallelPosition  < 0)) {
+            throw new EtException("Bad value for parallel position");
+        }
+
+        // check station configuration for self consistency
+        configCheck(config);
+
+        // command
+        out.writeInt(EtConstants.netStatCrAt);
+
+        // station configuration
+        out.writeInt(EtConstants.structOk); // not used in Java
+        out.writeInt(config.getFlowMode());
+        out.writeInt(config.getUserMode());
+        out.writeInt(config.getRestoreMode());
+        out.writeInt(config.getBlockMode());
+        out.writeInt(config.getPrescale());
+        out.writeInt(config.getCue());
+        out.writeInt(config.getSelectMode());
+        int[] select = config.getSelect();
+        for (int i=0; i < EtConstants.stationSelectInts; i++) {
+            out.writeInt(select[i]);
+        }
+
+        int functionLength = 0; // no function
+        if (config.getSelectFunction() != null) {
+            functionLength = config.getSelectFunction().length() + 1;
+        }
+        out.writeInt(functionLength);
+
+        int libraryLength = 0; // no lib
+        if (config.getSelectLibrary() != null) {
+            libraryLength = config.getSelectLibrary().length() + 1;
+        }
+        out.writeInt(libraryLength);
+
+        int classLength = 0; // no class
+        if (config.getSelectClass() != null) {
+            classLength = config.getSelectClass().length() + 1;
+        }
+        out.writeInt(classLength);
+
+        // station name and position
+        int nameLength = name.length() + 1;
+        out.writeInt(nameLength);
+        out.writeInt(position);
+        out.writeInt(parallelPosition);
+
+        // write string(s)
+        try {
+            if (functionLength > 0) {
+                out.write(config.getSelectFunction().getBytes("ASCII"));
+                out.writeByte(0);
+            }
+            if (libraryLength > 0) {
+                out.write(config.getSelectLibrary().getBytes("ASCII"));
+                out.writeByte(0);
+            }
+            if (classLength > 0) {
+                out.write(config.getSelectClass().getBytes("ASCII"));
+                out.writeByte(0);
+            }
+            out.write(name.getBytes("ASCII"));
+            out.writeByte(0);
+        }
+        catch (UnsupportedEncodingException ex) { /* never happen */ }
+
+        out.flush();
+
+        int err = in.readInt();
+        int statId = in.readInt();
+
+        if (err ==  EtConstants.errorTooMany) {
+            throw new EtTooManyException("Maximum number of stations already created");
+        }
+        else if (err == EtConstants.errorExists) {
+            throw new EtExistsException("Station already exists with different definition");
+        }
+        else if (err ==  EtConstants.error) {
+            throw new EtException("Trying to add incompatible parallel station, or\n" +
+                    "trying to add parallel station to head of existing parallel group, or\n" +
+                    "cannot load select class");
+        }
+
+        // create station
+        EtStation station = new EtStation(name, statId, this);
+        station.setUsable(true);
+        if (debug >= EtConstants.debugInfo) {
+            System.out.println("Creating station " + name + " is done");
+        }
+        
+        return station;
+    }
+
+
+    /**
+     * Removes an existing station.
+     *
+     * @param station station object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if arg is null;
+     *     if not connected to ET system;
+     *     if attachments to the station still exist;
+     *     if the station is GRAND_CENTRAL (which must always exist);
+     *     if the station does not exist;
+     *     if the station object is invalid
+     */
+    synchronized public void removeStation(EtStation station) throws IOException, EtException {
+
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (station == null) {
+            throw new EtException("Invalid station");
+        }
+
+        // cannot remove GrandCentral
+        if (station.getId() == 0) {
+            throw new EtException("Cannot remove GRAND_CENTRAL station");
+        }
+
+        // station object invalid
+        if (!station.isUsable() || station.getSys() != this) {
+            throw new EtException("Invalid station");
+        }
+
+        out.writeInt(EtConstants.netStatRm);
+        out.writeInt(station.getId());
+        out.flush();
+
+        int err = in.readInt();
+        if (err ==  EtConstants.error) {
+            throw new EtException("Either no such station exists " +
+                                  "or remove all attachments before removing station");
+        }
+        
+        station.setUsable(false);
+    }
+
+
+  /**
+   * Changes the position of a station in the ordered list of stations.
+   *
+   * @param station   station object
+   * @param position  position in the main station list (starting at 0)
+   * @param parallelPosition  position in list of parallel stations (starting at 0)
+   *
+   * @throws IOException
+   *     if problems with network communications
+   * @throws EtException
+   *     if arg is null;
+   *     if not connected to ET system;
+   *     if the station does not exist;
+   *     if trying to move GRAND_CENTRAL;
+   *     if position is < 1 (GRAND_CENTRAL is always first);
+   *     if parallelPosition < 0;
+   *     if station object is invalid;
+   *     if trying to move an incompatible parallel station to an existing group
+   *        of parallel stations or to the head of an existing group of parallel
+   *        stations.
+   */
+  synchronized public void setStationPosition(EtStation station, int position,
+                                              int parallelPosition)
+          throws IOException, EtException {
+
+      if (!open) {
+          throw new EtException("Not connected to ET system");
+      }
+
+      if (station == null) {
+          throw new EtException("Invalid station");
+      }
+
+      // cannot move GrandCentral
+      if (station.getId() == 0) {
+          throw new EtException("Cannot move GRAND_CENTRAL station");
+      }
+
+      if ((position != EtConstants.end) && (position < 0)) {
+          throw new EtException("bad value for position");
+      }
+      else if (position == 0) {
+          throw new EtException("GRAND_CENTRAL station is always first");
+      }
+
+      if ((parallelPosition != EtConstants.end) &&
+          (parallelPosition != EtConstants.newHead) &&
+          (parallelPosition < 0)) {
+          throw new EtException("bad value for parallelPosition");
+      }
+
+      if (!station.isUsable() || station.getSys() != this) {
+          throw new EtException("Invalid station");
+      }
+
+      out.writeInt(EtConstants.netStatSPos);
+      out.writeInt(station.getId());
+      out.writeInt(position);
+      out.writeInt(parallelPosition);
+      out.flush();
+
+      int err = in.readInt();
+      if (err ==  EtConstants.error) {
+          station.setUsable(false);
+          throw new EtException("station does not exist");
+      }
+  }
+
+
+    /**
+     * Gets the position of a station in the ordered list of stations.
+     *
+     * @param station station object
+     * @return position of a station in the main linked list of stations
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if arg is null;
+     *     if not connected to ET system;
+     *     if the station does not exist;
+     *     if station object is invalid
+     */
+    synchronized public int getStationPosition(EtStation station)
+            throws IOException, EtException {
+
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (station == null || !station.isUsable() || station.getSys() != this) {
+            throw new EtException("Invalid station");
+        }
+
+        // GrandCentral is always first
+        if (station.getId() == 0) {
+            return 0;
+        }
+
+        out.writeInt(EtConstants.netStatGPos);
+        out.writeInt(station.getId());
+        out.flush();
+
+        int err = in.readInt();
+        int position = in.readInt();
+        // skip parallel position info
+        in.skipBytes(4);
+        if (err ==  EtConstants.error) {
+            station.setUsable(false);
+            throw new EtException("station does not exist");
+        }
+        
+        return position;
+    }
+
+
+    /**
+     * Gets the position of a parallel station in its ordered list of
+     * parallel stations.
+     *
+     * @param station station object
+     * @return position of a station in the linked list of stations
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if arg is null;
+     *     if not connected to ET system;
+     *     if the station does not exist;
+     *     if station object is invalid
+     */
+    synchronized public int getStationParallelPosition(EtStation station)
+            throws IOException, EtException {
+
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (station == null || !station.isUsable() || station.getSys() != this) {
+            throw new EtException("Invalid station");
+        }
+
+        // parallel position is 0 for serial stations (like GrandCentral)
+        if (station.getId() == 0) {
+            return 0;
+        }
+
+        out.writeInt(EtConstants.netStatGPos);
+        out.writeInt(station.getId());
+        out.flush();
+
+        int err = in.readInt();
+        // skip main position info
+        in.skipBytes(4);
+        int pPosition = in.readInt();
+        if (err ==  EtConstants.error) {
+            station.setUsable(false);
+            throw new EtException("station does not exist");
+        }
+
+        return pPosition;
+    }
+
+
+    /**
+     * Create an attachment to a station.
+     *
+     * @param station station object
+     * @return an attachment object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if arg is null;
+     *     if not connected to ET system;
+     *     if the station does not exist;
+     *     if station object is invalid
+     * @throws EtTooManyException
+     *     if no more attachments are allowed to the station;
+     *     if no more attachments are allowed to ET system
+     */
+    synchronized public EtAttachment attach(EtStation station)
+            throws IOException, EtException, EtTooManyException {
+
+        if (!open) {
+            throw new EtException("Not connected to ET system");
+        }
+
+        if (station == null || !station.isUsable() || station.getSys() != this) {
+            throw new EtException("Invalid station");
+        }
+
+        // find name of our host
+        String host = "unknown";
+        try {host = InetAddress.getLocalHost().getHostName();}
+        catch (UnknownHostException ex) { /* host = "unknown" */ }
+
+        // find interface (ip address) socket is using
+        String ipAddr = sock.getLocalAddress().getHostAddress();
+
+        out.writeInt(EtConstants.netStatAtt);
+        out.writeInt(station.getId());
+        out.writeInt(-1); // no pid in Java
+        out.writeInt(host.length() + 1);
+        out.writeInt(ipAddr.length() + 1);
+
+        // write strings
+        try {
+            out.write(host.getBytes("ASCII"));
+            out.writeByte(0);
+            out.write(ipAddr.getBytes("ASCII"));
+            out.writeByte(0);
+        }
+        catch (UnsupportedEncodingException ex) { /* never happen */ }
+        out.flush();
+
+        int err = in.readInt();
+        int attId = in.readInt();
+        if (err ==  EtConstants.error) {
+            station.setUsable(false);
+            throw new EtException("station does not exist");
+        }
+        else if (err ==  EtConstants.errorTooMany) {
+            throw new EtTooManyException("no more attachments allowed to either station or system");
+        }
+
+        EtAttachment att = new EtAttachment(station, attId, this);
+        att.setUsable(true);
+        return att;
+    }
+
+
+
+    /**
+     * Remove an attachment from a station.
+     *
+     * @param att attachment object
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
[truncated at 1000 lines; 1704 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et
EtSystemOpen.java added at 1.1
diff -N EtSystemOpen.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtSystemOpen.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,1471 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.nio.channels.FileChannel;
+import java.nio.MappedByteBuffer;
+import java.nio.ByteOrder;
+
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class opens (finds and connects to) an ET system. The use of this class
+ * is hidden from the user. There is no reason to use it explicitly.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtSystemOpen {
+
+    /** Object specifying how to open an ET system. */
+    private EtSystemOpenConfig config;
+
+    /** TCP socket connection established with an ET system's server. */
+    private Socket sock;
+
+    /** IP address (dot decimal) of the host the ET system resides on. */
+    private String hostAddress;
+
+    /** List of all IP addresses (dot decimal) of the host the ET system resides on. */
+    private ArrayList<String> hostAddresses;
+
+    /** Port number of the ET system's tcp server. */
+    private int tcpPort;
+
+    /** In case of multiple responding ET systems, a map of their addresses & ports. */
+    private LinkedHashMap<ArrayList<String>, Integer> responders;
+
+    /** Is this object connected to a real, live ET system? */
+    private boolean connected;
+
+    /** Is the ET system on the local host? */
+    private boolean etOnLocalHost;
+
+    /** Debug level. Set by {@link EtSystemOpen#setDebug(int)}. */
+    private int debug;
+
+    // using shared memory
+
+    /** If opening a local, C-based ET system, try mapping the memory containing
+     *  the event data instead of sending it over sockets. */
+    private boolean mapLocalSharedMemory;
+
+    /** Buffer containing mapped memory if {@link #mapLocalSharedMemory} flag is true. */
+    private MappedByteBuffer buffer;
+
+    /** Object for accessing native methods which use C library to get and put events. */
+    private EtJniAccess jni;
+
+    // properties of opened ET system
+
+    /** Endian value of the opened ET system. */
+    private int endian;
+
+    /** Total number of events of the opened ET system. */
+    private int numEvents;
+
+    /** Event size in bytes of the opened ET system. */
+    private long eventSize;
+
+    /** Major version number of the opened ET system. */
+    private int version;
+
+    /** Number of select integers in the opened ET system. */
+    private int stationSelectInts;
+
+    /** Language used to implement the opened ET system. The possible values are
+     *  {@link EtConstants#langJava} for Java, {@link EtConstants#langCpp} for C++,
+     *  and {@link EtConstants#langC} for C. */
+    private int language;
+
+    /** True if ET system is 64 bit, else false. */
+    private boolean bit64;
+
+    private ArrayList<String> localHostIpAddrs;
+
+
+    // convenience variables
+    private final boolean  foundServer=true, cannotFindServer=false;
+    private final boolean  gotMatch=true,    noMatch=false;
+
+
+    /**
+     * Constructor which stores copy of argument.
+     * @param config EtSystemOpenConfig object
+     */
+    public EtSystemOpen(EtSystemOpenConfig config) {
+        this.config = new EtSystemOpenConfig(config);
+        debug = EtConstants.debugError;
+        responders = new LinkedHashMap<ArrayList<String>, Integer>(20);
+        hostAddresses = new ArrayList<String>();
+
+        // get set of all host's IP addresses (dot-decimal)
+        localHostIpAddrs = new ArrayList<String>();
+        try {
+            InetAddress[] haddrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
+            for (InetAddress ia : haddrs) {
+                localHostIpAddrs.add(ia.getHostAddress());
+            }
+        }
+        catch (UnknownHostException e) {
+            if (debug >= EtConstants.debugWarn) {
+                System.out.println("EtSystemOpen constructor: cannot find local IP addresses");
+            }
+        }
+    }
+
+
+    // public sets
+
+
+    /**
+     * Sets the debug output level. Must be either {@link EtConstants#debugNone},
+     * {@link EtConstants#debugSevere}, {@link EtConstants#debugError},
+     * {@link EtConstants#debugWarn}, or {@link EtConstants#debugInfo}.
+     *
+     * @param debug debug level
+     * @throws EtException
+     *     if bad argument value
+     */
+    public void setDebug(int debug) throws EtException {
+        if ((debug != EtConstants.debugNone)   &&
+            (debug != EtConstants.debugSevere) &&
+            (debug != EtConstants.debugError)  &&
+            (debug != EtConstants.debugWarn)   &&
+            (debug != EtConstants.debugInfo))    {
+            throw new EtException("bad debug argument");
+        }
+        this.debug = debug;
+    }
+
+
+    // public gets
+
+
+    /** Gets the total number of events of the opened ET system.
+     *  @return total number of events */
+    public int getNumEvents() {return numEvents;}
+
+    /** Gets the size of the normal events in bytes of the opened ET system.
+     *  @return size of normal events in bytes */
+    public long getEventSize() {return eventSize;}
+
+    /** Gets the tcp server port number of the opened ET system.
+     *  @return tcp server port number */
+    public int getTcpPort() {return tcpPort;}
+
+    /** Gets the address (dot decimal) of the host the opened ET system is running on.
+     *  @return the address (dot decimal) of the host the opened ET system is running on */
+    public String getHostAddress() {return hostAddress;}
+
+    /** Gets list of all the IP addresses (dot decimal) of the host the opened ET system is running on.
+     * @return list of all the IP addresses (dot decimal) of the host the opened ET system is running on */
+    public ArrayList<String> getHostAddresses() {return hostAddresses;}
+
+    /** Gets the name of the ET system (file).
+     *  @return ET system name */
+    public String getName() {return config.getEtName();}
+
+    /** Gets the endian value of the opened ET system.
+     *  @return endian value */
+    public int getEndian() {return endian;}
+
+    /** Gets the major version number of the opened ET system.
+     *  @return major ET version number */
+    public int getVersion() {return version;}
+
+    /** Gets the language used to implement the opened ET system.
+     *  @return language */
+    public int getLanguage() {return language;}
+
+    /** Gets the number of station select integers of the opened ET system.
+     *  @return number of select integers */
+    public int getSelectInts() {return stationSelectInts;}
+
+    /** Gets the socket connecting this object to the ET system.
+     *  @return socket */
+    public Socket getSocket() {return sock;}
+
+    /** Gets the debug output level.
+     *  @return debug output level */
+    public int getDebug() {return debug;}
+
+    /** Gets a copy of the EtSystemOpenConfig configuration object.
+     *  @return copy of configuration object */
+    public EtSystemOpenConfig getConfig() {return new EtSystemOpenConfig(config);}
+
+    /** Gets whether the ET system is connected (opened) or not.
+     *  @return status of connection to ET system */
+    synchronized public boolean isConnected() {return connected;}
+
+    /** Gets whether the operating system is 64 bit or not.
+     *  @return <code>true</code> if the operating system is 64 bit, else <code>false</code>  */
+    public boolean isBit64() {return bit64;}
+
+    /** Gets a map of the hosts and ports of responding ET systems to broad/multicasts.
+     *  @return a map of the hosts and ports of responding ET systems to broad/multicasts */
+    public LinkedHashMap<ArrayList<String>, Integer> getResponders() {return responders;}
+
+    /** Gets whether opening a local, C-based ET system and trying to map the memory containing
+     *  the event data instead of sending it over sockets.
+     *  @return <code>true</code> if opening a local, C-based ET system and trying to map the memory containing
+     *          the event data instead of sending it over sockets  */
+    public boolean isMapLocalSharedMemory() {return mapLocalSharedMemory;}
+
+    /** Gets buffer containing the memory mapped file if {@link #isMapLocalSharedMemory} returns true.
+     *  @return buffer contained the memory mapped file */
+    public MappedByteBuffer getBuffer() {return buffer;}
+
+    /** Gets the object used to access native methods when using local, C-based ET system. */
+    public EtJniAccess getJni() {return jni;}
+
+
+    // The next two methods are really only useful when the
+    // EtTooManyException is thrown from "connect" or findServerPort.
+
+
+    /** Gets all host names when multiple ET systems respond.
+     *  @return all host names from responding ET systems */
+    public String[] getAllHosts() {
+        if (responders.size() == 0) {
+            if (hostAddress == null) {
+                return null;
+            }
+            return new String[] {hostAddress};
+        }
+        return (String []) responders.keySet().toArray();
+    }
+
+    /** Gets all port numbers when multiple ET systems respond.
+     *  @return all port numbers from responding ET systems */
+    public int[] getAllPorts() {
+        if (responders.size() == 0) {
+            if (tcpPort == 0) {
+                return null;
+            }
+            return new int[] {tcpPort};
+        }
+
+        Integer[] p = (Integer []) responders.values().toArray();
+        int[] ports = new int[p.length];
+        for (int i=0; i < p.length; i++) {
+            ports[i] = p[i];
+        }
+        return ports;
+    }
+
+
+    /**
+     * Finds the ET system's tcp server port number and host.
+     *
+     * @return <code>true</code> if server found, else <code>false</code>
+     *
+     * @throws java.io.IOException
+     *     if problems with network communications
+     * @throws java.net.UnknownHostException
+     *     if the host address(es) is(are) unknown
+     * @throws EtTooManyException
+     *     if there were more than one valid response when policy is set to
+     *     {@link EtConstants#policyError} and we are looking either
+     *     remotely or anywhere for the ET system.
+     */
+    private boolean findServerPort() throws IOException, UnknownHostException, EtTooManyException {
+
+        boolean match = noMatch;
+        int     status, totalPacketsSent = 0, sendPacketLimit = 4;
+        int     timeOuts[] = {100, 2000, 4000, 7000};
+        int     waitTime, socketTimeOut = 20000; // socketTimeOut > sum of timeOuts
+        String  specifiedHost = null;
+        HashSet<String> knownHostIpAddrs = new HashSet<String>();
+
+        // clear out any previously stored objects
+        responders.clear();
+        hostAddresses.clear();
+
+        // Put outgoing packet info into a byte array to send to ET systems
+        ByteArrayOutputStream  baos = new ByteArrayOutputStream(122);
+        DataOutputStream        dos = new DataOutputStream(baos);
+
+        // write magic #s
+        dos.writeInt(EtConstants.magicNumbers[0]);
+        dos.writeInt(EtConstants.magicNumbers[1]);
+        dos.writeInt(EtConstants.magicNumbers[2]);
+        // write ET version
+        dos.writeInt(EtConstants.version);
+        // write string length of ET name
+        dos.writeInt(config.getEtName().length() + 1);
+        // write ET name
+        try {
+            dos.write(config.getEtName().getBytes("ASCII"));
+            dos.writeByte(0);
+        }
+        catch (UnsupportedEncodingException ex) {/* will never happen */}
+        dos.flush();
+
+        // construct byte array to send over a socket
+        final byte sbuffer[] = baos.toByteArray();
+        dos.close();
+        baos.close();
+
+        // We may need to send packets over many different sockets
+        // as there may be broadcasting on multiple subnets as well
+        // as multicasts on several addresses. Keep track of these
+        // sockets, addresses, & packets with this class:
+        class send {
+            int             port;
+            String          address;
+            InetAddress     addr;
+            MulticastSocket socket;
+            DatagramPacket  packet;
+
+            send (String address, MulticastSocket socket, int port) throws UnknownHostException {
+                this.port    = port;
+                this.address = address;
+                this.socket  = socket;
+                addr    = InetAddress.getByName(address);  //UnknownHostEx
+                packet  = new DatagramPacket(sbuffer, sbuffer.length, addr, port);
+            }
+        }
+
+        // store all places to send packets to in a list
+        LinkedList<send> sendList = new LinkedList<send>();
+
+        // find local host
+        String localHost = null;
+        InetAddress localAddr = null;
+        try {
+            localAddr = InetAddress.getLocalHost();
+            localHost = localAddr.getHostName();
+        }
+        catch (UnknownHostException ex) {}
+
+        // If the host is not remote or anywhere out there. If it's
+        // local or we know its name, send a UDP packet to it alone.
+        if ((!config.getHost().equals(EtConstants.hostRemote)) &&
+            (!config.getHost().equals(EtConstants.hostAnywhere)))  {
+
+            // We can use multicast socket for regular UDP - it works
+            MulticastSocket socket = new MulticastSocket();	//IOEx
+            // Socket will unblock after timeout,
+            // letting reply collecting thread quit
+            try {socket.setSoTimeout(socketTimeOut);}
+            catch (SocketException ex) {}
+
+            // If it's local, find name and send packet directly there.
+            // This will work in Java where the server listens on all addresses.
+            // But it won't work for C where only broad and multicast address
+            // are listened to.
+            if ((config.getHost().equals(EtConstants.hostLocal)) ||
+                (config.getHost().equals("localhost")))  {
+                specifiedHost = localHost;
+            // else if we know host's name ...
+            } else {
+                specifiedHost = config.getHost();
+            }
+
+            // get set of all host's IP addresses (dot-decimal)
+            InetAddress[] haddrs = InetAddress.getAllByName(specifiedHost);  // UnknownHostException
+            for (InetAddress ia : haddrs) {
+                knownHostIpAddrs.add(ia.getHostAddress());
+            }
+
+            sendList.add(new send(specifiedHost, socket, config.getUdpPort()));
+
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("findServerPort: send to local or specified host " + specifiedHost +
+                        " on port " + config.getUdpPort());
+            }
+        }
+        // else if the host name is not specified, and it's either
+        // remote or anywhere out there, broad/multicast to find it
+        else { }
+
+
+        // setup broadcast sockets & packets first
+        if ((config.getNetworkContactMethod() == EtConstants.broadcast) ||
+            (config.getNetworkContactMethod() == EtConstants.broadAndMulticast)) {
+
+            // if no broadcast addresses have been specifically set, use 255.255.255.255
+            if (config.getBroadcastAddrs().size() < 1) {
+                // We can use multicast socket for broadcasting - it works
+                MulticastSocket socket = new MulticastSocket();    //IOEx
+                // Socket will unblock after timeout,
+                // letting reply collecting thread quit
+                try {
+                    socket.setSoTimeout(socketTimeOut);
+                    socket.setBroadcast(true);
+                }
+                catch (SocketException ex) {
+                }
+
+                sendList.add(new send(config.broadcastIP, socket, config.getUdpPort()));
+                if (debug >= EtConstants.debugInfo) {
+                    System.out.println("findServerPort: broadcasting to " + config.broadcastIP +
+                                               " on port " + config.getUdpPort());
+                }
+            }
+            // otherwise only broadcast on addresses specifically set
+            else {
+                for (String addr : config.getBroadcastAddrs()) {
+                    MulticastSocket socket = new MulticastSocket();    //IOEx
+                    try {
+                        socket.setSoTimeout(socketTimeOut);
+                        socket.setBroadcast(true);
+                    }
+                    catch (SocketException ex) {
+                    }
+
+                    sendList.add(new send(addr, socket, config.getUdpPort()));
+                    if (debug >= EtConstants.debugInfo) {
+                        System.out.println("findServerPort: broadcasting to " + addr +
+                                                   " on port " + config.getUdpPort());
+                    }
+                }
+            }
+        }
+
+        // setup multicast sockets & packets next
+        if ((config.getNetworkContactMethod() == EtConstants.multicast) ||
+            (config.getNetworkContactMethod() == EtConstants.broadAndMulticast)) {
+
+            for (String addr : config.getMulticastAddrs()) {
+                MulticastSocket socket = new MulticastSocket();    //IOEx
+                try {
+                    socket.setSoTimeout(socketTimeOut);
+                }
+                catch (SocketException ex) {
+                }
+
+                if (config.getTTL() != 1) {
+                    socket.setTimeToLive(config.getTTL());        //IOEx
+                }
+
+                sendList.add(new send(addr, socket, config.getMulticastPort()));
+                if (debug >= EtConstants.debugInfo) {
+                    System.out.println("findServerPort: multicasting to " + addr + " on port " + config.getMulticastPort());
+                }
+            }
+        }
+
+
+        /** Class to help receive a packet on a socket. */
+        class get {
+            // min data size = 8*4 + 3 + Constants.ipAddrStrLen +
+            //                 2*Constants.maxHostNameLen(); = 558 bytes
+            // but give us a bit of extra room for lots of names with 4k bytes
+            byte[] buffer = new byte[4096];
+            DatagramReceive thread;
+            DatagramPacket  packet;
+            MulticastSocket socket;
+
+            get(MulticastSocket sock) {
+                packet = new DatagramPacket(buffer, buffer.length);
+                socket = sock;
+            }
+
+            // start up thread to receive single udp packet on single socket
+            void start() {
+                thread = new DatagramReceive(packet, socket);
+                thread.start();
+            }
+        }
+
+        // store things here
+        LinkedList<get> receiveList = new LinkedList<get>();
+
+        // start reply collecting threads
+        for (send sender : sendList) {
+            get receiver = new get(sender.socket);
+            receiveList.add(receiver);
+            // start single thread
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("findServerPort: starting thread to socket " + sender.socket);
+            }
+            receiver.start();
+        }
+
+        Thread.yield();
+
+        sendPoint:
+        // set a limit on the total # of packet groups sent out to find a server
+        while (totalPacketsSent < sendPacketLimit) {
+            // send packets out on all sockets
+            for (send sender : sendList) {
+                sender.socket.send(sender.packet); //IOException
+            }
+            // set time to wait for reply (gets longer with each round)
+            waitTime = timeOuts[totalPacketsSent++];
+
+            get:
+            while (true) {
+                if (debug >= EtConstants.debugInfo) {
+                    System.out.println("findServerPort: wait for " + waitTime + " milliseconds");
+                }
+                // wait for replies
+                try {
+                    Thread.sleep(waitTime);
+                }
+                catch (InterruptedException ix) {
+                }
+
+                // check for replies on all sockets
+                for (get receiver : receiveList) {
+                    status = receiver.thread.waitForReply(10);
+                    if (debug >= EtConstants.debugInfo) {
+                        System.out.println("findServerPort: receive on socket " + receiver.socket +
+                                ", status = " + status);
+                    }
+
+                    // if error or timeout ...
+                    if ((status == DatagramReceive.error) || (status == DatagramReceive.timedOut)) {
+                        // continue;
+                    }
+
+                    // else if got packet ...
+                    else if (status == DatagramReceive.receivedPacket) {
+                        // Analyze packet to see if it matches the ET system we were
+                        // looking for; if not, try to get another packet. If it
+                        // is a match, store it in a HashMap (responders).
+                        if (replyMatch(receiver.packet, knownHostIpAddrs)) { // IOEx, UnknownHostEx
+                            if (debug >= EtConstants.debugInfo) {
+                                System.out.println("findServerPort: found match");
+                            }
+                            match = gotMatch;
+                        }
+                        else {
+                            if (debug >= EtConstants.debugInfo) {
+                                System.out.println("findServerPort: no match");
+                            }
+                        }
+                        // See if there are other packets cued up,
+                        // but don't wait too long. The thread we
+                        // started is ended so start another up again.
+                        waitTime = 50;
+                        receiver.start();
+                        Thread.yield();
+
+                        continue get;
+                    }
+
+                }
+
+
+                // if we don't have a match, try again
+                if (!match) {
+                    // If max # of packets not yet sent, send another
+                    // batch and try again with a longer wait
+                    if (totalPacketsSent < sendPacketLimit) {
+                        if (debug >= EtConstants.debugInfo) {
+                            System.out.println("findServerPort: timedout, try again with longer wait");
+                        }
+                        continue sendPoint;
+                    }
+                }
+
+                break sendPoint;
+
+            } // while (true)
+        } // while (totalPacketsSent < sendPacketLimit)
+
+
+        if (match) {
+            // If the host is not remote or anywhere (i.e. we know its name) ...
+            if ((!config.getHost().equals(EtConstants.hostRemote)) &&
+                (!config.getHost().equals(EtConstants.hostAnywhere))) {
+
+                // In this case we only keep a single response even
+                // though there may be more since each of these must
+                // have come from the same ET system.
+            }
+            // if we're looking remotely or anywhere
+            else {
+                // if we have more than one responding ET system
+                if (responders.size() > 1) {
+                    // if picking first responding ET system ...
+                    if (config.getResponsePolicy() == EtConstants.policyFirst) {
+                        Iterator<Map.Entry<ArrayList<String>,Integer>> i = responders.entrySet().iterator();
+                        Map.Entry<ArrayList<String>,Integer> entry = i.next();
+                        hostAddresses = entry.getKey();
+                        hostAddress = hostAddresses.get(0);
+                        tcpPort = entry.getValue();
+                        etOnLocalHost = isHostLocal(hostAddresses);
+                    }
+                    // else if picking local system first ...
+                    else if (config.getResponsePolicy() == EtConstants.policyLocal) {
+                        // compare local host to responding hosts
+                        etOnLocalHost = false;
+
+                        for (Map.Entry<ArrayList<String>, Integer> entry : responders.entrySet()) {
+                            ArrayList<String> addrList = entry.getKey();
+                            // see if this responder is local
+                            if (isHostLocal(addrList)) {
+                                hostAddresses = entry.getKey();
+                                hostAddress = hostAddresses.get(0);
+                                tcpPort = entry.getValue();
+                                etOnLocalHost = true;
+                                break;
+                            }
+                        }
+
+                        // if no local host found, pick first responder
+                        if (!etOnLocalHost) {
+                            Iterator<Map.Entry<ArrayList<String>,Integer>> i = responders.entrySet().iterator();
+                            Map.Entry<ArrayList<String>,Integer> entry = i.next();
+                            hostAddresses = entry.getKey();
+                            hostAddress = hostAddresses.get(0);
+                            tcpPort = entry.getValue();
+                        }
+                    }
+                    // else if policy.Error
+                    else {
+                        throw new EtTooManyException("too many responding ET systems");
+                    }
+                }
+            }
+            return foundServer;
+        }
+
+        if (debug >= EtConstants.debugInfo) {
+            System.out.println("findServerPort: cannot find server, quitting");
+        }
+
+        hostAddresses.clear();
+        hostAddress = null;
+        tcpPort = 0;
+
+        return cannotFindServer;
+    }
+
+
+    /**
+     * Analyze a received UDP packet & see if it matches the ET system we're looking for.
+     *
+     * @param packet responding UDP packet
+     * @throws java.io.IOException
+     *     if problems with network comunications
+     * @throws java.net.UnknownHostException
+     *     if the replied host address(es) is(are) unknown
+     */
+    private boolean replyMatch(DatagramPacket packet, HashSet<String> knownHostIpAddrs)
+            throws IOException, UnknownHostException {
+
+        byte buf[];
+        ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
+        DataInputStream dis = new DataInputStream(bais);
+        // In case of multiple addresses from a responding ET system, a list of addresses. */
+        ArrayList<String> addresses = new ArrayList<String>(20);
+
+        // decode packet from ET system:  (NEW!!!)
+        //
+        // (0)  ET magic numbers (3 ints)
+        // (1)  ET version #
+        // (2)  port of tcp server thread (not udp config->port)
+        // (3)  Constants.broadcast .multicast or broadAndMulticast (int)
+        // (4)  length of next string
+        // (5)    broadcast address (dotted-dec) if broadcast received or
+        //        multicast address (dotted-dec) if multicast received
+        //        (see int #3)
+        // (6)  length of next string
+        // (7)    hostname given by "uname" (used as a general
+        //        identifier of this host no matter which interface is used)
+        // (8)  length of next string
+        // (9)    canonical name of host
+        // (10) number of IP addresses
+        // (11)   32bit, net-byte ordered IPv4 address assoc with following address
+        // (12)   length of next string
+        // (13)       first dotted-decimal IPv4 address
+        // (14)   32bit, net-byte ordered IPv4 address assoc with following address
+        // (15)   length of next string
+        // (16)       second dotted-decimal IPv4 address ...
+        //
+        // All known IP addresses are sent here both in numerical & dotted-decimal forms.
+        //
+
+
+        // (0)  ET magic numbers (3 ints)
+        int magic1 = dis.readInt();
+        int magic2 = dis.readInt();
+        int magic3 = dis.readInt();
+        if (magic1 != EtConstants.magicNumbers[0] ||
+            magic2 != EtConstants.magicNumbers[1] ||
+            magic3 != EtConstants.magicNumbers[2])  {
+//System.out.println("replyMatch:  Magic numbers did NOT match");
+            return noMatch;
+        }
+
+        // (1) ET version #
+        int version = dis.readInt();         //IOEx
+        if (version != EtConstants.version) {
+//System.out.println("replyMatch:  version did NOT match");
+            return noMatch;
+        }
+//System.out.println("replyMatch:  version = " + version);
+
+        // (2) server port #
+        int port = dis.readInt();
+        if ((port < 1) || (port > 65536)) {
+            return noMatch;
+        }
+//System.out.println("replyMatch:  server port = " + port);
+
+        // (3) response to what type of cast?
+        int cast = dis.readInt();
+        if ((cast != EtConstants.broadcast) &&
+            (cast != EtConstants.multicast) &&
+            (cast != EtConstants.broadAndMulticast)) {
+            return noMatch;
+        }
+
+//        if (cast == EtConstants.broadcast) {
+//            System.out.println("replyMatch:  broadcasting");
+//        }
+//        else if (cast != EtConstants.multicast) {
+//            System.out.println("replyMatch:  multicasting");
+//        }
+//        else if (cast != EtConstants.broadAndMulticast) {
+//            System.out.println("replyMatch:  broad & multi casting");
+//        }
+//        else {
+//            System.out.println("replyMatch:  don't know if broad or multi casting");
+//        }
+
+        // (4) read length of IP address (dotted-decimal) of responding address
+        //     or 0.0.0.0 if java
+        int length = dis.readInt();
+        if ((length < 1) || (length > EtConstants.ipAddrStrLen)) {
+            return noMatch;
+        }
+
+        // (5) read IP address
+        buf = new byte[length];
+        dis.readFully(buf, 0, length);
+        String repliedIpAddress = null;
+        try {repliedIpAddress = new String(buf, 0, length - 1, "ASCII");}
+        catch (UnsupportedEncodingException e) {/*never happens*/}
+//System.out.println("replyMatch:  IP address = " + repliedIpAddress);
+
+        // (6) Read length of "uname" or InetAddress.getLocalHost().getHostName() if java,
+        //     used as identifier of this host no matter which interface used.
+        length = dis.readInt();
+        if ((length < 1) || (length > EtConstants.maxHostNameLen)) {
+            return noMatch;
+        }
+
+        // (7) read uname
+        buf = new byte[length];
+        dis.readFully(buf, 0, length);
+        String repliedUname = null;
+        try {repliedUname = new String(buf, 0, length - 1, "ASCII");}
+        catch (UnsupportedEncodingException e) {}
+//System.out.println("replyMatch:  uname len = " + length);
+//System.out.println("replyMatch:  uname = " + repliedUname);
+
+        // (8) Read length of canonical name
+        length = dis.readInt();
+        if ((length < 1) || (length > EtConstants.maxHostNameLen)) {
+            return noMatch;
+        }
+
+        // (9) read canonical name
+        buf = new byte[length];
+        dis.readFully(buf, 0, length);
+        String canonicalName = null;
+        try {canonicalName = new String(buf, 0, length - 1, "ASCII");}
+        catch (UnsupportedEncodingException e) {}
+//System.out.println("replyMatch:  canonical name len = " + length);
+//System.out.println("replyMatch:  canonical name = " + canonicalName);
+
+        // (10) # of following addresses
+        int numAddrs = dis.readInt();
+        if (numAddrs < 0) {
+            return noMatch;
+        }
+//System.out.println("replyMatch:  # of addresses to come = " + numAddrs);
+
+        int addr;
+        String repliedHostAddress = null;
+
+        for (int i=0; i<numAddrs; i++) {
+            // (11) 32 bit network byte ordered address - not currently used
+            addr = dis.readInt();
+//System.out.println("replyMatch:  addr #" + i + ": numeric addr = " + addr);
+
+            // (12) read length of string address of responding host
+            length = dis.readInt();
+//System.out.println("replyMatch:  addr #" + i + ": string len = " + length);
+
+            // (13) read host address (minus ending null)
+            buf = new byte[length];
+            dis.readFully(buf, 0, length);
+            try {repliedHostAddress = new String(buf, 0, length - 1, "ASCII");}
+            catch (UnsupportedEncodingException e) {}
+//System.out.println("replyMatch:  addr #" + i + ": string addr = " + repliedHostAddress);
+
+            // store things
+            addresses.add(repliedHostAddress);
+        }
+
+        if (debug >= EtConstants.debugInfo) {
+            System.out.println("replyMatch: port = " + port +
+                    ", replied IP addr = " + repliedIpAddress +
+                    ", uname = " + repliedUname);
+            for (int i=0; i<numAddrs; i++) {
+                System.out.println("          : addr " + (i + 1) + " = " + addresses.get(i));
+            }
+            System.out.println();
+        }
+
+        dis.close();
+        bais.close();
+
+        //InetAddress localHost = InetAddress.getLocalHost();      //UnknownHostEx
+
+        // if we're looking for a host anywhere
+        if (config.getHost().equals(EtConstants.hostAnywhere)) {
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("replyMatch: ET is anywhere, addresses = ");
+                for (String address : addresses) {
+                    System.out.println("            " + address);
+                }
+            }
+
+            // Store host & port in ordered map in case there are several systems
+            // that respond and user must chose which one he wants.
+
+            // Potential difficulty here is that the host may be responding with
+            // several address, but we're only using one. What if our
+            // host does not know about this particular IP address? It may not
+            // be able to connect, but might be able to with one of the others.
+            // How do we fix this problem?
+            responders.put(addresses, port);
+
+            // store info here in case only 1 response
+            hostAddresses = addresses;
+            hostAddress = addresses.get(0);
+            tcpPort = port;
+            return gotMatch;
+        }
+
+        // else if we're looking for a remote host
+        else if (config.getHost().equals(EtConstants.hostRemote)) {
+            for (String address : addresses) {
+                for (String localIP : localHostIpAddrs) {
+                    // if ET system's address matches a local one, it's not remote
+                    if (localIP.equals(address)) {
+                        if (debug >= EtConstants.debugInfo) {
+                            System.out.println("replyMatch: ET is local but looking for remote, " + address);
+                        }
+
+                        return noMatch;
+                    }
+                }
+            }
+
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("replyMatch: ET is remote, addresses = ");
+                for (String address : addresses) {
+                    System.out.println("            " + address);
+                }
+            }
+
+            // If we're here, then we have a remote responder.
+            // Store address(es) & port in lists in case there are several systems
+            // that respond and user must chose which one he wants
+            responders.put(addresses, port);
+
+            // store info here in case only 1 response
+            etOnLocalHost = false;
+            hostAddresses = addresses;
+            hostAddress = addresses.get(0);
+            tcpPort = port;
+            return gotMatch;
+        }
+
+        // else if we're looking for a local host
+        else if ((config.getHost().equals(EtConstants.hostLocal)) ||
+                 (config.getHost().equals("localhost"))) {
+
+            for (String address : addresses) {
+                for (String localIP : localHostIpAddrs) {
+                    if (localIP.equals(address)) {
+                        if (debug >= EtConstants.debugInfo) {
+                            System.out.println("replyMatch: ET is local, " + address);
+                        }
+
+                        // Store values. In this case no other match will be examined.
+                        etOnLocalHost = true;
+                        hostAddresses = addresses;
+                        hostAddress = address;
+                        tcpPort = port;
+                        return gotMatch;
+                    }
+                }
+            }
+
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("replyMatch: no local match");
+            }
+        }
+
+        // else a specific host name has been specified
+        else {
+            if (debug >= EtConstants.debugInfo) {
+                System.out.println("replyMatch: <name>, addresses = ");
+                for (String address : addresses) {
+                    System.out.println("            " + address);
+                }
+            }
+
+            for (String address : addresses) {
+                for (String hostIP : knownHostIpAddrs) {
+//System.out.println("replyMatch: compare " + address + " to " + hostIP);
+                    if (hostIP.equals(address)) {
+                        if (debug >= EtConstants.debugInfo) {
+                            System.out.println("replyMatch: <name> matched, " + address);
+                        }
+
+                        // Store values. In this case no other match will be examined.
+                        etOnLocalHost = isHostLocal(addresses);
+                        hostAddresses = addresses;
+                        hostAddress = address;
+                        tcpPort = port;
+                        return gotMatch;
+                    }
+                }
+            }
+        }
+
+        return noMatch;
+    }
+
+
+    /**
+     * Connect to ET system's server.
+     *
+     * @throws IOException
+     *     if problems with network communications
+     * @throws EtException
+     *     if the responing ET system has the wrong name, runs a different version
+     *     of ET, or has a different value for {@link EtConstants#stationSelectInts}
+     */
+    private void connectToEtServer() throws IOException, EtException {
+
+        DataInputStream  dis = new DataInputStream(sock.getInputStream());
+        DataOutputStream dos = new DataOutputStream(sock.getOutputStream());
+
+        // write magic #s
+        dos.writeInt(EtConstants.magicNumbers[0]);
+        dos.writeInt(EtConstants.magicNumbers[1]);
+        dos.writeInt(EtConstants.magicNumbers[2]);
+
+        // write our endian, length of ET filename, and ET filename
+        dos.writeInt(EtConstants.endianBig);
+        dos.writeInt(config.getEtName().length() + 1);
+        dos.writeInt(0);    // 1 means 64 bit, 0 means 32 bit (all java is 32 bit)
+        dos.writeLong(0L);	// write one 64 bit long instead of 2, 32 bit ints since = 0 anyway
+        try {
+            dos.write(config.getEtName().getBytes("ASCII"));
+            dos.writeByte(0);
+        }
+        catch (UnsupportedEncodingException ex) {/* will never happen */}
+        dos.flush();
+
+        // read what ET's tcp server sends back
+        if (dis.readInt() != EtConstants.ok) {
+            throw new EtException("found the wrong ET system");
+        }
+        endian            = dis.readInt();
+        numEvents         = dis.readInt();
+        eventSize         = dis.readLong();
+        version           = dis.readInt();
[truncated at 1000 lines; 475 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et
EtSystemOpenConfig.java added at 1.1
diff -N EtSystemOpenConfig.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtSystemOpenConfig.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,804 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.lang.*;
+import java.util.*;
+import java.net.*;
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class defines a set of configuration parameters used to open an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class EtSystemOpenConfig {
+
+    /** Broadcast address. */
+    static public final String broadcastIP = "255.255.255.255";
+
+
+    /** ET system name. */
+    private String name;
+
+    /** Either ET system host name or destination of broadcasts and multicasts. */
+    private String host;
+
+    /** Network interface used for actually connecting to ET system. */
+    private String networkInterface;
+
+    /** Are we broadcasting on all local subnets to find ET system? */
+    private boolean broadcasting;
+
+    /** Broadcast addresses. */
+    private HashSet<String>  broadcastAddrs;
+
+    /** Multicast addresses. */
+    private HashSet<String>  multicastAddrs;
+
+    /**
+     * If true, only connect to ET systems with sockets (remotely). If false, try
+     * opening any local C-based ET systems using mapped memory and JNI interface.
+     */
+    private boolean connectRemotely;
+
+    /**
+     * Means used to contact an ET system over network. The possible values are
+     * @link Constants#broadcast} for broadcasting, {@link EtConstants#multicast}
+     * for multicasting, {@link EtConstants#direct} for connecting directly to the
+     * ET tcp server, and {@link EtConstants#broadAndMulticast} for using both
+     * broadcasting and multicasting.
+     */
+    private int networkContactMethod;
+
+    /** UDP port number for broadcasting or sending udp packets to known hosts. */
+    private int udpPort;
+
+    /** TCP server port number of the ET system. */
+    private int tcpPort;
+
+    /** Port number to multicast to. In Java, a multicast socket cannot have same
+     *  port number as another datagram socket. */
+    private int multicastPort;
+
+    /** Time-to-live value for multicasting. */
+    private int ttl;
+
+    /**
+     * Policy on what to do about multiple responding ET systems to a broadcast
+     * or multicast. The possible values are {@link EtConstants#policyFirst} which
+     * chooses the first ET system to respond, {@link EtConstants#policyLocal}
+     * which chooses the first local ET system to respond and if none then the
+     * first response, or {@link EtConstants#policyError} which throws an
+     * EtTooManyException exception.
+     */
+    private int responsePolicy;
+
+    /** If no ET system is available, how many milliseconds do we wait while trying to open it? */
+    private long waitTime;
+
+    /** TCP send buffer size in bytes. */
+    private int tcpSendBufSize;
+
+    /** TCP receive buffer size in bytes. */
+    private int tcpRecvBufSize;
+
+    /**
+     * TCP socket's no-delay setting.
+     * <code>True</code> if no delay, else <code>false</code>.
+     */
+    private boolean noDelay;
+
+
+    /**
+     * No arg constructor.
+     * Only ET name and host need to be set.
+     */
+    public EtSystemOpenConfig() {
+        // some default values
+        broadcasting = true;
+        connectRemotely = false;
+        networkContactMethod = EtConstants.broadcast;
+        multicastPort = EtConstants.multicastPort;
+        udpPort = EtConstants.broadcastPort;
+        tcpPort = EtConstants.serverPort;
+        ttl = 32;
+        responsePolicy = EtConstants.policyError;
+        broadcastAddrs = new HashSet<String>(10);
+        multicastAddrs = new HashSet<String>(10);
+    }
+
+
+    /**
+     * Most general constructor for creating a new EtSystemOpenConfig object.
+     *
+     * @param etName ET system name
+     * @param hostName may open an ET system on the given host which could be the:
+     *                 1) actual ET system's host name,
+     *                 2) dotted decimal address of ET system's host, or
+     *                 3) general location of ET system such as {@link EtConstants#hostAnywhere},
+     *                   {@link EtConstants#hostLocal}, or {@link EtConstants#hostRemote}
+     * @param bAddrs collection of broadcast addresses (as Strings) to broadcast on in order to
+     *               find ET system
+     * @param mAddrs collection of multicast addresses (as Strings) to multicast to in order to
+     *               find ET system
+     * @param remoteOnly <code>true</code> if talking to ET system only through sockets
+     *                   (as if remote), or <code>false</code> if also using JNI/shared memory
+     *                   for talking to local C-based ET systems
+     * @param method means used to contact an ET system over the network:
+     *               {@link EtConstants#broadcast}, {@link EtConstants#multicast},
+     *               {@link EtConstants#direct}, or {@link EtConstants#broadAndMulticast}
+     * @param tPort  TCP server port number of the ET system
+     * @param uPort  UDP port number for broadcasting or sending udp packets to known hosts
+     * @param mPort  Port number to multicast to
+     * @param ttlNum Time-to_live value for multicasting
+     * @param policy policy on what to do about multiple responding ET systems to
+     *               a broadcast or multicast: {@link EtConstants#policyFirst},
+     *               {@link EtConstants#policyLocal}, or {@link EtConstants#policyError}
+     *
+     * @throws EtException
+     *     if method value is not valid;
+     *     if method is not direct and no broad/multicast addresses were specified;
+     *     if method is direct and no actual host name was specified;
+     *     if port numbers are < 1024 or > 65535;
+     *     if ttl is < 0 or > 254;
+     *     if string args are null or blank;
+     *     if policy value is not valid
+     */
+    public EtSystemOpenConfig(String etName, String hostName,
+                             Collection<String> bAddrs, Collection<String> mAddrs,
+                             boolean remoteOnly,
+                             int method, int tPort, int uPort,
+                             int mPort, int ttlNum, int policy)
+            throws EtException {
+
+        name = etName;
+        if (etName == null || etName.equals("")) {
+            throw new EtException("Bad ET system name");
+        }
+
+        host = hostName;
+        if (host == null || host.equals("")) {
+            if (method != EtConstants.broadcast) {
+                throw new EtException("Bad host or location name");
+            }
+        }
+
+        if ((bAddrs == null) || (bAddrs.size() < 1)) {
+            broadcastAddrs = new HashSet<String>(10);
+        }
+        else {
+            broadcastAddrs = new HashSet<String>(bAddrs);
+        }
+
+        boolean noMulticastAddrs = true;
+        if ((mAddrs == null) || (mAddrs.size() < 1)) {
+            multicastAddrs = new HashSet<String>(10);
+        }
+        else {
+            multicastAddrs = new HashSet<String>(mAddrs);
+            noMulticastAddrs = false;
+        }
+
+        connectRemotely = remoteOnly;
+        
+        if ((method != EtConstants.multicast) &&
+            (method != EtConstants.broadcast) &&
+            (method != EtConstants.broadAndMulticast) &&
+            (method != EtConstants.direct))     {
+            throw new EtException("Bad contact method value");
+        }
+        else {
+            networkContactMethod = method;
+        }
+
+        // do we broadcast?
+        broadcasting = networkContactMethod == EtConstants.broadcast ||
+                       networkContactMethod == EtConstants.broadAndMulticast;
+
+        // inconsistencies?
+        if (networkContactMethod == EtConstants.direct) {
+            if (host.equals(EtConstants.hostRemote) ||
+                host.equals(EtConstants.hostAnywhere)) {
+                throw new EtException("Need to specify an actual host name");
+            }
+        }
+        else if ( ((networkContactMethod == EtConstants.multicast) ||
+                   (networkContactMethod == EtConstants.broadAndMulticast)) &&
+                    noMulticastAddrs) {
+            throw new EtException("Need to specify a multicast address");
+        }
+
+
+        if ((uPort < 1024) || (uPort > 65535)) {
+            throw new EtException("Bad UDP port value");
+        }
+        udpPort = uPort;
+
+        if ((tPort < 1024) || (tPort > 65535)) {
+            throw new EtException("Bad TCP port value");
+        }
+        tcpPort = tPort;
+
+        if ((mPort < 1024) || (mPort > 65535)) {
+            throw new EtException("Bad multicast port value");
+        }
+        multicastPort = mPort;
+
+
+        if ((ttlNum < 0) || (ttlNum > 254)) {
+            throw new EtException("Bad TTL value");
+        }
+        ttl = ttlNum;
+
+
+        if ((policy != EtConstants.policyFirst) &&
+            (policy != EtConstants.policyLocal) &&
+            (policy != EtConstants.policyError))  {
+            throw new EtException("Bad policy value");
+        }
+
+        if ((host.equals(EtConstants.hostRemote)) &&
+            (policy == EtConstants.policyLocal)) {
+            // stupid combination of settings
+            throw new EtException("Policy value cannot be local if host is remote");
+        }
+        responsePolicy = policy;
+    }
+
+
+    /**
+     * Constructor for broadcasting on all subnets. First responder is chosen.
+     *
+     * @param etName ET system name
+     * @param hostName may open an ET system on the given host which could be the:
+     *                 1) actual ET system's host name,
+     *                 2) dotted decimal address of ET system's host, or
+     *                 3) general location of ET system such as {@link EtConstants#hostAnywhere},
+     *                   {@link EtConstants#hostLocal}, or {@link EtConstants#hostRemote}
+     *
+     * @throws EtException
+     *     if no broadcast addresses were specified;
+     *     if port number is < 1024 or > 65535
+     */
+    public EtSystemOpenConfig(String etName, String hostName)
+            throws EtException {
+        this (etName, hostName, null, null, false, EtConstants.broadcast,
+              EtConstants.serverPort, EtConstants.broadcastPort, EtConstants.multicastPort,
+              EtConstants.multicastTTL, EtConstants.policyFirst);
+    }
+
+
+    /**
+     * Constructor for broadcasting on all subnets. First responder is chosen.
+     *
+     * @param etName ET system name
+     * @param uPort UDP port number to broadcast to
+     * @param hostName may open an ET system on the given host which could be the:
+     *                 1) actual ET system's host name,
+     *                 2) dotted decimal address of ET system's host, or
+     *                 3) general location of ET system such as {@link EtConstants#hostAnywhere},
+     *                   {@link EtConstants#hostLocal}, or {@link EtConstants#hostRemote}
+     *
+     * @throws EtException
+     *     if no broadcast addresses were specified;
+     *     if port number is < 1024 or > 65535
+     */
+    public EtSystemOpenConfig(String etName, int uPort, String hostName)
+            throws EtException {
+        this (etName, hostName, null, null, false, EtConstants.broadcast,
+              EtConstants.serverPort, uPort, EtConstants.multicastPort,
+              EtConstants.multicastTTL, EtConstants.policyFirst);
+    }
+
+
+    /**
+     * Constructor for multicasting. First responder is chosen.
+     *
+     * @param etName ET system name
+     * @param hostName may open an ET system on the given host which could be the:
+     *                 1) actual ET system's host name,
+     *                 2) dotted decimal address of ET system's host, or
+     *                 3) general location of ET system such as {@link EtConstants#hostAnywhere},
+     *                   {@link EtConstants#hostLocal}, or {@link EtConstants#hostRemote}
+     * @param mAddrs collection of multicast addresses (as Strings)
+     * @param mPort  multicasting port number
+     * @param ttlNum multicasting time-to_live value 
+     *
+     * @throws EtException
+     *     if no multicast addresses were specified;
+     *     if port number is < 1024 or > 65535, or ttl is < 0 or > 254
+     */
+    public EtSystemOpenConfig(String etName, String hostName,
+                             Collection<String> mAddrs, int mPort, int ttlNum)
+            throws EtException {
+        this (etName, hostName, null, mAddrs, false, EtConstants.multicast,
+              EtConstants.serverPort, EtConstants.broadcastPort, mPort,
+              ttlNum, EtConstants.policyFirst);
+    }
+
+
+    /**
+     * Constructor for multicasting. First responder is chosen.
+     *
+     * @param etName ET system name
+     * @param hostName may open an ET system on the given host which could be the:
+     *                 1) actual ET system's host name,
+     *                 2) dotted decimal address of ET system's host, or
+     *                 3) general location of ET system such as {@link EtConstants#hostAnywhere},
+     *                   {@link EtConstants#hostLocal}, or {@link EtConstants#hostRemote}
+     * @param mAddrs collection of multicast addresses (as Strings)
+     * @param uPort  port number to send direct udp packet to
+     * @param mPort  multicasting port number
+     * @param ttlNum multicasting time-to_live value
+     *
+     * @throws EtException
+     *     if no multicast addresses were specified;
+     *     if port numbers are < 1024 or > 65535, or ttl is < 0 or > 254
+     */
+    public EtSystemOpenConfig(String etName, String hostName,
+                             Collection<String> mAddrs, int uPort, int mPort, int ttlNum)
+            throws EtException {
+        this (etName, hostName, null, mAddrs, false, EtConstants.multicast,
+              EtConstants.serverPort, uPort, mPort,
+              ttlNum, EtConstants.policyFirst);
+    }
+
+
+    /**
+     * Constructor for connecting directly to tcp server. First responder is
+     * chosen.
+     *
+     * @param etName ET system name
+     * @param hostName ET system host name
+     * @param tPort TCP server port number of the ET system
+     *
+     * @throws EtException
+     *     if no actual host name was specified;
+     *     if port number is < 1024 or > 65535
+     */
+    public EtSystemOpenConfig(String etName, String hostName, int tPort)
+            throws EtException {
+        this (etName, hostName, null, null, false, EtConstants.direct,
+              tPort, EtConstants.broadcastPort, EtConstants.multicastPort,
+              EtConstants.multicastTTL, EtConstants.policyFirst);
+    }
+
+
+    /**
+     * Constructor to create a new EtSystemOpenConfig object from another.
+     * @param config EtSystemOpenConfig object from which to create a new configuration
+     */
+    public EtSystemOpenConfig(EtSystemOpenConfig config) {
+        name                 = config.name;
+        host                 = config.host;
+        broadcastAddrs       = config.getBroadcastAddrs();
+        multicastAddrs       = config.getMulticastAddrs();
+        networkContactMethod = config.networkContactMethod;
+        connectRemotely      = config.connectRemotely;
+        udpPort              = config.udpPort;
+        tcpPort              = config.tcpPort;
+        multicastPort        = config.multicastPort;
+        ttl                  = config.ttl;
+        responsePolicy       = config.responsePolicy;
+        waitTime             = config.waitTime;
+        networkInterface     = config.networkInterface;
+        tcpRecvBufSize       = config.tcpRecvBufSize;
+        tcpSendBufSize       = config.tcpSendBufSize;
+        noDelay              = config.noDelay;
+    }
+
+
+    /**
+     * Determine if vital parameters are set and all settings are self consistent.
+     * @return <code>true</code> if setting are self consistent, else <code>false</code>
+     */
+    public boolean selfConsistent() {
+        if (name == null || name.equals("") ||
+            host == null || host.equals(""))  {
+            return false;
+        }
+
+        boolean noMulticastAddrs = multicastAddrs.size() < 1;
+
+        if (networkContactMethod == EtConstants.direct) {
+            if (host.equals(EtConstants.hostRemote) ||
+                host.equals(EtConstants.hostAnywhere)) {
+                return false;
+            }
+        }
+        else if ( ((networkContactMethod == EtConstants.multicast) ||
+                   (networkContactMethod == EtConstants.broadAndMulticast)) &&
+                    noMulticastAddrs) {
+            return false;
+        }
+
+        // stupid combination of settings
+        if ((host.equals(EtConstants.hostRemote)) &&
+            (responsePolicy == EtConstants.policyLocal)) {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    // Getters
+
+
+    /** Gets the ET system name.
+     *  @return ET system name */
+    public String getEtName() {return name;}
+
+    /** Gets the ET system host name or general location of ET system.
+     *  @return ET system host name or general location of ET system */
+    public String getHost() {return host;}
+
+    /** Gets multicast addresses.
+     *  @return multicast addresses */
+    public HashSet<String> getBroadcastAddrs() {return (HashSet<String>) broadcastAddrs.clone();}
+
+    /** Gets multicast addresses.
+     *  @return multicast addresses */
+    public HashSet<String> getMulticastAddrs() {return (HashSet<String>) multicastAddrs.clone();}
+
+    /** Gets the means used to contact an ET system.
+     *  @return means used to contact an ET system */
+    public int getNetworkContactMethod() {return networkContactMethod;}
+
+    /** Gets policy on what to do about multiple responding ET systems to a
+     *  broadcast or multicast.
+     *  @return policy on what to do about multiple responding ET systems to a broadcast or multicast */
+    public int getResponsePolicy() {return responsePolicy;}
+
+    /** Gets UDP port number for broadcasting or sending udp packets to known hosts.
+     *  @return UDP port number for broadcast or sending udp packets to known hosts */
+    public int getUdpPort() {return udpPort;}
+
+    /** Gets TCP server port number of the ET system.
+     *  @return TCP server port number of the ET system */
+    public int getTcpPort() {return tcpPort;}
+
+    /** Gets port number to multicast to.
+     *  @return port number to multicast to */
+    public int getMulticastPort() {return multicastPort;}
+
+    /** Gets time-to-live value for multicasting.
+     *  @return time-to-live value for multicasting */
+    public int getTTL() {return ttl;}
+
+    /** Gets the number of multicast addresses.
+     *  @return the number of multicast addresses */
+    public int getNumMulticastAddrs() {return multicastAddrs.size();}
+
+    /** Are we broadcasting to find ET system?
+     *  @return boolean indicating wether we are broadcasting to find ET system */
+    public boolean isBroadcasting() {return broadcasting;}
+
+    /** Set true if we're broadcasting to find ET system. */
+    public void broadcasting(boolean on) {broadcasting = on;}
+
+    /** Are we going to connect to an ET system remotely only (=true), or will
+     *  we also try to use memory mapping and JNI with local C-based ET systems?
+     *  @return <code>true</code> if connecting to ET system remotely only, else <code>false</code> */
+    public boolean isConnectRemotely() {return connectRemotely;}
+
+    /** If no ET system is available, the number of milliseconds we wait while trying to open it.
+     *  @return the number of milliseconds we wait while trying to open ET system */
+    public long getWaitTime() {return waitTime;}
+
+    /** Get the network interface used for connecting to the ET system.
+     *  @return the network interface used for connecting to the ET system or null if none specified. */
+    public String getNetworkInterface() {
+        return networkInterface;
+    }
+
+    /** Get the TCP receive buffer size in bytes.
+     *  @return TCP receive buffer size in bytes */
+    public int getTcpSendBufSize() {
+        return tcpSendBufSize;
+    }
+
+    /** Get the TCP send buffer size in bytes.
+     *  @return TCP send buffer size in bytes */
+    public int getTcpRecvBufSize() {
+        return tcpRecvBufSize;
+    }
+
+    /** Get the TCP no-delay setting.
+     *  @return TCP no-delay setting */
+    public boolean isNoDelay() {
+        return noDelay;
+    }
+
+
+    // Setters
+
+
+    /** Sets the ET system name.
+     *  @param etName ET system name  */
+    public void setEtName(String etName) {name = etName;}
+
+    /** Sets the ET system host name or broad/multicast destination.
+     *  @param hostName system host name or broad/multicast destination */
+    public void setHost(String hostName) {host = hostName;}
+
+    /** Removes a multicast address from the set.
+     *  @param addr multicast address to be removed */
+    public void removeMulticastAddr(String addr) {multicastAddrs.remove(addr);}
+
+    /** Sets whether we going to connect to an ET system remotely only (=true), or whether
+     *  we will try to use memory mapping and JNI with local C-based ET systems.
+     *  @param connectRemotely <code>true</code> if connecting to ET system remotely only, else <code>false</code> */
+    public void setConnectRemotely(boolean connectRemotely) {this.connectRemotely = connectRemotely;}
+
+    /** If no ET system is available, set the number of milliseconds we wait while trying to open it.
+     *  @param waitTime  the number of milliseconds we wait while trying to open ET system */
+    public void setWaitTime(long waitTime) {
+        if (waitTime < 0) {
+            waitTime = 0;
+        }
+        this.waitTime = waitTime;
+    }
+
+
+
+    /**
+     *  Adds a broadcast address to the set.
+     *
+     *  @param addr broadcast address to be added
+     *  @throws EtException if the address is not a broadcast address
+     */
+    public void addBroadcastAddr(String addr) throws EtException {
+        try {InetAddress.getByName(addr);}
+        catch (UnknownHostException ex) {
+            throw new EtException("not a broadcast address");
+        }
+
+        broadcastAddrs.add(addr);
+    }
+
+
+    /**
+     *  Sets the collection of broadcast addresses.
+     *
+     *  @param addrs collection of broadcast addresses (as Strings) or null
+     *  @throws EtException if one of the addresses is not a broadcast address
+     */
+    public void setBroadcastAddrs(Collection<String> addrs) throws EtException {
+        if (addrs == null) {
+            broadcastAddrs = new HashSet<String>(10);
+            return;
+        }
+
+        for (String addr : addrs) {
+            try {InetAddress.getByName(addr);}
+            catch (UnknownHostException ex) {
+                throw new EtException("not a broadcast address");
+            }
+        }
+        broadcastAddrs = new HashSet<String>(addrs);
+    }
+
+
+    /**
+     *  Adds a multicast address to the set.
+     *
+     *  @param addr multicast address to be added
+     *  @throws EtException if the address is not a multicast address
+     */
+    public void addMulticastAddr(String addr) throws EtException {
+        InetAddress inetAddr;
+        try {inetAddr = InetAddress.getByName(addr);}
+        catch (UnknownHostException ex) {
+            throw new EtException("not a multicast address");
+        }
+
+        if (!inetAddr.isMulticastAddress()) {
+            throw new EtException("not a multicast address");
+        }
+        multicastAddrs.add(addr);
+    }
+
+
+    /**
+     *  Sets the collection of multicast addresses.
+     *
+     *  @param addrs collection of multicast addresses (as Strings) or null
+     *  @throws EtException if one of the addresses is not a multicast address
+     */
+    public void setMulticastAddrs(Collection<String> addrs) throws EtException {
+        if (addrs == null) {
+            multicastAddrs = new HashSet<String>(10);
+            return;
+        }
+
+        InetAddress inetAddr;
+        for (String addr : addrs) {
+            try {inetAddr = InetAddress.getByName(addr);}
+            catch (UnknownHostException ex) {
+                throw new EtException("not a broadcast address");
+            }
+            if (!inetAddr.isMulticastAddress()) {
+                throw new EtException(addr + " is not a multicast address");
+            }
+        }
+        multicastAddrs = new HashSet<String>(addrs);
+    }
+
+
+    /**
+     *  Sets the means or method of contacting an ET system. Its values may be
+     *  {@link EtConstants#broadcast} for broadcasting, {@link EtConstants#multicast}
+     *  for multicasting, {@link EtConstants#direct} for connecting directly to the
+     *  ET tcp server, and {@link EtConstants#broadAndMulticast} for using both
+     *  broadcasting and multicasting.
+     *
+     *  @param method means or method of contacting an ET system
+     *  @throws EtException if the argument has a bad value
+     */
+    public void setNetworkContactMethod(int method) throws EtException {
+        if ((method != EtConstants.multicast) &&
+            (method != EtConstants.broadcast) &&
+            (method != EtConstants.broadAndMulticast) &&
+            (method != EtConstants.direct))     {
+            throw new EtException("bad contact method value");
+        }
+        networkContactMethod = method;
+    }
+
+
+    /**
+     *  Sets the policy on what to do about multiple responding ET systems to a
+     *  broadcast or multicast. The possible values are
+     *  {@link EtConstants#policyFirst} which chooses the first ET system to
+     *  respond, {@link EtConstants#policyLocal} which chooses the first local ET
+     *  system to respond and if none then the first response, or
+     *  {@link EtConstants#policyError} which throws an EtTooManyException
+     *  exception.
+     *
+     *  @param policy policy on what to do about multiple responding ET systems
+     *  @throws EtException
+     *     if the argument has a bad value or if the policy says to choose a local
+     *     ET system but the host is set to chose a remote system.
+     */
+    public void setResponsePolicy(int policy) throws EtException {
+        if ((policy != EtConstants.policyFirst) &&
+            (policy != EtConstants.policyLocal) &&
+            (policy != EtConstants.policyError))  {
+            throw new EtException("bad policy value");
+        }
+        
+        if ((host.equals(EtConstants.hostRemote)) &&
+            (policy == EtConstants.policyLocal)) {
+            // stupid combination of settings
+            throw new EtException("policy value cannot be local if host is remote");
+        }
+        responsePolicy = policy;
+    }
+
+
+    /**
+     *  Sets the UDP port number for broadcasting and sending udp packets to known hosts.
+     *
+     *  @param port UDP port number for broadcasting and sending udp packets to known hosts
+     *  @throws EtException if the port number is < 1024 or > 65535
+     */
+    public void setUdpPort(int port) throws EtException {
+        if ((port < 1024) || (port > 65535)) {
+            throw new EtException("bad UDP port value");
+        }
+        udpPort = port;
+    }
+
+
+    /**
+     *  Sets the TCP server port number of the ET system.
+     *
+     *  @param port TCP server port number of the ET system
+     *  @throws EtException if the port number is < 1024 or > 65535
+     */
+    public void setTcpPort(int port) throws EtException {
+        if ((port < 1024) || (port > 65535)) {
+            throw new EtException("bad TCP port value");
+        }
+        tcpPort = port;
+    }
+
+
+    /**
+     *  Sets the port number to multicast to.
+     *
+     *  @param port port number to multicast to
+     *  @throws EtException if the port number is < 1024 or > 65535
+     */
+    public void setMulticastPort(int port) throws EtException {
+        if ((port < 1024) || (port > 65535)) {
+            throw new EtException("bad multicast port value");
+        }
+        multicastPort = port;
+    }
+
+
+    /**
+     *  Sets the time-to-live value for multicasting.
+     *
+     *  @param ttlNum time-to-live value for multicasting
+     *  @throws EtException if the port number is < 0 or > 254
+     */
+    public void setTTL(int ttlNum) throws EtException {
+        if ((ttlNum < 0) || (ttlNum > 254)) {
+            throw new EtException("bad TTL value");
+        }
+        ttl = ttlNum;
+    }
+
+    /**
+     * Set the network interface (in dotted-decimal format) used for connecting to the ET system.
+     * @param networkInterface the network interface used for connecting to the ET system,
+     *                         or null if none specified.
+     * @throws EtException
+     *    if the interface is not in dotted-decimal format or is an invalid IP address.
+     */
+    public void setNetworkInterface(String networkInterface) throws EtException {
+        if (networkInterface != null) {
+            try {InetAddress.getByName(networkInterface);}
+            catch (UnknownHostException ex) {
+                throw new EtException("not a valid network interface");
+            }
+        }
+        this.networkInterface = networkInterface;
+    }
+
+    /**
+     * Set the TCP send buffer size in bytes. A value of 0
+     * means use the operating system default.
+     *
+     * @param tcpSendBufSize TCP send buffer size in bytes
+     * @throws EtException
+     *     if the argument is less than 0
+     */
+    public void setTcpSendBufSize(int tcpSendBufSize) throws EtException {
+        if (tcpSendBufSize < 0) {
+            throw new EtException("buffer size must be >= than 0");
+        }
+        this.tcpSendBufSize = tcpSendBufSize;
+    }
+
+    /**
+     * Set the TCP receive buffer size in bytes. A value of 0
+     * means use the operating system default.
+     *
+     * @param tcpRecvBufSize TCP receive buffer size in bytes
+     * @throws EtException
+     *     if the argument is less than 0
+     */
+    public void setTcpRecvBufSize(int tcpRecvBufSize) throws EtException {
+        if (tcpRecvBufSize < 0) {
+            throw new EtException("buffer size must be >= than 0");
+        }
+        this.tcpRecvBufSize = tcpRecvBufSize;
+    }
+
+    /**
+     * Set the TCP no-delay setting. It is off by default.
+     * @param noDelay TCP no-delay setting
+     */
+    public void setNoDelay(boolean noDelay) {
+        this.noDelay = noDelay;
+    }
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et
EtUtils.java added at 1.1
diff -N EtUtils.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtUtils.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,291 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et;
+
+import java.nio.ByteOrder;
+
+/**
+ * Collection of methods to help manipulate bytes in arrays.
+ * @author timmer
+ */
+public class EtUtils {
+
+    /**
+     * Turn short into byte array.
+     * Avoids creation of new byte array with each call.
+     *
+     * @param data short to convert
+     * @param byteOrder byte order of returned bytes (big endian if null)
+     * @param dest array in which to store returned bytes
+     * @param off offset into dest array where returned bytes are placed
+     * @throws org.jlab.coda.jevio.EvioException if dest is null or too small or offset negative
+     */
+    public static void shortToBytes(short data, ByteOrder byteOrder, byte[] dest, int off) {
+
+        if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+            dest[off  ] = (byte)(data >>> 8);
+            dest[off+1] = (byte)(data      );
+        }
+        else {
+            dest[off  ] = (byte)(data      );
+            dest[off+1] = (byte)(data >>> 8);
+        }
+    }
+
+
+    /**
+      * Turn int into byte array.
+      * Avoids creation of new byte array with each call.
+      *
+      * @param data int to convert
+      * @param byteOrder byte order of returned bytes (big endian if null)
+      * @param dest array in which to store returned bytes
+      * @param off offset into dest array where returned bytes are placed
+      */
+     public static void intToBytes(int data, ByteOrder byteOrder, byte[] dest, int off) {
+
+         if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+             dest[off  ] = (byte)(data >> 24);
+             dest[off+1] = (byte)(data >> 16);
+             dest[off+2] = (byte)(data >>  8);
+             dest[off+3] = (byte)(data      );
+         }
+         else {
+             dest[off  ] = (byte)(data      );
+             dest[off+1] = (byte)(data >>  8);
+             dest[off+2] = (byte)(data >> 16);
+             dest[off+3] = (byte)(data >> 24);
+         }
+     }
+
+     /**
+      * Turn long into byte array.
+      * Avoids creation of new byte array with each call.
+      *
+      * @param data long to convert
+      * @param byteOrder byte order of returned bytes (big endian if null)
+      * @param dest array in which to store returned bytes
+      * @param off offset into dest array where returned bytes are placed
+      */
+     public static void longToBytes(long data, ByteOrder byteOrder, byte[] dest, int off) {
+
+         if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+             dest[off  ] = (byte)(data >> 56);
+             dest[off+1] = (byte)(data >> 48);
+             dest[off+2] = (byte)(data >> 40);
+             dest[off+3] = (byte)(data >> 32);
+             dest[off+4] = (byte)(data >> 24);
+             dest[off+5] = (byte)(data >> 16);
+             dest[off+6] = (byte)(data >>  8);
+             dest[off+7] = (byte)(data      );
+         }
+         else {
+             dest[off  ] = (byte)(data      );
+             dest[off+1] = (byte)(data >>  8);
+             dest[off+2] = (byte)(data >> 16);
+             dest[off+3] = (byte)(data >> 24);
+             dest[off+4] = (byte)(data >> 32);
+             dest[off+5] = (byte)(data >> 40);
+             dest[off+6] = (byte)(data >> 48);
+             dest[off+7] = (byte)(data >> 56);
+         }
+     }
+
+    /**
+     * Copies a short value into 2 bytes of a byte array.
+     * @param shortVal short value
+     * @param b byte array
+     * @param off offset into the byte array
+     */
+    public static void shortToBytes(short shortVal, byte[] b, int off) {
+        shortToBytes(shortVal, null, b, off);
+    }
+
+    /**
+     * Copies an integer value into 4 bytes of a byte array.
+     * @param intVal integer value
+     * @param b byte array
+     * @param off offset into the byte array
+     */
+    public static void intToBytes(int intVal, byte[] b, int off) {
+        intToBytes(intVal, null, b, off);
+    }
+
+    /**
+     * Copies an long (64 bit) value into 8 bytes of a byte array.
+     * @param longVal long value
+     * @param b byte array
+     * @param off offset into the byte array
+     */
+    public static void longToBytes(long longVal, byte[] b, int off) {
+        longToBytes(longVal, null, b, off);
+    }
+
+
+    /**
+     * Turn section of byte array into a short.
+     *
+     * @param data byte array to convert
+     * @param byteOrder byte order of supplied bytes (big endian if null)
+     * @param off offset into data array
+     * @return short converted from byte array
+     */
+    public static short bytesToShort(byte[] data, ByteOrder byteOrder, int off) {
+
+        if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+            return (short)(
+                (0xff & data[  off]) << 8 |
+                (0xff & data[1+off])
+            );
+        }
+        else {
+            return (short)(
+                (0xff & data[  off]) |
+                (0xff & data[1+off] << 8)
+            );
+        }
+    }
+
+    /**
+     * Turn section of byte array into an int.
+     *
+     * @param data byte array to convert
+     * @param byteOrder byte order of supplied bytes (big endian if null)
+     * @param off offset into data array
+     * @return int converted from byte array
+     */
+    public static int bytesToInt(byte[] data, ByteOrder byteOrder, int off) {
+
+        if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+            return (
+                (0xff & data[  off]) << 24 |
+                (0xff & data[1+off]) << 16 |
+                (0xff & data[2+off]) <<  8 |
+                (0xff & data[3+off])
+            );
+        }
+        else {
+            return (
+                (0xff & data[  off])       |
+                (0xff & data[1+off]) <<  8 |
+                (0xff & data[2+off]) << 16 |
+                (0xff & data[3+off]) << 24
+            );
+        }
+    }
+
+    /**
+     * Turn section of byte array into a long.
+     *
+     * @param data byte array to convert
+     * @param byteOrder byte order of supplied bytes (big endian if null)
+     * @param off offset into data array
+     * @return long converted from byte array
+     */
+    public static long bytesToLong(byte[] data, ByteOrder byteOrder, int off) {
+
+        if (byteOrder == null || byteOrder == ByteOrder.BIG_ENDIAN) {
+            return (
+                // Convert to longs before shift because digits
+                // are lost with ints beyond the 32-bit limit
+                (long)(0xff & data[  off]) << 56 |
+                (long)(0xff & data[1+off]) << 48 |
+                (long)(0xff & data[2+off]) << 40 |
+                (long)(0xff & data[3+off]) << 32 |
+                (long)(0xff & data[4+off]) << 24 |
+                (long)(0xff & data[5+off]) << 16 |
+                (long)(0xff & data[6+off]) <<  8 |
+                (long)(0xff & data[7+off])
+            );
+        }
+        else {
+            return (
+                (long)(0xff & data[  off])       |
+                (long)(0xff & data[1+off]) <<  8 |
+                (long)(0xff & data[2+off]) << 16 |
+                (long)(0xff & data[3+off]) << 24 |
+                (long)(0xff & data[4+off]) << 32 |
+                (long)(0xff & data[5+off]) << 40 |
+                (long)(0xff & data[6+off]) << 48 |
+                (long)(0xff & data[7+off]) << 56
+            );
+        }
+    }
+
+    /**
+     * Converts 2 bytes of a byte array into a short.
+     * @param b byte array
+     * @param off offset into the byte array (0 = start at first element)
+     * @return short value
+     */
+    public static short bytesToShort(byte[] b, int off) {
+        return bytesToShort(b, null, off);
+    }
+
+    /**
+     * Converts 4 bytes of a byte array into an integer.
+     *
+     * @param b   byte array
+     * @param off offset into the byte array (0 = start at first element)
+     * @return integer value
+     */
+    public static int bytesToInt(byte[] b, int off) {
+        return bytesToInt(b, null, off);
+    }
+
+    /**
+     * Converts 8 bytes of a byte array into a long.
+     * @param b byte array
+     * @param off offset into the byte array (0 = start at first element)
+     * @return long value
+     */
+    public static long bytesToLong(byte[] b, int off) {
+        return bytesToLong(b, null, off);
+    }
+
+    /**
+     * Swaps 4 bytes of a byte array in place.
+     * @param b byte array
+     * @param off offset into the byte array
+     */
+    public static void swapArrayInt(byte[] b, int off) {
+        byte b1, b2, b3, b4;
+        b1 = b[off];
+        b2 = b[off+1];
+        b3 = b[off+2];
+        b4 = b[off+3];
+        b[off+3] = b1;
+        b[off+2] = b2;
+        b[off+1] = b3;
+        b[off]   = b4;
+    }
+
+    /**
+     * Swaps 2 bytes of a byte array in place.
+     * @param b byte array
+     * @param off offset into the byte array
+     */
+    public static void swapArrayShort(byte[] b, int off) {
+        byte b1, b2;
+        b1 = b[off];
+        b2 = b[off+1];
+        b[off+1] = b1;
+        b[off]   = b2;
+    }
+
+
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
Blaster.java added at 1.1
diff -N Blaster.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Blaster.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,280 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.apps;
+
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Mode;
+
+import java.awt.image.DataBuffer;
+import java.lang.Exception;
+import java.lang.NumberFormatException;
+import java.lang.String;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * This class is an example of an event producer designed to blast data
+ * at the highest possible rate to the ET system.
+ *
+ * @author Carl Timmer
+ */
+public class Blaster {
+
+    public Blaster() {
+    }
+
+
+    private static void usage() {
+        System.out.println("\nUsage: java Blaster -f <ET name> -host <ET host> [-h] [-v] [-c <chunk size>]\n" +
+                "                     [-s <event size>] [-g <group>] [-p <ET server port>] [-i <interface address>]\n" +
+                "                     [-rb <buffer size>] [-sb <buffer size>] [-nd]\n\n" +
+                "       -host  ET system's host\n" +
+                "       -f     ET system's (memory-mapped file) name\n" +
+                "       -h     help\n" +
+                "       -v     verbose output\n" +
+                "       -c     number of events in one get/put array\n" +
+                "       -s     event size in bytes\n" +
+                "       -g     group from which to get new events (1,2,...)\n" +
+                "       -p     ET server port\n" +
+                "       -i     outgoing network interface IP address (dot-decimal)\n\n" +
+                "       -rb    TCP receive buffer size (bytes)\n" +
+                "       -sb    TCP send buffer size (bytes)\n" +
+                "       -nd    turn on TCP no-delay\n" +
+                "        This consumer works by making a direct connection to the\n" +
+                "        ET system's server port.\n");
+    }
+
+
+    public static void main(String[] args) {
+
+        String etName = null, host = null, netInterface = null;
+        int port = EtConstants.serverPort;
+        int group = 1;
+        int size  = 32;
+        int chunk = 1;
+        int recvBufSize = 0;
+        int sendBufSize = 0;
+        boolean noDelay = false;
+        boolean verbose = false;
+
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equalsIgnoreCase("-f")) {
+                etName = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-i")) {
+                netInterface = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-host")) {
+                host = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-p")) {
+                try {
+                    port = Integer.parseInt(args[++i]);
+                    if ((port < 1024) || (port > 65535)) {
+                        System.out.println("Port number must be between 1024 and 65535.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper port number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-c")) {
+                try {
+                    chunk = Integer.parseInt(args[++i]);
+                    if ((chunk < 1) || (chunk > 1000)) {
+                        System.out.println("Chunk size may be 1 - 1000.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper chunk size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-s")) {
+                try {
+                    size = Integer.parseInt(args[++i]);
+                    if (size < 1) {
+                        System.out.println("Size needs to be positive int.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-g")) {
+                try {
+                    group = Integer.parseInt(args[++i]);
+                    if ((group < 1) || (group > 10)) {
+                        System.out.println("Group number must be between 0 and 10.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper group number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-rb")) {
+                try {
+                    recvBufSize = Integer.parseInt(args[++i]);
+                    if (recvBufSize < 1) {
+                        System.out.println("recv buffer must be > 0.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper recv buffer size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-sb")) {
+                try {
+                    sendBufSize = Integer.parseInt(args[++i]);
+                    if (sendBufSize < 1) {
+                        System.out.println("send buffer must be > 0.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper send buffer size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-nd")) {
+                noDelay = true;
+            }
+            else if (args[i].equalsIgnoreCase("-v")) {
+                verbose = true;
+            }
+            else {
+                usage();
+                return;
+            }
+        }
+
+        if (host == null || etName == null) {
+            usage();
+            return;
+        }
+
+        try {
+            // Make a direct connection to ET system's tcp server
+            EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host, port);
+            config.setConnectRemotely(true);
+
+            if (noDelay)              config.setNoDelay(noDelay);
+            if (recvBufSize > 0)      config.setTcpRecvBufSize(recvBufSize);
+            if (sendBufSize > 0)      config.setTcpSendBufSize(sendBufSize);
+            if (netInterface != null) config.setNetworkInterface(netInterface);
+
+            // create ET system object with verbose debugging output
+            EtSystem sys = new EtSystem(config);
+            if (verbose) sys.setDebug(EtConstants.debugInfo);
+            sys.open();
+
+            // get GRAND_CENTRAL station object
+            EtStation gc = sys.stationNameToObject("GRAND_CENTRAL");
+
+            // attach to GRAND_CENTRAL
+            EtAttachment att = sys.attach(gc);
+
+            // array of events
+            EtEvent[] mevs;
+            EtEventImpl realEvent;
+
+            // data to put in new events
+            byte[] data = new byte[size];
+            ByteBuffer byteBuffer = ByteBuffer.wrap(data);
+
+            long   eventCount=0L, byteCount=0L;
+            long   t1, t2, time, totalT=0L, totalEventCount=0L, totalByteCount=0L;
+            double eventRate, avgEventRate, byteRate, avgByteRate;
+
+
+            // keep track of time for event rate calculations
+            t1 = System.currentTimeMillis();
+
+            while (true) {
+                // get array of new events without allocating memory for data
+                mevs = sys.newEvents(att, Mode.SLEEP, true, 0, chunk, size, group);
+
+                // example of how to manipulate events
+                for (EtEvent mev : mevs) {
+                    // A little bit of trickery to set the data buffer
+                    // without having to create objects and allocate
+                    // memory each time.
+                    realEvent = (EtEventImpl) mev;
+                    realEvent.setDataBuffer(byteBuffer);
+
+                    // set data length
+                    mev.setLength(size);
+                }
+
+                // put events back into ET system
+                sys.putEvents(att, mevs);
+                eventCount += mevs.length;
+                byteCount  += mevs.length*(size + 52) + 20; // 52 is event overhead, 20 is ET call overhead
+
+                // calculate the event rate
+                t2 = System.currentTimeMillis();
+                time = t2 - t1;
+
+                if (time > 5000) {
+                    eventRate = 1000.0 * eventCount / time;
+                    byteRate  = 1000.0 * byteCount  / time;
+
+                    totalEventCount += eventCount;
+                    totalByteCount  += byteCount;
+
+                    totalT += time;
+
+                    avgEventRate = 1000.0 * totalEventCount / totalT;
+                    avgByteRate  = 1000.0 * totalByteCount  / totalT;
+
+                    System.out.printf("evRate: %3.4g Hz,  %3.4g avg;  byteRate: %3.4g bytes/sec,  %3.4g avg\n",
+                                       eventRate, avgEventRate, byteRate, avgByteRate);
+
+                    eventCount = 0;
+                    byteCount  = 0;
+
+                    t1 = System.currentTimeMillis();
+                }
+            }
+        }
+        catch (Exception ex) {
+            System.out.println("Error using ET system as producer");
+            ex.printStackTrace();
+        }
+    }
+    
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
Consumer.java added at 1.1
diff -N Consumer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Consumer.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,267 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.apps;
+
+import java.lang.*;
+import java.nio.ByteBuffer;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Mode;
+
+
+/**
+ * This class is an example of an event consumer for an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class Consumer {
+
+    public Consumer() {
+    }
+
+
+    private static void usage() {
+        System.out.println("\nUsage: java Consumer -f <et name> -host <ET host> -s <station name> [-h] [-v] [-nb]\n" +
+                "                      [-p <ET server port>] [-c <chunk size>] [-q <queue size>]\n" +
+                "                      [-pos <station position>] [-ppos <parallel station position>]\n\n" +
+                "       -host  ET system's host\n" +
+                "       -f     ET system's (memory-mapped file) name\n" +
+                "       -s     create station of this name\n" +
+                "       -h     help\n" +
+                "       -v     verbose output\n" +
+                "       -nb    make station non-blocking\n" +
+                "       -p     ET server port\n" +
+                "       -c     number of events in one get/put array\n" +
+                "       -q     queue size if creating nonblocking station\n" +
+                "       -pos   position of created station in station list (1,2,...)\n" +
+                "       -ppos  position of created station within a group of parallel stations (-1=end, -2=head)\n\n" +
+                "        This consumer works by making a direct connection\n" +
+                "        to the ET system's tcp server port.\n");
+    }
+
+
+    public static void main(String[] args) {
+
+        int position = 1, pposition = 0, qSize = 0, chunk = 1;
+        boolean blocking = true, verbose = false;
+        String etName = null, host = null, statName = null;
+        int port = EtConstants.serverPort;
+        int flowMode = EtConstants.stationSerial;
+
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equalsIgnoreCase("-f")) {
+                etName = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-host")) {
+                host = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-nb")) {
+                blocking = false;
+            }
+            else if (args[i].equalsIgnoreCase("-v")) {
+                verbose = true;
+            }
+            else if (args[i].equalsIgnoreCase("-s")) {
+                statName = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-p")) {
+                try {
+                    port = Integer.parseInt(args[++i]);
+                    if ((port < 1024) || (port > 65535)) {
+                        System.out.println("Port number must be between 1024 and 65535.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper port number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-c")) {
+                try {
+                    chunk = Integer.parseInt(args[++i]);
+                    if ((chunk < 1) || (chunk > 1000)) {
+                        System.out.println("Chunk size may be 1 - 1000.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper chunk size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-q")) {
+                try {
+                    qSize = Integer.parseInt(args[++i]);
+                    if (qSize < 1) {
+                        System.out.println("Queue size must be > 0.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper queue size number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-pos")) {
+                try {
+                    position = Integer.parseInt(args[++i]);
+                    if (position < 1) {
+                        System.out.println("Position must be > 0.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper position number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-ppos")) {
+                try {
+                    pposition = Integer.parseInt(args[++i]);
+                    if (pposition < -2 || pposition == 0) {
+                        System.out.println("Parallel position must be > -3 and != 0.");
+                        usage();
+                        return;
+                    }
+                    System.out.println("FLOW moDE is ||");
+                    flowMode = EtConstants.stationParallel;
+                    if (pposition == -2) pposition = EtConstants.newHead;
+                    else if (pposition == -1) pposition = EtConstants.end;
+
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper parallel position number.");
+                    usage();
+                    return;
+                }
+            }
+            else {
+                usage();
+                return;
+            }
+        }
+
+        if (host == null || etName == null || statName == null) {
+            usage();
+            return;
+        }
+
+        try {
+            // make a direct connection to ET system's tcp server
+            EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host, port);
+
+            // create ET system object with verbose debugging output
+            EtSystem sys = new EtSystem(config, EtConstants.debugInfo);
+            sys.open();
+
+            // configuration of a new station
+            EtStationConfig statConfig = new EtStationConfig();
+            statConfig.setFlowMode(flowMode);
+            if (!blocking) {
+                statConfig.setBlockMode(EtConstants.stationNonBlocking);
+                if (qSize > 0) {
+                    statConfig.setCue(qSize);
+                }
+            }
+
+            // create station
+            EtStation stat = sys.createStation(statConfig, statName, position, pposition);
+
+            // attach to new station
+            EtAttachment att = sys.attach(stat);
+
+            // array of events
+            EtEvent[] mevs;
+
+            int num, count = 0;
+            long t1=0, t2=0, time, totalT=0, totalCount=0;
+            double rate, avgRate;
+
+            // keep track of time
+            t1 = System.currentTimeMillis();
+
+            while (true) {
+
+                // get events from ET system
+                mevs = sys.getEvents(att, Mode.SLEEP, null, 0, chunk);
+
+                // example of reading & printing event data
+                if (verbose) {
+                    for (EtEvent mev : mevs) {
+                        // Get event's data buffer
+                        // buf.limit() = length of the actual data (not buffer capacity)
+                        ByteBuffer buf = mev.getDataBuffer();
+
+                        num = buf.getInt(0);
+                        System.out.println("data byte order = " + mev.getByteOrder());
+                        if (mev.needToSwap()) {
+                            System.out.println("    data needs swapping, swapped int = " + Integer.reverseBytes(num));
+                        }
+                        else {
+                            System.out.println("    data does NOT need swapping, int = " + num);
+                        }
+
+                        System.out.print("control array = {");
+                        int[] con = mev.getControl();
+                        for (int j : con) {
+                            System.out.print(j + " ");
+                        }
+                        System.out.println("}");
+                    }
+                }
+
+                // put events back into ET system
+                sys.putEvents(att, mevs);
+                count += mevs.length;
+
+                // calculate the event rate
+                t2 = System.currentTimeMillis();
+                time = t2 - t1;
+
+                if (time > 5000) {
+                    // reset things if necessary
+                    if ( (totalCount >= (Long.MAX_VALUE - count)) ||
+                         (totalT >= (Long.MAX_VALUE - time)) )  {
+                        totalT = totalCount = count = 0;
+                        t1 = System.currentTimeMillis();
+                        continue;
+                    }
+                    rate = 1000.0 * ((double) count) / time;
+                    totalCount += count;
+                    totalT += time;
+                    avgRate = 1000.0 * ((double) totalCount) / totalT;
+                    System.out.println("rate = " + String.format("%.3g", rate) +
+                                       " Hz,  avg = " + String.format("%.3g", avgRate));
+                    count = 0;
+                    t1 = System.currentTimeMillis();
+                }
+            }
+        }
+        catch (Exception ex) {
+            System.out.println("Error using ET system as consumer");
+            ex.printStackTrace();
+        }
+    }
+    
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
EtMonitor.java added at 1.1
diff -N EtMonitor.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtMonitor.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,548 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.apps;
+
+import java.lang.*;
+import java.io.*;
+import java.net.*;
+
+import org.jlab.coda.et.data.*;
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.EtConstants;
+import org.jlab.coda.et.EtSystemOpenConfig;
+import org.jlab.coda.et.EtSystem;
+
+/**
+ * This class implements a monitor of an ET system. It opens the system,
+ * receives all relevant data over a tcp connection, and prints it out.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtMonitor {
+
+  static int  period = 3; // seconds
+  static long prevGcOut;
+
+  public EtMonitor() {
+  }
+  
+  
+  private static void usage() {
+    System.out.println("\nUsage: java EtMonitor -f <et name> [-p <period>] [-port <server port>] [-h <host>]\n\n" +
+	               "       -f     ET system's name\n" +
+	               "       -p     period in seconds between data updates\n" +
+	               "       -port  port number for a direct connection\n" +
+	               "       -h     host the ET system resides on (defaults to local)\n" +
+	               "        This monitor works by making a direct connection to the\n" +
+		       "        ET system's tcp server port.\n");
+  }
+  
+  
+  public static void main(String[] args) {
+      String etName = null, host = null;
+      int port = EtConstants.serverPort;
+
+      try {
+          for (int i = 0; i < args.length; i++) {
+              if (args[i].equalsIgnoreCase("-f")) {
+                  etName = args[++i];
+              }
+              else if (args[i].equalsIgnoreCase("-h")) {
+                  host = args[++i];
+              }
+              else if (args[i].equalsIgnoreCase("-port")) {
+                  try {
+                      port = Integer.parseInt(args[++i]);
+                      if ((port < 1024) || (port > 65535)) {
+                          System.out.println("Port number must be between 1024 and 65535.");
+                          usage();
+                          return;
+                      }
+                  }
+                  catch (NumberFormatException ex) {
+                      System.out.println("Did not specify a proper port number.");
+                      usage();
+                      return;
+                  }
+              }
+              else if (args[i].equalsIgnoreCase("-p")) {
+                  try {
+                      period = Integer.parseInt(args[++i]);
+                      if (period < 1) {
+                          System.out.println("Period must be at least 1 second.");
+                          usage();
+                          return;
+                      }
+                  }
+                  catch (NumberFormatException ex) {
+                      System.out.println("Did not specify a proper period value.");
+                      usage();
+                      return;
+                  }
+              }
+              else {
+                  usage();
+                  return;
+              }
+          }
+
+          if (host == null) {
+              try {
+                  host = InetAddress.getLocalHost().getHostName();
+              }
+              catch (UnknownHostException ex) {
+                  System.out.println("Host not specified and cannot find local host name.");
+                  usage();
+                  return;
+              }
+          }
+
+          if (etName == null) {
+              usage();
+              return;
+          }
+
+          // make a direct connection to ET system's tcp server
+          EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host, port);
+
+          // create ET system object with debugging output
+          EtSystem sys = new EtSystem(config, EtConstants.debugError);
+          AllData etData = new AllData();
+
+/*
+      // timing
+      long t1, t2;
+      for (int j=0; j < 10; j++) {
+        t1 = System.currentTimeMillis();
+        for(int i=0; i < 2000; i++) {
+          etData = sys.getData();
+        }
+        t2 = System.currentTimeMillis();
+        double rate = 1000.0*2000.0/((double)(t2-t1));
+        System.out.println("rate = " + rate + " Hz");
+      }
+*/
+
+          while (true) {
+              try {
+                  etData = sys.getData();
+                  display(sys, etData);
+              }
+              catch (EtException ex) {
+                  System.out.print("\n*****************************************\n");
+                  System.out.print("*   Error getting data from ET system   *");
+                  System.out.print("\n*****************************************\n");
+              }
+              Thread.sleep(period * 1000);
+          }
+
+
+      }
+      catch (IOException ex) {
+          System.out.println("Communication error with ET system:");
+          ex.printStackTrace();
+      }
+      catch (Exception ex) {
+          System.out.println("ERROR:");
+          ex.printStackTrace();
+      }
+
+  }
+
+
+    private static void display(EtSystem sys, AllData data)
+  {
+    int           end = 499, lang;
+    boolean       blocking;
+    double	  rate = 0.0;
+    StringBuffer  str = new StringBuffer(end+1);
+
+    str.append("  ET SYSTEM - (");
+    str.append(data.sysData.getEtName());
+    str.append(") (host ");
+    str.append(sys.getHost());
+    str.append(") (bits ");
+    if (data.sysData.isBit64()) {
+      str.append("64)\n");
+    }
+    else {
+      str.append("32)\n");
+    }
+    str.append("              (tcp port ");
+    str.append(data.sysData.getTcpPort());
+    str.append(") (udp port ");
+    str.append(data.sysData.getUdpPort());
+    str.append(") (multicast port ");
+    str.append(data.sysData.getMulticastPort());
+    str.append(")\n              (pid ");
+    str.append(data.sysData.getMainPid());
+    str.append(") (lang ");
+    lang = sys.getLanguage();
+    if (lang == EtConstants.langJava) {
+      str.append("Java) (period ");
+    }
+    else if (lang == EtConstants.langC) {
+      str.append("C) (period ");
+    }
+    else if (lang == EtConstants.langCpp) {
+      str.append("C++) (period ");
+    }
+    else {
+      str.append("unknown) (period ");
+    }
+    str.append(period);
+    str.append(" sec)\n");
+    System.out.println(str.toString());
+    str.delete(0, end);
+
+    str.append("  STATIC INFO - maximum of:\n");
+    str.append("    events(");
+    str.append(data.sysData.getEvents());
+    str.append("), event size(");
+    str.append(data.sysData.getEventSize());
+    str.append("), temps(");
+    str.append(data.sysData.getTempsMax());
+    str.append(")\n");
+    str.append("    stations(");
+    str.append(data.sysData.getStationsMax());
+    str.append("), attaches(");
+    str.append(data.sysData.getAttachmentsMax());
+    str.append("), procs(");
+    str.append(data.sysData.getProcessesMax());
+    str.append(")\n");
+
+    if (data.sysData.getInterfaces() > 0) {
+      String[] ifAddrs = data.sysData.getInterfaceAddresses();
+      str.append("    network interfaces(");
+      str.append(ifAddrs.length);
+      str.append(")  ");
+      for (int i=0; i < ifAddrs.length; i++) {
+        str.append(ifAddrs[i]);
+        str.append(", ");
+      }
+      str.append("\n");
+    }
+    else {
+      str.append("    network interfaces(0): none\n");
+    }
+
+    if (data.sysData.getMulticasts() > 0) {
+      String[] mAddrs = data.sysData.getMulticastAddresses();
+      str.append("    multicast addresses(");
+      str.append(mAddrs.length);
+      str.append(")  ");
+      for (int i=0; i < mAddrs.length; i++) {
+        str.append(mAddrs[i]);
+        str.append(", ");
+      }
+      str.append("\n");
+    }
+
+    str.append("\n  DYNAMIC INFO - currently there are:\n");
+    str.append("    processes(");
+    str.append(data.sysData.getProcesses());
+    str.append("), attachments(");
+    str.append(data.sysData.getAttachments());
+    str.append("), temps(");
+    str.append(data.sysData.getTemps());
+    str.append(")\n    stations(");
+    str.append(data.sysData.getStations());
+    str.append("), hearbeat(");
+    str.append(data.sysData.getHeartbeat());
+    str.append(")\n");
+    System.out.println(str.toString());
+    str.delete(0, end);
+
+    str.append("  STATIONS:\n");
+
+    for (int i=0; i < data.statData.length; i++) {
+      str.append("    \"");
+      str.append(data.statData[i].getName());
+      str.append("\" (id = ");
+      str.append(data.statData[i].getId());
+      str.append(")\n      static info\n");
+
+      if (data.statData[i].getStatus() == EtConstants.stationIdle)
+        str.append("        status(IDLE), ");
+      else
+        str.append("        status(ACTIVE), ");
+
+      if (data.statData[i].getFlowMode() == EtConstants.stationSerial) {
+        str.append("flow(SERIAL), ");
+      }
+      else {
+        str.append("flow(PARALLEL), ");
+      }
+
+      if (data.statData[i].getBlockMode() == EtConstants.stationBlocking) {
+        str.append("blocking(YES), ");
+        blocking = true;
+      }
+      else {
+        str.append("blocking(NO), ");
+        blocking = false;
+      }
+
+      if (data.statData[i].getUserMode() == EtConstants.stationUserMulti) {
+        str.append("user(MULTI), ");
+      }
+      else {
+        str.append("user(");
+	str.append(data.statData[i].getUserMode());
+	str.append("), ");
+      }
+
+      if (data.statData[i].getSelectMode() == EtConstants.stationSelectAll)
+        str.append("select(ALL)\n");
+      else if (data.statData[i].getSelectMode() == EtConstants.stationSelectMatch)
+        str.append("select(MATCH)\n");
+      else if (data.statData[i].getSelectMode() == EtConstants.stationSelectUser)
+        str.append("select(USER)\n");
+      else if (data.statData[i].getSelectMode() == EtConstants.stationSelectRRobin)
+        str.append("select(RROBIN)\n");
+      else
+        str.append("select(EQUALCUE)\n");
+
+      if (data.statData[i].getRestoreMode() == EtConstants.stationRestoreOut)
+        str.append("        restore(OUT), ");
+      else if (data.statData[i].getRestoreMode() == EtConstants.stationRestoreIn)
+        str.append("        restore(IN), ");
+      else
+        str.append("        restore(GC), ");
+
+      str.append("prescale(");
+      str.append(data.statData[i].getPrescale());
+      str.append("), cue(");
+      str.append(data.statData[i].getCue());
+      str.append("), ");
+
+      str.append("select words(");
+      int[] select = data.statData[i].getSelect();
+      for (int j=0; j < select.length; j++) {
+          str.append(select[j]);
+          str.append(", ");
+      }
+      str.append(")");
+
+      if (data.statData[i].getSelectMode() == EtConstants.stationSelectUser) {
+        str.append("\n        lib = ");
+        str.append(data.statData[i].getSelectLibrary());
+        str.append(",  function = ");
+        str.append(data.statData[i].getSelectFunction());
+        str.append(",  class = ");
+        str.append(data.statData[i].getSelectClass());
+        str.append("");
+      }
+
+      System.out.println(str.toString());
+      str.delete(0, end);
+
+      // dynamic station info or info on active stations
+      if (data.statData[i].getStatus() != EtConstants.stationActive) {
+        System.out.println();
+        continue;
+      }
+
+      str.append("      dynamic info\n");
+      str.append("        attachments: total#(");
+      str.append(data.statData[i].getAttachments());
+      str.append("),  ids(");
+
+      int[] attIds = data.statData[i].getAttachmentIds();
+      for (int j=0; j < attIds.length; j++) {
+        str.append(attIds[j]);
+          str.append(", ");
+      }
+      str.append(")\n");
+
+      str.append("        input  list: cnt = ");
+      str.append(data.statData[i].getInListCount());
+      str.append(", events in = ");
+      str.append(data.statData[i].getInListIn());
+
+      // if blocking station and not grandcentral ...
+      if (blocking && (data.statData[i].getId() != 0)) {
+        str.append(", events try = ");
+        str.append(data.statData[i].getInListTry());
+      }
+      str.append("\n");
+
+      str.append("        output list: cnt = ");
+      str.append(data.statData[i].getOutListCount());
+      str.append(", events out = ");
+      str.append(data.statData[i].getOutListOut());
+      str.append("\n");
+
+      System.out.println(str.toString());
+      str.delete(0, end);
+
+      // keep track of grandcentral data rate
+      if (i==0) {
+        rate = (data.statData[i].getOutListOut() - prevGcOut)/period;
+        prevGcOut = data.statData[i].getOutListOut();
+      }
+    } // for (int i=0; i < data.statData.length; i++) {
+
+
+    // user processes
+    if (data.procData.length > 0) {
+      str.append("  LOCAL USERS:\n");
+      for (int i=0; i < data.procData.length; i++) {
+        if (data.procData[i].getAttachments() < 1) {
+          str.append("    process id# ");
+          str.append(data.procData[i].getId());
+          str.append(", # attachments(0), ");
+        }
+        else {
+          str.append("    process id# ");
+          str.append(data.procData[i].getId());
+          str.append(", # attachments(");
+          str.append(data.procData[i].getAttachments());
+          str.append("), attach ids(");
+          int[] atIds = data.procData[i].getAttachmentIds();
+          for (int j=0; j < atIds.length; j++) {
+            str.append(atIds[j]);
+            str.append(", ");
+          }
+          str.append("), ");
+        }
+        str.append("pid(");
+        str.append(data.procData[i].getPid());
+        str.append("), hbeat(");
+        str.append(data.procData[i].getHeartbeat());
+        str.append(")\n");
+      }
+      System.out.println(str.toString());
+      str.delete(0, end);
+    }
+
+
+    // user attachments
+    if (data.attData.length > 0) {
+        str.append("  ATTACHMENTS: len = ");
+        str.append(data.attData.length);
+        str.append("\n");
+      for (int i=0; i < data.attData.length; i++) {
+        str.append("    att #");
+        str.append(data.attData[i].getId());
+        str.append(", is at station(");
+        str.append(data.attData[i].getStationName());
+        str.append(") on host(");
+        str.append(data.attData[i].getHost());
+        str.append(") at pid(");
+        str.append(data.attData[i].getPid());
+        str.append(")\n");
+        str.append("    proc(");
+        str.append(data.attData[i].getProc());
+        str.append("), ");
+        if (data.attData[i].blocked()) {
+          str.append("blocked(YES)");
+        }
+        else {
+          str.append("blocked(NO)");
+        }
+        if (data.attData[i].quitting()) {
+          str.append(", told to quit");
+        }
+        str.append("\n      events:  make(");
+        str.append(data.attData[i].getEventsMake());
+        str.append("), get(");
+        str.append(data.attData[i].getEventsGet());
+        str.append("), put(");
+        str.append(data.attData[i].getEventsPut());
+        str.append("), dump(");
+        str.append(data.attData[i].getEventsDump());
+        str.append(")");
+        System.out.println(str.toString());
+        str.delete(0, end);
+      }
+    }
+
+    str.append("\n  EVENTS OWNED BY:\n");
+    str.append("    system (");
+    str.append(data.sysData.getEventsOwned());
+    str.append("),");
+    for (int i=0; i < data.attData.length; i++) {
+      str.append("  att");
+      str.append(data.attData[i].getId());
+      str.append(" (");
+      str.append(data.attData[i].getEventsOwned());
+      str.append("),");
+      if ((i+1)%6 == 0)
+        str.append("\n    ");
+    }
+    str.append("\n\n");
+
+    // Event rate
+    str.append("  EVENT RATE of GC = ");
+    str.append(rate);
+    str.append(" events/sec\n\n");
+
+    // idle stations
+    str.append("  IDLE STATIONS:      ");
+    for (int i=0; i < data.statData.length; i++) {
+      if (data.statData[i].getStatus() == EtConstants.stationIdle) {
+        str.append(data.statData[i].getName());
+        str.append(", ");
+      }
+    }
+    str.append("\n");
+
+    // stations linked list
+    str.append("  STATION CHAIN:      ");
+    for (int i=0; i < data.statData.length; i++) {
+      str.append(data.statData[i].getName());
+      str.append(", ");
+    }
+    str.append("\n");
+
+
+    if (lang != EtConstants.langJava) {
+      // mutexes
+      str.append("  LOCKED MUTEXES:     ");
+      if (data.sysData.getMutex() == EtConstants.mutexLocked)
+        str.append("system, ");
+      if (data.sysData.getStatMutex() == EtConstants.mutexLocked)
+        str.append("station, ");
+      if (data.sysData.getStatAddMutex() == EtConstants.mutexLocked)
+        str.append("add_station, ");
+
+      for (int i=0; i < data.statData.length; i++) {
+        if (data.statData[i].getMutex() == EtConstants.mutexLocked) {
+          str.append(data.statData[i].getName());
+        }
+        if (data.statData[i].getInListMutex() == EtConstants.mutexLocked) {
+          str.append(data.statData[i].getName());
+          str.append("-in, ");
+        }
+        if (data.statData[i].getOutListMutex() == EtConstants.mutexLocked) {
+          str.append(data.statData[i].getName());
+          str.append("-out, ");
+        }
+      }
+      str.append("\n");
+    }
+
+    str.append("\n*****************************************\n");
+    System.out.println(str.toString());
+    str.delete(0, end);
+
+  }
+
+
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
EvioProducer.java added at 1.1
diff -N EvioProducer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EvioProducer.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,314 @@
+package org.jlab.coda.et.apps;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Mode;
+import org.jlab.coda.jevio.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: timmer
+ * Date: May 28, 2010
+ * Time: 4:01:01 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class EvioProducer {
+
+
+    public EvioProducer() {
+    }
+
+
+     private static void usage() {
+         System.out.println("\nUsage: java Producer -f <et name> [-p <server port>] [-host <host>]" +
+                 "                     [-d <delay in millisec>] [-g <group #>]\n\n" +
+                 "       -f     ET system's name\n" +
+                 "       -s     size in bytes for requested events\n" +
+                 "       -p     port number for a udp broadcast\n" +
+                 "       -d     delay in millisec between getting and putting events\n" +
+                 "       -g     group number of new events to get\n" +
+                 "       -host  host the ET system resides on (defaults to anywhere)\n\n" +
+                 "        This consumer works by making a connection to the\n" +
+                 "        ET system's tcp server port.\n");
+     }
+
+    /** Setting this to false will make the buffer be recreated from scratch for each event. */
+    static boolean fastMode = true;
+
+    /** Buffer to use for generated evio data. */
+    static ByteBuffer buffie;
+
+    /**
+     * Create an evio bank for sending.
+     */
+    public static ByteBuffer evioBytes() throws EvioException {
+
+        if (fastMode && buffie != null) {
+            buffie.flip();
+            return buffie;
+        }
+
+        // count the events we make for testing
+        int eventNumber = 1;
+
+        // use a tag of 11 for events--for no particular reason
+        int tag = 11;
+
+        // second event, more traditional bank of banks
+        EventBuilder eventBuilder = new EventBuilder(tag, DataType.BANK, eventNumber++);
+        EvioEvent event2 = eventBuilder.getEvent();
+
+        // add a bank of doubles
+        EvioBank bank1 = new EvioBank(22, DataType.DOUBLE64, 0);
+        eventBuilder.appendDoubleData(bank1, new double[] {1.1,2.2,-3.3, 1.12345678912345678912, -1.2e-99, -2.2e-11, -6.7e-10});
+        eventBuilder.addChild(event2, bank1);
+
+        // add a bank of floats
+        EvioBank bank4 = new EvioBank(22, DataType.FLOAT32, 0);
+        eventBuilder.appendFloatData(bank4, new float[] {1.1F,2.2F,-3.3F, 1.12345678912345678912F, -1.2e+38F, -2.2e-38F, -6.7e-29F});
+        eventBuilder.addChild(event2, bank4);
+
+        // add a bank of longs
+        EvioBank bank5 = new EvioBank(22, DataType.LONG64, 0);
+        eventBuilder.appendLongData(bank5, new long[] {1L,2L,3L, 1000000000000000000L, -1000000000000000000L, -2L, -3L});
+        eventBuilder.addChild(event2, bank5);
+
+        // add a bank of ints
+        EvioBank bank6 = new EvioBank(22, DataType.INT32, 0);
+        eventBuilder.appendIntData(bank6, new int[] {1,2,3, 1000000000, -1000000000, -2, -3});
+        eventBuilder.addChild(event2, bank6);
+
+        // add a bank of bytes
+        EvioBank bank7 = new EvioBank(22, DataType.CHAR8, 0);
+        eventBuilder.appendByteData(bank7, new byte[] {1,2,3});
+        eventBuilder.addChild(event2, bank7);
+
+        // lets modify event2
+        event2.getHeader().setNumber(eventNumber++);
+        EvioBank bank2 = new EvioBank(33, DataType.BANK, 0);
+        eventBuilder.addChild(event2, bank2);
+
+        EvioBank subBank1 = new EvioBank(34, DataType.INT32, 1);
+        eventBuilder.addChild(bank2, subBank1);
+        eventBuilder.appendIntData(subBank1, new int[] {4,5,6});
+
+        // now add a bank of segments
+        EvioBank subBank2 = new EvioBank(33, DataType.SEGMENT, 0);
+        eventBuilder.addChild(bank2, subBank2);
+
+        EvioSegment segment1 = new EvioSegment(34, DataType.SHORT16);
+        eventBuilder.addChild(subBank2, segment1);
+        eventBuilder.appendShortData(segment1, new short[] {7,8,9,10, 10000, 20000});
+
+        // now add a bank of tag segments
+        EvioBank subBank3 = new EvioBank(45, DataType.TAGSEGMENT, 0);
+        eventBuilder.addChild(bank2, subBank3);
+
+        // now add a tag segment of tag segments
+        EvioTagSegment tagsegment2 = new EvioTagSegment(35, DataType.TAGSEGMENT);
+        eventBuilder.addChild(subBank3, tagsegment2);
+
+        EvioTagSegment tagsegment3 = new EvioTagSegment(36, DataType.CHARSTAR8);
+        eventBuilder.addChild(tagsegment2, tagsegment3);
+        eventBuilder.appendStringData(tagsegment3, "This is a string");
+
+        event2.setAllHeaderLengths();
+
+
+        // write the event
+        buffie = ByteBuffer.allocate(event2.getTotalBytes());
+        event2.write(buffie);
+        buffie.flip();
+
+        //System.out.println("Event = \n"+ event2.toXML());
+        return buffie;
+    }
+
+
+    /**
+     * Main program for testing.
+     */
+    public static void main(String[] args) {
+
+         String etName = null, host = null;
+         int port = EtConstants.serverPort;
+         int group = 1;
+         int delay = 0;
+         int size = 32;
+
+         try {
+             for (int i = 0; i < args.length; i++) {
+                 if (args[i].equalsIgnoreCase("-f")) {
+                     etName = args[++i];
+                 }
+                 else if (args[i].equalsIgnoreCase("-host")) {
+                     host = args[++i];
+                 }
+                 else if (args[i].equalsIgnoreCase("-p")) {
+                     try {
+                         port = Integer.parseInt(args[++i]);
+                         if ((port < 1024) || (port > 65535)) {
+                             System.out.println("Port number must be between 1024 and 65535.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper port number.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-s")) {
+                     try {
+                         size = Integer.parseInt(args[++i]);
+                         if (size < 1) {
+                             System.out.println("Size needs to be positive int.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper size.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-g")) {
+                     try {
+                         group = Integer.parseInt(args[++i]);
+                         if ((group < 1) || (group > 10)) {
+                             System.out.println("Group number must be between 0 and 10.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper group number.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-d")) {
+                     try {
+                         delay = Integer.parseInt(args[++i]);
+                         if (delay < 1) {
+                             System.out.println("delay must be > 0.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper delay.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else {
+                     usage();
+                     return;
+                 }
+             }
+
+             if (host == null) {
+                 host = EtConstants.hostAnywhere;
+                 /*
+                 try {
+                     host = InetAddress.getLocalHost().getHostName();
+                 }
+                 catch (UnknownHostException ex) {
+                     System.out.println("Host not specified and cannot find local host name.");
+                     usage();
+                     return;
+                 }
+                 */
+             }
+
+             if (etName == null) {
+                 usage();
+                 return;
+             }
+
+             // make a direct connection to ET system's tcp server
+             EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host, port);
+
+             // create ET system object with verbose debugging output
+             EtSystem sys = new EtSystem(config, EtConstants.debugInfo);
+             sys.open();
+
+             // get GRAND_CENTRAL station object
+             EtStation gc = sys.stationNameToObject("GRAND_CENTRAL");
+
+             // attach to grandcentral
+             EtAttachment att = sys.attach(gc);
+
+             // array of events
+             EtEvent[] mevs;
+
+             int chunk = 1, count = 0, startingVal = 0;
+             long t1, t2, counter = 0, totalT = 0, totalCount = 0;
+             double rate, avgRate;
+             int[] con = {1, 2, 3, 4};
+             String s;
+             ByteBuffer buf;
+
+             // keep track of time for event rate calculations
+             t1 = System.currentTimeMillis();
+
+             for (int i = 0; i < 50; i++) {
+                 while (count < 30000L) {
+                     // get array of new events
+                     mevs = sys.newEvents(att, Mode.SLEEP, false, 0, chunk, size, group);
+
+                     if (delay > 0) Thread.sleep(delay);
+
+                     // example of how to manipulate events
+                     if (true) {
+                         for (int j = 0; j < mevs.length; j++) {
+                             // put integer (j) into front of data buffer
+                             //int swappedData = j + startingVal;
+                             //swappedData = Integer.reverseBytes(swappedData);
+                             buf = evioBytes();
+
+                             mevs[j].getDataBuffer().put(buf);
+                             int len = buf.position();
+                             //mevs[j].setByteOrder(ByteOrder.LITTLE_ENDIAN);
+                             // set data length to be 4 bytes (1 integer)
+                             mevs[j].setLength(len);
+                             // set every other event's priority as high
+                             //if (j % 2 == 0) mevs[j].setPriority(Priority.HIGH);
+                             // set event's control array
+                             //mevs[j].setControl(con);
+                         }
+                         startingVal++;
+                     }
+
+                     // put events back into ET system
+                     sys.putEvents(att, mevs);
+                     count += mevs.length;
+
+                 }
+
+                 // calculate the event rate
+                 t2 = System.currentTimeMillis();
+                 rate = 1000.0 * ((double) count) / ((double) (t2 - t1));
+                 totalCount += count;
+                 totalT += t2 - t1;
+                 avgRate = 1000.0 * ((double) totalCount) / totalT;
+                 System.out.println("rate = " + String.format("%.3g", rate) +
+                                    " Hz,   avg = " + String.format("%.3g", avgRate));
+                 count = 0;
+                 t1 = System.currentTimeMillis();
+             }
+             System.out.println("End of producing events, now close");
+             sys.close();
+         }
+         catch (Exception ex) {
+             System.out.println("Error using ET system as producer");
+             ex.printStackTrace();
+         }
+     }
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
Producer.java added at 1.1
diff -N Producer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Producer.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,271 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.apps;
+
+
+import java.lang.*;
+import java.nio.ByteOrder;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Mode;
+
+/**
+ * This class is an example of an event producer for an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class Producer {
+
+    public Producer() {
+    }
+
+
+    private static void usage() {
+        System.out.println("\nUsage: java Producer -f <ET name> -host <ET host> [-h] [-v] [-r] [-c <chunk size>] [-d <delay>]\n" +
+                "                     [-s <event size>] [-g <group>] [-p <ET server port>] [-i <interface address>]\n\n" +
+                "       -host  ET system's host\n" +
+                "       -f     ET system's (memory-mapped file) name\n" +
+                "       -h     help\n" +
+                "       -v     verbose output\n" +
+                "       -r     act as remote (TCP) client even if ET system is local\n" +
+                "       -c     number of events in one get/put array\n" +
+                "       -d     delay in millisec between each round of getting and putting events\n" +
+                "       -s     event size in bytes\n" +
+                "       -g     group from which to get new events (1,2,...)\n" +
+                "       -p     ET server port\n" +
+                "       -i     outgoing network interface IP address (dot-decimal)\n\n" +
+                "        This consumer works by making a direct connection to the\n" +
+                "        ET system's server port.\n");
+    }
+
+
+    public static void main(String[] args) {
+
+        String etName = null, host = null, netInterface = null;
+        int port = EtConstants.serverPort;
+        int group = 1;
+        int delay = 0;
+        int size  = 32;
+        int chunk = 1;
+        boolean verbose = false;
+        boolean remote  = false;
+
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equalsIgnoreCase("-f")) {
+                etName = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-i")) {
+                netInterface = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-host")) {
+                host = args[++i];
+            }
+            else if (args[i].equalsIgnoreCase("-p")) {
+                try {
+                    port = Integer.parseInt(args[++i]);
+                    if ((port < 1024) || (port > 65535)) {
+                        System.out.println("Port number must be between 1024 and 65535.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper port number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-c")) {
+                try {
+                    chunk = Integer.parseInt(args[++i]);
+                    if ((chunk < 1) || (chunk > 1000)) {
+                        System.out.println("Chunk size may be 1 - 1000.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper chunk size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-s")) {
+                try {
+                    size = Integer.parseInt(args[++i]);
+                    if (size < 1) {
+                        System.out.println("Size needs to be positive int.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper size.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-g")) {
+                try {
+                    group = Integer.parseInt(args[++i]);
+                    if ((group < 1) || (group > 10)) {
+                        System.out.println("Group number must be between 0 and 10.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper group number.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-d")) {
+                try {
+                    delay = Integer.parseInt(args[++i]);
+                    if (delay < 1) {
+                        System.out.println("delay must be > 0.");
+                        usage();
+                        return;
+                    }
+                }
+                catch (NumberFormatException ex) {
+                    System.out.println("Did not specify a proper delay.");
+                    usage();
+                    return;
+                }
+            }
+            else if (args[i].equalsIgnoreCase("-v")) {
+                verbose = true;
+            }
+            else if (args[i].equalsIgnoreCase("-r")) {
+                remote = true;
+            }
+            else {
+                usage();
+                return;
+            }
+        }
+
+        if (host == null || etName == null) {
+            usage();
+            return;
+        }
+
+        try {
+            // Make a direct connection to ET system's tcp server
+            EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host, port);
+            config.setConnectRemotely(remote);
+
+            // EXAMPLE: Broadcast to find ET system
+            //EtSystemOpenConfig config = new EtSystemOpenConfig();
+            //config.setHost(host);
+            //config.setEtName(etName);
+            //config.addBroadcastAddr("129.57.29.255"); // this call is not necessary
+
+            // EXAMPLE: Multicast to find ET system
+            //ArrayList<String> mAddrs = new ArrayList<String>();
+            //mAddrs.add(EtConstants.multicastAddr);
+            //EtSystemOpenConfig config = new EtSystemOpenConfig(etName, host,
+            //                                mAddrs, EtConstants.multicastPort, 32);
+
+            if (netInterface != null) config.setNetworkInterface(netInterface);
+
+            // create ET system object with verbose debugging output
+            EtSystem sys = new EtSystem(config);
+            if (verbose) sys.setDebug(EtConstants.debugInfo);
+            sys.open();
+
+            // get GRAND_CENTRAL station object
+            EtStation gc = sys.stationNameToObject("GRAND_CENTRAL");
+
+            // attach to GRAND_CENTRAL
+            EtAttachment att = sys.attach(gc);
+
+            // array of events
+            EtEvent[] mevs;
+
+            int    count = 0, startingVal = 0;
+            long   t1, t2, time, totalT = 0, totalCount = 0;
+            double rate, avgRate;
+
+            // create control array of correct size
+            int[] con = new int[EtConstants.stationSelectInts];
+            for (int i=0; i < EtConstants.stationSelectInts; i++) {
+                con[i] = i+1;
+            }
+
+            // keep track of time for event rate calculations
+            t1 = System.currentTimeMillis();
+
+            while (true) {
+                // get array of new events
+                mevs = sys.newEvents(att, Mode.SLEEP, false, 0, chunk, size, group);
+
+                if (delay > 0) Thread.sleep(delay);
+
+                // example of how to manipulate events
+                if (false) {
+                    for (int j = 0; j < mevs.length; j++) {
+                        // put integer (j + startingVal) into data buffer
+                        int swappedData = Integer.reverseBytes(j + startingVal);
+                        mevs[j].getDataBuffer().putInt(swappedData);
+
+                        // big endian by default
+                        mevs[j].setByteOrder(ByteOrder.LITTLE_ENDIAN);
+
+                        // set data length to be 4 bytes (1 integer)
+                        mevs[j].setLength(4);
+
+                        // set event's control array
+                        mevs[j].setControl(con);
+                    }
+                    startingVal += mevs.length;
+                }
+
+                // put events back into ET system
+                sys.putEvents(att, mevs);
+                count += mevs.length;
+
+                // calculate the event rate
+                t2 = System.currentTimeMillis();
+                time = t2 - t1;
+
+                if (time > 5000) {
+                    // reset things if necessary
+                    if ( (totalCount >= (Long.MAX_VALUE - count)) ||
+                         (totalT >= (Long.MAX_VALUE - time)) )  {
+                        totalT = totalCount = count = 0;
+                        t1 = System.currentTimeMillis();
+                        continue;
+                    }
+                    rate = 1000.0 * ((double) count) / time;
+                    totalCount += count;
+                    totalT += time;
+                    avgRate = 1000.0 * ((double) totalCount) / totalT;
+                    System.out.println("rate = " + String.format("%.3g", rate) +
+                                       " Hz,  avg = " + String.format("%.3g", avgRate));
+                    count = 0;
+                    t1 = System.currentTimeMillis();
+                }
+            }
+        }
+        catch (Exception ex) {
+            System.out.println("Error using ET system as producer");
+            ex.printStackTrace();
+        }
+    }
+    
+}

hps-et-java/src/main/java/org/jlab/coda/et/apps
StartEt.java added at 1.1
diff -N StartEt.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ StartEt.java	13 Feb 2012 22:43:45 -0000	1.1
@@ -0,0 +1,226 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.apps;
+
+import java.io.File;
+import java.lang.*;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.system.*;
+
+/**
+ * This class is an example of starting up an ET system.
+ *
+ * @author Carl Timmer
+ * @version 7.0
+ */
+public class StartEt {
+
+    /** Method to print out correct program command line usage. */
+    private static void usage() {
+
+        System.out.println("\nUsage: java StartEt [-h] [-v] [-d] [-f <file>] [-n <events>] [-s <evenSize>]\n" +
+                             "                    [-g <groups>] [-p <TCP server port>] [-u <UDP port>]\n" +
+                             "                    [-m <UDP multicast port>] [-a <multicast address>]\n" +
+                             "                    [-rb <buf size>] [-sb <buf size>] [-nd]\n\n" +
+
+        "          -h for help\n" +
+        "          -v for verbose output\n" +
+        "          -d deletes an existing file first\n" +
+        "          -f sets memory-mapped file name\n" +
+        "          -n sets number of events\n" +
+        "          -s sets event size in bytes\n" +
+        "          -g sets number of groups to divide events into\n" +
+        "          -p sets TCP server port #\n" +
+        "          -u sets UDP broadcast port #\n" +
+        "          -m sets UDP multicast port #\n" +
+        "          -a sets multicast address\n" +
+        "          -rb TCP receive buffer size (bytes)\n" +
+        "          -sb TCP send    buffer size (bytes)\n" +
+        "          -nd use TCP_NODELAY option\n");
+
+    }
+
+
+    public StartEt() {
+    }
+
+    public static void main(String[] args) {
+        int numEvents = 3000, size = 128;
+        int serverPort = EtConstants.serverPort;
+        int udpPort = EtConstants.broadcastPort;
+        int multicastPort = EtConstants.multicastPort;
+        int recvBufSize = 0, sendBufSize = 0;
+        int numGroups = 1;
+        boolean debug = false;
+        boolean noDelay = false;
+        boolean deleteFile = false;
+        String file = null;
+        String mcastAddr = null;
+
+        // loop over all args
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equalsIgnoreCase("-h")) {
+                usage();
+                System.exit(-1);
+            }
+            else if (args[i].equalsIgnoreCase("-n")) {
+                numEvents = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-f")) {
+                file = args[i + 1];
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-p")) {
+                serverPort = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-u")) {
+                udpPort = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-m")) {
+                multicastPort = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-s")) {
+                size = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-rb")) {
+                recvBufSize = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-sb")) {
+                sendBufSize = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-nd")) {
+                noDelay = true;
+            }
+            else if (args[i].equalsIgnoreCase("-v")) {
+                debug = true;
+            }
+            else if (args[i].equalsIgnoreCase("-g")) {
+                numGroups = Integer.parseInt(args[i + 1]);
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-a")) {
+                mcastAddr = args[i + 1];
+                i++;
+            }
+            else if (args[i].equalsIgnoreCase("-d")) {
+                deleteFile = true;
+            }
+            else {
+                usage();
+                System.exit(-1);
+            }
+        }
+
+        if (file == null) {
+            String et_filename = System.getenv("SESSION");
+            if (et_filename == null) {
+                System.out.println("No ET file name given and SESSION env variable not defined");
+                usage();
+                System.exit(-1);
+            }
+
+            file = "/tmp/et_sys_" + et_filename;
+        }
+
+        // check length of name
+        if (file.length() >=  EtConstants.fileNameLengthMax) {
+            System.out.println("ET file name is too long");
+            usage();
+            System.exit(-1);
+        }
+
+        if (deleteFile) {
+            File f = new File(file);
+            f.delete();
+        }
+
+        try {
+            System.out.println("STARTING ET SYSTEM");
+            // ET system configuration object
+            SystemConfig config = new SystemConfig();
+
+            // listen for multicasts at this address
+            if (mcastAddr != null) {
+                config.addMulticastAddr(mcastAddr);
+            }
+            // set tcp server port
+            config.setServerPort(serverPort);
+            // set port for listening for udp packets
+            config.setUdpPort(udpPort);
+            // set port for listening for multicast udp packets
+            // (on Java this must be different than the udp port)
+            config.setMulticastPort(multicastPort);
+            // set total number of events
+            config.setNumEvents(numEvents);
+            // set size of events in bytes
+            config.setEventSize(size);
+            // set tcp receive buffer size in bytes
+            if (recvBufSize > 0) {
+                config.setTcpRecvBufSize(recvBufSize);
+            }
+            // set tcp send buffer size in bytes
+            if (sendBufSize > 0) {
+                config.setTcpSendBufSize(sendBufSize);
+            }
+            // set tcp no-delay
+            if (noDelay) {
+                config.setNoDelay(noDelay);
+            }
+            // set debug level
+            if (debug) {
+                config.setDebug(EtConstants.debugInfo);
+            }
+
+            // divide events into equal groups and any leftovers into another group */
+            if (numGroups > 1) {
+                int addgroup=0;
+
+                int n = numEvents / numGroups;
+                int r = numEvents % numGroups;
+                if (r > 0) {
+                    addgroup = 1;
+                }
+
+                int[] groups = new int[numGroups+addgroup];
+
+                for (int i=0; i < numGroups; i++) {
+                    groups[i] = n;
+                }
+
+                if (addgroup > 0) {
+                    groups[numGroups] = r;
+                }
+
+                config.setGroups(groups);
+            }
+
+            // create an active ET system
+            SystemCreate sys = new SystemCreate(file, config);
+        }
+        catch (Exception ex) {
+            System.out.println("ERROR STARTING ET SYSTEM");
+            ex.printStackTrace();
+        }
+
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et/data
AllData.java added at 1.1
diff -N AllData.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AllData.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,52 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.data;
+
+
+/**
+ * This class holds all the information about an ET system. This includes
+ * information about attachments, stations, processes, and the system
+ * level.
+ *
+ * @author Carl Timmer
+ */
+public class AllData {
+
+    /**
+     * Creates the bare minimum needed to hold the information of an ET system.
+     * Information about stations, attachments, and processes are added by
+     * other methods.
+     *
+     * @see org.jlab.coda.et.EtSystem#getData
+     */
+    public AllData() {
+        sysData = new SystemData();
+    }
+
+    /** Holds system information. */
+    public SystemData sysData;
+
+    /** Holds station information. */
+    public StationData statData[];
+
+    /** Holds attachment information. */
+    public AttachmentData attData[];
+
+    /**
+     * Hold process information. There are no processes (local processes which
+     * have direct access to the ET shared memory) in Java language ET.
+     */
+    public ProcessData procData[];
+}

hps-et-java/src/main/java/org/jlab/coda/et/data
AttachmentData.java added at 1.1
diff -N AttachmentData.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AttachmentData.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,214 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.data;
+
+import org.jlab.coda.et.EtConstants;
+import org.jlab.coda.et.EtUtils;
+
+import java.io.*;
+
+/**
+ * This class holds all information about an attachment. It parses
+ * the information from a stream of data sent by an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class AttachmentData {
+
+    /** Attachment's id number.
+     *  @see org.jlab.coda.et.EtAttachment#id
+     *  @see org.jlab.coda.et.system.AttachmentLocal#id */
+    private int num;
+
+    /** Id number of ET process that created this attachment
+     * (only relevant in C-based ET systems). */
+    private int proc;
+
+    /** Id number of the attachment's station.
+     *  @see org.jlab.coda.et.EtAttachment#station
+     *  @see org.jlab.coda.et.system.AttachmentLocal#station */
+    private int stat;
+
+    /** Unix process id of the program that created this attachment
+     * (only relevant in C-based ET systems).
+     *  @see org.jlab.coda.et.system.AttachmentLocal#pid */
+    private int pid;
+
+    /** Flag indicating if this attachment is blocked waiting to read events. Its
+     *  value is {@link org.jlab.coda.et.EtConstants#attBlocked} if blocked and
+     *  {@link org.jlab.coda.et.EtConstants#attUnblocked} otherwise.
+     *  This is not boolean for C ET system compatibility.
+     *  @see org.jlab.coda.et.system.AttachmentLocal#waiting */
+    private int blocked;
+
+    /** Flag indicating if this attachment has been told to quit trying to read
+     *  events and return. Its value is {@link org.jlab.coda.et.EtConstants#attQuit} if it has been
+     *  told to quit and {@link org.jlab.coda.et.EtConstants#attContinue} otherwise.
+     *  This is not boolean for C ET system compatibility.
+     *  @see org.jlab.coda.et.system.AttachmentLocal#wakeUp */
+    private int quit;
+
+    /** The number of events owned by this attachment */
+    private int eventsOwned;
+
+    /** Number of events put back into the station.
+     *  @see org.jlab.coda.et.EtAttachment#getEventsPut
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsPut */
+    private long eventsPut;
+
+    /** Number of events gotten from the station.
+     *  @see org.jlab.coda.et.EtAttachment#getEventsGet
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsGet */
+    private long eventsGet;
+
+    /** Number of events dumped (recycled by returning to GRAND_CENTRAL) through the station.
+     *  @see org.jlab.coda.et.EtAttachment#getEventsDump
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsDump */
+    private long eventsDump;
+
+    /** Number of new events gotten from the station.
+     *  @see org.jlab.coda.et.EtAttachment#getEventsMake
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsMake */
+    private long eventsMake;
+
+    /** Name of the host running this attachment.
+     *  @see org.jlab.coda.et.system.AttachmentLocal#host */
+    private String host;
+
+    /**  Name of the station this attachment is associated with. */
+    private String stationName;
+
+    /** IP address of the network interface the attachment is sending data through. */
+    private String ipAddress;
+
+
+    // getters
+
+
+    /** Get the attachment's id number.
+     *  @return attachment's id number
+     *  @see org.jlab.coda.et.EtAttachment#id
+     *  @see org.jlab.coda.et.system.AttachmentLocal#id */
+    public int getId() {return num;}
+
+    /** Get the id number of ET process that created this attachment
+     *  (only relevant in C-based ET systems).
+     *  @return id number of ET process that created this attachment */
+    public int getProc() {return proc;}
+
+    /** Get the id number of the station to which this attachment belongs.
+     *  @return id number of station to which this attachment belongs
+     *  @see org.jlab.coda.et.EtAttachment#station
+     *  @see org.jlab.coda.et.system.AttachmentLocal#station */
+    public int getStationId() {return stat;}
+
+    /** Get the Unix process id of the program that created this attachment
+     * (only relevant in C-based ET systems).
+     *  @return Unix process id of the program that created this attachment
+     *  @see org.jlab.coda.et.system.AttachmentLocal#pid */
+    public int getPid() {return pid;}
+
+    /** Indicates if this attachment is blocked waiting to read events.
+     *  @return <code>true</code> if blocked waiting to read events, else <code>false</code>
+     *  @see org.jlab.coda.et.system.AttachmentLocal#waiting */
+    public boolean blocked() {return blocked == EtConstants.attBlocked;}
+
+    /** Indicates if this attachment has been told to quit trying to read events and return.
+     *  @return <code>true</code> if this attachment has been told to quit trying to read
+     *          events and return, else <code>false</code>
+     *  @see org.jlab.coda.et.system.AttachmentLocal#wakeUp */
+    public boolean quitting() {return quit == EtConstants.attQuit;}
+
+
+    /** Get the number of events owned by this attachment.
+     *  @return number of events owned by this attachment */
+    public int getEventsOwned() {return eventsOwned;}
+
+    /** Get the number of events put back into the station.
+     *  @return number of events put back into the station
+     *  @see org.jlab.coda.et.EtAttachment#getEventsPut
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsPut */
+    public long getEventsPut() {return eventsPut;}
+
+    /** Get the number of events gotten from the station.
+     *  @return number of events gotten from the station
+     *  @see org.jlab.coda.et.EtAttachment#getEventsGet
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsGet */
+    public long getEventsGet() {return eventsGet;}
+
+    /** Get the number of events dumped (recycled by returning to GRAND_CENTRAL)
+     *  through the station.
+     *  @return number of events dumped through the station
+     *  @see org.jlab.coda.et.EtAttachment#getEventsDump
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsDump */
+    public long getEventsDump() {return eventsDump;}
+
+    /** Get the number of new events gotten from the station.
+     *  @return number of new events gotten from the station
+     *  @see org.jlab.coda.et.EtAttachment#getEventsMake
+     *  @see org.jlab.coda.et.system.AttachmentLocal#eventsMake */
+    public long getEventsMake() {return eventsMake;}
+
+    /** Get the name of the host running this attachment.
+     *  @return name of the host running this attachment
+     *  @see org.jlab.coda.et.system.AttachmentLocal#host */
+    public String getHost() {return host;}
+
+    /** Get the name of the station this attachment is associated with.
+     *  @return name of the station this attachment is associated with */
+    public String getStationName() {return stationName;}
+
+    /** Get the IP address of the network interface the attachment is sending data through.
+     *  @return IP address of the network interface the attachment is sending data through. */
+    public String getIpAddress() {return ipAddress;}
+
+    /**
+     *  Reads the attachment information from an ET system over the network.
+     *  @param dis data input stream
+     *  @throws IOException if data read error
+     */
+    public void read(DataInputStream dis) throws IOException {
+        byte[] info = new byte[72];
+        dis.readFully(info);
+
+        num         = EtUtils.bytesToInt(info,   0);
+        proc        = EtUtils.bytesToInt(info,   4);
+        stat        = EtUtils.bytesToInt(info,   8);
+        pid         = EtUtils.bytesToInt(info,  12);
+        blocked     = EtUtils.bytesToInt(info,  16);
+        quit        = EtUtils.bytesToInt(info,  20);
+        eventsOwned = EtUtils.bytesToInt(info,  24);
+        eventsPut   = EtUtils.bytesToLong(info, 28);
+        eventsGet   = EtUtils.bytesToLong(info, 36);
+        eventsDump  = EtUtils.bytesToLong(info, 44);
+        eventsMake  = EtUtils.bytesToLong(info, 52);
+
+        // read strings, lengths first
+        int length1 = EtUtils.bytesToInt(info, 60);
+        int length2 = EtUtils.bytesToInt(info, 64);
+        int length3 = EtUtils.bytesToInt(info, 68);
+
+        if (length1 + length2 + length3 > 72) {
+            info = new byte[length1 + length2 + length3];
+        }
+        dis.readFully(info, 0, length1 + length2 + length3);
+        host = new String(info, 0, length1 - 1, "US-ASCII");
+        stationName = new String(info, length1, length2 - 1, "US-ASCII");
+        ipAddress = new String(info, length1+length2, length3 - 1, "US-ASCII");
+    }
+}
+
+
+

hps-et-java/src/main/java/org/jlab/coda/et/data
ProcessData.java added at 1.1
diff -N ProcessData.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ProcessData.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,114 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.data;
+
+import org.jlab.coda.et.EtConstants;
+
+import java.io.*;
+
+/**
+ * This class holds all information about an ET process. It parses
+ * the information from a stream of data sent by an ET system. There
+ * are no processes in Java ET systems.
+ *
+ * @author Carl Timmer
+ */
+public class ProcessData {
+
+    /** Unique id number. */
+    private int num;
+
+    /** Heartbeat count. */
+    private int heartbeat;
+
+    /** Unix process id. */
+    private int pid;
+
+    /** Number of attachments this process created. */
+    private int attachments;
+
+    /**
+     * An array of attachment id numbers. Only the first "attachments"
+     * number of elements are meaningful.
+     */
+    private int attIds[] = new int[EtConstants.attachmentsMax];
+
+
+    // get methods
+
+
+    /**
+     * Get the process' unique id number.
+     * @return process' unique id number
+     */
+    public int getId() {
+        return num;
+    }
+
+    /**
+     * Get the heartbeat count.
+     * @return heartbeat count
+     */
+    public int getHeartbeat() {
+        return heartbeat;
+    }
+
+    /**
+     * Get the Unix process id.
+     * @return Unix process id
+     */
+    public int getPid() {
+        return pid;
+    }
+
+    /**
+     * Get the number of attachments this process created.
+     * @return number of attachments this process created
+     */
+    public int getAttachments() {
+        return attachments;
+    }
+
+    /**
+     * Get the array of attachment id numbers.
+     * @return array of attachment id numbers
+     */
+    public int[] getAttachmentIds() {
+        return attIds.clone();
+    }
+
+    /**
+     * Reads the process information from an ET system over the network.
+     *
+     * @param dis data input stream
+     * @throws java.io.IOException if data read error
+     */
+    public void read(DataInputStream dis) throws IOException {
+        attachments = dis.readInt();
+        num         = dis.readInt();
+        heartbeat   = dis.readInt();
+        pid         = dis.readInt();
+        for (int i = 0; i < attachments; i++) {
+            attIds[i] = dis.readInt();
+        }
+    }
+}
+
+
+
+
+
+
+

hps-et-java/src/main/java/org/jlab/coda/et/data
StationData.java added at 1.1
diff -N StationData.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ StationData.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,347 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.data;
+
+import org.jlab.coda.et.EtConstants;
+
+import java.lang.*;
+import java.io.*;
+
+/**
+ * This class holds all information about an station. It parses
+ * the information from a stream of data sent by an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class StationData {
+
+    /** Station's id number.
+     *  @see org.jlab.coda.et.EtStation#id
+     *  @see org.jlab.coda.et.system.StationLocal#id */
+    private int num;
+
+    /** Station's status. It may have the values {@link org.jlab.coda.et.EtConstants#stationUnused},
+     *  {@link org.jlab.coda.et.EtConstants#stationIdle}, or {@link org.jlab.coda.et.EtConstants#stationActive}.
+     *  @see org.jlab.coda.et.system.StationLocal#status */
+    private int status;
+
+    /** Transfer mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked} if
+     *  locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems, since in Java, mutexes cannot be tested without
+     *  possibility of blocking. This is not boolean for C-based ET system compatibility.
+     *  @see org.jlab.coda.et.system.StationLocal#stopTransferLock */
+    private int mutex;
+
+    /** Number of attachments to this station.
+     *  @see org.jlab.coda.et.system.StationLocal#attachments */
+    private int attachments;
+
+    /** Array of attachment id numbers. Only the first "attachments"
+     *  number of elements are meaningful.
+     *  @see org.jlab.coda.et.system.StationLocal#attachments */
+    private int attIds[] = new int[EtConstants.attachmentsMax];
+
+
+    /** Input list mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked} if
+     *  locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only relevant
+     *  in C-based ET systems, since in Java, mutexes cannot be tested without the
+     *  chance of blocking. This is not boolean for C-based ET system compatibility. */
+    private int  inListMutex;
+
+    /** Number of events in the input list.
+     *  @see org.jlab.coda.et.system.EventList#events */
+    private int  inListCount;
+
+    /** Number of events that were attempted to be put into the input list. This is
+     *  relevant only when there is prescaling.
+     *  @see org.jlab.coda.et.system.EventList#eventsTry */
+    private long inListTry;
+
+    /** Number of events that were put into the input list.
+     *  @see org.jlab.coda.et.system.EventList#eventsIn */
+    private long inListIn;
+
+
+    /** Output list mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked} if
+     *  locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only relevant
+     *  in C-based ET systems, since in Java, mutexes cannot be tested without the
+     *  chance of blocking. This is not boolean for C-based ET system compatibility. */
+    private int  outListMutex;
+
+    /** Number of events in the output list.
+     *  @see org.jlab.coda.et.system.EventList#events */
+    private int  outListCount;
+
+    /** Number of events that were taken out of the output list.
+     *  @see org.jlab.coda.et.system.EventList#eventsOut */
+    private long outListOut;
+
+
+    // station configuration
+
+
+    /** Station configuration's flow mode.
+     *  @see org.jlab.coda.et.EtStationConfig#userMode */
+    private int flowMode;
+
+    /** Station configuration's user mode.
+     *  @see org.jlab.coda.et.EtStationConfig#userMode */
+    private int userMode;
+
+    /** Station configuration's restore mode.
+     *  @see org.jlab.coda.et.EtStationConfig#restoreMode */
+    private int restoreMode;
+
+    /** Station configuration's blocking mode.
+     *  @see org.jlab.coda.et.EtStationConfig#blockMode */
+    private int blockMode;
+
+    /** Station configuration's prescale value.
+     *  @see org.jlab.coda.et.EtStationConfig#prescale */
+    private int prescale;
+
+    /** Station configuration's input cue size.
+     *  @see org.jlab.coda.et.EtStationConfig#cue */
+    private int cue;
+
+    /** Station configuration's select mode.
+     *  @see org.jlab.coda.et.EtStationConfig#selectMode */
+    private int selectMode;
+
+    /** Station configuration's select array.
+     *  @see org.jlab.coda.et.EtStationConfig#select */
+    private int select[] = new int[EtConstants.stationSelectInts];
+
+    /** Name of user select function in C-based ET library.
+     *  @see org.jlab.coda.et.EtStationConfig#selectFunction */
+    private String selectFunction;
+
+    /** Name of C library containing user select function in C-based ET system.
+     *  @see org.jlab.coda.et.EtStationConfig#selectLibrary */
+    private String selectLibrary;
+
+    /** Name of Java class containing user select method in Java-based ET system.
+     *  @see org.jlab.coda.et.EtStationConfig#selectClass */
+    private String selectClass;
+
+    /** Name of station.
+     *  @see org.jlab.coda.et.EtStation#name
+     *  @see org.jlab.coda.et.system.StationLocal#name */
+    private String name;
+
+
+    // get methods
+
+
+    /** Get the station's id number.
+     *  @return station's id number
+     *  @see org.jlab.coda.et.EtStation#id
+     *  @see org.jlab.coda.et.system.StationLocal#id */
+    public int getId() {return num;}
+
+    /** Get the station's status. It may have the values {@link org.jlab.coda.et.EtConstants#stationUnused},
+     *  {@link org.jlab.coda.et.EtConstants#stationIdle}, or {@link org.jlab.coda.et.EtConstants#stationActive}.
+     *  @return station's status
+     *  @see org.jlab.coda.et.system.StationLocal#status */
+    public int getStatus() {return status;}
+
+    /** Get the transfer mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems.
+     *  @return transfer mutex status */
+    public int getMutex() {return mutex;}
+
+    /** Get the number of attachments to this station.
+     *  @return number of attachments to this station
+     *  @see org.jlab.coda.et.system.StationLocal#attachments */
+    public int getAttachments() {return attachments;}
+
+    /** Get the array of attachment id numbers.
+     *  @return array of attachment id numbers
+     *  @see org.jlab.coda.et.system.StationLocal#attachments */
+    public int[] getAttachmentIds() {return attIds.clone();}
+
+
+    /** Get the input list mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only relevant
+     *  in C-based ET systems.
+     *  @return input list mutex status */
+    public int  getInListMutex() {return inListMutex;}
+
+    /** Get the number of events in the input list.
+     *  @return number of events in the input list
+     *  @see org.jlab.coda.et.system.EventList#events */
+    public int  getInListCount() {return inListCount;}
+
+    /** Get the number of events that were attempted to be put into the input list.
+     *  This is relevant only when there is prescaling.
+     *  @return number of events that were attempted to be put into the input list
+     *  @see org.jlab.coda.et.system.EventList#eventsTry */
+    public long getInListTry() {return inListTry;}
+
+    /** Get the number of events that were put into the input list.
+     *  @return number of events that were put into the input list
+     *  @see org.jlab.coda.et.system.EventList#eventsIn */
+    public long getInListIn() {return inListIn;}
+
+
+    /** Get the output list mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only relevant
+     *  in C ET systems.
+     *  @return output list mutex status */
+    public int  getOutListMutex() {return outListMutex;}
+
+    /** Get the number of events in the output list.
+     *  @return number of events in the output list
+     *  @see org.jlab.coda.et.system.EventList#events */
+    public int  getOutListCount() {return outListCount;}
+
+    /** Get the number of events that were taken out of the output list.
+     *  @return number of events that were taken out of the output list
+     *  @see org.jlab.coda.et.system.EventList#eventsOut */
+    public long getOutListOut() {return outListOut;}
+
+
+    // station configuration parameters ...
+
+
+    /** Get the station configuration's flow mode.
+     *  @return station configuration's flow mode
+     *  @see org.jlab.coda.et.EtStationConfig#flowMode */
+    public int getFlowMode() {return flowMode;}
+
+    /** Get the station configuration's user mode.
+     *  @return station configuration's user mode
+     *  @see org.jlab.coda.et.EtStationConfig#userMode */
+    public int getUserMode() {return userMode;}
+
+    /** Get the station configuration's restore mode.
+     *  @return station configuration's restore mode
+     *  @see org.jlab.coda.et.EtStationConfig#restoreMode */
+    public int getRestoreMode() {return restoreMode;}
+
+    /** Get the station configuration's blocking mode.
+     *  @return station configuration's blocking mode
+     *  @see org.jlab.coda.et.EtStationConfig#blockMode */
+    public int getBlockMode() {return blockMode;}
+
+    /** Get the station configuration's prescale value.
+     *  @return station configuration's prescale value
+     *  @see org.jlab.coda.et.EtStationConfig#prescale */
+    public int getPrescale() {return prescale;}
+
+    /** Get the station configuration's input cue size.
+     *  @return station configuration's input cue size
+     *  @see org.jlab.coda.et.EtStationConfig#cue */
+    public int getCue() {return cue;}
+
+    /** Get the station configuration's select mode.
+     *  @return station configuration's select mode
+     *  @see org.jlab.coda.et.EtStationConfig#selectMode */
+    public int getSelectMode() {return selectMode;}
+
+    /** Get the station configuration's select array.
+     *  @return station configuration's select array
+     *  @see org.jlab.coda.et.EtStationConfig#select */
+    public int[] getSelect() {return select.clone();}
+
+    /** Get the name of the user select function in the C-based ET library.
+     *  @return name of the user select function in the C-based ET library
+     *  @see org.jlab.coda.et.EtStationConfig#selectFunction */
+    public String getSelectFunction() {return selectFunction;}
+
+    /** Get the name of the C library containing the user select function in
+     *  the C-based ET system.
+     *  @return name of the C library containing the user select function
+     *  @see org.jlab.coda.et.EtStationConfig#selectLibrary */
+    public String getSelectLibrary() {return selectLibrary;}
+
+    /** Get the name of the Java class containing the user select method in
+     *  the Java-based ET system.
+     *  @return name of the Java class containing the user select method
+     *  @see org.jlab.coda.et.EtStationConfig#selectClass */
+    public String getSelectClass() {return selectClass;}
+
+    /** Get the name of the station.
+     *  @return name of the station
+     *  @see org.jlab.coda.et.EtStation#name
+     *  @see org.jlab.coda.et.system.StationLocal#name */
+    public String getName() {return name;}
+
+
+    /**
+     *  Reads the station information from an ET system over the network.
+     *  @param dis data input stream
+     *  @throws IOException if data read error
+     */
+    public void read(DataInputStream dis) throws IOException {
+        attachments  = dis.readInt();
+        num          = dis.readInt();
+        status       = dis.readInt();
+        mutex        = dis.readInt();
+        for (int i=0; i < attachments; i++) {
+            attIds[i]  = dis.readInt();
+        }
+
+        inListMutex  = dis.readInt();
+        inListCount  = dis.readInt();
+        inListTry    = dis.readLong();
+        inListIn     = dis.readLong();
+        outListMutex = dis.readInt();
+        outListCount = dis.readInt();
+        outListOut   = dis.readLong();
+
+        flowMode     = dis.readInt();
+        userMode     = dis.readInt();
+        restoreMode  = dis.readInt();
+        blockMode    = dis.readInt();
+        prescale     = dis.readInt();
+        cue          = dis.readInt();
+        selectMode   = dis.readInt();
+
+        for (int i=0; i < EtConstants.stationSelectInts; i++) {
+            select[i]  = dis.readInt();
+        }
+
+        // read strings, lengths first
+        int length1 = dis.readInt();
+        int length2 = dis.readInt();
+        int length3 = dis.readInt();
+        int length4 = dis.readInt();
+        int length  = length1 + length2 + length3 + length4;
+
+        byte[] buf = new byte[length];
+        dis.readFully(buf, 0, length);
+        int off = 0;
+
+        if (length1 > 0) {
+            selectFunction = new String(buf, off, length1-1, "US-ASCII");
+            off += length1;
+        }
+        if (length2 > 0) {
+            selectLibrary = new String(buf, off, length2-1, "US-ASCII");
+            off += length2;
+        }
+        if (length3 > 0) {
+            selectClass = new String(buf, off, length3-1, "US-ASCII");
+            off += length3;
+        }
+        if (length4 > 0) {
+            name = new String(buf, off, length4-1, "US-ASCII");
+        }
+
+    }
+}
+

hps-et-java/src/main/java/org/jlab/coda/et/data
SystemData.java added at 1.1
diff -N SystemData.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SystemData.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,398 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.data;
+
+import org.jlab.coda.et.EtUtils;
+
+import java.io.*;
+
+/**
+ * This class holds all system level information about an ET system. It parses
+ * the information from a stream of data sent by an ET system.
+ *
+ * @author Carl Timmer
+ */
+public class SystemData {
+
+
+    // values which can change
+
+
+    /** Flag which specifying whether the ET system is alive. A value of 1 means
+     *  alive and 0 means dead. */
+    private int alive;
+
+    /** Heartbeat count of the ET system process. It is not relevant in Java-based ET
+     *  systems. */
+    private int heartbeat;
+
+    /** Count of the current amount of temporary events. It is not relevant in
+     *  Java-based ET systems. */
+    private int temps;
+
+    /** Count of the current number of stations in the linked list (are either
+     *  active or idle).
+     *  @see org.jlab.coda.et.system.SystemCreate#stations */
+    private int stations;
+
+    /** Count of the current number of attachments.
+     *  @see org.jlab.coda.et.system.SystemCreate#attachments */
+    private int attachments;
+
+    /** Count of the current number of processes. It is not relevant in Java-based ET
+     *  systems. */
+    private int processes;
+
+    /** Number of events owned by the system (as opposed to attachments). */
+    private int eventsOwned;
+
+
+    /** System mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked} if
+     *  locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems, since in Java, mutexes cannot be tested without
+     *  possibility of blocking. This is not boolean for C-based ET system compatibility.
+     *  {@link org.jlab.coda.et.system.SystemCreate#systemLock}. */
+    private int mutex;
+
+    /** Station mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked} if
+     *  locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems, since in Java, mutexes cannot be tested without
+     *  possibility of blocking. This is not boolean for C-based ET system compatibility.
+     *  {@link org.jlab.coda.et.system.SystemCreate#stationLock}. */
+    private int statMutex;
+
+    /** Add-station mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems as this mutex is not used in Java systems. */
+    private int statAddMutex;
+
+
+    // values which do NOT change
+
+
+    /** Endian of host running the ET system. This can have values of either
+     * {@link org.jlab.coda.et.EtConstants#endianBig} or
+     * {@link org.jlab.coda.et.EtConstants#endianLittle}. */
+    private int endian;
+
+    /** Flag specifying whether the operating system can share mutexes between
+     *  processes. It has the value {@link org.jlab.coda.et.EtConstants#mutexShare} if they can be
+     *  shared and {@link org.jlab.coda.et.EtConstants#mutexNoShare} otherwise. This is not
+     *  relevant in Java-based ET systems. */
+    private int share;
+
+    /** Unix pid of the ET system process. This is not relevant for Java-based ET
+     *  systems, and C-based ET systems on Linux may have several pids. */
+    private int mainPid;
+
+    /** The number of ints in a station's select array.
+     *  @see org.jlab.coda.et.EtConstants#stationSelectInts */
+    private int selects;
+
+    /** Total number of events in a system.
+     *  @see org.jlab.coda.et.system.SystemConfig#numEvents
+     *  @see org.jlab.coda.et.system.SystemCreate#events */
+    private int events;
+
+    /** Size of "normal" events in bytes.
+     *  @see org.jlab.coda.et.system.SystemConfig#eventSize  */
+    private long eventSize;
+
+    /** Is the operating system running the ET system 64 bit? */
+    private boolean bit64;
+
+    /** Maximum number of temporary events allowed in the ET system.  This is not
+     *  relevant in Java-based ET systems. */
+    private int tempsMax;
+
+    /** Maximum number of stations allowed in the ET system.
+     *  @see org.jlab.coda.et.system.SystemConfig#stationsMax */
+    private int stationsMax;
+
+    /** Maximum number of attachments allowed in the ET system.
+     *  @see org.jlab.coda.et.system.SystemConfig#attachmentsMax */
+    private int attachmentsMax;
+
+    /** Maximum number of processes allowed in the ET system. This is not
+     *  relevant in Java-based ET systems. */
+    private int processesMax;
+
+
+    /** Port number of the ET TCP server.
+     *  @see org.jlab.coda.et.system.SystemConfig#serverPort */
+    private int tcpPort;
+
+    /** Port number of the ET UDP broadcast listening thread.
+     *  @see org.jlab.coda.et.system.SystemConfig#udpPort */
+    private int udpPort;
+
+    /** Port number of the ET UDP multicast listening thread.
+     *  @see org.jlab.coda.et.system.SystemConfig#multicastPort */
+    private int multicastPort;
+
+    /** Number of network interfaces on the host computer. */
+    private int interfaceCount;
+
+    /** Number of multicast addresses the UDP server listens on. */
+    private int multicastCount;
+
+    /** Dotted-decimal IP addresses of network interfaces on the host. */
+    private String interfaceAddresses[];
+
+    /** Dotted-decimal multicast addresses the UDP server listens on.
+     *  @see org.jlab.coda.et.system.SystemConfig#getMulticastStrings()
+     *  @see org.jlab.coda.et.system.SystemConfig#getMulticastAddrs()
+     *  @see org.jlab.coda.et.system.SystemConfig#addMulticastAddr(String)
+     *  @see org.jlab.coda.et.system.SystemConfig#removeMulticastAddr(String)  */
+    private String multicastAddresses[];
+
+    /** The ET system (file) name.
+     *  @see org.jlab.coda.et.system.SystemCreate#SystemCreate(String)
+     *  @see org.jlab.coda.et.system.SystemCreate#name */
+    private String etName;
+
+
+    // Getters
+
+
+    /** Specifies whether the ET system is alive.
+     *  @return <code>true</code> if ET system alive, else <code>false</code> */
+    public boolean alive() {return alive == 1;}
+
+    /** Get the heartbeat count of the ET system process. It is not relevant
+     *  in Java-based ET systems.
+     *  @return heartbeat count of the ET system process */
+    public int getHeartbeat() {return heartbeat;}
+
+    /** Get the current number of temporary events.
+     *  @return current number of temporary events */
+    public int getTemps() {return temps;}
+
+    /** Get the current number of stations in the linked list
+     * (either active or idle).
+     *  @return current number of stations in the linked list */
+    public int getStations() {return stations;}
+
+    /** Get the current number of attachments.
+     *  @return current number of attachments */
+    public int getAttachments() {return attachments;}
+
+    /** Get the current number of processes. It is not relevant in Java-based ET systems.
+     *  @return current number of processes */
+    public int getProcesses() {return processes;}
+
+    /** Get the number of events owned by the system (not by attachments).
+     *  @return number of events owned by the system */
+    public int getEventsOwned() {return eventsOwned;}
+
+
+    /** Get the system mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems as this mutex is not used in Java-based systems.
+     *  @return system mutex status */
+    public int getMutex() {return mutex;}
+
+    /** Get the station mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems as this mutex is not used in Java-based systems.
+     *  @return station mutex status */
+    public int getStatMutex() {return statMutex;}
+
+    /** Get the add-station mutex status. It has the value {@link org.jlab.coda.et.EtConstants#mutexLocked}
+     *  if locked and {@link org.jlab.coda.et.EtConstants#mutexUnlocked} otherwise. This is only
+     *  relevant in C-based ET systems as this mutex is not used in Java-based systems.
+     *  @return add-station mutex status */
+    public int getStatAddMutex() {return statAddMutex;}
+
+
+    /** Get the endian value of the host running the ET system.  This can
+     *  have values of either {@link org.jlab.coda.et.EtConstants#endianBig} or
+     *  {@link org.jlab.coda.et.EtConstants#endianLittle}.
+     *  @return endian value of the host running the ET system */
+    public int getEndian() {return endian;}
+
+    /** Get the value specifying whether the operating system can share
+     *  mutexes between processes. It has the value {@link org.jlab.coda.et.EtConstants#mutexShare}
+     *  if they can be shared and {@link org.jlab.coda.et.EtConstants#mutexNoShare} otherwise.
+     *  It is not relevant in Java ET systems.
+     *  @return value specifying whether the operating system can share
+     *          mutexes between processes */
+    public int getShare() {return share;}
+
+    /** Get the Unix pid of the ET system process. Java-based ET systems return
+     *  -1, and C-based ET systems on Linux may have several, additional pids
+     *  not given here.
+     *  @return Unix pid of the ET system process */
+    public int getMainPid() {return mainPid;}
+
+    /** Get the number of ints in a station's select array.
+     *  @return number of ints in a station's select array
+     *  @see org.jlab.coda.et.EtConstants#stationSelectInts */
+    public int getSelects() {return selects;}
+
+    /** Get the total number of events in a system.
+     *  @return total number of events in a system
+     *  @see org.jlab.coda.et.system.SystemConfig#numEvents
+     *  @see org.jlab.coda.et.system.SystemCreate#events */
+    public int getEvents() {return events;}
+
+    /** Get the size of "normal" events in bytes.
+     *  @return size of "normal" events in bytes
+     *  @see org.jlab.coda.et.system.SystemConfig#eventSize  */
+    public long getEventSize() {return eventSize;}
+
+    /** Gets whether the number of bits of the operating system running the ET system
+     *  is 64 bits. If not, then it's 32 bits.
+     *  @return <code>true</code> if the operating system running the ET system
+     *          is 64 bits, else <code>false</code> */
+    public boolean isBit64() {return bit64;}
+
+    /** Get the maximum number of temporary events allowed in the ET system.
+     *  This is not relevant in Java ET systems.
+     *  @return maximum number of temporary events allowed in the ET system */
+    public int getTempsMax() {return tempsMax;}
+
+    /** Get the maximum number of stations allowed in the ET system.
+     *  @return maximum number of stations allowed in the ET system
+     *  @see org.jlab.coda.et.system.SystemConfig#stationsMax */
+    public int getStationsMax() {return stationsMax;}
+
+    /** Get the maximum number of attachments allowed in the ET system.
+     *  @return maximum number of attachments allowed in the ET system
+     *  @see org.jlab.coda.et.system.SystemConfig#attachmentsMax */
+    public int getAttachmentsMax() {return attachmentsMax;}
+
+    /** Get the maximum number of processes allowed in the ET system.
+     *  @return maximum number of processes allowed in the ET system
+     *  This is not relevant in Java ET systems. */
+    public int getProcessesMax() {return processesMax;}
+
+
+    /** Get the port number of the ET TCP server.
+     *  @return port number of the ET TCP server
+     *  @see org.jlab.coda.et.system.SystemConfig#serverPort */
+    public int getTcpPort() {return tcpPort;}
+
+    /** Get the port number of the ET UDP broadcast listening thread.
+     *  @return port number of the ET UDP broadcase listening thread
+     *  @see org.jlab.coda.et.system.SystemConfig#udpPort */
+    public int getUdpPort() {return udpPort;}
+
+    /** Get the port number of the ET UDP multicast listening thread.
+     *  @return port number of the ET UDP multicast listening thread
+     *  @see org.jlab.coda.et.system.SystemConfig#multicastPort */
+    public int getMulticastPort() {return multicastPort;}
+
+    /** Get the number of network interfaces on the host computer.
+     *  @return number of network interfaces on the host computer */
+    public int getInterfaces() {return interfaceCount;}
+
+    /** Get the number of multicast addresses the UDP server listens on.
+     *  @return number of multicast addresses the UDP server listens on */
+    public int getMulticasts() {return multicastCount;}
+
+    /** Get the dotted-decimal IP addresses of network interfaces on the host.
+     *  @return dotted-decimal IP addresses of network interfaces on the host */
+    public String[] getInterfaceAddresses() {return interfaceAddresses.clone();}
+
+    /** Get the dotted-decimal multicast addresses the UDP server listens on.
+     *  @return dotted-decimal multicast addresses the UDP server listens on
+     *  @see org.jlab.coda.et.system.SystemConfig#getMulticastStrings()
+     *  @see org.jlab.coda.et.system.SystemConfig#getMulticastAddrs()
+     *  @see org.jlab.coda.et.system.SystemConfig#addMulticastAddr(String)
+     *  @see org.jlab.coda.et.system.SystemConfig#removeMulticastAddr(String)  */
+    public String[] getMulticastAddresses() {return multicastAddresses.clone();}
+
+    /** Get the ET system (file) name.
+     *  @return ET system (file) name
+     *  @see org.jlab.coda.et.system.SystemCreate#SystemCreate(String)
+     *  @see org.jlab.coda.et.system.SystemCreate#name */
+    public String getEtName() {return etName;}
+
+
+    /**
+     *  Reads the system level information from an ET system over the network.
+     *  @param dis data input stream
+     *  @throws IOException if data read error
+     */
+    public void read(DataInputStream dis) throws IOException {
+        int off = 0;
+        byte[] info = new byte[108];
+        dis.readFully(info);
+
+        alive          = EtUtils.bytesToInt(info, off);
+        heartbeat      = EtUtils.bytesToInt(info, off+=4);
+        temps          = EtUtils.bytesToInt(info, off+=4);
+        stations       = EtUtils.bytesToInt(info, off+=4);
+        attachments    = EtUtils.bytesToInt(info, off+=4);
+        processes      = EtUtils.bytesToInt(info, off+=4);
+        eventsOwned    = EtUtils.bytesToInt(info, off+=4);
+        mutex          = EtUtils.bytesToInt(info, off+=4);
+        statMutex      = EtUtils.bytesToInt(info, off+=4);
+        statAddMutex   = EtUtils.bytesToInt(info, off+=4);
+
+        endian         = EtUtils.bytesToInt(info, off+=4);
+        share          = EtUtils.bytesToInt(info, off+=4);
+        mainPid        = EtUtils.bytesToInt(info, off+=4);
+        selects        = EtUtils.bytesToInt(info, off+=4);
+        events         = EtUtils.bytesToInt(info, off+=4);
+        eventSize      = EtUtils.bytesToLong(info, off+=4);
+        bit64          = EtUtils.bytesToInt(info, off+=8) == 1;
+
+        tempsMax       = EtUtils.bytesToInt(info, off+=4);
+        stationsMax    = EtUtils.bytesToInt(info, off+=4);
+        attachmentsMax = EtUtils.bytesToInt(info, off+=4);
+        processesMax   = EtUtils.bytesToInt(info, off+=4);
+
+        tcpPort        = EtUtils.bytesToInt(info, off+=4);
+        udpPort        = EtUtils.bytesToInt(info, off+=4);
+        multicastPort  = EtUtils.bytesToInt(info, off+=4);
+
+        interfaceCount = EtUtils.bytesToInt(info, off+=4);
+        multicastCount = EtUtils.bytesToInt(info, off+=4);
+
+        // read string lengths first
+        off = 0;
+        int lengthTotal = 0;
+        int lengths[] = new int[interfaceCount+multicastCount+1];
+        for (int i=0; i < interfaceCount+multicastCount+1; i++) {
+            lengths[i]   = dis.readInt();
+            lengthTotal += lengths[i];
+        }
+
+        if (lengthTotal > 100) {
+            info = new byte[lengthTotal];
+        }
+        dis.readFully(info, 0, lengthTotal);
+
+        // read network interface addresses
+        interfaceAddresses = new String[interfaceCount];
+        for (int i=0; i < interfaceCount; i++) {
+            interfaceAddresses[i] = new String(info, off, lengths[i]-1, "US-ASCII");
+            off += lengths[i];
+        }
+
+        // read multicast addresses
+        multicastAddresses = new String[multicastCount];
+        for (int i=0; i < multicastCount; i++) {
+            multicastAddresses[i] = new String(info, off, lengths[i+interfaceCount]-1, "US-ASCII");
+            off += lengths[i+interfaceCount];
+        }
+
+        // read et name
+        etName = new String(info, off, lengths[interfaceCount+multicastCount]-1, "US-ASCII");
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/enums
Age.java added at 1.1
diff -N Age.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Age.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,79 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.enums;
+
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This enum indicates whether an event is a new or unused event, obtained by a call to
+ * {@link org.jlab.coda.et.EtSystem#newEvents}, or whether it is an existing or used event, obtained by
+ * a call to {@link org.jlab.coda.et.EtSystem#getEvents}.
+ *  
+ * @author timmer
+ */
+public enum Age {
+
+    /** Existing event with data, obtained throug getEvents(). */
+    USED     (EtConstants.eventUsed),
+    /** New event with no data, obtained throug newEvents(). */
+    NEW      (EtConstants.eventNew);
+
+    
+    private int value;
+
+    private Age(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the enum's value.
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Obtain the name from the value.
+     *
+     * @param value the value to match.
+     * @return the name, or null.
+     */
+    public static String getName(int value) {
+        Age ages[] = Age.values();
+        for (Age a : ages) {
+            if (a.value == value) {
+                return a.name();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Obtain the enum from the value.
+     *
+     * @param value the value to match.
+     * @return the matching enum, or <code>null</code>.
+     */
+    public static Age getAge(int value) {
+        Age ages[] = Age.values();
+        for (Age a : ages) {
+            if (a.value == value) {
+                return a;
+            }
+        }
+        return null;
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et/enums
DataStatus.java added at 1.1
diff -N DataStatus.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ DataStatus.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,80 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.enums;
+
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This enum represents the 3 possible states of an event's data's status.
+ * OK is default. CORRUPT is never used. POSSIBLYCORRUPT is assigned to events
+ * whose owning process crashed and were recovered by the system.
+ * 
+ * @author timmer
+ */
+public enum DataStatus {
+    /** Data is OK or uncorrupted. */
+    OK               (EtConstants.dataOk),
+    /** Data is worthless or corrupted. */
+    CORRUPT          (EtConstants.dataCorrupt),
+    /** Data status is unkown and might be corrupted. */
+    POSSIBLYCORRUPT  (EtConstants.dataPossiblyCorrupt);
+
+    private int value;
+
+    private DataStatus(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the enum's value.
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Obtain the name from the value.
+     *
+     * @param value the value to match.
+     * @return the name, or null.
+     */
+    public static String getName(int value) {
+        DataStatus stats[] = DataStatus.values();
+        for (DataStatus s : stats) {
+            if (s.value == value) {
+                return s.name();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Obtain the enum from the value.
+     *
+     * @param value the value to match.
+     * @return the matching enum, or <code>null</code>.
+     */
+    public static DataStatus getStatus(int value) {
+        DataStatus stats[] = DataStatus.values();
+        for (DataStatus s : stats) {
+            if (s.value == value) {
+                return s;
+            }
+        }
+        return null;
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/enums
Mode.java added at 1.1
diff -N Mode.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Mode.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,82 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.enums;
+
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This enum represents 3 possible modes in which to get new or existing events
+ * when no events are currently available (in calls newEvents() or getEvents()).
+ * SLEEP indicates that the user will wait (forever if necessary) until some
+ * are available. TIMED means the user will wait up to the given delay time, and
+ * ASYNC means that the call will return immediately.
+ *
+ * @author timmer
+ */
+public enum Mode {
+    /** Wait forever for events to become available. */
+    SLEEP   (EtConstants.sleep),
+    /** Wait up to a given delay time for events to become available. */
+    TIMED   (EtConstants.timed),
+    /** Do not wait for events to become available. */
+    ASYNC   (EtConstants.async);
+
+    private int value;
+
+    private Mode(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the enum's value.
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Obtain the name from the value.
+     *
+     * @param value the value to match.
+     * @return the name, or null.
+     */
+    public static String getName(int value) {
+        Mode modes[] = Mode.values();
+        for (Mode m : modes) {
+            if (m.value == value) {
+                return m.name();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Obtain the enum from the value.
+     *
+     * @param value the value to match.
+     * @return the matching enum, or <code>null</code>.
+     */
+    public static Mode getMode(int value) {
+        Mode modes[] = Mode.values();
+        for (Mode m : modes) {
+            if (m.value == value) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/enums
Modify.java added at 1.1
diff -N Modify.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Modify.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.enums;
+
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This enum represents the 3 possible modifications a networked user can make to
+ * an event. NOTHING means no changes will be made. HEADER means only information
+ * in the event header (non-data) will possibly be modified. ANYTHING means that either
+ * header or data will possibly be modified. If the user gets events in which NOTHING will
+ * be modified, the server sends a copy of the event to the user over the network
+ * and immediately puts the originals back into the system. This greatly increases
+ * performance.
+ *
+ * @author timmer
+ */
+public enum Modify {
+    /** Network user will make no changes to data or header (non-data). Event is readonly. */
+    NOTHING  (0),
+    /** Network user may make changes to data and/or header (non-data). Event is read-write. */
+    ANYTHING (EtConstants.modify),
+    /** Network user may make changes to header (non-data) only. */
+    HEADER   (EtConstants.modifyHeader);
+
+    private int value;
+
+    private Modify(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the enum's value.
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Obtain the name from the value.
+     *
+     * @param value the value to match.
+     * @return the name, or null.
+     */
+    public static String getName(int value) {
+        Modify mods[] = Modify.values();
+        for (Modify m : mods) {
+            if (m.value == value) {
+                return m.name();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Obtain the enum from the value.
+     *
+     * @param value the value to match.
+     * @return the matching enum, or <code>null</code>.
+     */
+    public static Modify getModify(int value) {
+        Modify mods[] = Modify.values();
+        for (Modify m : mods) {
+            if (m.value == value) {
+                return m;
+            }
+        }
+        return null;
+    }
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/enums
Priority.java added at 1.1
diff -N Priority.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Priority.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,76 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2010        Jefferson Science Associates,                   *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.enums;
+
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This enum represents the 2 possible priorities an event can have.
+ * Low is normal, but high puts events to the front of station input/output lists.
+ * @author timmer
+ */
+public enum Priority {
+    /** Low or normal priority, events take their proper turn. */
+    LOW      (EtConstants.low),
+    /** High priority, events cut in and move to the front of the list. */
+    HIGH     (EtConstants.high);
+
+    private int value;
+
+    private Priority(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the enum's value.
+     * @return the value
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Obtain the name from the value.
+     *
+     * @param value the value to match.
+     * @return the name, or null.
+     */
+    public static String getName(int value) {
+        Priority pris[] = Priority.values();
+        for (Priority p : pris) {
+            if (p.value == value) {
+                return p.name();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Obtain the enum from the value.
+     *
+     * @param value the value to match.
+     * @return the matching enum, or <code>null</code>.
+     */
+    public static Priority getPriority(int value) {
+        Priority pris[] = Priority.values();
+        for (Priority p : pris) {
+            if (p.value == value) {
+                return p;
+            }
+        }
+        return null;
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtBusyException.java added at 1.1
diff -N EtBusyException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtBusyException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents an error of an ET system when a user cannot access a
+ * station's input list because another thread or process is accessing it.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtBusyException extends Exception {
+
+    /**
+     * Create an exception indicating when a user cannot access a
+     * station's input list because another thread or process is accessing it.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtBusyException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtDeadException.java added at 1.1
diff -N EtDeadException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtDeadException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,20 @@
+package org.jlab.coda.et.exception;
+
+/**
+ * This class represents an error of an ET system when its processes are dead.
+ *
+ * @author Carl Timmer
+ */
+public class EtDeadException extends Exception {
+
+    /**
+     * Create an exception indicating an error of an ET system when its processes are dead.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtDeadException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtEmptyException.java added at 1.1
diff -N EtEmptyException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtEmptyException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents an error of an ET system when a station's input list
+ * is empty.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtEmptyException extends Exception {
+
+    /**
+     * Create an exception indicating an error of an ET system when a station's input list is empty.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtEmptyException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtException.java added at 1.1
diff -N EtException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents a general error of an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtException extends Exception {
+
+    /**
+     * Create an exception indicating an error specific to the ET system.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtExistsException.java added at 1.1
diff -N EtExistsException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtExistsException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,37 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents an error of an ET system when an item to be created
+ * already exists.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtExistsException extends Exception {
+
+    /**
+     * Create an exception indicating when an item to be created already exists.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtExistsException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtReadException.java added at 1.1
diff -N EtReadException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtReadException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents a network read error of an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtReadException extends Exception {
+
+    /**
+     * Create an exception indicating a network read error of an ET system.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtReadException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtTimeoutException.java added at 1.1
diff -N EtTimeoutException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtTimeoutException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents a timeout error of an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtTimeoutException extends Exception {
+
+    /**
+     * Create an exception indicating a timeout error of an ET system.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtTimeoutException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtTooManyException.java added at 1.1
diff -N EtTooManyException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtTooManyException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,39 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents an error of an ET system when creating an item would
+ * result in too many such items existing.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtTooManyException extends Exception {
+
+    /**
+     * Create an exception indicating an error of an ET system when
+     * creating an item would result in too many such items existing.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtTooManyException(String message) {
+        super(message);
+    }
+
+}
+

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtWakeUpException.java added at 1.1
diff -N EtWakeUpException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtWakeUpException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,38 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents an error of an ET system when an attachment has been
+ * told to wake up from a blocking read.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtWakeUpException extends Exception {
+
+    /**
+     * Create an exception indicating an error of an ET system
+     * when an attachment has been told to wake up from a blocking read.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtWakeUpException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/exception
EtWriteException.java added at 1.1
diff -N EtWriteException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EtWriteException.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.exception;
+import java.lang.*;
+
+/**
+ * This class represents a network write error of an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class EtWriteException extends Exception {
+
+    /**
+     * Create an exception indicating a network write error of an ET system.
+     * {@inheritDoc}<p/>
+     *
+     * @param message {@inheritDoc}<p/>
+     */
+    public EtWriteException(String message) {
+        super(message);
+    }
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
Monitor.java added at 1.1
diff -N Monitor.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Monitor.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,2048 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2002        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.monitorGui;
+
+import java.lang.*;
+import java.net.*;
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+import org.xml.sax.SAXException;
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.exception.*;
+
+/**
+ * This class implements a monitor of ET systems.
+ *
+ * @author Carl Timmer
+ */
+
+public class Monitor extends JFrame {
+    // static variables
+    private static MonitorConfiguration config;
+    private static File configurationFile;
+
+    // important widgets' names
+    private final JTabbedPane tabbedPane;
+    private final JFrame openFrame;
+    private final JMenu disconnectMenu, loadConnectionParametersMenu;
+    private JComboBox bAddress, mAddress, etName, hostname, cast;
+    private WholeNumberField ttl, udpPort, mcastPort, tcpPort, period;
+    private JButton connect;
+
+    // other variables
+    private String currentMonitorKey;
+    private int defaultPeriod;
+
+    // keep track of connections to & monitors of ET systems
+    public final Map<String, EtSystem> connections =
+            Collections.synchronizedMap(new HashMap<String, EtSystem>(20));
+    public final Map<String,MonitorSingleSystem> monitors =
+            Collections.synchronizedMap(new HashMap<String,MonitorSingleSystem>(20));
+
+    // Default colors
+    public final Color textColorDefault = Color.black;
+    public final Color textBackgroundColorDefault = Color.white;
+    public final Color titleColorDefault = Color.black;
+    public final Color backgroundColorDefault = new Color(238, 220, 130); // lightGoldenrod2
+    public final Color selectedTabColorDefault = Color.yellow;
+    public final Color tabsBackgroundColorDefault = Color.cyan;
+    // Colors used
+    private Color textColor = textColorDefault;
+    private Color textBackgroundColor = textBackgroundColorDefault;
+    private Color titleColor = titleColorDefault;
+    private Color backgroundColor = backgroundColorDefault;
+    private Color selectedTabColor = selectedTabColorDefault;
+    private Color tabsBackgroundColor = tabsBackgroundColorDefault;
+
+
+    public Monitor() {
+        this(null, null, null);
+    }
+
+
+    public Monitor(Color[] colors, Dimension frameSize, Point frameLocation) {
+        super("ET System Monitor");
+
+        // Set application colors.
+        if (colors != null) {
+            if (colors[0] != null) titleColor = colors[0];
+            if (colors[1] != null) backgroundColor = colors[1];
+            if (colors[2] != null) selectedTabColor = colors[2];
+            if (colors[3] != null) tabsBackgroundColor = colors[3];
+            if (colors[4] != null) textColor = colors[4];
+            if (colors[5] != null) textBackgroundColor = colors[5];
+        }
+        // Set window location.
+        if (frameLocation != null) {
+            setLocation(frameLocation);
+        }
+        // Default data update period in seconds.
+        defaultPeriod = 5;
+
+        // To change some colors, the following is the only way to do it.
+        UIManager.put("ComboBox.foreground", textColor);
+        UIManager.put("ComboBox.background", textBackgroundColor);
+        // UIManager.put("ComboBox.disabledForeground", Color.blue);
+        // UIManager.put("ComboBox.selectionForeground", Color.cyan);
+        // UIManager.put("ComboBox.selectionBackground", Color.magenta);
+
+        // tabbedPane stuff
+        UIManager.put("TabbedPane.selected", selectedTabColor);
+        tabbedPane = new JTabbedPane();
+        tabbedPane.setFont(MonitorFonts.buttonTabMenuFont);
+        tabbedPane.setBackground(backgroundColor);
+        tabbedPane.setForeground(titleColor);
+        if (frameSize == null) {
+            frameSize = new Dimension(1100, 700);
+        }
+        tabbedPane.setPreferredSize(frameSize);
+        // Keep track of which ET system we're currently looking at.
+        tabbedPane.addChangeListener(
+                new ChangeListener() {
+                    public void stateChanged(ChangeEvent e) {
+                        JTabbedPane source = (JTabbedPane) e.getSource();
+                        int tabIndex = source.getSelectedIndex();
+                        // if help pane is showing, reset period & return
+                        if (tabIndex < 1) {
+                            period.setValue(defaultPeriod);
+                            currentMonitorKey = "Help";
+                            return;
+                        }
+                        currentMonitorKey = source.getTitleAt(tabIndex);
+                        int updatePeriod = ((MonitorSingleSystem) (monitors.get(currentMonitorKey))).getUpdatePeriod();
+                        period.setValue(updatePeriod);
+                    }
+                }
+        );
+        getContentPane().setBackground(tabsBackgroundColor);
+        getContentPane().add(tabbedPane, BorderLayout.CENTER);
+
+        // Final members need to be initialized in all constructors.
+        openFrame = new JFrame("Open ET System");
+        disconnectMenu = new JMenu("Disconnect");
+        loadConnectionParametersMenu = new JMenu("Load Connection Parameters");
+
+        // Make window used to input data needed to connect to an ET system.
+        makeEtOpenWindow();
+        // Define this window's menubar.
+        makeMenubar();
+        // Add to help screen to main window's tabbed pane
+        tabbedPane.addTab("Help", null, makeHelpPane(), "help");
+        currentMonitorKey = "Help";
+    }
+
+    // Change the update period of current single system monitor.
+    private void setUpdatePeriod() {
+        if (currentMonitorKey.equals("Help")) return;
+        int updatePeriod = period.getValue();
+        MonitorSingleSystem mon = (MonitorSingleSystem) monitors.get(currentMonitorKey);
+        mon.setUpdatePeriod(updatePeriod);
+        return;
+    }
+
+    //===================
+    // Getters & Setters
+    //===================
+
+    // add ET file names to combo box
+    public void addFileName(String name) {
+        boolean nameIsThere = false;
+        int count = etName.getItemCount();
+
+        for (int i = 0; i < count; i++) {
+            if (name.equals((String) etName.getItemAt(i))) {
+                return;
+            }
+        }
+        if (!nameIsThere) {
+            etName.addItem(name);
+        }
+        return;
+    }
+
+    // add host names to combo box
+    public boolean addHostname(String name) {
+        if (name.equals(EtConstants.hostLocal) ||
+                name.equals(EtConstants.hostRemote) ||
+                name.equals(EtConstants.hostAnywhere)) {
+            return false;
+        }
+        boolean nameIsThere = false;
+        int count = hostname.getItemCount();
+        for (int i = 0; i < count; i++) {
+            if (name.equals((String) hostname.getItemAt(i))) {
+                return true;
+            }
+        }
+        if (!nameIsThere) {
+            hostname.addItem(name);
+        }
+        return true;
+    }
+
+    // add addresses to combo boxes
+    public void addBroadcastAddress(String addr) {
+        bAddress.addItem(addr);
+    }
+
+    public void addMulticastAddress(String addr) {
+        mAddress.addItem(addr);
+    }
+
+    //get ET names from combo box
+    public String[] getFileNames() {
+        int count = etName.getItemCount();
+        if (count == 0) return null;
+        String[] names = new String[count];
+        for (int i = 0; i < count; i++) {
+            names[i] = (String) etName.getItemAt(i);
+        }
+        return names;
+    }
+
+    //get host names from combo box
+    public String[] getHostnames() {
+        // Skip the first 3 items as they never change.
+        int count = hostname.getItemCount() - 3;
+        if (count < 1) return null;
+        String[] names = new String[count];
+        for (int i = 0; i < count; i++) {
+            names[i] = (String) hostname.getItemAt(i + 3);
+        }
+        return names;
+    }
+
+    public int getMonitorWidth() {
+        return tabbedPane.getWidth();
+    }
+
+    public int getMonitorHeight() {
+        return tabbedPane.getHeight();
+    }
+
+    public Color getTextColor() {
+        return new Color(textColor.getRGB());
+    }
+
+    public Color getTextBackgroundColor() {
+        return new Color(textBackgroundColor.getRGB());
+    }
+
+    public Color getTitleColor() {
+        return new Color(titleColor.getRGB());
+    }
+
+    public Color getBackgroundColor() {
+        return new Color(backgroundColor.getRGB());
+    }
+
+    public Color getSelectedTabColor() {
+        return new Color(selectedTabColor.getRGB());
+    }
+
+    public Color getTabsBackgroundColor() {
+        return new Color(tabsBackgroundColor.getRGB());
+    }
+
+    private boolean isValidIpAddress(String addr) {
+        StringTokenizer tok = new StringTokenizer(addr, ".");
+        if (tok.countTokens() != 4) {
+            return false;
+        }
+
+        int number;
+        String num;
+        try {
+            while (tok.hasMoreTokens()) {
+                num = tok.nextToken();
+                number = Integer.parseInt(num);
+                if (number < 0 || number > 255) {
+                    return false;
+                }
+                if (num.charAt(0) == '0' && (number != 0 || num.length() > 1)) {
+                    return false;
+                }
+            }
+        }
+        catch (NumberFormatException ex) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isValidMulticastAddress(String addr) {
+        InetAddress address = null;
+        try {
+            address = InetAddress.getByName(addr);
+        }
+        catch (UnknownHostException e) {
+            return false;
+        }
+
+        return (address.isMulticastAddress());
+
+        /*
+        StringTokenizer tok = new StringTokenizer(addr, ".");
+        if (tok.countTokens() != 4) {
+            return false;
+        }
+
+        int number, round = 1;
+        String num;
+        try {
+            while (tok.hasMoreTokens()) {
+                num = tok.nextToken();
+                number = Integer.parseInt(num);
+                if ((round++ == 1) && (number < 224 || number > 239)) {
+                    return false;
+                }
+                if (number < 0 || number > 255) {
+                    return false;
+                }
+                if (num.charAt(0) == '0' && (number != 0 || num.length() > 1)) {
+                    return false;
+                }
+            }
+        }
+        catch (NumberFormatException ex) {
+            return false;
+        }
+        return true;
+        */
+    }
+
+    public static void main(String[] args) {
+        try {
+            Monitor frame = null;
+
+            // allow for a configuration file argument
+            if (args.length > 0) {
+                if (args.length != 2) {
+                    System.out.println("Usage: java Monitor [-f,-file <configFile>]");
+                    return;
+                }
+                if (!(args[0].equalsIgnoreCase("-f") || args[0].equalsIgnoreCase("-file"))) {
+                    System.out.println("Usage: java Monitor [-f,-file <configFile>]");
+                    return;
+                }
+                configurationFile = new File(args[1]);
+
+                // Read config file once to get main application window &
+                // color data only.
+                // This is done because the frame needs to have the colors,
+                // size, and position BEFORE it displays anything.
+                config = new MonitorConfiguration(null);
+                config.loadWindowParameters(configurationFile);
+                Color[] colors = config.getWindowColors();
+                Dimension size = config.getWindowSize();
+                Point location = config.getWindowLocation();
+                frame = new Monitor(colors, size, location);
+                // Read config file again to get the rest of the data.
+                // This needs the application to have already started
+                // (as in the previous line) - the reason being that
+                // connections to ET systems need to be made etc.
+                config.setMonitor(frame);
+                config.load(configurationFile);
+            }
+            else {
+                frame = new Monitor();
+                config = new MonitorConfiguration(frame);
+            }
+            frame.addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent e) {
+                    System.exit(0);
+                }
+            });
+
+            frame.pack();
+            frame.setVisible(true);
+
+            MonitorSingleSystem mon = null;
+            DefaultMutableTreeNode monNode = null;
+
+            // Class designed to run graphics commands in the Swing thread.
+            class Updater extends Thread {
+                MonitorSingleSystem mon;  // single system monitor of interest
+
+                public void setMonitor(MonitorSingleSystem m) {
+                    mon = m;
+                }
+
+                public Updater(MonitorSingleSystem m) {
+                    mon = m;
+                }
+
+                public void run() {
+                    if (mon.isInitialized()) {
+                        mon.updateDisplay();
+                        mon.treeDidChange();
+                    }
+                    else {
+                        mon.staticDisplay();
+                        mon.updateDisplay();
+                        mon.updateUI();
+                    }
+                }
+            }
+
+            Updater updater = new Updater(mon);
+
+            while (true) {
+                // While we're in the iterator, we CANNOT have monitors added
+                // (and thereby change the structure of the HashMap).
+                synchronized (frame.monitors) {
+                    for (Iterator i = frame.monitors.entrySet().iterator(); i.hasNext();) {
+                        // get monitor object
+                        mon = (MonitorSingleSystem) (((Map.Entry) i.next()).getValue());
+                        monNode = mon.getNode();
+
+                        try {
+                            // only update if enough time has elapsed
+                            if (mon.timeToUpdate()) {
+                                // get data
+                                mon.getData();
+                                updater.setMonitor(mon);
+                                // display new data
+                                SwingUtilities.invokeLater(updater);
+                            }
+                        }
+                        catch (EtException ex) {
+                            //System.out.print("\n*****************************************\n");
+                            //System.out.print("*   Error getting data from ET system   *");
+                            //System.out.print("\n*****************************************\n");
+                            //ex.printStackTrace();
+                        }
+                        catch (Exception ex) {
+                            //System.out.print("\n*****************************************\n");
+                            //System.out.print("* I/O error getting data from ET system *");
+                            //System.out.print("\n*****************************************\n");
+                            String key = mon.getKey();
+                            // Remove connection with the IO problem.
+                            frame.removeConnection(frame, mon, key, false);
+                            // Remove single system monitor from hash table.
+                            i.remove();
+                            // Remove EtSystem object from hash table.
+                            frame.connections.remove(key);
+
+                            //ex.printStackTrace();
+                        }
+                    }
+                }
+                Thread.sleep(500);
+            }
+        }
+
+        catch (Exception ex) {
+            System.out.println("Unrecoverable error in ET monitor:");
+            ex.printStackTrace();
+        }
+
+    }
+
+
+    private void makeMenubar() {
+
+        JMenuBar menuBar = new JMenuBar();
+        menuBar.setBackground(backgroundColor);
+        setJMenuBar(menuBar);
+
+        // file menu
+        JMenu fileMenu = new JMenu("File");
+        fileMenu.setFont(MonitorFonts.buttonTabMenuFont);
+        fileMenu.setBackground(backgroundColor);
+        fileMenu.setForeground(titleColor);
+        menuBar.add(fileMenu);
+
+        // Create a file chooser
+        final JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
+
+        // file menu item to save configuration
+        JMenuItem menuItem = new JMenuItem("Save Configuration");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        fileMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        File file;
+                        if (configurationFile == null) {
+                            if (fc.showSaveDialog(Monitor.this) == JFileChooser.CANCEL_OPTION) {
+                                return;
+                            }
+                            file = fc.getSelectedFile();
+                        }
+                        else {
+                            file = configurationFile;
+                        }
+
+                        try {
+                            config.save(file);
+                        }
+                        catch (IOException ex) {
+                            JOptionPane.showMessageDialog(new JFrame(),
+                                                          "Cannot write to file \"" + file.getName() + "\"",
+                                                          "Error",
+                                                          JOptionPane.ERROR_MESSAGE);
+                            return;
+                        }
+                        configurationFile = file;
+
+                    }
+                }
+        );
+
+        // file menu item to save configuration
+        menuItem = new JMenuItem("Save Configuration As");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        fileMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        int returnVal = fc.showSaveDialog(Monitor.this);
+
+                        if (returnVal == JFileChooser.APPROVE_OPTION) {
+                            File file = fc.getSelectedFile();
+                            try {
+                                if (file.exists()) {
+                                    int n = JOptionPane.showConfirmDialog(
+                                            new JFrame(),
+                                            "Overwrite existing file?",
+                                            "WARNING",
+                                            JOptionPane.YES_NO_OPTION);
+                                    if (n == JOptionPane.NO_OPTION) return;
+                                }
+                                config.save(file);
+                            }
+                            catch (IOException ex) {
+                                JOptionPane.showMessageDialog(new JFrame(),
+                                                              "Cannot write to file \"" + file.getName() + "\"",
+                                                              "Error",
+                                                              JOptionPane.ERROR_MESSAGE);
+                                return;
+                            }
+                            configurationFile = file;
+                        }
+                    }
+                }
+        );
+
+        // file menu item to load configuration
+        menuItem = new JMenuItem("Load Configuration");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        fileMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        int returnVal = fc.showDialog(Monitor.this, "Load");
+
+                        if (returnVal == JFileChooser.APPROVE_OPTION) {
+                            File file = fc.getSelectedFile();
+                            try {
+                                config.load(file);
+                            }
+                            catch (SAXException ex) {
+                                JOptionPane.showMessageDialog(new JFrame(),
+                                                              "Cannot load file \"" + file.getName() + "\"",
+                                                              "Error",
+                                                              JOptionPane.ERROR_MESSAGE);
+                                return;
+                            }
+                            catch (IOException ex) {
+                                JOptionPane.showMessageDialog(new JFrame(),
+                                                              "Cannot load file \"" + file.getName() + "\"",
+                                                              "Error",
+                                                              JOptionPane.ERROR_MESSAGE);
+                                return;
+                            }
+                        }
+                    }
+                }
+        );
+
+        // File menu item to quit.
+        menuItem = new JMenuItem("Quit");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        fileMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        System.exit(0);
+                    }
+                }
+        );
+
+        // View menu to change update period of monitored ET system.
+        JMenu viewMenu = new JMenu("View");
+        viewMenu.setFont(MonitorFonts.buttonTabMenuFont);
+        viewMenu.setBackground(backgroundColor);
+        viewMenu.setForeground(titleColor);
+        menuBar.add(viewMenu);
+
+        period = new WholeNumberField(defaultPeriod, 5, 1, Integer.MAX_VALUE);
+        period.setFont(MonitorFonts.inputFont);
+        period.setAlignmentX(Component.LEFT_ALIGNMENT);
+        period.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                WholeNumberField source = (WholeNumberField) e.getSource();
+                source.correctValue();
+                setUpdatePeriod();
+            }
+        }
+        );
+        period.addMouseListener(new MouseAdapter() {
+            public void mouseExited(MouseEvent e) {
+                WholeNumberField source = (WholeNumberField) e.getSource();
+                source.correctValue();
+                setUpdatePeriod();
+            }
+        }
+        );
+
+        JMenu updatePeriod = new JMenu("Update Period (sec)");
+        updatePeriod.setFont(MonitorFonts.buttonTabMenuFont);
+        updatePeriod.setBackground(backgroundColor);
+        updatePeriod.setForeground(titleColor);
+        updatePeriod.add(period);
+        viewMenu.add(updatePeriod);
+
+        // menu to load connection parameters from a specific, existing connection
+        loadConnectionParametersMenu.setFont(MonitorFonts.buttonTabMenuFont);
+        loadConnectionParametersMenu.setBackground(backgroundColor);
+        loadConnectionParametersMenu.setForeground(titleColor);
+        viewMenu.add(loadConnectionParametersMenu);
+
+        // menuitem to switch JSplitPane orientation
+        menuItem = new JMenuItem("Change Orientation");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        viewMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        if (currentMonitorKey.equals("Help")) return;
+                        MonitorSingleSystem mon = (MonitorSingleSystem) monitors.get(currentMonitorKey);
+                        int orient = mon.getOrientation();
+                        if (orient == JSplitPane.HORIZONTAL_SPLIT) {
+                            mon.setOrientation(JSplitPane.VERTICAL_SPLIT);
+                        }
+                        else {
+                            mon.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+                        }
+                    }
+                }
+        );
+
+        // connect menu
+        JMenu connectMenu = new JMenu("Connections");
+        connectMenu.setFont(MonitorFonts.buttonTabMenuFont);
+        connectMenu.setBackground(backgroundColor);
+        connectMenu.setForeground(titleColor);
+        menuBar.add(connectMenu);
+
+        menuItem = new JMenuItem("Connect to ET System");
+        menuItem.setFont(MonitorFonts.buttonTabMenuFont);
+        menuItem.setBackground(backgroundColor);
+        menuItem.setForeground(titleColor);
+        connectMenu.add(menuItem);
+        menuItem.addActionListener(
+                new ActionListener() {
+                    public void actionPerformed(ActionEvent e) {
+                        openFrame.setVisible(true);
+                        openFrame.setState(Frame.NORMAL);
+                    }
+                }
+        );
+
+        // menu to disconnect existing connections
+        disconnectMenu.setFont(MonitorFonts.buttonTabMenuFont);
+        disconnectMenu.setBackground(backgroundColor);
+        disconnectMenu.setForeground(titleColor);
+        connectMenu.add(disconnectMenu);
+    }
+
+
+    private JScrollPane makeHelpPane() {
+        // Put this into the tabbedPane.
+        JTextArea text = new JTextArea(10, 200);
+        text.setFont(MonitorFonts.helpFont);
+        text.setLineWrap(true);
+        text.setWrapStyleWord(true);
+        text.setTabSize(3);
+        text.setEditable(false);
+        text.setBorder(new EmptyBorder(20, 20, 20, 20));
+        JScrollPane pane = new JScrollPane(text);
+
+        // Put stuff into the text area.
+        text.append(
+                "CONNECTING TO AN ET SYSTEM\n" +
+
+                        "Select the \"Connect to ET System\" option of the \"Connections\" menu. " +
+                        "There are a number of options on the appearing window which must be set.\n\n" +
+
+                        "1) ET Name\nThis is the name of the ET system (actually, its file) that you " +
+                        "want to connect to. The names of several ET systems can be stored in its " +
+                        "list. The \"X\" button is for removing unwanted entries.\n\n" +
+
+                        "2) ET Location\nTo look for the named ET system on the local computer or host, " +
+                        "select \"local\". To look only on another computer, select \"remote\", " +
+                        "or \"anywhere\" if you don't care where the ET system is. If you know the " +
+                        "name of the computer, this is the place to type it in.\n\n" +
+
+                        "3) Find ET by\n" +
+                        "There are several ways to connect to an ET system. The following list showing " +
+                        "the available choices:\n\n" +
+
+                        "\ta) broadcasting\nThis selection is generally chosen when the name of the host " +
+                        "that the ET system is residing on is unknown or if the user wants to write a very " +
+                        "general application with no hostnames \"hardcoded\" or input in some fashion. " +
+                        "(If a specific hostname is used, a UDP packet is sent directly to that host in " +
+                        "addition to a broadcast being made.)\n" +
+                        "A UDP broadcast is made on all the subnet broadcast addresses listed in the " +
+                        "\"Subnet Addresses\" entry. Items can be removed with the \"X\" button. " +
+                        "This broadcast is sent to the port found in the \"UDP Port\" entry. " +
+                        "Once an ET system receives the broadcast, it responds by sending its host name " +
+                        "and the tcp port on which it is listening. This information is used " +
+                        "to establish a permanent tcp connection.\n\n" +
+
+                        "\tb) multicasting\nAs in broadcasting, this selection is generally chosen when " +
+                        "the name of the host that the ET system is residing on is unknown or if the user " +
+                        "wants to write a very general application with no hostnames \"hardcoded\" or input " +
+                        "in some fashion. (If a specific hostname is used, a UDP packet is sent directly to " +
+                        "that host on the port in the \"UDP Port\" entry in addition to a multicast " +
+                        "being made.)\n" +
+                        "A UDP multicast is made on all the multicast addresses " +
+                        "listed in the \"Multicast Addresses\" entry. Items can be removed with the \"X\" " +
+                        "button. This multicast is sent to the port found in the \"Multicast Port\" " +
+                        "entry, and its \"ttl\" value can be set as well. (It defaults to \"1\" which " +
+                        "should limit its scope to the local subnets.) " +
+                        "Once an ET system receives the multicast, it responds by sending its host name " +
+                        "and the tcp port on which it is listening. This information is used " +
+                        "to establish a permanent tcp connection.\n\n" +
+
+                        "\tc) broad & multicasting\nThis selection can simultaneously UDP broadcast " +
+                        "and UDP multicast.\n\n" +
+
+                        "\td) direct connection\nA direct, permanent tcp connection is made between the ET " +
+                        "system and the user. In this case, a specific hostname must be used (not \"local\", " +
+                        "\"remote\", or \"anywhere\"). The \"TCP Port\" entry is used for the port number.\n\n" +
+
+                        "RESETTING CONNECTION PARAMETERS\n" +
+                        "Reseting all connection parameters to those previously used to make an actual " +
+                        "connection can be done by selecting the \"Load connection parameters\" item from " +
+                        "the \"View\" menu. Simply select from the list of existing connections.\n\n\n\n" +
+
+                        "VIEWING AN ET SYSTEM\n" +
+
+                        "After connecting to an ET system, a tab appears with the ET system's name on it. " +
+                        "By selecting this tab, the user can see all the system parameters in text form on " +
+                        "the left side of the window and a visual representation on the right side. Not all " +
+                        "text information is relevant for all systems. For example, the ET systems written in " +
+                        "Java do not have process or mutex information available. Text information " +
+                        "is divided into sections with a short explanation of each following:\n\n" +
+
+                        "1) System - general ET system parameters\n" +
+                        "\ta) Static Info - information that does NOT change\n" +
+                        "\t\tHost - host system is running on, language code was written in, and unix pid\n" +
+                        "\t\tPorts - the tcp, udp, and multicast port numbers\n" +
+                        "\t\tEvents - total # of events, size of each, # of temporary (extra large) events\n" +
+                        "\t\tMax - maximum number of stations, attachments, and processes allowed\n" +
+                        "\t\tNetwork interfaces - list of host's network interfaces\n" +
+                        "\t\tMulticast addreses - list of multicast addresses the system is listening on\n\n" +
+
+                        "\tb) Dynamic Info - information that can or will change in time\n" +
+                        "\t\tEvents rate - rate of events leaving GRAND_CENTRAL station\n" +
+                        "\t\tEvents owned by - number of events owned by each attachment & system.\n" +
+                        "\t\tIdle stations - list of stations with no attachments (receive no events)\n" +
+                        "\t\tAll stations - list of all stations in proper order\n" +
+                        "\t\tStations - current number of stations, attachments, and temporary events\n" +
+                        "\t\tProcesses - # of non-system, unix processes with access to shared memory (Solaris)\n" +
+                        "\t\tHeartbeat - value of non-Java system's counter in shared memory (changes if alive)\n" +
+                        "\t\tLocked Mutexes - on non-Java systems, locked pthread mutexes.\n\n" +
+
+                        "2) Stations - stations are listed by name under this heading\n" +
+                        "\ta) Configuration - parameters which define station behavior\n" +
+                        "\t\t- active or idle,  blocking or nonblocking,  prescale & cue values\n" +
+                        "\t\t- single user, multiple users, or the exact number of allowed users\n" +
+                        "\t\t- events restored to station's input, output, or to GRAND_CENTRAL station\n" +
+                        "\t\t- select all events, those matching default condition, or matching user condition\n" +
+                        "\t\t- values of integers in selection array\n" +
+                        "\t\t- class or library & function of user's matching condition\n\n" +
+
+                        "\tb) Statistics - \n" +
+                        "\t\t- total number of attachments and their id numbers\n" +
+                        "\t\t- current # of events in input list, total # put in input, # tried to put in input\n" +
+                        "\t\t- current # of events in output list, total # put in output list\n\n" +
+
+                        "3) Processes - on Solaris, local unix processes with attachments are listed by id #\n" +
+                        "\t- total # of attachments, list of attachments' ids, unix pid, current heartbeat value\n\n" +
+
+                        "4) Attachments - attachments are listed by their id numbers\n" +
+                        "\t- name of station attached to, host attachment is running on\n" +
+                        "\t- is attachment blocked waiting to read events?\n" +
+                        "\t- has attachment been told to quit reading events and return?\n" +
+                        "\t- unix pid and process id (non-Java)\n" +
+                        "\t- # events currently owned, total #: newly made, gotten, put, and dumped\n\n\n\n" +
+
+                        "SETTING AN UPDATE PERIOD\n" +
+                        "Each ET system has its information updated at a regular period which can be set " +
+                        "by selecting the \"View\" menu item and typing in the period value.\n\n\n\n" +
+
+                        "DISCONNECTING AN ET SYSTEM\n" +
+                        "Each ET system can be removed from the monitor by selecting the \"Connections\" " +
+                        "menu item followed by selecting the \"Disconnect\" item, and then selecting the " +
+                        "system to be removed.\n\n\n\n" +
+
+                        "CONFIGURATION FILES\n" +
+                        "Configuration files can be created, saved, and loaded through the \"File\" menu item. " +
+                        "The configuration files are in XML format and use a schema defined in " +
+                        "the file \"monitorConfiguration.xsd\". Without going into great detail, configuration " +
+                        "files store all current connections and the current state of the application. Colors " +
+                        "used in this application, as well as the " +
+                        "main window's size and placement, can be set in the configuration file. These particular " +
+                        "parameters, however, will only be set in the application if the configuration file is " +
+                        "given on the command line (-f or -file). Once the monitor is up and running, loading a " +
+                        "configuration file simply adds any additional ET system connections listed there as well " +
+                        "as adding items to the \"ET Name\" or \"ET Location\" lists.\n\n" +
+
+                        "Setting colors in a configuration file can only be done by hand-editing it. Modifying the colors " +
+                        "in the main application can be done by inserting the following lines (without the explanation) " +
+                        "in any order, under the \"<graphics>\" element. Simply change the red, green, and blue " +
+                        "values (between 0 and 255 inclusive) to suit:\n\n" +
+
+                        "\tText on menus, titles, buttons, tabs (default black):\n" +
+                        "\t\t<titleColor  red=\"0\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tGeneral background: (default lightGoldenrod2)\n" +
+                        "\t\t<backgroundColor  red=\"238\" green=\"220\" blue=\"130\"/>\n\n" +
+                        "\tSelected tab background (default yellow):\n" +
+                        "\t\t<selectedTabColor  red=\"255\" green=\"255\" blue=\"0\"/>\n\n" +
+                        "\tBehind all tabs background (default cyan):\n" +
+                        "\t\t<tabsBackgroundColor  red=\"150\" green=\"255\" blue=\"255\"/>\n\n" +
+                        "\tText in entry widgets (default black):\n" +
+                        "\t\t<textColor  red=\"0\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tText entry widget background (default white):\n" +
+                        "\t\t<textBackgroundColor  red=\"255\" green=\"255\" blue=\"255\"/>\n\n" +
+
+                        "Colors may also be changed in the view of a monitored ET system. To do so, the following " +
+                        "lines may be added. HOWEVER, THEY MAY ONLY BE ADDED AT THE END OF EACH \"<etConnection>\" " +
+                        "ELEMENT AND ONLY IN THE GIVEN ORDER:\n\n" +
+
+                        "\tEvents (default red):\n" +
+                        "\t\t<eventColor  red=\"255\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tStations Active (default cyan):\n" +
+                        "\t\t<stationColor  red=\"0\" green=\"255\" blue=\"255\"/>\n\n" +
+                        "\tStations Idle (default pink):\n" +
+                        "\t\t<stationIdleColor  red=\"255\" green=\"192\" blue=\"203\"/>\n\n" +
+                        "\tAttachments (default magenta):\n" +
+                        "\t\t<attachmentColor  red=\"255\" green=\"0\" blue=\"255\"/>\n\n" +
+                        "\tLines between stations and attachments (default black):\n" +
+                        "\t\t<lineColor  red=\"0\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tText in stations and attachments (default black):\n" +
+                        "\t\t<textColor  red=\"0\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tStation and attachment text background (default white):\n" +
+                        "\t\t<textBackgroundColor  red=\"255\" green=\"255\" blue=\"255\"/>\n\n" +
+                        "\tGraph background (default white):\n" +
+                        "\t\t<backgroundColor  red=\"255\" green=\"255\" blue=\"255\"/>\n\n" +
+                        "\tText of tree widget (default black):\n" +
+                        "\t\t<treeTextColor  red=\"0\" green=\"0\" blue=\"0\"/>\n\n" +
+                        "\tTree widget background (default white):\n" +
+                        "\t\t<treeBackgroundColor  red=\"255\" green=\"255\" blue=\"255\"/>"
+
+        );
+        return pane;
+    }
+
+
+    private void makeEtOpenWindow() {
+        // widget sizes & spacings
+        int edge1 = 20,
+                edge2 = 10,
+                edge3 = 5,
+                prefWidth = 500,
+                maxWidth = 800,
+                indent = 15,
+                horSpace = 10,
+                verSpace = 10,
+                prefRemBut = 50,
+                maxRemBut = 70,
+                prefHeight1 = 50,
+                maxHeight = 60,
+                prefHeight2 = 40;
+        // convenient sizes
+        int prefHalf = prefWidth / 2 - edge2 - horSpace / 2,
+                maxHalf = maxWidth / 2 - edge2 - horSpace / 2;
+
+        // Several combo boxes use this to filter input.
+        ActionListener al = new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                JComboBox jcb = (JComboBox) e.getSource();
+                String listItem;
+                String selectedItem = (String) jcb.getSelectedItem();
+                int numItems = jcb.getItemCount();
+                boolean addNewItem = true;
+
+                if (selectedItem == null || selectedItem.equals("")) {
+                    addNewItem = false;
+                }
+                else if (numItems == 0) {
+                    addNewItem = true;
+                }
+                else {
+                    for (int i = 0; i < numItems; i++) {
+                        listItem = (String) jcb.getItemAt(i);
+                        if (listItem.equals(selectedItem) == true) {
+                            addNewItem = false;
+                            break;
+                        }
+                    }
+                }
+
+                if (addNewItem) {
+                    jcb.addItem(selectedItem);
+                }
+            }
+        };
+
+        // put main panel into one main window
+        JPanel openPanel = new JPanel();
+        openPanel.setBackground(backgroundColor);
+        openPanel.setLayout(new BoxLayout(openPanel, BoxLayout.Y_AXIS));
+        openPanel.setBorder(new EmptyBorder(edge1, edge1, edge1, edge1));
+
+        // setting ET name
+        TitledBorder border1 = new TitledBorder(new EmptyBorder(0, 0, 0, 0),
+                                                "ET Name",
+                                                TitledBorder.LEFT,
+                                                TitledBorder.ABOVE_TOP,
+                                                MonitorFonts.titleFont,
+                                                titleColor);
+
+        JPanel p1 = new JPanel();
+        p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
+        p1.setBorder(border1);
+        p1.setBackground(backgroundColor);
+        p1.setPreferredSize(new Dimension(prefWidth, prefHeight1 + edge3));
+        p1.setMaximumSize(new Dimension(maxWidth, maxHeight + edge3));
+        p1.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+        etName = new JComboBox();
+        etName.setBackground(textBackgroundColor);
+        etName.setEditable(true);
+        etName.setFont(MonitorFonts.inputFont);
+        etName.setAlignmentX(Component.CENTER_ALIGNMENT);
+        etName.setPreferredSize(new Dimension(prefWidth - indent, prefHeight1));
+        etName.setMaximumSize(new Dimension(maxWidth - indent, maxHeight));
+        etName.addActionListener(al);
+        // Set editable comboBox colors
+        Component c = etName.getEditor().getEditorComponent();
+        c.setBackground(textBackgroundColor);
+        c.setForeground(textColor);
+
+        // button for ET name removal
+        final JButton removeName = new JButton("X");
+        removeName.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                int index = etName.getSelectedIndex();
+                if (index > -1) {
+                    etName.removeItemAt(index);
+                }
+            }
+        });
+        removeName.setAlignmentX(Component.LEFT_ALIGNMENT);
+        removeName.setForeground(titleColor);
+        removeName.setBackground(backgroundColor);
+        removeName.setPreferredSize(new Dimension(prefRemBut, prefHeight2));
+        removeName.setMaximumSize(new Dimension(maxRemBut, maxHeight));
+
+        p1.add(Box.createRigidArea(new Dimension(indent, 0)));
+        p1.add(etName);
+        p1.add(removeName);
+
+        // setting ET location
+        TitledBorder border2 = new TitledBorder(new EmptyBorder(0, 0, 0, 0),
+                                                "ET Location",
+                                                TitledBorder.LEFT,
+                                                TitledBorder.ABOVE_TOP,
+                                                MonitorFonts.titleFont,
+                                                titleColor);
+
+        JPanel p2 = new JPanel();
+        p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
[truncated at 1000 lines; 1052 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
MonitorConfiguration.java added at 1.1
diff -N MonitorConfiguration.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MonitorConfiguration.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,814 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2002        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.monitorGui;
+
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import javax.swing.JSplitPane;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.XMLConstants;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.exception.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A SAX2 ContentHandler.
+ *
+ */
+public class MonitorConfiguration extends DefaultHandler {
+    // Defaults
+    private SAXParser parser;
+    private static boolean setValidation        = true;
+    private static boolean setNameSpaces        = true;
+    private static boolean setSchemaSupport     = true;
+    private static boolean setSchemaFullSupport = true;
+    
+    private StringBuffer buffer = new StringBuffer(100);
+    private HashMap<String,Object>  dataStorage = new HashMap<String,Object>(100);
+    
+    private Monitor   monitor;
+    private boolean   isColor;
+    private boolean   readWindowParametersOnly;
+    private boolean   finishedReadingWindowParameters;
+    private String    currentElement;
+    private String    findMethod;
+    private Color[]   mainColors = new Color[6];
+    private Point     windowLocation;
+    private Dimension windowSize;
+    
+
+    /** Constructor. */
+    public MonitorConfiguration(Monitor mon) {
+        monitor = mon;
+	
+        // Use the validating parser
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = null;
+        try {
+            schema = sf.newSchema(new File("monitorConfiguration.xsd"));
+        }
+        catch (SAXException e) {
+            e.printStackTrace();
+        }
+
+        factory.setSchema(schema);
+
+        // Parse the input
+        try {
+            parser = factory.newSAXParser();
+        }
+        catch (ParserConfigurationException e) {
+            e.printStackTrace();
+        }
+        catch (SAXException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    
+
+    public void setMonitor(Monitor mon) {monitor = mon;}
+    
+    // Methods for getting application window & color data from
+    // window parameter reading of config file.
+    public Point getWindowLocation() {return new Point(windowLocation);}
+    public Dimension getWindowSize() {return new Dimension(windowSize);}
+    public Color[] getWindowColors() {return mainColors.clone();}
+    
+    // Methods for parsing window & color data from config file.
+    public void loadWindowParameters(File file) throws IOException, SAXException {
+      loadWindowParameters(file.getPath());
+    }
+    public void loadWindowParameters(String fileName) throws IOException, SAXException {
+        File f = new File(fileName);
+
+        readWindowParametersOnly = true;
+        parser.parse(f,this);
+        readWindowParametersOnly = false;
+        finishedReadingWindowParameters = false;
+        return;
+    }
+    
+    // Methods for reading the rest of the config information.
+    public void load(String fileName) throws IOException, SAXException {
+        File f = new File(fileName);
+        parser.parse(f, this);
+    }
+    public void load(File file) throws IOException, SAXException {
+      load(file.getPath());
+    }
+
+
+    //=============================
+    // SAX DocumentHandler methods
+    //=============================
+    // Start element.
+    public void startElement(String uri, String local, String qname,
+                             Attributes attrs) {
+        // keep track of the current element
+        currentElement = local;
+        // If we're setting a color, its attributes give red, green, & blue.
+        if (local.indexOf("Color") > -1) {
+            try {
+                // Get rgb components.
+                Color c = new Color(Integer.parseInt(attrs.getValue("red")),
+                                    Integer.parseInt(attrs.getValue("green")),
+                                    Integer.parseInt(attrs.getValue("blue")));
+                dataStorage.put(currentElement, c);
+                isColor = true;
+            }
+            catch (NumberFormatException ex) {
+            }
+        }
+        // Keep track of method used to find ET system.
+        else if (local.equals("broadcasting") ||
+                local.equals("multicasting") ||
+                local.equals("broadAndMulticasting") ||
+                local.equals("direct") ||
+                local.equals("udpToHost")) {
+            findMethod = currentElement;
+        }
+    }
+
+    // Characters. This may be called more than once for each item.
+    public void characters(char ch[], int start, int length) {
+      if (finishedReadingWindowParameters || ch == null || length == 0) {
+        return;
+      }
+      // put data into a buffer
+      buffer.append(ch, start, length);
+    }
+    
+    
+    // End element. Note that white space is ignored when validating an element's
+    // value. So, white space gets passed on to the user and must be trimmed off.
+    public void endElement(String uri, String local, String qname) {
+        if (finishedReadingWindowParameters) {
+            return;
+        }
+
+        if (isColor) {
+            isColor = false;
+        }
+        else if (buffer.length() > 0) {
+            // put data (as string) into hash table
+            dataStorage.put(currentElement, buffer.toString());
+            // erase buffer for next element
+            buffer.setLength(0);
+        }
+
+        // adjust GUI parameters
+        if (local.equals("graphics")) {
+            // First, handle case of only reading main application's window's parameters.
+            if (readWindowParametersOnly) {
+                // optional elements
+                if (dataStorage.containsKey("titleColor")) {
+                    mainColors[0] = (Color) dataStorage.get("titleColor");
+                }
+                if (dataStorage.containsKey("backgroundColor")) {
+                    mainColors[1] = (Color) dataStorage.get("backgroundColor");
+                }
+                if (dataStorage.containsKey("selectedTabColor")) {
+                    mainColors[2] = (Color) dataStorage.get("selectedTabColor");
+                }
+                if (dataStorage.containsKey("tabsBackgroundColor")) {
+                    mainColors[3] = (Color) dataStorage.get("tabsBackgroundColor");
+                }
+                if (dataStorage.containsKey("textColor")) {
+                    mainColors[4] = (Color) dataStorage.get("textColor");
+                }
+                if (dataStorage.containsKey("textBackgroundColor")) {
+                    mainColors[5] = (Color) dataStorage.get("textBackgroundColor");
+                }
+
+                // mandatory elements
+                int w = Integer.parseInt(((String) dataStorage.get("width")).trim());
+                int h = Integer.parseInt(((String) dataStorage.get("height")).trim());
+                int x = Integer.parseInt(((String) dataStorage.get("xPosition")).trim());
+                int y = Integer.parseInt(((String) dataStorage.get("yPosition")).trim());
+                windowLocation = new Point(x, y);
+                windowSize = new Dimension(w, h);
+                finishedReadingWindowParameters = true;
+
+                dataStorage.clear();
+                return;
+            }
+
+            // optional elements
+            if (dataStorage.containsKey("fileNameList")) {
+                // Divide list - items separated by white space - into component parts.
+                StringTokenizer tok = new StringTokenizer((String) dataStorage.get("fileNameList"));
+                while (tok.hasMoreTokens()) {
+                    monitor.addFileName(tok.nextToken());
+                }
+            }
+            if (dataStorage.containsKey("hostList")) {
+                StringTokenizer tok = new StringTokenizer((String) dataStorage.get("hostList"));
+                while (tok.hasMoreTokens()) {
+                    monitor.addHostname(tok.nextToken());
+                }
+            }
+
+            dataStorage.clear();
+        }
+
+        // try to make connection to ET system
+        else if (local.equals("etConnection")) {
+            String etSystem = (String) dataStorage.get("fileName");
+            int period = Integer.parseInt((String) dataStorage.get("period"));
+            int divider = Integer.parseInt((String) dataStorage.get("dividerPosition"));
+            int orientation = JSplitPane.HORIZONTAL_SPLIT;
+            if (((String) dataStorage.get("orientation")).equals("vertical")) {
+                orientation = JSplitPane.VERTICAL_SPLIT;
+            }
+
+            Color[] colors = new Color[10];
+            if (dataStorage.containsKey("stationColor")) {
+                colors[0] = (Color) dataStorage.get("stationColor");
+            }
+            if (dataStorage.containsKey("stationIdleColor")) {
+                colors[1] = (Color) dataStorage.get("stationIdleColor");
+            }
+            if (dataStorage.containsKey("attachmentColor")) {
+                colors[2] = (Color) dataStorage.get("attachmentColor");
+            }
+            if (dataStorage.containsKey("eventColor")) {
+                colors[3] = (Color) dataStorage.get("eventColor");
+            }
+            if (dataStorage.containsKey("lineColor")) {
+                colors[4] = (Color) dataStorage.get("lineColor");
+            }
+            if (dataStorage.containsKey("textColor")) {
+                colors[5] = (Color) dataStorage.get("textColor");
+            }
+            if (dataStorage.containsKey("textBackgroundColor")) {
+                colors[6] = (Color) dataStorage.get("textBackgroundColor");
+            }
+            if (dataStorage.containsKey("backgroundColor")) {
+                colors[7] = (Color) dataStorage.get("backgroundColor");
+            }
+            if (dataStorage.containsKey("treeTextColor")) {
+                colors[8] = (Color) dataStorage.get("treeTextColor");
+            }
+            if (dataStorage.containsKey("treeBackgroundColor")) {
+                colors[9] = (Color) dataStorage.get("treeBackgroundColor");
+            }
+
+            int index = 0, ttl = 0, dummy = 11111;
+            int broadcastPort = 0, multicastPort = 0, port = 0;
+            String host = null;
+            EtSystemOpenConfig config = null;
+
+            try {
+                if (findMethod.equals("broadcasting")) {
+                    if (dataStorage.containsKey("location")) {
+                        host = (String) dataStorage.get("location");
+                        if (host.equals("local")) {
+                            host = EtConstants.hostLocal;
+                        }
+                        else if (host.equals("remote")) {
+                            host = EtConstants.hostRemote;
+                        }
+                        else {
+                            host = EtConstants.hostAnywhere;
+                        }
+                    }
+                    else {
+                        host = (String) dataStorage.get("host");
+                        monitor.addHostname(host);
+                    }
+                    broadcastPort = Integer.parseInt((String) dataStorage.get("broadcastPort"));
+                    // Can dispense with the address list which now only contains "255.255.255.255"
+                    StringTokenizer tok = new StringTokenizer((String) dataStorage.get("broadcastAddressList"));
+                    String[] addrs = new String[tok.countTokens()];
+                    while (tok.hasMoreTokens()) {
+                        addrs[index++] = tok.nextToken();
+                    }
+                    config = new EtSystemOpenConfig(etSystem, broadcastPort, host);
+                }
+                else if (findMethod.equals("multicasting")) {
+                    if (dataStorage.containsKey("location")) {
+                        host = (String) dataStorage.get("location");
+                        if (host.equals("local")) {
+                            host = EtConstants.hostLocal;
+                        }
+                        else if (host.equals("remote")) {
+                            host = EtConstants.hostRemote;
+                        }
+                        else {
+                            host = EtConstants.hostAnywhere;
+                        }
+                    }
+                    else {
+                        host = (String) dataStorage.get("host");
+                        monitor.addHostname(host);
+                    }
+                    ttl = Integer.parseInt((String) dataStorage.get("ttl"));
+                    multicastPort = Integer.parseInt((String) dataStorage.get("multicastPort"));
+                    StringTokenizer tok = new StringTokenizer((String) dataStorage.get("multicastAddressList"));
+                    String[] addrs = new String[tok.countTokens()];
+                    while (tok.hasMoreTokens()) {
+                        addrs[index++] = tok.nextToken();
+                    }
+
+                    int udpPort = EtConstants.broadcastPort;
+                    if (dataStorage.containsKey("udpPort")) {
+                        udpPort = Integer.parseInt((String) dataStorage.get("udpPort"));
+                    }
+                    config = new EtSystemOpenConfig(etSystem, host,
+                                                  Arrays.asList(addrs),
+                                                  udpPort, multicastPort, ttl);
+                }
+                else if (findMethod.equals("broadAndMulticasting")) {
+                    if (dataStorage.containsKey("location")) {
+                        host = (String) dataStorage.get("location");
+                        if (host.equals("local")) {
+                            host = EtConstants.hostLocal;
+                        }
+                        else if (host.equals("remote")) {
+                            host = EtConstants.hostRemote;
+                        }
+                        else {
+                            host = EtConstants.hostAnywhere;
+                        }
+                    }
+                    else {
+                        host = (String) dataStorage.get("host");
+                        monitor.addHostname(host);
+                    }
+                    ttl = Integer.parseInt((String) dataStorage.get("ttl"));
+                    broadcastPort = Integer.parseInt((String) dataStorage.get("broadcastPort"));
+                    multicastPort = Integer.parseInt((String) dataStorage.get("multicastPort"));
+                    StringTokenizer tok = new StringTokenizer((String) dataStorage.get("broadcastAddressList"));
+                    String[] bAddrs = new String[tok.countTokens()];
+                    while (tok.hasMoreTokens()) {
+                        bAddrs[index++] = tok.nextToken();
+                    }
+                    index = 0;
+                    tok = new StringTokenizer((String) dataStorage.get("multicastAddressList"));
+                    String[] mAddrs = new String[tok.countTokens()];
+                    while (tok.hasMoreTokens()) {
+                        mAddrs[index++] = tok.nextToken();
+                    }
+                    config = new EtSystemOpenConfig(etSystem, host, null,
+                                                    Arrays.asList(mAddrs), true,
+                                                    EtConstants.broadAndMulticast,
+                                                    dummy, broadcastPort, multicastPort, ttl,
+                                                    EtConstants.policyError);
+                }
+                else if (findMethod.equals("direct")) {
+                    if (dataStorage.containsKey("location")) {
+                        host = (String) dataStorage.get("location");
+                        if (host.equals("local")) {
+                            host = EtConstants.hostLocal;
+                        }
+                    }
+                    else {
+                        host = (String) dataStorage.get("host");
+                        monitor.addHostname(host);
+                    }
+                    port = Integer.parseInt((String) dataStorage.get("tcpPort"));
+                    config = new EtSystemOpenConfig(etSystem, host, port);
+                }
+
+            }
+            catch (EtException ex) {
+                // Should never occur. All problems should be caught by schema validation.
+            }
+
+            monitor.addFileName(etSystem);
+            monitor.addEtSystem(config, period, divider, orientation, colors);
+            dataStorage.clear();
+        }
+    }
+
+
+    // Warning.
+    public void warning(SAXParseException ex) {
+        System.err.println("[Warning] "+
+                           getLocationString(ex)+": "+
+                           ex.getMessage());
+    }
+
+
+    // Error.
+    public void error(SAXParseException ex) throws SAXException {
+        System.err.println("[Error] "+
+                           getLocationString(ex)+": "+
+                           ex.getMessage());
+        throw ex;
+    }
+
+
+    // Fatal error.
+    public void fatalError(SAXParseException ex) throws SAXException {
+        System.err.println("[Fatal Error] "+
+                           getLocationString(ex)+": "+
+                           ex.getMessage());
+        throw ex;
+    }
+
+    //===================================
+    // End of SAX DocumentHandler methods
+    //===================================
+    
+    
+
+    // Returns a string of the location.
+    private String getLocationString(SAXParseException ex) {
+        StringBuffer str = new StringBuffer();
+        String systemId  = ex.getSystemId();
+        if (systemId != null) {
+            int index = systemId.lastIndexOf('/');
+            if (index != -1)
+                systemId = systemId.substring(index + 1);
+            str.append(systemId);
+        }
+        str.append(": line ");
+        str.append(ex.getLineNumber());
+        str.append(" :col ");
+        str.append(ex.getColumnNumber());
+
+        return str.toString();
+    }
+
+    
+    // Saves data nto a proper xml format configuration file.
+    public void save(File file) throws FileNotFoundException {
+      String fileName = file.getPath();
+      try {
+	FileOutputStream fos   = new FileOutputStream(fileName);
+	OutputStreamWriter osw = new OutputStreamWriter(fos, "ASCII");
+
+	StringBuffer text = new StringBuffer(1000);
+
+	// Configuration file is in XML format.
+	text.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
+        text.append("<configuration xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+	text.append("            xsi:noNamespaceSchemaLocation=\"monitorConfiguration.xsd\">\n\n");
+        text.append("  <graphics>\n    <width>");
+	text.append(monitor.getMonitorWidth());
+	text.append("</width>\n    <height>");
+	text.append(monitor.getMonitorHeight());
+	text.append("</height>\n    <xPosition>");
+	text.append(monitor.getX());
+	text.append("</xPosition>\n    <yPosition>");
+	text.append(monitor.getY());
+	text.append("</yPosition>\n");
+	
+	// Only put non-default colors into config file.
+	Color monColor = monitor.getTitleColor();
+	if (monColor.getRGB() != monitor.titleColorDefault.getRGB()) {
+	  text.append("    <titleColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	monColor = monitor.getBackgroundColor();
+	if (monColor.getRGB() != monitor.backgroundColorDefault.getRGB()) {
+	  text.append("    <backgroundColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	monColor = monitor.getSelectedTabColor();
+	if (monColor.getRGB() != monitor.selectedTabColorDefault.getRGB()) {
+	  text.append("    <selectedTabColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	monColor = monitor.getTabsBackgroundColor();
+	if (monColor.getRGB() != monitor.tabsBackgroundColorDefault.getRGB()) {
+	  text.append("    <tabsBackgroundColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	monColor = monitor.getTextBackgroundColor();
+	if (monColor.getRGB() != monitor.textBackgroundColorDefault.getRGB()) {
+	  text.append("    <textBackgroundColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	monColor = monitor.getTextColor();
+	if (monColor.getRGB() != monitor.textColorDefault.getRGB()) {
+	  text.append("    <textColor red=\"");
+	  text.append(monColor.getRed());
+	  text.append("\" green=\"");
+	  text.append(monColor.getGreen());
+	  text.append("\" blue=\"");
+	  text.append(monColor.getBlue());
+	  text.append("\"/>\n");
+	}
+	
+	osw.write(text.toString());
+	text.setLength(0);
+
+	// Lists of host and ET names
+	String[] names = monitor.getHostnames();
+	if (names != null) {
+	  text.append("    <hostList>");
+	  for (int i=0; i < names.length; i++) {
+	    text.append("\n      ");
+	    text.append(names[i]);
+	  }
+	  text.append("\n    </hostList>\n");
+	}
+		
+	names = monitor.getFileNames();
+	if (names != null) {
+	  text.append("    <fileNameList>");
+	  for (int i=0; i < names.length; i++) {
+	    text.append("\n      ");
+	    text.append(names[i]);
+	  }
+	  text.append("\n    </fileNameList>\n");
+	}
+	text.append("  </graphics>\n\n");
+	
+	osw.write(text.toString());
+	text.setLength(0);
+
+	// Connections to ET systems
+	String key;
+	EtSystem use=null;
+	EtSystemOpenConfig config;
+    for (Map.Entry<String, EtSystem> entry : monitor.connections.entrySet()) {
+      // Get object with connection info in it.
+	  use = entry.getValue();
+	  key = entry.getKey();
+	  config = use.getConfig();
+	  
+	  text.append("  <etConnection>\n    <fileName>");
+	  // ET name.
+	  text.append(config.getEtName());
+	  text.append("</fileName>\n");
+	  
+	  // Method of finding ET system.
+	  int method = config.getNetworkContactMethod();
+	  if (method == EtConstants.broadcast) {
+	      text.append("    <broadcasting>\n");
+	      // Location or host?
+	      String host = config.getHost();
+	      if (host.equals(EtConstants.hostLocal)) {
+		    text.append("      <location>local</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostRemote)) {
+		    text.append("      <location>remote</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostAnywhere)) {
+		    text.append("      <location>anywhere</location>\n");
+	      }
+	      else {
+        	text.append("      <host>");
+		    text.append(host);
+        	text.append("</host>\n");
+	      }
+	      // List of subnet addresses to broadcast on.
+	      text.append("      <broadcastAddressList>");
+		  text.append("\n        255.255.255.255");
+	      text.append("\n      </broadcastAddressList>\n      <broadcastPort>");
+	      text.append(config.getUdpPort());
+	      text.append("</broadcastPort>\n    </broadcasting>\n");
+	  }
+	  else if (method == EtConstants.multicast) {
+	      text.append("    <multicasting>\n");
+	      // Location or host?
+	      String host = config.getHost();
+	      if (host.equals(EtConstants.hostLocal)) {
+		text.append("      <location>local</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostRemote)) {
+		text.append("      <location>remote</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostAnywhere)) {
+		text.append("      <location>anywhere</location>\n");
+	      }
+	      else {
+        	text.append("      <host>");
+		text.append(host);
+        	text.append("</host>\n");
+	      }
+	      // List of multicast addresses to multicast on.
+	      text.append("      <multicastAddressList>");
+	      for (Iterator j=config.getMulticastAddrs().iterator(); j.hasNext();) {
+		text.append("\n        ");
+		text.append((String)j.next());
+	      }
+	      text.append("\n      </multicastAddressList>\n      <multicastPort>");
+	      text.append(config.getMulticastPort());
+	      text.append("</multicastPort>\n      <ttl>");
+	      text.append(config.getTTL());
+	      text.append("</ttl>\n    </multicasting>\n");
+	  }
+	  else if (method == EtConstants.broadAndMulticast) {
+	      text.append("    <broadAndMulticasting>\n");
+	      // Location or host?
+	      String host = config.getHost();
+	      if (host.equals(EtConstants.hostLocal)) {
+		text.append("      <location>local</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostRemote)) {
+		text.append("      <location>remote</location>\n");
+	      }
+	      else if (host.equals(EtConstants.hostAnywhere)) {
+		text.append("      <location>anywhere</location>\n");
+	      }
+	      else {
+        	text.append("      <host>");
+		text.append(host);
+        	text.append("</host>\n");
+	      }
+	      // List of subnet addresses to broadcast on.
+	      text.append("      <broadcastAddressList>");
+          text.append("\n        255.255.255.255");
+	      text.append("\n      </broadcastAddressList>\n      <broadcastPort>");
+	      text.append(config.getUdpPort());
+	      text.append("</broadcastPort>\n");
+	      // List of multicast addresses to multicast on.
+	      text.append("      <multicastAddressList>");
+	      for (Iterator j=config.getMulticastAddrs().iterator(); j.hasNext();) {
+		text.append("\n        ");
+		text.append((String)j.next());
+	      }
+	      text.append("\n      </multicastAddressList>\n      <multicastPort>");
+	      text.append(config.getMulticastPort());
+	      text.append("</multicastPort>\n      <ttl>");
+	      text.append(config.getTTL());
+	      text.append("</ttl>\n    </broadAndMulticasting>\n");
+	  }
+	  else if (method == EtConstants.direct) {
+	      text.append("    <direct>\n");
+	      String host = config.getHost();
+	      if (host.equals(EtConstants.hostLocal)) {
+		text.append("      <location>local</location>\n");
+	      }
+	      else {
+        	text.append("      <host>");
+		text.append(host);
+        	text.append("</host>\n");
+	      }
+              text.append("      <tcpPort>");
+	      text.append(config.getTcpPort());
+	      text.append("</tcpPort>\n");
+	      text.append("    </direct>\n");
+	  }
+	  else {
+	      text.append("    <udpToHost>\n");
+	      String host = config.getHost();
+	      if (host.equals(EtConstants.hostLocal)) {
+		text.append("      <location>local</location>\n");
+	      }
+	      else {
+        	text.append("      <host>");
+		text.append(host);
+        	text.append("</host>\n");
+	      }
+              text.append("      <udpPort>");
+	      text.append(config.getUdpPort());
+	      text.append("</udpPort>\n");
+	      text.append("    </udpToHost>\n");
+	  }
+	  
+	  // Update period & splitPane divider position & orientation
+      MonitorSingleSystem singleMonitor = monitor.monitors.get(key);
+	  text.append("    <period>");
+	  text.append(singleMonitor.getUpdatePeriod());
+	  text.append("</period>\n    <dividerPosition>");
+	  text.append(singleMonitor.getDividerPosition());
+	  text.append("</dividerPosition>\n    <orientation>");
+	  if (singleMonitor.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
+	    text.append("horizontal");
+	  }
+	  else {
+	    text.append("vertical");
+	  }
+	  text.append("</orientation>\n");
+	  
+	  // Only put non-default colors into config file.
+	  monColor = singleMonitor.getEventColor();
+	  if (monColor.getRGB() != singleMonitor.eventColorDefault.getRGB()) {
+	    text.append("    <eventColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getStationColor();
+	  if (monColor.getRGB() != singleMonitor.stationColorDefault.getRGB()) {
+	    text.append("    <stationColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getStationIdleColor();
+	  if (monColor.getRGB() != singleMonitor.stationIdleColorDefault.getRGB()) {
+	    text.append("    <stationIdleColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getAttachmentColor();
+	  if (monColor.getRGB() != singleMonitor.attachColorDefault.getRGB()) {
+	    text.append("    <attachmentColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getLineColor();
+	  if (monColor.getRGB() != singleMonitor.lineColorDefault.getRGB()) {
+	    text.append("    <lineColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getTextColor();
+	  if (monColor.getRGB() != singleMonitor.textColorDefault.getRGB()) {
+	    text.append("    <textColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  monColor = singleMonitor.getTextBackgroundColor();
+	  if (monColor.getRGB() != singleMonitor.textBackgroundColorDefault.getRGB()) {
+	    text.append("    <textBackgroundColor red=\"");
+	    text.append(monColor.getRed());
+	    text.append("\" green=\"");
+	    text.append(monColor.getGreen());
+	    text.append("\" blue=\"");
+	    text.append(monColor.getBlue());
+	    text.append("\"/>\n");
+	  }
+	  
+	  text.append("  </etConnection>\n\n");
+	  osw.write(text.toString());
+	  text.setLength(0);
+	}
+	
+	text.append("</configuration>\n");
+	
+	osw.write(text.toString());
+	osw.close();
+	fos.close();
+      }
+      catch (UnsupportedEncodingException ex) {}
+      catch (IOException ex) {}
+    }
+   
+    
+}

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
MonitorFonts.java added at 1.1
diff -N MonitorFonts.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MonitorFonts.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,36 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2002        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.monitorGui;
+
+import java.lang.*;
+import java.awt.*;
+
+public class MonitorFonts {
+  // cannot construct object
+  private MonitorFonts () {
+  }
+
+  private static final Font default30 = new Font((String)null, Font.BOLD,  30);
+  private static final Font default16 = new Font((String)null, Font.BOLD,  16);
+  private static final Font default14 = new Font((String)null, Font.BOLD,  14);
+  private static final Font default12 = new Font((String)null, Font.PLAIN, 12);
+  
+  public  static final Font titleFont = default16;
+  public  static final Font inputFont = default14;
+  public  static final Font helpFont  = default12;
+  public  static final Font treeFont  = default12;
+  public  static final Font graphFont = null;
+  public  static final Font buttonTabMenuFont = default14;
+}

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
MonitorSingleSystem.java added at 1.1
diff -N MonitorSingleSystem.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ MonitorSingleSystem.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,1826 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2002        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.monitorGui;
+
+import java.lang.*;
+import java.io.*;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.data.*;
+import org.jlab.coda.et.exception.*;
+import com.loox.jloox.*;
+import com.loox.jloox.layout.*;
+
+/**
+ * This class implements a view of a single ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class MonitorSingleSystem {
+    // general stuff
+    private int        updatePeriod; // in seconds
+    private int        dividerPosition, graphHeight, orientation;
+    private double     attWidth, stationWidth, stationGap;
+    private String     key;
+    private EtSystem   sys;
+    private AllData    data;
+    private boolean    initialized, updated;
+    private boolean    isSolaris, isJava, isLinux;
+    private boolean    debug = false;
+
+    // rate stuff
+    private long  rate, prevGcOut, time1, time2, updateTime;
+    private final JSplitPane splitPane;
+    private JScrollPane graphPane;
+
+    // tree stuff
+    private final JTree tree;
+    private final DefaultTreeModel treeModel;
+
+    // JLoox widgets
+    private final LxView  view;
+    private final LxGraph graph;
+    private final LxAlignLayout layout;
+    private final LxLink mainLink1, mainLink2;
+
+    // nodes
+    private final DefaultMutableTreeNode topNode;
+    private final DefaultMutableTreeNode systemNode;
+    private final DefaultMutableTreeNode systemStaticNode;
+    private final DefaultMutableTreeNode systemDynamicNode;
+    private final DefaultMutableTreeNode stationNode;
+    private final DefaultMutableTreeNode attachNode;
+    private final DefaultMutableTreeNode processNode;
+
+    // object storage
+    private final HashMap    stations;
+    private final HashMap    attachments;
+    // private final HashMap    stationIcons;
+    private final HashMap    attachIcons;
+    private final LinkedList stationManagers;
+    private final LinkedList parallelManagers;
+
+    // Default colors
+    public final Color stationColorDefault        = Color.cyan;
+    public final Color stationIdleColorDefault    = Color.pink;
+    public final Color attachColorDefault         = new Color(255, 200 , 255);
+    public final Color eventColorDefault          = Color.red;
+    public final Color lineColorDefault           = Color.black;
+    public final Color textColorDefault           = Color.black;
+    public final Color textBackgroundColorDefault = Color.white;
+    public final Color backgroundColorDefault     = Color.white;
+    public final Color treeTextColorDefault       = Color.black;
+    public final Color treeBackgroundColorDefault = Color.white;
+    // Colors used
+    private Color stationColor        = stationColorDefault;
+    private Color stationIdleColor    = stationIdleColorDefault;
+    private Color attachColor         = attachColorDefault;
+    private Color eventColor          = eventColorDefault;
+    private Color lineColor           = lineColorDefault;
+    private Color textColor           = textColorDefault;
+    private Color textBackgroundColor = textBackgroundColorDefault;
+    private Color backgroundColor     = backgroundColorDefault;
+    private Color treeTextColor       = treeTextColorDefault;
+    private Color treeBackgroundColor = treeBackgroundColorDefault;
+
+    // Define constants
+    public static final boolean HORIZONTAL = true;
+    public static final boolean VERTICAL   = false;
+
+    // class to hold flow data needed for graphical station layout
+    class StationFlowData {
+        int flowMode;
+        boolean isHead;
+        LxAlignLayout parentLayout;
+    }
+    // class to hold link data needed for graphical station drawing
+    class StationLinkData {
+        LxLink link1;
+        LxLink link2;
+        public StationLinkData(LxLink l1) {
+            link1 = l1;
+        }
+        public StationLinkData(LxLink l1, LxLink l2) {
+            link1 = l1;
+            link2 = l2;
+        }
+    }
+
+    // Constructor
+    public MonitorSingleSystem(EtSystem use, JTabbedPane tabbedPane,
+                               int period) {
+        this(use, tabbedPane, period, tabbedPane.getWidth()/2,
+             JSplitPane.HORIZONTAL_SPLIT, null);
+    }
+
+    public MonitorSingleSystem(EtSystem use, JTabbedPane tabbedPane,
+                               int period, int divider,
+                               int orient, Color[] colors) {
+        sys  = use;
+        data = new AllData();
+        updatePeriod = period;
+        dividerPosition = divider;
+
+        if (colors != null) {
+            if (colors[0] != null) stationColor        = colors[0];
+            if (colors[1] != null) stationIdleColor    = colors[1];
+            if (colors[2] != null) attachColor         = colors[2];
+            if (colors[3] != null) eventColor          = colors[3];
+            if (colors[4] != null) lineColor           = colors[4];
+            if (colors[5] != null) textColor           = colors[5];
+            if (colors[6] != null) textBackgroundColor = colors[6];
+            if (colors[7] != null) backgroundColor     = colors[7];
+            if (colors[8] != null) treeTextColor       = colors[8];
+            if (colors[9] != null) treeBackgroundColor = colors[9];
+        }
+
+        // Create unique name for this ET system - used as key in
+        // Monitor's hash tables.
+        EtSystemOpenConfig config = sys.getConfig();
+        if (sys.getHost().indexOf(".") < 0) {
+            key = new String(config.getEtName() + " (" + sys.getHost() + ")");
+        }
+        else {
+            key = new String(config.getEtName() +
+                             " (" + sys.getHost().substring(0, sys.getHost().indexOf(".")) + ")");
+        }
+
+        // Create static tree nodes.
+        topNode           = new DefaultMutableTreeNode(key);
+        systemNode        = new DefaultMutableTreeNode("System");
+        systemStaticNode  = new DefaultMutableTreeNode("Static Info");
+        systemDynamicNode = new DefaultMutableTreeNode("Dynamic Info");
+        stationNode       = new DefaultMutableTreeNode("Stations");
+        attachNode        = new DefaultMutableTreeNode("Attachments");
+        processNode       = new DefaultMutableTreeNode("Proceses");
+        topNode.add(systemNode);
+        systemNode.add(systemStaticNode);
+        systemNode.add(systemDynamicNode);
+        topNode.add(stationNode);
+        topNode.add(attachNode);
+
+        // Create a tree that allows one selection at a time.
+        treeModel = new DefaultTreeModel(topNode);
+        tree      = new JTree(treeModel);
+        tree.setFont(MonitorFonts.treeFont);
+        tree.setBackground(treeBackgroundColor);
+        tree.setForeground(treeTextColor);
+        tree.setDoubleBuffered(true);
+        tree.setLargeModel(true);
+        tree.getSelectionModel().setSelectionMode
+                (TreeSelectionModel.SINGLE_TREE_SELECTION);
+        tree.putClientProperty("JTree.lineStyle", "Angled");
+        // Get rid of tree's leaf icon.
+        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
+        renderer.setLeafIcon(null);
+        renderer.setBackgroundNonSelectionColor(treeBackgroundColor);
+        renderer.setTextNonSelectionColor(treeTextColor);
+        tree.setCellRenderer(renderer);
+
+        // Create the scroll pane and add the tree to it.
+        JScrollPane treePane = new JScrollPane(tree);
+
+        // Graphics panel
+        graph = new LxGraph();
+        // Make graph visible
+        view = (LxView)graph.addView();
+        // Allow user to interact with the objects in EDITOR_MODE
+        view.setEditMode(LxView.STANDARD_MODE);
+        if (debug) {
+            view.setEditMode(LxView.EDITOR_MODE);
+        }
+        // Allow smoother graphics
+        view.setAntialiasingActivated(true);
+        view.setDoubleBuffered(true);
+        // Scrollbars appear when smaller than preferred size.
+        // The preferred width must be reset according to the
+        // number & size of station graphics.
+        graphHeight = 304;
+        view.setPreferredSize(new Dimension(500, graphHeight));
+        view.setBackground(backgroundColor);
+
+        // Create scroll pane and add graph to it.
+        graphPane = new JScrollPane();
+        graphPane.setViewportView(view);
+
+        // Add the split pane to this frame.
+        orientation = orient;
+        splitPane = new JSplitPane(orient);
+        splitPane.setLeftComponent(treePane);
+        splitPane.setRightComponent(graphPane);
+        // Ignored in some releases of Swing. bug 4101306
+        splitPane.setDividerLocation(dividerPosition);
+        // Workaround for bug 4101306:
+        // treePane.setPreferredSize(new Dimension(100, 100));
+        splitPane.setPreferredSize(new Dimension(1100, 700));
+
+        // Add to main window's tabbed pane
+        tabbedPane.addTab(key, null, splitPane, "monitored ET system");
+
+        // JLoox layout of graphics
+        layout = new LxAlignLayout(new Rectangle2D.Double(0., 0., 600., (double)graphHeight));
+        layout.setOrder(LxAlignLayout.LIST_ORDER);
+        layout.setOrientation(LxAlignLayout.HORIZONTAL);
+        layout.setAlignAxisMethod(LxAlignLayout.EVEN_USE_SIZE_METHOD);
+        layout.setNormalAxisMethod(LxAlignLayout.LEFT_TOP_METHOD);
+        layout.setVisible(true);
+        if (debug) {
+            graph.add(layout);
+        }
+
+        // Store objects for future use (more efficient
+        // than always recreating objects)
+        int size1 = EtConstants.defaultStationsMax,
+            size2 = EtConstants.defaultAttsMax;
+        try {
+            size1 = sys.getStationsMax();
+            size2 = sys.getAttachmentsMax();
+        }
+        catch (IOException ex) {
+        }
+        catch (EtException ex) {
+        }
+
+        float loadfactor = 0.75F;
+        stations         = new HashMap(size1, loadfactor);
+        attachments      = new HashMap(size2, loadfactor);
+        //stationIcons     = new HashMap(size1, loadfactor);
+        attachIcons      = new HashMap(size2, loadfactor);
+        stationManagers  = new LinkedList();
+        parallelManagers = new LinkedList();
+        mainLink1        = new LxLink();
+        mainLink2        = new LxLink();
+        mainLink1.setLineArrow(LxArrowElement.ARROW_END);
+        mainLink1.setLineThickness(2.f);
+        mainLink1.setLineColor(lineColor);
+        mainLink2.setLineArrow(LxArrowElement.ARROW_MIDDLE);
+        mainLink2.setLineThickness(2.f);
+        mainLink2.setLineColor(lineColor);
+        mainLink1.setName("link1");
+        mainLink2.setName("link2");
+    }
+
+
+    // Setters, getters, etc.
+    public void setOrientation(int orient) {
+        if (orient == orientation) {
+            return;
+        }
+        splitPane.setOrientation(orient);
+
+        if (orient == JSplitPane.HORIZONTAL_SPLIT) {
+            splitPane.setDividerLocation(dividerPosition);
+            orientation = JSplitPane.HORIZONTAL_SPLIT;
+        }
+        else {
+            // Give bottom window just enough room to view graph
+            // unless the window is too small. In that case split it.
+            int height = splitPane.getHeight();
+            height = (height < 2*(graphHeight+50)) ? height/2 : height-(graphHeight + 50);
+            splitPane.setDividerLocation(height);
+            orientation = JSplitPane.VERTICAL_SPLIT;
+        }
+        splitPane.updateUI();
+    }
+
+    public int getOrientation() {return orientation;}
+
+    public boolean timeToUpdate() {
+        long currentTime = System.currentTimeMillis();
+        if ((currentTime - updateTime) > 1000*updatePeriod) {
+            return true;
+        }
+        return false;
+    }
+
+    public void setUpdatePeriod(int period) {
+        updatePeriod = (period < 1) ? 1 : period;
+    }
+
+    public int  getUpdatePeriod()     {return updatePeriod;}
+    public int  getDividerPosition()  {return splitPane.getDividerLocation();}
+    public Component getDisplayPane() {return splitPane;}
+    public void treeDidChange()       {tree.treeDidChange();}
+    public void updateUI()            {tree.updateUI();}
+    public boolean isInitialized()    {return initialized;}
+    public boolean isUpdated()        {return updated;}
+    public DefaultMutableTreeNode getNode() {return topNode;}
+    public void getData() throws EtException, IOException {
+        data = sys.getData();
+    }
+    public void   close()  {sys.close();}
+    public String getKey() {return key;}
+
+    public Color getEventColor()          {return new Color(eventColor.getRGB());}
+    public Color getStationColor()        {return new Color(stationColor.getRGB());}
+    public Color getStationIdleColor()    {return new Color(stationIdleColor.getRGB());}
+    public Color getAttachmentColor()     {return new Color(attachColor.getRGB());}
+    public Color getLineColor()           {return new Color(lineColor.getRGB());}
+    public Color getTextColor()           {return new Color(textColor.getRGB());}
+    public Color getTextBackgroundColor() {return new Color(textBackgroundColor.getRGB());}
+
+
+    public void staticDisplay()
+    {
+        int           end = 499;
+        StringBuffer  str = new StringBuffer(500);
+
+        // Display static system data
+        str.append("Host = ");
+        str.append(sys.getHost());
+        int lang = sys.getLanguage();
+        if (lang != EtConstants.langJava) {
+            str.append(",  language = C,  pid = ");
+            str.append(data.sysData.getMainPid());
+            // processes exist on Solaris only
+            if (data.sysData.getShare() == EtConstants.mutexShare) {
+                isSolaris = true;
+                topNode.add(processNode);
+            }
+            else {
+                isLinux = true;
+            }
+        }
+        else {
+            isJava = true;
+            str.append(",  language = Java");
+        }
+        if (data.sysData.isBit64()) {
+            str.append(", bits = 64");
+        }
+        else {
+            str.append(", bits = 32");
+
+        }
+        systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+
+        str.delete(0, end);
+        str.append("Ports: tcp = ");
+        str.append(data.sysData.getTcpPort());
+        str.append(", udp = ");
+        str.append(data.sysData.getUdpPort());
+        str.append(", mcast = ");
+        str.append(data.sysData.getMulticastPort());
+        systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+
+        str.delete(0, end);
+        str.append("Events: total = ");
+        str.append(data.sysData.getEvents());
+        str.append(", size = ");
+        str.append(data.sysData.getEventSize());
+        str.append(" bytes, temps = ");
+        str.append(data.sysData.getTempsMax());
+        systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+
+        str.delete(0, end);
+        str.append("Max #: stations = ");
+        str.append(data.sysData.getStationsMax());
+        str.append(", attachments = ");
+        str.append(data.sysData.getAttachmentsMax());
+        if (isSolaris) {
+            str.append(", processes = ");
+            str.append(data.sysData.getProcessesMax());
+        }
+        systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+
+        str.delete(0, end);
+        if (data.sysData.getInterfaces() > 0) {
+            str.append("Network interfaces: ");
+            int limit = data.sysData.getInterfaces();
+            for (int i=0; i < limit; i++) {
+                str.append(data.sysData.getInterfaceAddresses()[i]);
+                if (i == limit-1) break;
+                str.append(", ");
+            }
+        }
+        else {
+            str.append("network interfaces(0): none");
+        }
+        systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+
+        if (data.sysData.getMulticasts() > 0) {
+            str.delete(0, end);
+            str.append("Multicast addresses: ");
+            int limit = data.sysData.getMulticasts();
+            for (int i=0; i < limit; i++) {
+                str.append(data.sysData.getMulticastAddresses()[i]);
+                if (i == limit-1) break;
+                str.append(", ");
+            }
+            systemStaticNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+        initialized = true;
+        return;
+    }
+
+
+    public void updateDisplay()
+    {
+        int           end = 499;
+        int[]         kids3 = {0, 1, 2},  kids4 = {1, 2, 3, 4};
+        int[]         kids6 = {1, 2, 3, 4, 5, 6};
+        Integer       attId;
+        boolean       blocking=false, isNewNode=false;
+        String        statName;
+        StringBuffer  str = new StringBuffer(end+1);
+        DefaultMutableTreeNode node = null, leaf = null;
+        DefaultMutableTreeNode statsNode = null, configNode = null;
+        // Update system info
+
+        // Event rate
+        if (!updated) {
+            time1 = System.currentTimeMillis();
+            str.append("Event rate = ");
+            str.append(rate);
+            str.append(" Hz");
+            systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+
+        str.delete(0, end);
+        str.append("Events owned by: ");
+        str.append(" sys (");
+        str.append(data.sysData.getEventsOwned());
+        str.append("), atts ");
+        for (int i=0; i < data.attData.length; i++) {
+            str.append(data.attData[i].getId());
+            str.append("(");
+            str.append(data.attData[i].getEventsOwned());
+            str.append(")");
+            if (i == data.attData.length - 1) break;
+            str.append(", ");
+        }
+        if (updated) {
+            leaf = systemDynamicNode.getFirstLeaf().getNextLeaf();
+            leaf.setUserObject(str.toString());
+        }
+        else {
+            systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+        // idle stations
+        str.delete(0, end);
+        str.append("Idle stations: ");
+        boolean gotNone = true;
+        for (int i=0; i < data.statData.length; i++) {
+            if (data.statData[i].getStatus() == EtConstants.stationIdle) {
+                str.append(data.statData[i].getName());
+                str.append(", ");
+                gotNone = false;
+            }
+        }
+        if (gotNone) {
+            str.append("none");
+        }
+        if (updated) {
+            leaf = leaf.getNextLeaf();
+            leaf.setUserObject(str.toString());
+        }
+        else {
+            systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+
+        // stations linked list
+        str.delete(0, end);
+        str.append("All stations: ");
+        for (int i=0; i < data.statData.length; i++) {
+            str.append(data.statData[i].getName());
+            if (i == data.statData.length - 1) break;
+            str.append(", ");
+        }
+        if (updated) {
+            leaf = leaf.getNextLeaf();
+            leaf.setUserObject(str.toString());
+        }
+        else {
+            systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+        str.delete(0, end);
+        str.append("Stations =");
+        str.append(data.sysData.getStations());
+        str.append(", attachments = ");
+        str.append(data.sysData.getAttachments());
+        str.append(", temp events = ");
+        str.append(data.sysData.getTemps());
+        if (updated) {
+            leaf = leaf.getNextLeaf();
+            leaf.setUserObject(str.toString());
+        }
+        else {
+            systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+        }
+
+        if (!isJava) {
+            str.delete(0, end);
+            str.append("Processes = ");
+            str.append(data.sysData.getProcesses());
+            str.append(", hearbeat = ");
+            str.append(data.sysData.getHeartbeat());
+            if (updated) {
+                leaf = leaf.getNextLeaf();
+                leaf.setUserObject(str.toString());
+            }
+            else {
+                systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+            }
+
+            // mutexes
+            str.delete(0, end);
+            str.append("Locked mutexes: ");
+            if (data.sysData.getMutex() == EtConstants.mutexLocked)
+                str.append("sys, ");
+            if (data.sysData.getStatMutex() == EtConstants.mutexLocked)
+                str.append("stat, ");
+            if (data.sysData.getStatAddMutex() == EtConstants.mutexLocked)
+                str.append("add_stat, ");
+
+            for (int i=0; i < data.statData.length; i++) {
+                if (data.statData[i].getMutex() == EtConstants.mutexLocked) {
+                    str.append(data.statData[i].getName());
+                    str.append(", ");
+                }
+                if (data.statData[i].getInListMutex() == EtConstants.mutexLocked) {
+                    str.append(data.statData[i].getName());
+                    str.append("-in, ");
+                }
+                if (data.statData[i].getOutListMutex() == EtConstants.mutexLocked) {
+                    str.append(data.statData[i].getName());
+                    str.append("-out, ");
+                }
+            }
+            if (updated) {
+                leaf = systemDynamicNode.getLastLeaf();
+                leaf.setUserObject(str.toString());
+                treeModel.nodesChanged(systemDynamicNode, kids6);
+            }
+            else {
+                systemDynamicNode.add(new DefaultMutableTreeNode(str.toString()));
+            }
+        }
+        else if (updated) {
+            treeModel.nodesChanged(systemDynamicNode, kids4);
+        }
+
+        // Update station info
+
+        // first remove stations not in current list
+        int numStations = data.statData.length;
+        oldList: for (Iterator i=stations.keySet().iterator(); i.hasNext();) {
+            statName = (String) i.next();
+            newList: for (int j=0; j < numStations; j++) {
+                if (statName.equals(data.statData[j].getName())) {
+                    continue oldList;
+                }
+            }
+//System.out.println("Removing node for station " + statName);
+            node = (DefaultMutableTreeNode) stations.get(statName);
+            treeModel.removeNodeFromParent(node);
+            i.remove();
+        }
+
+        // create new stations and update existing stations
+        for (int i=0; i < numStations; i++) {
+
+            // Get station name & find its node object if there is one,
+            // else make a new node and store it in the hash table
+            statName = data.statData[i].getName();
+            if (stations.containsKey(statName)) {
+                isNewNode = false;
+                node = (DefaultMutableTreeNode) stations.get(statName);
+//System.out.println("Node " + node + " has got " + node.getChildCount() + " children");
+                configNode = (DefaultMutableTreeNode)node.getFirstChild();
+                statsNode  = (DefaultMutableTreeNode)node.getLastChild();
+//System.out.println("Child 1 = " + configNode);
+//System.out.println("Child 2 = " + statsNode);
+            }
+            else {
+//System.out.println("Adding node for station " + statName);
+                isNewNode  = true;
+                node       = new DefaultMutableTreeNode(statName);
+                configNode = new DefaultMutableTreeNode("Configuration");
+                statsNode  = new DefaultMutableTreeNode("Status");
+                node.add(configNode);
+                node.add(statsNode);
+                stations.put(statName, node);
+                // wait for all "node" changes before inserting into tree
+            }
+
+            // station config (skip GC as it never changes)
+            if ((i != 0) || isNewNode ) {
+                str.delete(0, end);
+                if (data.statData[i].getFlowMode() == EtConstants.stationSerial) {
+                    str.append("Serial, ");
+                }
+                else {
+                    str.append("Parallel, ");
+                }
+
+                if (data.statData[i].getBlockMode() == EtConstants.stationBlocking) {
+                    str.append("blocking, ");
+                    blocking = true;
+                    str.append("prescale = ");
+                    str.append(data.statData[i].getPrescale());
+                    str.append(", (cue = ");
+                    str.append(data.statData[i].getCue());
+                    str.append(")");
+                }
+                else {
+                    str.append("nonblocking, ");
+                    blocking = false;
+                    str.append("cue = ");
+                    str.append(data.statData[i].getCue());
+                    str.append(", (prescale = ");
+                    str.append(data.statData[i].getPrescale());
+                    str.append(")");
+                }
+
+                if (isNewNode) {
+//System.out.println("Add first leaf to config node");
+                    configNode.add(new DefaultMutableTreeNode(str.toString()));
+                }
+                else {
+//System.out.println("Config has got " + configNode.getLeafCount() + " # of leaves");
+                    leaf = configNode.getFirstLeaf();
+//System.out.println("First config leaf = " + leaf);
+                    leaf.setUserObject(str.toString());
+                }
+
+
+                str.delete(0, end);
+                if (data.statData[i].getUserMode() == EtConstants.stationUserMulti) {
+                    str.append("Users = multi");
+                }
+                else {
+                    str.append("Users = ");
+                    str.append(data.statData[i].getUserMode());
+                }
+
+                if (data.statData[i].getRestoreMode() == EtConstants.stationRestoreOut)
+                    str.append(", restore = out, ");
+                else if (data.statData[i].getRestoreMode() == EtConstants.stationRestoreIn)
+                    str.append(", restore = in, ");
+                else
+                    str.append(", restore = GC, ");
+
+                if (data.statData[i].getSelectMode() == EtConstants.stationSelectAll)
+                    str.append("select = all");
+                else if (data.statData[i].getSelectMode() == EtConstants.stationSelectMatch)
+                    str.append("select = match");
+                else if (data.statData[i].getSelectMode() == EtConstants.stationSelectUser)
+                    str.append("select = user");
+                else if (data.statData[i].getSelectMode() == EtConstants.stationSelectRRobin)
+                    str.append("select = rrobin");
+                else
+                    str.append("select = equalcue");
+
+                if (isNewNode) {
+//System.out.println("Add second leaf to config node");
+                    configNode.add(new DefaultMutableTreeNode(str.toString()));
+                }
+                else {
+                    leaf = leaf.getNextLeaf();
+//System.out.println("Next config leaf = " + leaf);
+                    leaf.setUserObject(str.toString());
+                }
+
+
+                str.delete(0, end);
+                str.append("Select words: ");
+                for (int j=0; j < EtConstants.stationSelectInts; j++) {
+                    str.append(data.statData[i].getSelect()[j]);
+                    if (j == EtConstants.stationSelectInts - 1) break;
+                    str.append(", ");
+                }
+                if (isNewNode) {
+//System.out.println("Add third leaf to config node");
+                    configNode.add(new DefaultMutableTreeNode(str.toString()));
+                }
+                else {
+                    leaf = leaf.getNextLeaf();
+//System.out.println("Next config leaf = " + leaf);
+                    leaf.setUserObject(str.toString());
+                }
+
+                // Select mode never changes after station creation,
+                // but station can be removed and then recreated with
+                // a new configuration (in less time than it takes to
+                // update).
+                if (data.statData[i].getSelectMode() == EtConstants.stationSelectUser) {
+                    str.delete(0, end);
+                    if (isJava) {
+                        str.append("Class = ");
+                        str.append(data.statData[i].getSelectClass());
+                    }
+                    else {
+                        str.append("Function = ");
+                        str.append(data.statData[i].getSelectFunction());
+                        str.append(", library = ");
+                        str.append(data.statData[i].getSelectLibrary());
+                    }
+                    if (isNewNode) {
+//System.out.println("Add fourth leaf to config node");
+                        configNode.add(new DefaultMutableTreeNode(str.toString()));
+                    }
+                    else {
+                        leaf = leaf.getNextLeaf();
+//System.out.println("Next config leaf = " + leaf);
+                        leaf.setUserObject(str.toString());
+                    }
+                }
+
+                if (!isNewNode) {
+                    treeModel.nodesChanged(configNode, kids3);
+                }
+
+
+            } // if not GC
+
+
+
+            // statistical station info
+
+            str.delete(0, end);
+            if (data.statData[i].getStatus() == EtConstants.stationIdle) {
+                str.append("Idle, ");
+            }
+            else {
+                str.append("Active, ");
+            }
+            str.append("attachments: total = ");
+            str.append(data.statData[i].getAttachments());
+            str.append(",  ids = ");
+            int limit = data.statData[i].getAttachments();
+            for (int j=0; j < limit; j++) {
+                str.append(data.statData[i].getAttachmentIds()[j]);
+                if (j == limit - 1) break;
+                str.append(", ");
+            }
+
+            if (isNewNode) {
+//System.out.println("Add first leaf to statistics");
+                statsNode.add(new DefaultMutableTreeNode(str.toString()));
+            }
+            else {
+//System.out.println("Statistics has got " + statsNode.getLeafCount() + " # of leaves");
+                leaf = statsNode.getFirstLeaf();
+//System.out.println("First statistics leaf = " + leaf);
+                leaf.setUserObject(str.toString());
+            }
+
+            str.delete(0, end);
+            str.append("Input events:   ");
+            str.append(data.statData[i].getInListCount());
+            str.append(", total = ");
+            str.append(data.statData[i].getInListIn());
+            // if blocking station and not grandcentral ...
+            if (blocking && (data.statData[i].getId() != 0)) {
+                str.append(", try = ");
+                str.append(data.statData[i].getInListTry());
+            }
+            // helps reduce widget flashing
+            str.append("            ");
+
+            if (isNewNode) {
+//System.out.println("Add second leaf to statisics");
+                statsNode.add(new DefaultMutableTreeNode(str.toString()));
+            }
+            else {
+                leaf = leaf.getNextLeaf();
+//System.out.println("Next statistics leaf = " + leaf);
+                leaf.setUserObject(str.toString());
+            }
+
+            str.delete(0, end);
+            str.append("Output events: ");
+            str.append(data.statData[i].getOutListCount());
+            str.append(", total = ");
+            str.append(data.statData[i].getOutListOut());
+            str.append("            ");
+
+            if (isNewNode) {
+//System.out.println("Add third leaf to statisics");
+                statsNode.add(new DefaultMutableTreeNode(str.toString()));
+                // add new station to main tree
+                treeModel.insertNodeInto(node, stationNode, i);
+            }
+            else {
+                leaf = leaf.getNextLeaf();
+//System.out.println("Next statistics leaf = " + leaf);
+                //treeModel.valueForPathChanged(new TreePath(leaf), str.toString());
+                leaf.setUserObject(str.toString());
+                treeModel.nodesChanged(statsNode, kids3);
+            }
+
+            // keep track of grandcentral data rate
+            if ((i==0) && (updated)) {
+                long gcOut = data.statData[i].getOutListOut();
+                time2 = System.currentTimeMillis();
+                rate = ((1000 * (gcOut - prevGcOut))/(time2-time1));
+                prevGcOut = gcOut;
+                time1 = time2;
+                str.delete(0, end);
+                str.append("Event rate = ");
+                str.append(rate);
+                str.append(" Hz");
+                leaf = systemDynamicNode.getFirstLeaf();
+                leaf.setUserObject(str.toString());
+                treeModel.nodeChanged(leaf);
+            }
+        } // for (int i=0; i < numStations; i++) {
+
+        // User processes exist on Solaris only
+        if (isSolaris) {
+            // Processes are only leaves on the tree, so reuse
+            // any that are there, delete or add to suit.
+
+            int numProcs    = data.procData.length;
+            int numLeaves   = processNode.getChildCount();
+            int leafCounter = numLeaves;
+
+            if (numProcs > 0) {
+                for (int i=0; i < numProcs; i++) {
+                    str.delete(0, end);
+                    if (data.procData[i].getAttachments() < 1) {
+                        str.append("Id = ");
+                        str.append(data.procData[i].getId());
+                        str.append(", no attachments, ");
+                    }
+                    else {
+                        str.append("Id = ");
+                        str.append(data.procData[i].getId());
+                        str.append(", ");
+                        str.append(data.procData[i].getAttachments());
+                        str.append(" attachments, ids = ");
+                        for (int j=0; j < data.procData[i].getAttachments(); j++) {
+                            str.append(data.procData[i].getAttachmentIds()[j]);
+                            str.append(", ");
+                        }
+                    }
+                    str.append("pid = ");
+                    str.append(data.procData[i].getPid());
+                    str.append(", hbeat = ");
+                    str.append(data.procData[i].getHeartbeat());
+
+                    if (leafCounter < 1) {
+                        node = new DefaultMutableTreeNode(str.toString());
+                        treeModel.insertNodeInto(node, processNode, i);
+                    }
+                    else {
+                        node = (DefaultMutableTreeNode) processNode.getChildAt(i);
+                        node.setUserObject(str.toString());
+                        leafCounter--;
+                    }
+                }
+
+                if (numLeaves > 1) {
+//System.out.println("More than one leaf");
+                    // update through leaves that were reused
+                    leafCounter = numProcs > numLeaves ? numLeaves : numProcs;
+                    int[] leaves = new int[leafCounter];
+                    for (int i=0; i < leafCounter; i++) {
+                        leaves[i] = i;
+                    }
+                    treeModel.nodesChanged(processNode, leaves);
+
+                    // remove leaves that aren't needed
+                    if (numLeaves > numProcs) {
+//System.out.println("More leaves than processes");
+                        for (int i=0; i < numLeaves-numProcs; i++) {
+                            node = (DefaultMutableTreeNode) processNode.getChildAt(i + numProcs);
+//System.out.println("Remove node " + (i+numProcs) + " called " + node);
+                            treeModel.removeNodeFromParent(node);
+                        }
+                    }
+                }
+            }
+        }
+
+        // user attachments
+
+        // first remove attachments not in current list
+        int numAtts = data.attData.length;
+
+        oldList: for (Iterator i=attachments.keySet().iterator(); i.hasNext();) {
+            attId = (Integer) i.next();
+            newList: for (int j=0; j < numAtts; j++) {
+                if (attId.intValue() == data.attData[j].getId()) {
+                    continue oldList;
+                }
+            }
+//System.out.println("Removing node for att " + attId);
+            node = (DefaultMutableTreeNode) attachments.get(attId);
+            treeModel.removeNodeFromParent(node);
+            i.remove();
+        }
+
+        if (data.attData.length > 0) {
+            // create new attachments and update existing attachments
+            for (int i=0; i < numAtts; i++) {
+                // Get Attachment Id & find its node object if there is one,
+                // else make a new node and store it in the hash table
+                attId = new Integer(data.attData[i].getId());
+                if (attachments.containsKey(attId)) {
+                    isNewNode = false;
+//System.out.println("Using old node for attachment " + attId);
+                    node = (DefaultMutableTreeNode) attachments.get(attId);
+                }
+                else {
+//System.out.println("Adding node for attachment " + attId);
+                    isNewNode  = true;
+                    node       = new DefaultMutableTreeNode(attId);
+                    attachments.put(attId, node);
+                    // wait for all "node" changes before inserting into tree
+                }
+
+                // graph attIcons & links
+
+                str.delete(0, end);
+                str.append("Station = ");
+                str.append(data.attData[i].getStationName());
+                str.append(", host = ");
+                str.append(data.attData[i].getHost());
+
+                if (isNewNode) {
+                    node.add(new DefaultMutableTreeNode(str.toString()));
+                }
+                else {
+                    leaf = node.getFirstLeaf();
+                    leaf.setUserObject(str.toString());
+                }
+
+                if (data.attData[i].getIpAddress() != null) {
+                    str.delete(0, end);
+                    str.append("Sending ip address = ");
+                    str.append(data.attData[i].getIpAddress());
+
+                    if (isNewNode) {
+                        node.add(new DefaultMutableTreeNode(str.toString()));
+                    }
+                    else {
+                        leaf = leaf.getNextLeaf();
+                        leaf.setUserObject(str.toString());
+                    }
+                }
+
+                str.delete(0, end);
+                if (data.attData[i].blocked() == true) {
+                    str.append("Blocked");
+                }
+                else {
+                    str.append("Not blocked");
+                }
+                if (data.attData[i].quitting() == true) {
+                    str.append(", quitting");
+                }
+
[truncated at 1000 lines; 830 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
WholeNumberField.java added at 1.1
diff -N WholeNumberField.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ WholeNumberField.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,162 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2002        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.monitorGui;
+
+import java.awt.Toolkit;
+import javax.swing.*; 
+import javax.swing.text.*; 
+//import java.text.NumberFormat;
+//import java.text.ParseException;
+//import java.util.Locale;
+
+public class WholeNumberField extends JTextField {
+    private Toolkit toolkit;
+    // private NumberFormat integerFormatter;
+    private boolean enforceLimits = false;
+    private int upperLimit=0;
+    private int lowerLimit=0;
+
+    public WholeNumberField(int value, int columns) {
+        super(columns);
+        toolkit = Toolkit.getDefaultToolkit();
+        // integerFormatter = NumberFormat.getNumberInstance(Locale.US);
+        // integerFormatter.setParseIntegerOnly(true);
+        setValue(value);
+    }
+
+    public WholeNumberField(int value, int columns, int limit1, int limit2) {
+        super(columns);
+        toolkit = Toolkit.getDefaultToolkit();
+        // integerFormatter = NumberFormat.getNumberInstance(Locale.US);
+        // integerFormatter.setParseIntegerOnly(true);
+	enforceLimits = true;
+	setLimits(limit1, limit2);
+        setValue(value);
+    }
+
+    private int adjustValue(int value) {
+        if (enforceLimits == true) {
+	    if (value > upperLimit) {
+	        value = upperLimit;
+	    }
+	    else if (value < lowerLimit) {
+	        value = lowerLimit;
+	    }
+	}
+	return value;
+     }
+    
+    public int getValue() {
+        int value = 0;
+        try {
+            // value = integerFormatter.parse(getText()).intValue();
+            value = Integer.parseInt(getText());
+        } catch (NumberFormatException e) {
+            // This should never happen because insertString allows
+            // only properly formatted data to get in the field.
+            toolkit.beep();
+        }
+	value = adjustValue(value);
+        return value;
+    }
+
+    public void correctValue() {
+        int value = 0;
+        try {
+            // value = integerFormatter.parse(getText()).intValue();
+            value = Integer.parseInt(getText());
+        } catch (NumberFormatException e) {
+            // This should never happen because insertString allows
+            // only properly formatted data to get in the field.
+            toolkit.beep();
+        }
+	setValue(value);
+     }
+    
+    public void setValue(int value) {
+	value = adjustValue(value);
+        setText(""+value);
+	// setText(integerFormatter.format(value));
+    }
+
+    public void setLimits(int limit1, int limit2) {
+        enforceLimits = true;
+	if (limit1 >= limit2) {
+            upperLimit = limit1;
+	    lowerLimit = limit2;
+	}
+	else {
+            upperLimit = limit2;
+	    lowerLimit = limit1;
+	}
+    }
+    
+    public void removeLimits() {
+        enforceLimits = false;
+    }
+    
+    public void setUpperLimit(int limit) {
+        enforceLimits = true;
+        upperLimit = limit;
+    }
+    
+    public void setLowerLimit(int limit) {
+        enforceLimits = true;
+        lowerLimit = limit;
+    }
+    
+    public int getUpperLimit() {
+      return upperLimit;
+    }
+    
+    public int getLowerLimit() {
+      return lowerLimit;
+    }
+    
+    protected Document createDefaultModel() {
+        return new WholeNumberDocument();
+    }
+
+    protected class WholeNumberDocument extends PlainDocument {
+        public void insertString(int offs, String str, AttributeSet a) 
+                     throws BadLocationException {
+            char[] source = str.toCharArray();
+            char[] result = new char[source.length];
+            int value, j=0;
+
+            for (int i=0; i < result.length; i++) {
+                // allow for typing in minus sign
+		if ((offs == 0) && (i == 0) && (source[0] == '-')) {
+                    result[j++] = source[0];
+		    if (result.length == 1) {
+                      super.insertString(0, new String(source,0,1), a);
+		      return;
+		    }
+		}
+		else if (Character.isDigit(source[i]))
+                    result[j++] = source[i];
+                else {
+                    toolkit.beep();
+                }
+            }
+	    String number = new String(getText(0,offs) + new String(result, 0, j));
+	    // value = integerFormatter.parse(number).intValue();
+ 	    // value = adjustValue(value);
+            super.remove(0, offs);
+            // super.insertString(0, integerFormatter.format(value), a);
+            super.insertString(0, number, a);
+        }
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et/monitorGui
monitorConfiguration.xsd added at 1.1
diff -N monitorConfiguration.xsd
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ monitorConfiguration.xsd	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema  xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	version="7.0">
+ 
+  <!-- definition of some useful types -->
+
+  <xs:simpleType name="port">
+    <xs:restriction base="xs:unsignedShort">
+      <xs:minInclusive value="1024"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="dimension">
+    <xs:restriction base="xs:unsignedShort">
+      <xs:maxInclusive value="2000"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="orientation">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="vertical"/>
+      <xs:enumeration value="horizontal"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="location">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="local"/>
+      <xs:enumeration value="remote"/>
+      <xs:enumeration value="anywhere"/>
+    </xs:restriction>
+  </xs:simpleType>
+  
+  <xs:simpleType name="hostname">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="\w+(\.\w+)*"/>
+    </xs:restriction>
+  </xs:simpleType>
+  
+  <xs:simpleType name="hostnameList">
+    <xs:list itemType="hostname"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="ipAddress">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="(([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.){3}([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="ipAddressList">
+    <xs:list itemType="ipAddress"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="multicastAddress">
+    <xs:restriction base="ipAddress">
+      <xs:pattern value="(22[4-9]|23\d)(\.\d{1,3}){3}"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:simpleType name="multicastAddressList">
+    <xs:list itemType="multicastAddress"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="fileNameList">
+    <xs:list itemType="xs:string"/>
+  </xs:simpleType>
+
+  <xs:simpleType name="ttl">
+    <xs:restriction base="xs:unsignedByte">
+      <xs:maxInclusive value="254"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+  <xs:complexType name="color">
+    <xs:attribute name="red"   type="xs:unsignedByte" use="required"/>
+    <xs:attribute name="green" type="xs:unsignedByte" use="required"/>
+    <xs:attribute name="blue"  type="xs:unsignedByte" use="required"/>
+  </xs:complexType>
+
+  <!-- here is where the real elements begin -->
+
+  <xs:element name="configuration">
+    <xs:complexType>
+      <xs:sequence>
+	<xs:element name="graphics">
+	  <xs:complexType>
+	    <xs:all>
+	      <xs:element name="width"     type="dimension"/>
+	      <xs:element name="height"    type="dimension"/>
+	      <xs:element name="xPosition" type="dimension"/>
+	      <xs:element name="yPosition" type="dimension"/>
+	      
+	      <!-- optional colors -->
+	      <xs:element name="titleColor"          type="color" minOccurs="0"/>
+	      <xs:element name="backgroundColor"     type="color" minOccurs="0"/>
+	      <xs:element name="selectedTabColor"    type="color" minOccurs="0"/>
+	      <xs:element name="tabsBackgroundColor" type="color" minOccurs="0"/>
+	      <xs:element name="textColor"           type="color" minOccurs="0"/>
+	      <xs:element name="textBackgroundColor" type="color" minOccurs="0"/>
+
+	      <!-- optional lists of extra ET systems & hosts -->
+	      <xs:element name="hostList"     type="hostnameList" minOccurs="0"/>
+	      <xs:element name="fileNameList" type="fileNameList" minOccurs="0"/>
+	    </xs:all>
+	  </xs:complexType>
+	</xs:element>
+
+	<xs:element name="etConnection" minOccurs="0" maxOccurs="unbounded">
+	  <xs:complexType>
+	    <xs:sequence>
+	      <xs:element name="fileName" type="xs:string"/>
+
+	      <xs:choice>
+	        <xs:element name="broadcasting">
+		  <xs:complexType>
+		    <xs:sequence>
+	              <xs:choice>
+	                <xs:element name="location"           type="location"/>
+	                <xs:element name="host"               type="hostname"/>
+	              </xs:choice>
+	              <xs:element name="broadcastAddressList" type="ipAddressList"/>
+	              <xs:element name="broadcastPort"        type="port"/>
+		    </xs:sequence>
+		  </xs:complexType>
+	        </xs:element>
+		
+	        <xs:element name="multicasting">
+		  <xs:complexType>
+		    <xs:sequence>
+	              <xs:choice>
+	                <xs:element name="location"           type="location"/>
+	                <xs:element name="host"               type="hostname"/>
+	              </xs:choice>
+		      <xs:element name="multicastAddressList" type="multicastAddressList"/>
+	              <xs:element name="multicastPort"        type="port"/>
+	              <xs:element name="ttl"                  type="ttl"/>
+	              <xs:element name="udpPort"              type="port" minOccurs="0"/>
+		    </xs:sequence>
+		  </xs:complexType>
+	        </xs:element>
+		
+	        <xs:element name="broadAndMulticasting">
+		  <xs:complexType>
+		    <xs:sequence>
+	              <xs:choice>
+	                <xs:element name="location"           type="location"/>
+	                <xs:element name="host"               type="hostname"/>
+	              </xs:choice>
+	              <xs:element name="broadcastAddressList" type="ipAddressList"/>
+	              <xs:element name="broadcastPort"        type="port"/>
+		      <xs:element name="multicastAddressList" type="multicastAddressList"/>
+	              <xs:element name="multicastPort"        type="port"/>
+	              <xs:element name="ttl"                  type="ttl"/>
+		    </xs:sequence>
+		  </xs:complexType>
+	        </xs:element>
+		
+	        <xs:element name="direct">
+		  <xs:complexType>
+		    <xs:sequence>
+	              <xs:choice>
+	                <xs:element name="location" type="location" fixed="local"/>
+	                <xs:element name="host"     type="hostname"/>
+	              </xs:choice>
+	              <xs:element name="tcpPort" type="port"/>
+		    </xs:sequence>
+		  </xs:complexType>
+	        </xs:element>
+		
+	        <xs:element name="udpToHost">
+		  <xs:complexType>
+		    <xs:sequence>
+	              <xs:choice>
+	                <xs:element name="location" type="location" fixed="local"/>
+	                <xs:element name="host"     type="hostname"/>
+	              </xs:choice>
+	              <xs:element name="udpPort" type="port"/>
+		    </xs:sequence>
+		  </xs:complexType>
+	        </xs:element>
+	      </xs:choice>
+
+	      <xs:element name="period"          type="xs:nonNegativeInteger"/>
+	      <xs:element name="dividerPosition" type="xs:nonNegativeInteger"/>
+	      <xs:element name="orientation"     type="orientation"/>
+
+	      <!-- optional selection of tree/graph colors -->
+	      <xs:element name="eventColor"          type="color" minOccurs="0"/>
+	      <xs:element name="stationColor"        type="color" minOccurs="0"/>
+	      <xs:element name="stationIdleColor"    type="color" minOccurs="0"/>
+	      <xs:element name="attachmentColor"     type="color" minOccurs="0"/>
+	      <xs:element name="lineColor"           type="color" minOccurs="0"/>
+	      <xs:element name="textColor"           type="color" minOccurs="0"/>
+	      <xs:element name="textBackgroundColor" type="color" minOccurs="0"/>
+	      <xs:element name="backgroundColor"     type="color" minOccurs="0"/>
+	      <xs:element name="treeTextColor"       type="color" minOccurs="0"/>
+	      <xs:element name="treeBackgroundColor" type="color" minOccurs="0"/>
+
+	    </xs:sequence>
+	  </xs:complexType>
+	</xs:element>
+
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+</xs:schema>

hps-et-java/src/main/java/org/jlab/coda/et/system
AttachmentLocal.java added at 1.1
diff -N AttachmentLocal.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ AttachmentLocal.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,286 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+
+/**
+ * This class defines an attachment to a station of an ET system for use by the
+ * ET system itself and not the user. Attachments are used to keep track of
+ * event ownership and as places to conveniently keep some statistics and other
+ * information on the "getting" of events. Attachments can only be created by an
+ * ET system's {@link SystemCreate#attach(int)} method.
+ *
+ * @author Carl Timmer
+ */
+
+class AttachmentLocal {
+
+    // TODO: keep a list or set of events we currently have out?
+
+    /** Unique id number. */
+    private int id;
+
+    /** Process id number for attachments written in C language. */
+    private int pid;
+
+    /** Name of the host the attachment is residing on. */
+    private String host;
+
+    /** IP address of the network interface the attachment is sending data through. */
+    private String ipAddress;
+
+    /** Station the attachment is associated with. */
+    private StationLocal station;
+
+    /** Number of events put by a user into the attachment. */
+    private long eventsPut;
+
+    /** Number of events gotten by a user from the attachment. */
+    private long eventsGet;
+
+    /** Number of events dumped (recycled by returning to GRAND_CENTRAL station)
+     *  by a user through the attachment. */
+    private long eventsDump;
+
+    /** Number of new events gotten by a user from the attachment. */
+    private long eventsMake;
+
+    /** Flag telling whether the attachment is blocked waiting to read events
+     *  from a station that has no events.  */
+    private boolean waiting;
+
+    /**
+     * Flag telling whether the attachment is currently in the sleep mode of
+     * getEvents or newEvents. Since the implementation of this mode is
+     * done by using the timed wait mode, it occasionally happens that the
+     * attachment is told to wake up while it is not actually in getEvents or
+     * newEvents. If this flag is true, the command to wake up will go ahead
+     * and set "wakeUp" to true - even if "waiting" is false.
+     */
+    private volatile boolean sleepMode;
+
+    /** Flag telling the attachment blocked on a read to wake up or return. */
+    private volatile boolean wakeUp;
+
+
+    /**
+     * Constructor. Attachments are only created by an ET system's
+     * {@link SystemCreate#attach(int)} method.
+     */
+    AttachmentLocal() {
+        id         = -1;
+        pid        = -1;
+    }
+
+
+    /**
+     * Gets the attachment id number.
+     * @return attachment id number
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets the attachment id number.
+     * @param id attachment id number
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * Gets the process id number for C clients.
+     * @return the process id number for C clients
+     */
+    public int getPid() {
+        return pid;
+    }
+
+    /**
+     * Set the process id number.
+     * @param pid he process id number
+     */
+    public void setPid(int pid) {
+        this.pid = pid;
+    }
+
+    /**
+     * Get the host the attachment is residing on.
+     * @return host the attachment is residing on
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Set the host the attachment is residing on.
+     * @param host host the attachment is residing on
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Get the IP address of the network interface the attachment is sending data through.
+     * @return IP address of the network interface the attachment is sending data through.
+     */
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    /**
+     * Set the IP address of the network interface the attachment is sending data through.
+     * @param ipAddress IP address of the network interface the attachment is sending data through.
+     */
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    /**
+     * Is the attachment blocked waiting to read events from a station that has no events?
+     * @return <code>true</code> if attachment is blocked waiting to read events from a station that has no events
+     */
+    public boolean isWaiting() {
+        return waiting;
+    }
+
+    /**
+     * Set if attachment is blocked waiting to read events from a station that has no events
+     * @param waiting is attachment blocked waiting to read events from a station that has no events?
+     */
+    public void setWaiting(boolean waiting) {
+        this.waiting = waiting;
+    }
+
+    /**
+     * Is this attachment to wake up or return after returning from blocking read?
+     * @return <code>true</code> if this attachment is to wake up or return after returning from blocking read
+     */
+    public boolean isWakeUp() {
+        return wakeUp;
+    }
+
+    /**
+     * Set the flag to wake up or return after returning from blocking read.
+     * @param wakeUp flag to wake up or return after returning from blocking read
+     */
+    public void setWakeUp(boolean wakeUp) {
+        this.wakeUp = wakeUp;
+    }
+
+    /**
+     * Is this attachment currently in the sleep mode of getEvents or newEvents?
+     * @return <code>true</code> if this attachment is currently in the sleep mode of getEvents or newEvents
+     */
+    public boolean isSleepMode() {
+        return sleepMode;
+    }
+
+    /**
+     * Set the flag to be in the sleep mode of getEvents or newEvents.
+     * @param sleepMode sleep mode of getEvents or newEvents
+     */
+    public void setSleepMode(boolean sleepMode) {
+        this.sleepMode = sleepMode;
+    }
+
+    /**
+     * Get the station this attachment is associated with.
+     * @return station this attachment is associated with
+     */
+    public StationLocal getStation() {
+        return station;
+    }
+
+    /**
+     * Set the station this attachment is associated with.
+     * @param station station this attachment is associated with
+     */
+    public void setStation(StationLocal station) {
+        this.station = station;
+    }
+
+    /**
+     * Get the number of events put by a user into this attachment.
+     * @return number of events put by a user into this attachment
+     */
+    public long getEventsPut() {
+        return eventsPut;
+    }
+
+    /**
+     * Get the number of events put by a user into this attachment.
+     * @param eventsPut number of events put by a user into this attachment
+     */
+    public void setEventsPut(long eventsPut) {
+        this.eventsPut = eventsPut;
+    }
+
+    /**
+     * Get the number of events gotten by a user from this attachment.
+     * @return number of events gotten by a user from this attachment
+     */
+    public long getEventsGet() {
+        return eventsGet;
+    }
+
+    /**
+     * Set the number of events gotten by a user from this attachment
+     * @param eventsGet number of events gotten by a user from this attachment
+     */
+    public void setEventsGet(long eventsGet) {
+        this.eventsGet = eventsGet;
+    }
+
+    /**
+     * Get the number of events dumped (recycled by returning to GRAND_CENTRAL station)
+     * by a user through this attachment.
+     * @return number of events dumped by a user through this attachment
+     */
+    public long getEventsDump() {
+        return eventsDump;
+    }
+
+    /**
+     * Set the number of events dumped (recycled by returning to GRAND_CENTRAL station)
+     * by a user through this attachment.
+     * @param eventsDump number of events dumped by a user through this attachment.
+     */
+    public void setEventsDump(long eventsDump) {
+        this.eventsDump = eventsDump;
+    }
+
+    /**
+     * Get the number of new events gotten by a user from this attachment.
+     * @return number of new events gotten by a user from this attachment
+     */
+    public long getEventsMake() {
+        return eventsMake;
+    }
+
+    /**
+     * Set the number of new events gotten by a user from this attachment.
+     * @param eventsMake number of new events gotten by a user from this attachment
+     */
+    public void setEventsMake(long eventsMake) {
+        this.eventsMake = eventsMake;
+    }
+
+
+}
+
+
+

hps-et-java/src/main/java/org/jlab/coda/et/system
EventList.java added at 1.1
diff -N EventList.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EventList.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,595 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12B3       *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-6248             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.util.*;
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.EtEvent;
+import org.jlab.coda.et.EtConstants;
+import org.jlab.coda.et.EtEventImpl;
+import org.jlab.coda.et.enums.Priority;
+
+/**
+ * This class defines a linked list of events for use as either a station's
+ * input or output list in a station.
+ *
+ * @author Carl Timmer
+ */
+
+class EventList {
+
+    /** Linked list of events. */
+    private LinkedList<EtEventImpl> events;
+
+    /** Number of events put into this list. */
+    private long eventsIn;
+
+    /** Number of events taken out of this list. */
+    private long eventsOut;
+
+    // input list members only
+
+    /** Number of events tried to put into this list when used with prescaling. */
+    private long eventsTry;
+
+    /** Flag telling the list to wake up the user waiting to read events. */
+    private  boolean wakeAll;
+
+    /** Count of the number of users sleeping on reading events. Last one to wake
+     *  up needs to reset wakeAll. */
+    private int waitingCount;
+
+    // output list members only
+
+    /** Position of the last high priority event in the linked list. */
+    private int lastHigh;
+
+
+
+    /** Construct a new EventList object. */
+    EventList() {
+        events = new LinkedList<EtEventImpl>();
+    }
+
+
+
+    /**
+     * Get the linked list of events.
+     * @return linked list of events
+     */
+    LinkedList<EtEventImpl> getEvents() {
+        return events;
+    }
+
+    /**
+     * Get the number of events tried to put into this list when used with prescaling.
+     * @return number of events tried to put into this list when used with prescaling
+     */
+    long getEventsTry() {
+        return eventsTry;
+    }
+
+    /**
+     * set the number of events tried to put into this list when used with prescaling.
+     * @param eventsTry number of events tried to put into this list when used with prescaling
+     */
+    void setEventsTry(long eventsTry) {
+        this.eventsTry = eventsTry;
+    }
+
+    /**
+     * Get the number of events put into this list.
+     * @return number of events put into this list
+     */
+    long getEventsIn() {
+        return eventsIn;
+    }
+
+    /**
+     * Set the number of events put into this list.
+     * @param eventsIn number of events put into this list
+     */
+    void setEventsIn(long eventsIn) {
+        this.eventsIn = eventsIn;
+    }
+
+    /**
+     * Get the number of events taken out of this list.
+     * @return number of events taken out of this list
+     */
+    long getEventsOut() {
+        return eventsOut;
+    }
+
+    /**
+     * Set the number of events taken out of this list.
+     * @param eventsOut number of events taken out of this list
+     */
+    void setEventsOut(long eventsOut) {
+        this.eventsOut = eventsOut;
+    }
+
+
+    // methods for waking up reading attachments on input lists
+
+
+    /**
+     * Wake up an attachment waiting to read events from this list.
+     * @param att attachment to be woken up
+     */
+    synchronized void wakeUp(AttachmentLocal att) {
+        if (!att.isWaiting()) {
+            return;
+        }
+        att.setWakeUp(true);
+        notifyAll();
+    }
+
+
+    /** Wake up all attachments waiting to read events from this list. */
+    synchronized void wakeUpAll() {
+        if (waitingCount < 1) {
+            return;
+        }
+        wakeAll = true;
+        notifyAll();
+    }
+
+
+    /**
+     * Put all events into a station's input list as low priority. This is
+     * used inside synchronized blocks in conductor threads and in the initial
+     * filling of GRAND_CENTRAL station.
+     * @param newEvents list of events to put
+     */
+    void putInLow(List<EtEventImpl> newEvents) {
+        // add all events to list's end
+        events.addAll(newEvents);
+        // keep stats
+        eventsIn += newEvents.size();
+    }
+
+
+    /**
+     * Synchronized version of putInLow for user to dump events into
+     * GRAND_CENTRAL station.
+     * @param newEvents array of events to put
+     */
+    synchronized void putInGC(EtEventImpl[] newEvents) {
+        // convert array to list and put as low priority events
+        putInLow(Arrays.asList(newEvents));
+    }
+
+
+    /**
+     * Synchronized version of putInLow for user to dump events into
+     * GRAND_CENTRAL station.
+     * @param newEvents list of events to put
+     */
+    synchronized void putInGC(List<EtEventImpl> newEvents) {
+        putInLow(newEvents);
+    }
+
+
+    /**
+     * Put all events into the list regardless of how many are already in it.
+     * Synchronized and used only in conductor threads to put events into a
+     * station's input list. All high priority events are listed first in
+     * newEvents.
+     * @param newEvents list of events to put
+     */
+    void putAll(List<EtEventImpl> newEvents) {
+        // number of incoming events
+        int num = newEvents.size();
+
+        // all incoming events' priorities are low or no events in this EventList
+        if ((events.size() == 0) || ((newEvents.get(0)).getPriority() == Priority.LOW))  {
+            // adds new events to the end
+            events.addAll(newEvents);
+            /*
+            if ((newEvents.get(0)).priority == Constants.low) {
+              System.out.println("  putAll in as is as incoming are all low pri, " + newEvents.size());
+            }
+            if (events.size() == 0) {
+              System.out.println("  putAll in as is as list EventList empty, " + newEvents.size());
+            }
+            */
+        }
+
+        // if any high pri events (count != 0) ...
+        else {
+            // find last high priority event already in list
+            int highCount = 0;
+            for (EtEvent ev : events) {
+                if (ev.getPriority() != Priority.HIGH) {
+                    break;
+                }
+                highCount++;
+            }
+//System.out.println("  putAll last high of input list = " + highCount);
+
+            // add new high pri items
+            int newHighCount = 0;
+            for (EtEventImpl ev : newEvents) {
+                if (ev.getPriority() != Priority.HIGH) {
+                    break;
+                }
+//System.out.println("  putAll add high " + ev.id + " at " + (highCount + newHighCount));
+                events.add(highCount + newHighCount++, ev);
+            }
+
+            // rest are low pri, add to end
+            if (newHighCount < num) {
+//System.out.println("  putAll add " + (num - newHighCount) + " lows at end");
+                events.addAll(newEvents.subList(newHighCount, num));
+            }
+        }
+        // keep stats
+        eventsIn += num;
+        return;
+    }
+
+    /**
+     * For user to put all events into station's output list. High & low
+     * priorities may be mixed up in the newEvents list. May also be used to
+     * restore events to the input list when user connection is broken.
+     * @param newEvents array of events to put
+     */
+    synchronized void put(EtEventImpl[] newEvents) {
+        // if no events in list, initialize lastHigh
+        if (events.size() == 0) {
+            lastHigh = 0;
+        }
+
+        // put events in one-by-one - with place depending on priority
+        for (EtEventImpl ev : newEvents) {
+            // if low priority event, add to the list end
+            if (ev.getPriority() == Priority.LOW) {
+//System.out.println(" put in low - " + ev.id);
+                events.addLast(ev);
+            }
+            // else if high pri event, add after other high priority events
+            else {
+//System.out.println(" put in high - " + ev.id);
+                events.add(lastHigh++, ev);
+            }
+        }
+        notify();
+        return;
+    }
+
+    /**
+     * For user to put all events into station's output list. High & low
+     * priorities may be mixed up in the newEvents list. May also be used to
+     * restore events to the input list when user connection is broken.
+     * @param newEvents list of events to put
+     */
+    synchronized void put(List<EtEventImpl> newEvents) {
+        // if no events in list, initialize lastHigh
+        if (events.size() == 0) {
+            lastHigh = 0;
+        }
+
+        // put events in one-by-one - with place depending on priority
+        for (EtEventImpl ev : newEvents) {
+            // if low priority event, add to the list end
+            if (ev.getPriority() == Priority.LOW) {
+//System.out.println(" put in low - " + ev.id);
+                events.addLast(ev);
+            }
+            // else if high pri event, add after other high priority events
+            else {
+//System.out.println(" put in high - " + ev.id);
+                events.add(lastHigh++, ev);
+            }
+        }
+        notify();
+        return;
+    }
+
+
+    /**
+     * For user to put all events into a station's input or output list. High & low
+     * priorities may be mixed up in the newEvents list. Unlike {@link #put},
+     * this method puts the new events BEFORE those already in the list.
+     * Used to restore events to input/output lists when user connection is broken.
+     * @param newEvents list of events to put
+     */
+    synchronized void putReverse(List<EtEventImpl> newEvents) {
+        // if no events in list, initialize lastHigh
+        if (events.size() == 0) {
+            lastHigh = 0;
+        }
+        else {
+            // The lastHigh is NOT tracked for input lists, so let's do
+            // it here since this method can be used for input lists.
+            int highCount = 0;
+            for (EtEvent ev : events) {
+                if (ev.getPriority() != Priority.HIGH) {
+                    break;
+                }
+                highCount++;
+            }
+            lastHigh = highCount;
+        }
+
+        // put events in one-by-one - with place depending on priority
+        for (EtEventImpl ev : newEvents) {
+            // if low priority event, add below last high priority but above low priority events
+            if (ev.getPriority() == Priority.LOW) {
+//System.out.println(" put in low - " + ev.id);
+                events.add(lastHigh, ev);
+            }
+            // else if high pri event, add to the top
+            else {
+//System.out.println(" put in high - " + ev.id);
+                events.add(0, ev);
+                lastHigh++;
+            }
+        }
+        notify();
+        return;
+    }
+
+
+    /**
+     * Used only by conductor to get all events from a station's output list.
+     * @param eventsToGo list of event to get
+     */
+    synchronized void get(List<EtEventImpl> eventsToGo) {
+        eventsToGo.addAll(events);
+        eventsOut += events.size();
+        events.clear();
+        return;
+    }
+
+
+    /**
+     * Method for an attachment (in TcpServer thread) to get an array of events.
+     *
+     * @param att attachment
+     * @param mode wait mode
+     * @param microSec time in microseconds to wait if timed wait mode
+     * @param quantity number of events desired
+     *
+     * @throws EtEmptyException
+     *     if the mode is asynchronous and the station's input list is empty
+     * @throws EtTimeoutException
+     *     if the mode is timed wait and the time has expired
+     * @throws EtWakeUpException
+     *     if the attachment has been commanded to wakeup,
+     */
+    synchronized EtEventImpl[] get(AttachmentLocal att, int mode, int microSec, int quantity)
+            throws EtEmptyException, EtWakeUpException, EtTimeoutException {
+
+        int  nanos, count = events.size();
+        long begin, microDelay, milliSec, elapsedTime = 0;
+
+        // Sleep mode is never used since it is implemented in the TcpServer
+        // thread by repeated calls in timed mode.
+        if (count == 0) {
+            if (mode == EtConstants.sleep) {
+                while (count < 1) {
+                    waitingCount++;
+                    att.setWaiting(true);
+//System.out.println("  get" + att.id + ": sleep");
+                    try {
+                        wait();
+                    }
+                    catch (InterruptedException ex) {
+                    }
+
+                    // if we've been told to wakeup & exit ...
+                    if (att.isWakeUp() || wakeAll) {
+                        att.setWakeUp(false);
+                        att.setWaiting(false);
+                        // last man to wake resets variable
+                        if (--waitingCount < 1) {
+                            wakeAll = false;
+                        }
+                        throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                    }
+
+                    att.setWaiting(false);
+                    waitingCount--;
+                    count = events.size();
+                }
+            }
+            else if (mode == EtConstants.timed) {
+                while (count < 1) {
+                    microDelay = microSec - 1000*elapsedTime;
+                    milliSec   = microDelay/1000L;
+                    if (milliSec < 0) {
+                        throw new EtTimeoutException("timed out");
+                    }
+                    nanos = 1000 * (int)(microDelay - 1000*milliSec);
+
+                    waitingCount++;
+                    att.setWaiting(true);
+//System.out.println("  get" + att.getId() + ": wait " + milliSec + " ms and " +
+//                   nanos + " nsec, elapsed time = " + elapsedTime);
+                    begin = System.currentTimeMillis();
+                    try {
+                        wait(milliSec, nanos);
+                    }
+                    catch (InterruptedException ex) {
+                    }
+                    elapsedTime += System.currentTimeMillis() - begin;
+
+                    // if we've been told to wakeup & exit ...
+                    if (att.isWakeUp() || wakeAll) {
+                        att.setWakeUp(false);
+                        att.setWaiting(false);
+                        // last man to wake resets variable
+                        if (--waitingCount < 1) {
+                            wakeAll = false;
+                        }
+                        throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                    }
+
+                    att.setWaiting(false);
+                    waitingCount--;
+                    count = events.size();
+//System.out.println("  get" + att.id + ": woke up and counts = " + count);
+                }
+            }
+            else if (mode == EtConstants.async) {
+                throw new EtEmptyException("no events in list");
+            }
+        }
+
+        if (quantity > count) {
+            quantity = count;
+        }
+//System.out.println("  get"+ att.id + ": quantity = " + quantity);
+
+        List<EtEventImpl> deleteList = events.subList(0, quantity);
+        EtEventImpl[] eventsToGo = new EtEventImpl[quantity];
+        deleteList.toArray(eventsToGo);
+        deleteList.clear();
+
+        eventsOut += quantity;
+        return eventsToGo;
+    }
+
+
+    /**
+     * Method for an attachment (in TcpServer thread) to get a list of events.
+     *
+     * @param att attachment
+     * @param mode wait mode
+     * @param microSec time in microseconds to wait if timed wait mode
+     * @param quantity number of events desired
+     * @param group group number of events desired
+     *
+     * @throws EtEmptyException
+     *     if the mode is asynchronous and the station's input list is empty
+     * @throws EtTimeoutException
+     *     if the mode is timed wait and the time has expired
+     * @throws EtWakeUpException
+     *     if the attachment has been commanded to wakeup,
+     */
+    synchronized List<EtEventImpl> get(AttachmentLocal att, int mode, int microSec, int quantity, int group)
+            throws EtEmptyException, EtWakeUpException, EtTimeoutException {
+
+        int nanos, count = events.size(), groupCount = 0;
+        EtEventImpl ev;
+        boolean scanList = true;
+        long begin, microDelay, milliSec, elapsedTime = 0;
+        LinkedList<EtEventImpl> groupList = new LinkedList<EtEventImpl>();
+
+        // Sleep mode is never used since it is implemented in the TcpServer
+        // thread by repeated calls in timed mode.
+        do {
+            if (mode == EtConstants.sleep) {
+                while (count < 1 || !scanList) {
+                    waitingCount++;
+                    att.setWaiting(true);
+//System.out.println("  get" + att.id + ": sleep");
+                    try {
+                        wait();
+                    }
+                    catch (InterruptedException ex) {
+                    }
+
+                    // if we've been told to wakeup & exit ...
+                    if (att.isWakeUp() || wakeAll) {
+                        att.setWakeUp(false);
+                        att.setWaiting(false);
+                        // last man to wake resets variable
+                        if (--waitingCount < 1) {
+                            wakeAll = false;
+                        }
+                        throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                    }
+
+                    att.setWaiting(false);
+                    waitingCount--;
+                    count = events.size();
+                    scanList = true;
+                }
+            }
+            else if (mode == EtConstants.timed) {
+                while (count < 1 || !scanList) {
+                    microDelay = microSec - 1000*elapsedTime;
+                    milliSec   = microDelay/1000L;
+                    if (milliSec < 0) {
+                        throw new EtTimeoutException("timed out");
+                    }
+                    nanos = 1000 * (int)(microDelay - 1000*milliSec);
+//                    if (nanos > 999999) {
+//                        System.out.println("nanos = " + nanos + ", millisec = " +
+//                           milliSec + ", elapsed = " + elapsedTime + ", microSec = " + microSec + ", scanList = " + scanList);
+//                  }
+
+                    waitingCount++;
+                    att.setWaiting(true);
+//System.out.println("  get" + att.id + ": wait " + milliSec + " ms and " +
+//                   nanos + " nsec, elapsed time = " + elapsedTime);
+                    begin = System.currentTimeMillis();
+                    try {
+                        wait(milliSec, nanos);
+                    }
+                    catch (InterruptedException ex) {
+                    }
+                    elapsedTime += System.currentTimeMillis() - begin;
+
+                    // if we've been told to wakeup & exit ...
+                    if (att.isWakeUp() || wakeAll) {
+                        att.setWakeUp(false);
+                        att.setWaiting(false);
+                        // last man to wake resets variable
+                        if (--waitingCount < 1) {
+                            wakeAll = false;
+                        }
+                        throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                    }
+
+                    att.setWaiting(false);
+                    waitingCount--;
+                    count = events.size();
+//System.out.println("  get" + att.id + ": woke up and counts = " + count);
+                    scanList = true;
+                }
+            }
+            else if (mode == EtConstants.async) {
+                throw new EtEmptyException("no events in list");
+            }
+
+            if (quantity > count) {
+                quantity = count;
+            }
+//System.out.println("  get"+ att.id + ": quantity = " + quantity);
+
+            for (ListIterator liter = events.listIterator(); liter.hasNext(); ) {
+                ev = (EtEventImpl)liter.next();
+                if (ev.getGroup() == group) {
+                    groupList.add(ev);
+                    if (++groupCount >= quantity)  break;
+                }
+            }
+
+            scanList = false;
+
+            // If we got nothing and we're Constants.sleep or Constants.timed, then try again
+        } while (groupCount == 0 && mode != EtConstants.async);
+
+        // remove from this list
+        events.removeAll(groupList);
+        eventsOut += groupList.size();
+        return groupList;
+    }
+}

hps-et-java/src/main/java/org/jlab/coda/et/system
StationLocal.java added at 1.1
diff -N StationLocal.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ StationLocal.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,942 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.*;
+
+/**
+ * This class defines a station for ET system use.
+ *
+ * @author Carl Timmer
+ */
+
+public class StationLocal extends Thread implements EtEventSelectable {
+
+    /** ET system object. */
+    private SystemCreate sys;
+
+    /** Unique id number. */
+    private int id;
+
+    /** Unique station name. */
+    private String name;
+
+    /** Station configuration object. */
+    private EtStationConfig config;
+
+    /** Station status. It may have the values {@link org.jlab.coda.et.EtConstants#stationUnused},
+     *  {@link org.jlab.coda.et.EtConstants#stationCreating}, {@link org.jlab.coda.et.EtConstants#stationIdle}, and
+     *  {@link org.jlab.coda.et.EtConstants#stationActive}. */
+    private volatile int status;
+
+    /** Flag telling this station to kill the conductor thread */
+    private volatile boolean killConductor;
+
+    /** Flag telling if this station was the last to receive an event
+     *  when using the round-robin selection method for a parallel group
+     *  of stations. */
+    private volatile boolean wasLast;
+
+    /** Lock used to stop insertion/removal of stations when events
+     *  are being transferred by the conductor thread and vice versa. */
+    private final ReentrantLock stopTransferLock;
+
+    /** If this station is the first in a linked list of parallel stations,
+     *  this list contains all the parallel stations in that group.
+     *  It's protected by stopTransferLock & {@link SystemCreate#systemLock}. */
+    private LinkedList<StationLocal> parallelStations;
+
+    /** Input list of events. */
+    private EventList inputList;
+    
+    /** Output list of events. */
+    private EventList outputList;
+
+    /** Set of attachments to this station. */
+    private HashSet<AttachmentLocal> attachments;
+
+    /** Predefined event selection method used when the station's select mode
+     *  is {@link org.jlab.coda.et.EtConstants#stationSelectMatch}. */
+    private EtEventSelectable selector;
+
+    /**
+     * Creates a new StationLocal object.
+     *
+     * @param sys ET system object
+     * @param name station name
+     * @param config station configuration
+     * @param id unique station id number
+     * @throws EtException
+     *     if the station cannot load the selectClass
+     */
+    public StationLocal(SystemCreate sys, String name, EtStationConfig config, int id)
+            throws EtException {
+
+        this.id          = id;
+        this.sys         = sys;
+        this.name        = name;
+        this.config      = new EtStationConfig(config);
+        status           = EtConstants.stationUnused;
+        parallelStations = new LinkedList<StationLocal>();
+        stopTransferLock = new ReentrantLock();
+
+        inputList  = new EventList();
+        outputList = new EventList();
+
+        // attachments
+        attachments = new HashSet<AttachmentLocal>(EtConstants.attachmentsMax);
+
+        // user event selection routine
+        selector = this;
+        if (config.getSelectMode() == EtConstants.stationSelectUser) {
+            // instantiate object of proper class
+            try {
+                Object f = Class.forName(config.getSelectClass()).newInstance();
+                selector = (EtEventSelectable) f;
+            }
+            catch (ClassNotFoundException ex) {
+                throw new EtException("station cannot load select class " + config.getSelectClass());
+            }
+            catch (InstantiationException ex) {
+                throw new EtException("station cannot instantiate class " + config.getSelectClass());
+            }
+            catch (IllegalAccessException ex) {
+                throw new EtException("station cannot load class " + config.getSelectClass());
+            }
+
+            if (sys.getConfig().getDebug() >= EtConstants.debugInfo) {
+                System.out.println(name + " loaded select class " + config.getSelectClass());
+            }
+        }
+    }
+
+
+    /**
+     * Gets the station id number. Because this class extends Thread, calling this method
+     * getId() would override the method from the Thread class, which is something
+     * we do NOT want. So call this method getStationId() instead.
+     * @return station id number
+     */
+    public int getStationId() { return id; }
+
+    /**
+     * Gets the station name. Because this class extends Thread, calling this method
+     * getName() would override the method from the Thread class, which is something
+     * we do NOT want. So call this method getStationName() instead.
+     * @return station name
+     */
+    public String getStationName() { return name; }
+
+    /**
+     * Get object containing list of input events.
+     * @return object containing list of input events
+     */
+    public EventList getInputList() { return inputList; }
+
+    /**
+     * Get object containing list of utput events.
+     * @return object containing list of output events
+     */
+    public EventList getOutputList() { return outputList; }
+
+    /**
+     * Get lock object used to add and remove stations from the station linked list
+     * while blocking the moving of events.
+     * @return lock object
+     */
+    public ReentrantLock getStopTransferLock() { return stopTransferLock; }
+
+    /**
+     * Get the station configuration.
+     * @return tation configuration
+     */
+    public EtStationConfig getConfig() { return config; }
+
+    /**
+     * Get the linked list of parallel stations.
+     * @return linked list of parallel stations
+     */
+    public LinkedList<StationLocal> getParallelStations() { return parallelStations; }
+
+    /**
+     * Get the station status which may be one of the following values: {@link org.jlab.coda.et.EtConstants#stationUnused },
+     * {@link org.jlab.coda.et.EtConstants#stationCreating}, {@link org.jlab.coda.et.EtConstants#stationIdle}, or  {@link org.jlab.coda.et.EtConstants#stationActive}.
+     * @return station status
+     */
+    public int getStatus() { return status; }
+
+    /**
+     * Set the station status which may be one of the following values: {@link org.jlab.coda.et.EtConstants#stationUnused },
+     * {@link org.jlab.coda.et.EtConstants#stationCreating}, {@link org.jlab.coda.et.EtConstants#stationIdle}, or {@link org.jlab.coda.et.EtConstants#stationActive}.
+     * Since the user does not ever call this method, forget any argument checks.
+     * @param status station status
+     */
+    public void setStatus(int status) { this.status = status; }
+
+    /**
+     * Get the set of attachments to this station.
+     * @return set of attachments to this station
+     */
+    public HashSet<AttachmentLocal> getAttachments() { return attachments; }
+
+    /**
+     * Is the conductor thread scheduled to be terminated?
+     * @return <code>true</code> if conductor thread scheduled to be terminated, else <code>false</code>
+     */
+    public boolean isKillConductor() { return killConductor; }
+
+    /** Schedule conductor thread to be terminated. */
+    public void killConductor() { killConductor = true; }
+
+
+    /**
+     * Method to dynamically set a station's blocking mode.
+     * @param mode blocking mode value
+     */
+    void setBlockMode(int mode) {
+        if (config.getBlockMode() == mode) return;
+        synchronized(sys.getStationLock()) {
+            synchronized(inputList) {
+                try {
+                    config.setBlockMode(mode);
+                }
+                catch (EtException e) { /* should not happen. */  }
+            }
+        }
+    }
+
+
+    /**
+     * Method to dynamically set a station's cue.
+     * @param cue cue value
+     */
+    void setCue(int cue) {
+        if (config.getCue() == cue) return;
+        synchronized(sys.getStationLock()) {
+            synchronized(inputList) {
+                try {
+                    config.setCue(cue);
+                }
+                catch (EtException e) { /* should not happen. */  }
+            }
+        }
+    }
+
+
+    /**
+     * Method to dynamically set a station's prescale.
+     * @param prescale prescale value
+     */
+    void setPrescale(int prescale) {
+        if (config.getPrescale() == prescale) return;
+        synchronized(sys.getStationLock()) {
+            synchronized(inputList) {
+                try {
+                    config.setPrescale(prescale);
+                }
+                catch (EtException e) { /* should not happen. */  }
+            }
+        }
+    }
+
+
+    /**
+     * Method to dynamically set a station's select integers.
+     * @param select array of selection integers
+     */
+    void setSelectWords(int[] select) {
+        if (config.getSelect() == select) return;
+        synchronized(sys.getStationLock()) {
+            synchronized(inputList) {
+                try {
+                    config.setSelect(select.clone());
+                }
+                catch (EtException e) { /* should not happen. */  }
+            }
+        }
+    }
+
+
+    /**
+     * Method to dynamically set a station's user mode.
+     * @param mode user mode value
+     */
+    void setUserMode(int mode) {
+        if (config.getUserMode() == mode) return;
+        synchronized(sys.getStationLock()) {
+            try {
+                config.setUserMode(mode);
+            }
+            catch (EtException e) { /* should not happen. */  }
+        }
+    }
+
+
+    /**
+     * Method to dynamically set a station's restore mode.
+     * @param mode restore mode value
+     */
+    void setRestoreMode(int mode) {
+        if (config.getRestoreMode() == mode) return;
+        synchronized(sys.getStationLock()) {
+            try {
+                config.setRestoreMode(mode);
+            }
+            catch (EtException e) { /* should not happen. */  }
+        }
+    }
+
+
+    /**
+     * When selectMode equals {@link org.jlab.coda.et.EtConstants#stationSelectMatch}, this
+     * becomes the station's selection method.
+     *
+     * @param sys ET system object
+     * @param stat station object
+     * @param ev event object being evaluated
+     * @see org.jlab.coda.et.EtEventSelectable
+     */
+    public boolean select(SystemCreate sys, StationLocal stat, EtEvent ev) {
+        boolean result = false;
+        int[] select  = stat.config.getSelect();
+        int[] control = ev.getControl();
+
+        for (int i=0; i < EtConstants.stationSelectInts ; i++) {
+            if (i%2 == 0) {
+                result = result || ((select[i] != -1) &&
+                        (select[i] == control[i]));
+            }
+            else {
+                result = result || ((select[i] != -1) &&
+                        ((select[i] & control[i]) != 0));
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Shell's method of sorting from "Numerical Recipes" slightly modified.
+     * It is assumed that a and b have indexes from 1 to n. Since the input
+     * arrays will start at 0 index, put nonsense in the first element.
+     *
+     * @param n number of array elements to be sorted
+     * @param a array to be sorted
+     * @param b array to be sorted in the same manner that array a is sorted
+     */
+    private void shellSort(int n, int[] a, int[] b) {
+        int i, j, inc, v, w;
+        inc = 1;
+        do {
+            inc *= 3;
+            inc++;
+        } while (inc <= n);
+
+        do {
+            inc /= 3;
+            for (i = inc + 1; i <= n; i++) {
+                v = a[i];
+                w = b[i];
+                j = i;
+                while (a[j - inc] > v) {
+                    a[j] = a[j - inc];
+                    b[j] = b[j - inc];
+                    j -= inc;
+                    if (j <= inc) break;
+                }
+                a[j] = v;
+                b[j] = w;
+            }
+        } while (inc > 1);
+    }
+
+    
+    /**
+     * Method to implement thread conducting events between stations. This
+     * conductor places all events that go into a single station into one list
+     * then writes it. It looks downstream, one station at a time, and repeats
+     * the process.
+     * It optimizes for cases in which the next station is GRAND_CENTRAL or one
+     * which takes all events. In those cases, it dumps everything in that
+     * station's input list without bothering to sort or filter it.
+     */
+    public void run() {
+        int count, prescale, available, getListSize, position;
+        long listTry;
+        EtEventImpl ev;
+        boolean writeAll, parallelIsActive, rrobinOrEqualcue;
+        StationLocal currentStat, stat, firstActive, startStation;
+        List<EtEventImpl> subList;
+        ListIterator statIterator, pIterator = null;
+
+        // inputList of next station
+        EventList inList;
+        // events read from station's outputList
+        ArrayList<EtEventImpl> getList = new ArrayList<EtEventImpl>(sys.getConfig().getNumEvents());
+        // events to be put into the next station's inputList
+        ArrayList<EtEventImpl> putList = new ArrayList<EtEventImpl>(sys.getConfig().getNumEvents());
+
+        // store some constants in stack variables for greater speed
+        final int idle = EtConstants.stationIdle;
+        final int active = EtConstants.stationActive;
+        final int blocking = EtConstants.stationBlocking;
+        final int nonBlocking = EtConstants.stationNonBlocking;
+        final int selectAll = EtConstants.stationSelectAll;
+        final int parallel = EtConstants.stationParallel;
+
+        if (name.equals("GRAND_CENTRAL")) {
+            status = active;
+        }
+        else {
+            status = idle;
+        }
+
+        while (true) {
+            // wait for events
+            synchronized (outputList) {
+                while (outputList.getEvents().size() < 1) {
+                    try {
+                        outputList.wait();
+                    }
+                    catch (InterruptedException ex) {
+                    }
+                    if (killConductor) {
+                        return;
+                    }
+                }
+            }
+
+            // grab all events in station's outputList
+            outputList.get(getList);
+
+            // reinit items
+            writeAll = false;
+
+            // allow no change to linked list of created stations
+            stopTransferLock.lock();
+
+            // find next station in main linked list
+            position = sys.getStations().indexOf(this);
+            // If we're a parallel station which is NOT the head of its group,
+            // find our position in the main linked list
+            if (position < 0) {
+                position = 1;
+                for (ListIterator i = sys.getStations().listIterator(1); i.hasNext();) {
+                    stat = (StationLocal) i.next();
+                    if (stat.config.getFlowMode() == parallel) {
+                        // we've found the group of parallel stations we belong to & our position
+                        if (stat.parallelStations.indexOf(this) > -1) {
+                            break;
+                        }
+                    }
+                    position++;
+                }
+            }
+
+            statIterator = sys.getStations().listIterator(position + 1);
+            if (statIterator.hasNext()) {
+                currentStat = (StationLocal) statIterator.next();
+            }
+            else {
+                // the next station is GrandCentral, put everything in it
+                currentStat = sys.getStations().getFirst();
+                inList = currentStat.inputList;
+                synchronized (inList) {
+                    inList.putInLow(getList);
+                    getList.clear();
+                    inList.notifyAll();
+                }
+                stopTransferLock.unlock();
+                continue;
+            }
+
+            inList = currentStat.inputList;
+
+            while (getList.size() > 0) {
+                parallelIsActive = false;
+                rrobinOrEqualcue = false;
+                startStation = null;
+                firstActive = null;
+
+                // if this is a parallel station ...
+                if (currentStat.config.getFlowMode() == EtConstants.stationParallel) {
+                    // Are any of the parallel stations active or can we skip the bunch?
+                    pIterator = currentStat.parallelStations.listIterator();
+                    while (pIterator.hasNext()) {
+                        stat = (StationLocal) pIterator.next();
+                        if (stat.status == EtConstants.stationActive) {
+                            parallelIsActive = true;
+                            firstActive = stat;
+                            break;
+                        }
+                    }
+                    // At this point pIterator will give the station after firstActive
+                    // with the following next().
+
+                    // Which algorithm are we using?
+                    if (parallelIsActive &&
+                            ((currentStat.config.getSelectMode() == EtConstants.stationSelectRRobin) ||
+                                    (currentStat.config.getSelectMode() == EtConstants.stationSelectEqualCue))) {
+                        rrobinOrEqualcue = true;
+                    }
+                }
+
+                // if not rrobin/equalcue & station(s) is(are) active ...
+                if (!rrobinOrEqualcue &&
+                        (parallelIsActive || (currentStat.status == EtConstants.stationActive))) {
+
+                    if (currentStat.config.getFlowMode() == EtConstants.stationParallel) {
+                        // Skip to first active parallel station
+                        currentStat = firstActive;
+                        inList = currentStat.inputList;
+                    }
+
+                    // Loop through all the active parallel stations if necessary.
+                    parallelDo:
+                    do {
+                        // allow no exterior change to inputList
+                        synchronized (inList) {
+                            // if GrandCentral, put everything into it ...
+                            if (currentStat.id == 0) {
+                                writeAll = true;
+                            }
+
+                            // all events, blocking
+                            else if ((currentStat.config.getSelectMode() == selectAll) &&
+                                    (currentStat.config.getBlockMode() == blocking)) {
+
+                                // if prescale=1, dump everything into station
+                                getListSize = getList.size();
+                                if (currentStat.config.getPrescale() == 1) {
+                                    writeAll = true;
+                                }
+                                else {
+                                    prescale = currentStat.config.getPrescale();
+                                    listTry = inList.getEventsTry();
+                                    subList = getList.subList(0, (int) ((listTry + getListSize) / prescale - listTry / prescale));
+                                    putList.addAll(subList);
+                                    subList.clear();
+                                }
+                                inList.setEventsTry(inList.getEventsTry() + getListSize);
+                            }
+
+                            // all events, nonblocking
+                            else if ((currentStat.config.getSelectMode() == selectAll) &&
+                                    (currentStat.config.getBlockMode() == nonBlocking)) {
+                                if (inList.getEvents().size() < currentStat.config.getCue()) {
+                                    count = currentStat.config.getCue() - inList.getEvents().size();
+                                    available = getList.size();
+                                    subList = getList.subList(0, (count > available) ? available : count);
+                                    putList.addAll(subList);
+                                    subList.clear();
+                                }
+                            }
+
+                            //  condition (user or match), blocking
+                            else if (currentStat.config.getBlockMode() == blocking) {
+                                prescale = currentStat.config.getPrescale();
+                                for (ListIterator i = getList.listIterator(); i.hasNext();) {
+                                    ev = (EtEventImpl) i.next();
+                                    // apply selection method
+                                    if (currentStat.selector.select(sys, currentStat, ev)) {
+                                        // apply prescale
+                                        listTry = inList.getEventsTry();
+                                        inList.setEventsTry(listTry + 1);
+                                        if ((listTry % prescale) == 0) {
+                                            putList.add(ev);
+                                            i.remove();
+                                        }
+                                    }
+                                }
+                            }
+
+                            // condition (user or match) + nonblocking
+                            else if (currentStat.config.getBlockMode() == nonBlocking) {
+                                if (inList.getEvents().size() < currentStat.config.getCue()) {
+                                    count = currentStat.config.getCue() - inList.getEvents().size();
+                                    for (ListIterator i = getList.listIterator(); i.hasNext();) {
+                                        ev = (EtEventImpl) i.next();
+                                        // apply selection method
+                                        if (currentStat.selector.select(sys, currentStat, ev)) {
+                                            putList.add(ev);
+                                            i.remove();
+                                            if (--count < 1) {
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+
+                            // if items go in this station ...
+                            if ((putList.size() > 0) || (writeAll)) {
+                                // if grandcentral
+                                if (currentStat.id == 0) {
+                                    inList.putInLow(getList);
+                                    getList.clear();
+                                    writeAll = false;
+                                }
+
+                                else {
+                                    if (writeAll) {
+                                        inList.putAll(getList);
+                                        getList.clear();
+                                        writeAll = false;
+                                    }
+                                    else {
+                                        inList.putAll(putList);
+                                        putList.clear();
+                                    }
+                                }
+                                // signal reader that new events are here
+                                inList.notifyAll();
+                            } // if items go in this station
+                        } // end of inputList synchronization
+
+                        // go to next active parallel station, if there is one
+                        if (parallelIsActive) {
+                            do {
+                                if (pIterator.hasNext()) {
+                                    stat = (StationLocal) pIterator.next();
+                                    if (stat.status == EtConstants.stationActive) {
+                                        currentStat = stat;
+                                        inList = currentStat.inputList;
+                                        break;
+                                    }
+                                }
+                                else {
+                                    break parallelDo;
+                                }
+                            } while (stat.status != EtConstants.stationActive);
+                        }
+
+                        // loop through active parallel stations if necessary
+                    } while (parallelIsActive && (getList.size() > 0));
+
+                } // if station active and not rrobin or equalcue
+
+                // Implement the round-robin & equal-cue algorithms for dispensing
+                // events to a single group of parallel stations.
+                else if (rrobinOrEqualcue && parallelIsActive) {
+
+                    int num, extra, lastEventIndex = 0, eventsAlreadyPut, numActiveStations = 0;
+                    int index, numOfEvents, min, eventsToPut, eventsLeft;
+                    int eventsPerStation, nextHigherCue, eventsDoledOut, stationsWithSameCue;
+                    int[] numEvents;
+
+                    if (currentStat.config.getSelectMode() == EtConstants.stationSelectRRobin) {
+                        // Flag to start looking for station that receives first round-robin event
+                        boolean startLooking = false;
+                        stat = currentStat;
+                        pIterator = currentStat.parallelStations.listIterator(1);
+
+                        while (true) {
+                            // for each active station ...
+                            if (stat.status == EtConstants.stationActive) {
+                                if (startLooking) {
+                                    // This is the first active station after
+                                    // the last station to receive an event.
+                                    startStation = stat;
+                                    startLooking = false;
+                                }
+                                numActiveStations++;
+                            }
+
+                            // Find last station to receive a round-robin event and start looking
+                            // for the next active station to receive the first one.
+                            if (stat.wasLast) {
+                                stat.wasLast = false;
+                                startLooking = true;
+                            }
+
+                            // find next station in the parallel linked list
+                            if (pIterator.hasNext()) {
+                                stat = (StationLocal) pIterator.next();
+                            }
+                            // else if we're at the end of the list ...
+                            else {
+                                // If we still haven't found a place to start the round-robin
+                                // event dealing, make it the first active station.
+                                if (startStation == null) {
+                                    startStation = firstActive;
+                                }
+                                break;
+                            }
+                        }
+
+                        // Find the number of events going into each station
+                        num = getList.size() / numActiveStations;
+                        // Find the number of events left over (not enough for another round). */
+                        extra = getList.size() % numActiveStations;
+                        eventsAlreadyPut = count = 0;
+                        numEvents = new int[numActiveStations];
+
+                        // Rearrange events so all those destined for a particular
+                        // station are grouped together in the new array.
+                        for (int i = 0; i < numActiveStations; i++) {
+                            if (i < extra) {
+                                numEvents[i] = num + 1;
+                                if (i == (extra - 1)) {
+                                    lastEventIndex = i;
+                                }
+                            }
+                            else {
+                                numEvents[i] = num;
+                            }
+
+                            if (extra == 0) {
+                                lastEventIndex = numActiveStations - 1;
+                            }
+
+                            numOfEvents = numEvents[i];
+
+                            index = i;
+                            for (int j = 0; j < numOfEvents; j++) {
+                                putList.add(getList.get(index));
+                                index += numActiveStations;
+                            }
+                        }
+
+                        // Place the first event with the station after the one which
+                        // received the last event in the previous round.
+                        stat = startStation;
+                        inList = stat.inputList;
+                        count = 0;
+
+                        // set iterator to start with the station following startStation
+                        index = currentStat.parallelStations.indexOf(startStation) + 1;
+                        pIterator = currentStat.parallelStations.listIterator(index);
+
+                        while (true) {
+                            // For each active parallel station ...
+                            if (stat.status == EtConstants.stationActive) {
+                                // Mark station that got the last event
+                                if (count == lastEventIndex) {
+                                    stat.wasLast = true;
+                                }
+
+                                // Put "eventsToPut" number of events in the next active station
+                                eventsToPut = numEvents[count++];
+
+                                if (eventsToPut > 0) {
+                                    synchronized (inList) {
+                                        subList = putList.subList(eventsAlreadyPut, eventsAlreadyPut + eventsToPut);
+                                        inList.putAll(subList);
+                                        inList.setEventsTry(inList.getEventsTry() + eventsToPut);
+                                        // signal reader that new events are here
+                                        inList.notifyAll();
+                                    }
+
+                                    eventsAlreadyPut += eventsToPut;
+                                }
+                            }
+
+                            // Find next active station
+                            if (count >= numActiveStations) {
+                                break;
+                            }
+                            else if (pIterator.hasNext()) {
+                                stat = (StationLocal) pIterator.next();
+                                inList = stat.inputList;
+                            }
+                            else {
+                                // Go back to the first active parallel station
+                                stat = firstActive;
+                                inList = stat.inputList;
+                                index = currentStat.parallelStations.indexOf(stat) + 1;
+                                pIterator = currentStat.parallelStations.listIterator(index);
+                            }
+                        } // while (forever)
+
+                        putList.clear();
+
+                    } // if round-robin
+
+                    // else if equal-cue algorithm ...
+                    else {
+                        eventsLeft = getList.size();
+                        eventsDoledOut = 0;
+                        eventsAlreadyPut = 0;
+                        stationsWithSameCue = 0;
+
+                        // Array that keeps track of original station order, and
+                        // one that contains input list counts.
+                        // Give 'em an extra element as the sorting routine
+                        // assumes a starting index of 1.
+                        int[] place = new int[sys.getConfig().getStationsMax() + 1];
+                        int[] inListCount = new int[sys.getConfig().getStationsMax() + 1];
+                        for (int i = 1; i <= sys.getConfig().getStationsMax(); i++) {
+                            place[i] = i;
+                        }
+
+                        stat = firstActive;
+                        while (true) {
+                            // For each active station ...
+                            if (stat.status == EtConstants.stationActive) {
+                                // Find total # of events in stations' input lists.
+                                // Store this information as it will change and we don't
+                                // really want to grab all the input mutexes to make
+                                // sure these values don't change.
+                                inListCount[numActiveStations + 1] = stat.inputList.getEvents().size();
+
+                                // Total number of active stations
+                                numActiveStations++;
+                            }
+
+                            // find next station in the parallel linked list
+                            if (pIterator.hasNext()) {
+                                stat = (StationLocal) pIterator.next();
+                            }
+                            else {
+                                break;
+                            }
+                        }
+
+                        // Sort the input lists (cues) according to number of events. The "place"
+                        // array remembers the place in the presorted array of input lists.
+                        // Arrays to be sorted are assumed to have indexes from 1 to n,
+                        // so the first element contains nonsense.
+                        shellSort(numActiveStations, inListCount, place);
+
+                        // To determine which stations get how many events:
+                        // Take the lowest cues, add enough to make them equal
+                        // to the next higher cue. Continue doing this until all
+                        // are equal. Evenly divide any remaining events.
+                        nextHigherCue = 0;
+                        min = inListCount[1];
+                        numEvents = new int[numActiveStations];
+
+                        while (eventsDoledOut < eventsLeft) {
+                            // Find how many cues have the lowest # of events in them
+                            stationsWithSameCue = 0;
+                            for (int i = 1; i <= numActiveStations; i++) {
+                                // Does events in cue + events we've just given it = min?
+                                if (min == inListCount[i] + numEvents[place[i] - 1]) {
+                                    stationsWithSameCue++;
+                                }
+                                else {
+                                    nextHigherCue = inListCount[i];
+                                    break;
+                                }
+                            }
+
+                            // If all stations have same # of events, or if there are not enough
+                            // events to fill each lowest cue to level of the next higher cue,
+                            // we spread available events between them all ...
+                            if ((stationsWithSameCue == numActiveStations) ||
+                                    ((eventsLeft - eventsDoledOut) < ((nextHigherCue - min) * stationsWithSameCue)))
+                            {
+                                eventsToPut = eventsLeft - eventsDoledOut;
+                                eventsPerStation = eventsToPut / stationsWithSameCue;
+                                extra = eventsToPut % stationsWithSameCue;
+                                count = 0;
+                                for (int i = 1; i <= stationsWithSameCue; i++) {
+                                    if (count++ < extra) {
+                                        numEvents[place[i] - 1] += eventsPerStation + 1;
+                                    }
+                                    else {
+                                        numEvents[place[i] - 1] += eventsPerStation;
+                                    }
+                                }
+                                break;
+                            }
+                            // Else, fill the lowest cues to the level of the next higher cue
+                            // and repeat the cycle.
+                            else {
+                                eventsPerStation = nextHigherCue - min;
+                                for (int i = 1; i <= stationsWithSameCue; i++) {
+                                    numEvents[place[i] - 1] += eventsPerStation;
+                                }
+                                min = nextHigherCue;
+                            }
+                            eventsDoledOut += eventsPerStation * stationsWithSameCue;
+                        }
+
+                        stat = firstActive;
+                        count = 0;
+                        index = currentStat.parallelStations.indexOf(stat) + 1;
+                        pIterator = currentStat.parallelStations.listIterator(index);
+
+                        while (true) {
+                            // for each active parallel station ...
+                            if (stat.status == EtConstants.stationActive) {
+
+                                if ((eventsToPut = numEvents[count++]) < 1) {
+                                    // find next station in the parallel linked list
+                                    if (pIterator.hasNext()) {
+                                        stat = (StationLocal) pIterator.next();
+                                        continue;
+                                    }
+                                    else {
+                                        break;
+                                    }
+                                }
+
+                                // Put "eventsToPut" number of events in the next active station
+                                inList = stat.inputList;
+                                synchronized (inList) {
+                                    subList = getList.subList(eventsAlreadyPut, eventsAlreadyPut + eventsToPut);
+                                    inList.putAll(subList);
+                                    inList.setEventsTry(inList.getEventsTry() + eventsToPut);
+                                    // signal reader that new events are here
+                                    inList.notifyAll();
+                                }
+
+                                eventsAlreadyPut += eventsToPut;
+                            }
+
+                            // Find next station in the parallel linked list
+                            if (pIterator.hasNext()) {
+                                stat = (StationLocal) pIterator.next();
+                            }
+                            else {
+                                break;
+                            }
+                        } // while(true)
+                    } // else if equal-cue algorithm
+
+                    getList.clear();
+
+                } // Implement the round-robin & equal-cue algorithms
+
+                if (currentStat.id == 0) {
+                    break;
+                }
+
+                // find next station
+                if (statIterator.hasNext()) {
+                    currentStat = (StationLocal) statIterator.next();
+                }
+                else {
+                    currentStat = sys.getStations().getFirst();
+                }
+                inList = currentStat.inputList;
+
+            } // while(getList.size() > 0), events left to put
+
+            // stop transfer unlocked - now changes to stations linked list allowed
+            stopTransferLock.unlock();
+
+        } // while(true)
+
+    } // run method
+
+
+}

hps-et-java/src/main/java/org/jlab/coda/et/system
SystemConfig.java added at 1.1
diff -N SystemConfig.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SystemConfig.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,448 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.util.*;
+import java.net.*;
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.EtConstants;
+
+/**
+ * This class defines a configuration for the creation of an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class SystemConfig {
+
+    /** Total number of events. */
+    private int numEvents;
+
+    /** Size of the "normal" event in bytes. This is the memory allocated to each
+     *  event upon starting up the ET system. */
+    private int eventSize;
+
+    /** Number of events in each group. Used with multiple producers who want to
+     * guarantee available events for each producer. */
+    private int[] groups;
+
+    /** Maximum number of station. */
+    private int stationsMax;
+
+    /** Maximum number of attachments. */
+    private int attachmentsMax;
+
+    /**
+     *  Debug level. This may have values of {@link org.jlab.coda.et.EtConstants#debugNone} meaning
+     *  print nothing, {@link org.jlab.coda.et.EtConstants#debugSevere} meaning print only the
+     *  severest errors, {@link org.jlab.coda.et.EtConstants#debugError} meaning print all errors,
+     *  {@link org.jlab.coda.et.EtConstants#debugWarn} meaning print all errors and warnings, and
+     *  finally {@link org.jlab.coda.et.EtConstants#debugInfo} meaning print all errors, warnings,
+     *  and informative messages.
+     */
+    private int debug;
+
+    /** ET server's TCP send buffer size in bytes. */
+    private int tcpSendBufSize;
+
+    /** ET server's TCP receive buffer size in bytes. */
+    private int tcpRecvBufSize;
+
+    /**
+     * ET server's socket's no-delay setting.
+     * <code>True</code> if no delay, else <code>false</code>.
+     */
+    private boolean noDelay;
+
+    /** UDP port number for thread responding to users' broadcasts looking for the
+     *  ET system. */
+    private int udpPort;
+
+    /** TCP port number for the thread establishing connections with users,
+     *  otherwise referred to as the ET server thread. */
+    private int serverPort;
+
+    /** UDP port number for thread responding to users' multicasts looking for the
+     *  ET system. */
+    private int multicastPort;
+
+    /** Set of all multicast addresses to listen on (in String form). */
+    private HashSet<InetAddress> multicastAddrs;
+
+
+    /**
+     * Constructor that creates a new SystemConfig object using default parameters.
+     * The default parameters are:
+     *      number of events          = {@link org.jlab.coda.et.EtConstants#defaultNumEvents},
+     *      event size                = {@link org.jlab.coda.et.EtConstants#defaultEventSize},
+     *      max number of stations    = {@link org.jlab.coda.et.EtConstants#defaultStationsMax},
+     *      max number of attachments = {@link org.jlab.coda.et.EtConstants#defaultAttsMax},
+     *      debug level               = {@link org.jlab.coda.et.EtConstants#debugError},
+     *      udp port                  = {@link org.jlab.coda.et.EtConstants#broadcastPort},
+     *      server (tcp) port         = {@link org.jlab.coda.et.EtConstants#serverPort}, and
+     *      multicasting port         = {@link org.jlab.coda.et.EtConstants#multicastPort}.
+     */
+    public SystemConfig () {
+        numEvents       = EtConstants.defaultNumEvents;
+        eventSize       = EtConstants.defaultEventSize;
+        stationsMax     = EtConstants.defaultStationsMax;
+        attachmentsMax  = EtConstants.defaultAttsMax;
+        debug           = EtConstants.debugError;
+        udpPort         = EtConstants.broadcastPort;
+        serverPort      = EtConstants.serverPort;
+        multicastPort   = EtConstants.multicastPort;
+        multicastAddrs  = new HashSet<InetAddress>(10);
+        // by default there is one group with all events in it
+        groups          = new int[1];
+        groups[0]       = numEvents;
+    }
+
+    /** Constructor that creates a new SystemConfig object from an existing one. */
+    public SystemConfig (SystemConfig config) {
+        numEvents       = config.numEvents;
+        eventSize       = config.eventSize;
+        stationsMax     = config.stationsMax;
+        attachmentsMax  = config.attachmentsMax;
+        debug           = config.debug;
+        udpPort         = config.udpPort;
+        tcpRecvBufSize  = config.tcpRecvBufSize;
+        tcpSendBufSize  = config.tcpSendBufSize;
+        noDelay         = config.noDelay;
+        serverPort      = config.serverPort;
+        multicastPort   = config.multicastPort;
+        multicastAddrs  = new HashSet<InetAddress>(config.multicastAddrs);
+        groups          = config.groups.clone();
+    }
+
+
+    // public gets
+
+
+    /** Get the total number of events.
+     *  @return total number of events */
+    public int getNumEvents() {return numEvents;}
+
+    /** Get the size of the normal events in bytes.
+     *  @return size of normal events in bytes */
+    public int getEventSize() {return eventSize;}
+
+    /** Get the array of how many events in each group.
+     *  @return array of how many events in each group */
+    public int[] getGroups() {return groups.clone();}
+
+    /** Get the maximum number of stations.
+     *  @return maximum number of stations */
+    public int getStationsMax() {return stationsMax;}
+
+    /** Get the maximum number of attachments.
+     *  @return maximum number of attachments */
+    public int getAttachmentsMax() {return attachmentsMax;}
+
+    /** Get the debug level.
+     *  @return debug level */
+    public int getDebug() {return debug;}
+
+    /** Get the TCP receive buffer size in bytes.
+     *  @return TCP receive buffer size in bytes */
+    public int getTcpSendBufSize() {
+        return tcpSendBufSize;
+    }
+
+    /** Get the TCP send buffer size in bytes.
+     *  @return TCP send buffer size in bytes */
+    public int getTcpRecvBufSize() {
+        return tcpRecvBufSize;
+    }
+
+    /** Get the TCP no-delay setting.
+     *  @return TCP no-delay setting */
+    public boolean isNoDelay() {
+        return noDelay;
+    }
+
+    /** Get the udp port number.
+     *  @return udp port number */
+    public int getUdpPort() {return udpPort;}
+
+    /** Get the tcp server port number.
+     *  @return tcp server port number */
+    public int getServerPort() {return serverPort;}
+
+    /** Get the multicast port number.
+     *  @return multicast port number */
+    public int getMulticastPort() {return multicastPort;}
+
+    /** Get the set of multicast addresses.
+     *  @return set of multicast addresses */
+    public Set<InetAddress> getMulticastAddrs() {return new HashSet<InetAddress>(multicastAddrs);}
+
+    /** Get the multicast addresses as a String array.
+     *  @return multicast addresses as a String array */
+    public String[] getMulticastStrings() {
+        if (multicastAddrs == null) {
+            return null;
+        }
+        int index = 0;
+        String[] addrs = new String[multicastAddrs.size()];
+        for (InetAddress addr : multicastAddrs) {
+            addrs[index++] = addr.getHostAddress();
+        }
+        return addrs;
+    }
+
+
+    // public adds, removes
+
+
+    /**
+     * Adds a multicast address to the set.
+     * @param mCastAddr multicast address
+     * @throws EtException
+     *     if the argument is not a multicast address
+     */
+    public void addMulticastAddr(String mCastAddr) throws EtException {
+        InetAddress addr;
+        try {addr = InetAddress.getByName(mCastAddr);}
+        catch (UnknownHostException ex) {
+            throw new EtException("not a multicast address");
+        }
+
+        if (!addr.isMulticastAddress()) {
+            throw new EtException("not a multicast address");
+        }
+        multicastAddrs.add(addr);
+        return;
+    }
+
+
+    /**
+     * Removes a multicast address from the set.
+     * @param addr multicast address
+     */
+    public void removeMulticastAddr(String addr) {
+        InetAddress ad;
+        try {ad = InetAddress.getByName(addr);}
+        catch (UnknownHostException ex) {
+            return;
+        }
+        multicastAddrs.remove(ad);
+        return;
+    }
+
+
+  // public sets
+
+
+    /**
+     * Set the total number of events.
+     * @param num total number of events
+     * @throws EtException
+     *     if the argument is less than 1
+     */
+    public void setNumEvents(int num) throws EtException {
+        if (num < 1) {
+            throw new EtException("must have 1 or more events");
+        }
+        numEvents = num;
+        if (groups.length ==1) groups[0] = num;
+    }
+
+
+    /**
+     * Set the event size in bytes.
+     * @param size event size in bytes
+     * @throws EtException
+     *     if the argument is less than 1 byte
+     */
+    public void setEventSize(int size) throws EtException {
+        if (size < 1) {
+            throw new EtException("events must have at least one byte");
+        }
+        eventSize = size;
+    }
+
+
+    /**
+     * Set the number of events in each group. Used with mulitple producers who want to
+     * guarantee available events for each producer.
+     *
+     * @param groups array defining number of events in each group
+     * @throws EtException
+     *     if the groups array has length < 1 or values are not positive ints
+     */
+    public void setGroups(int[] groups) throws EtException {
+        if (groups.length < 1) {
+            throw new EtException("events must have at least one group");
+        }
+        for (int num : groups) {
+            if (num < 1) {
+                throw new EtException("each event group must contain at least one event");
+            }
+        }
+
+        this.groups = groups.clone();
+    }
+
+    /**
+     * Set the maximum number of stations.
+     * @param num maximum number of stations
+     * @throws EtException
+     *     if the argument is less than 2
+     */
+    public void setStationsMax(int num) throws EtException {
+        if (num < 2) {
+            throw new EtException("must have at least 2 stations");
+        }
+        stationsMax = num;
+    }
+
+
+    /**
+     * Set the maximum number of attachments.
+     * @param num maximum number of attachments
+     * @throws EtException
+     *     if the argument is less than 1
+     */
+    public void setAttachmentsMax(int num) throws EtException {
+        if (num < 1) {
+            throw new EtException("must be able to have at least one attachment");
+        }
+        attachmentsMax = num;
+    }
+
+
+    /**
+     * Set the debug level.
+     * @param level debug level
+     * @throws EtException
+     *     if the argument has a bad value
+     */
+    public void setDebug(int level) throws EtException {
+        if ((level != EtConstants.debugNone)   &&
+                (level != EtConstants.debugInfo)   &&
+                (level != EtConstants.debugWarn)   &&
+                (level != EtConstants.debugError)  &&
+                (level != EtConstants.debugSevere))  {
+            throw new EtException("bad debug value");
+        }
+        debug = level;
+    }
+
+
+    /**
+     * Set the TCP send buffer size in bytes. A value of 0
+     * means use the operating system default.
+     *
+     * @param tcpSendBufSize TCP send buffer size in bytes
+     * @throws EtException
+     *     if the argument is less than 0
+     */
+    public void setTcpSendBufSize(int tcpSendBufSize) throws EtException {
+        if (tcpSendBufSize < 0) {
+            throw new EtException("buffer size must be >= than 0");
+        }
+        this.tcpSendBufSize = tcpSendBufSize;
+    }
+
+
+    /**
+     * Set the TCP receive buffer size in bytes. A value of 0
+     * means use the operating system default.
+     *
+     * @param tcpRecvBufSize TCP receive buffer size in bytes
+     * @throws EtException
+     *     if the argument is less than 0
+     */
+    public void setTcpRecvBufSize(int tcpRecvBufSize) throws EtException {
+        if (tcpRecvBufSize < 0) {
+            throw new EtException("buffer size must be >= than 0");
+        }
+        this.tcpRecvBufSize = tcpRecvBufSize;
+    }
+
+
+    /**
+     * Set the TCP no-delay setting. It is off by default.
+     * @param noDelay TCP no-delay setting
+     */
+    public void setNoDelay(boolean noDelay) {
+        this.noDelay = noDelay;
+    }
+
+
+    /**
+     * Sets the udp port number.
+     * @param port udp port number
+     * @throws EtException
+     *     if the argument is less than 1024
+     */
+    public void setUdpPort(int port) throws EtException {
+        if (port < 1024) {
+            throw new EtException("port number must be greater than 1023");
+        }
+        udpPort = port;
+    }
+
+
+    /**
+     * Sets the tcp server port number.
+     * @param port tcp server port number
+     * @throws EtException
+     *     if the argument is less than 1024
+     */
+    public void setServerPort(int port) throws EtException {
+        if (port < 1024) {
+            throw new EtException("port number must be greater than 1023");
+        }
+        serverPort = port;
+    }
+
+
+    /**
+     * Sets the multicast port number.
+     * @param port multicast port number
+     * @throws EtException
+     *     if the argument is less than 1024
+     */
+    public void setMulticastPort(int port) throws EtException {
+        if (port < 1024) {
+            throw new EtException("port number must be greater than 1023");
+        }
+//    else if (port == udpPort) {
+//      throw new EtException("multicast port must be different than udp port");
+//    }
+        multicastPort = port;
+    }
+
+
+    /**
+     * Checks configuration settings for consistency.
+     * @return true if consistent, else false
+     */
+    public boolean selfConsistent() {
+        // Check to see if the number of events in groups equal the total number of events
+        int count = 0;
+        for (int i : groups) {
+            count += i;
+        }
+        if (count != numEvents) {
+            System.out.println("events in groups != total event number");
+            return false;
+        }
+        return true;
+    }
+}
+

hps-et-java/src/main/java/org/jlab/coda/et/system
SystemCreate.java added at 1.1
diff -N SystemCreate.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SystemCreate.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,1962 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.util.*;
+import java.io.*;
+import java.net.*;
+
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Priority;
+import org.jlab.coda.et.enums.Age;
+
+/**
+ * This class creates an ET system.
+ *
+ * @author Carl Timmer
+ */
+
+public class SystemCreate {
+
+    /** A copy of the ET system configuration. */
+    private SystemConfig config;
+
+    /** The ET system file name. */
+    private String name;
+
+    /** A list of stations defining the flow of events. Only the first
+     *  station of a single group of parallel stations is included in
+     *  this list. The other parallel stations are available in a list
+     *  kept by the first parallel station. */
+    private LinkedList<StationLocal> stations;            // protected by stopTransfer & systemLock
+
+    /** The total number of idle and active stations. This consists
+     * of the number of main stations given by the size of the "stations"
+     * linked list (stations.size()) and the number of additional parallel
+     * stations added together. */
+    private int stationCount;
+
+    /** GRAND_CENTRAL station object */
+    private StationLocal gcStation;
+
+    /** Map of all ET system attachments. */
+    private HashMap<Integer,AttachmentLocal> attachments;         // protected by systemLock
+
+    /** Map of all ET system events. */
+    private HashMap<Integer, EtEventImpl> events;
+
+    /** All local IP addresses */
+    private InetAddress[]netAddresses;
+
+    /** Flag telling if the ET system is running. */
+    private boolean running;
+
+    /** Object on which to synchronize for system stuff - attachments. */
+    private byte[] systemLock;
+
+    /** Object on which to synchronize for station stuff. */
+    private byte[] stationLock;
+
+    /** Flag for killing all threads started by ET system. */
+    private volatile boolean killAllThreads;
+
+    // Variables for gathering system information for distribution.
+    // Do it no more than once per second.
+
+    /** Flag for specifying it's time to regather system information. */
+    private boolean gather = true;
+
+    /** Monitor time when gathering system information. */
+    private long time1 = 0L;
+
+    /** Length of valid data in array storing system information. */
+    private int dataLength = 0;
+
+    /** Array for storing system information for distribution. */
+    private byte[] infoArray = new byte[6000];
+    
+
+    /**
+     * Constructor that creates a new ET system using default parameters and starts it running.
+     * The default parameters are:
+     *      number of events          = {@link org.jlab.coda.et.EtConstants#defaultNumEvents},
+     *      event size                = {@link org.jlab.coda.et.EtConstants#defaultEventSize},
+     *      max number of stations    = {@link org.jlab.coda.et.EtConstants#defaultStationsMax},
+     *      max number of attachments = {@link org.jlab.coda.et.EtConstants#defaultAttsMax},
+     *      debug level               = {@link org.jlab.coda.et.EtConstants#debugError},
+     *      udp port                  = {@link org.jlab.coda.et.EtConstants#broadcastPort},
+     *      server (tcp) port         = {@link org.jlab.coda.et.EtConstants#serverPort}, and
+     *      multicasting port         = {@link org.jlab.coda.et.EtConstants#multicastPort}
+     *
+     * @param name ET system file name
+     * @throws EtException
+     *     if the file already exists or cannot be created
+     */
+    public SystemCreate(String name) throws EtException {
+        this(name, new SystemConfig());
+    }
+
+
+    /**
+     * COnstructor that creates a new ET system with specified parameters and starts it running.
+     *
+     * @param name     file name
+     * @param config   ET system configuration
+     * @throws EtException
+     *     if the file already exists or cannot be created
+     */
+    public SystemCreate (String name, SystemConfig config) throws EtException {
+
+        // check config for consistency
+        if (!config.selfConsistent()) {
+            if (config.getDebug() >= EtConstants.debugInfo) {
+                System.out.println("Number of events in groups does not equal total number of events");
+            }
+            throw new EtException("Number of events in groups does not equal total number of events");
+        }
+
+        this.name = name;
+        this.config = new SystemConfig(config);
+        attachments = new HashMap<Integer, AttachmentLocal>(EtConstants.attachmentsMax + 1);
+        events = new HashMap<Integer, EtEventImpl>(config.getNumEvents() + 1);
+        stations = new LinkedList<StationLocal>();
+        // netAddresses will be set in SystemUdpServer
+        systemLock  = new byte[0];
+        stationLock = new byte[0];
+
+        // The ET name is a file (which is really irrelevant in Java)
+        // but is a convenient way to make all system names unique.
+        File etFile = new File(name);
+        try {
+            // if file already exists ...
+            if (!etFile.createNewFile()) {
+                if (config.getDebug() >= EtConstants.debugInfo) {
+                    System.out.println("ET file already exists");
+                }
+                throw new EtException("ET file already exists");
+            }
+        }
+        catch (IOException ex) {
+            if (config.getDebug() >= EtConstants.debugInfo) {
+                System.out.println("cannot create ET file");
+            }
+            throw new EtException("Cannot create ET file");
+        }
+        etFile.deleteOnExit();
+
+        // Write into the file indicating a JAVA ET system
+        // is creating and using it. This is for the benefit of
+        // C-based ET systems which may try to open and read local
+        // ET system files thinking they contain shared memory.
+        try {
+            FileOutputStream fos = new FileOutputStream(etFile);
+            DataOutputStream dos = new DataOutputStream(fos);
+            dos.writeInt(0x04030201);  // for determining byte order
+            dos.writeInt(EtConstants.systemTypeJava);
+            dos.writeInt(EtConstants.version);
+            dos.writeInt(EtConstants.minorVersion);
+            dos.writeInt(EtConstants.stationSelectInts);
+            // this & following not used in Java
+            dos.writeInt(0);
+            dos.writeLong(0L);
+            dos.writeLong(0L);
+            dos.writeLong(0L);
+            dos.writeLong(0L);
+            dos.writeLong(0L);
+            dos.flush();
+        }
+        catch (FileNotFoundException ex) {
+        }
+        catch (UnsupportedEncodingException ex) {
+        }
+        catch (IOException ex) {
+        }
+
+        // store local IP addresses
+        try {
+            netAddresses = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());
+        }
+        catch (UnknownHostException ex) {
+            if (config.getDebug() >= EtConstants.debugError) {
+                System.out.println("cannot find local IP addresses");
+                ex.printStackTrace();
+            }
+            throw new EtException("Cannot find local IP addresses");
+        }
+
+        // start things running
+        startUp();
+    }
+
+
+    /** Gets the ET system file name.
+     *  @return ET system file name */
+    public String getName() {return name;}
+
+    /** Gets the ET system configuration.
+     *  @return ET system configuration */
+    public SystemConfig getConfig() {return new SystemConfig(config);}
+
+    /** Tells if the ET system is running or not.
+     *  @return <code>true</code> if the system is running, else <code>false</code> */
+    synchronized public boolean running() {return running;}
+
+    /** Get the linked list of stations.
+     * @return linked list of stations */
+    public LinkedList<StationLocal> getStations() { return stations; }
+
+    /** Get the station synchronization object.
+     * @return  station synchronization object */
+    public byte[] getStationLock() { return stationLock; }
+
+    /** Get the system synchronization object.
+     * @return  system synchronization object */
+    public byte[] getSystemLock() { return systemLock; }
+
+    /** Get map holding all ET system's events.
+     * @return map holding all ET system's events */
+    public HashMap<Integer, EtEventImpl> getEvents() { return events; }
+
+    /** Gets the list of all network addresses.
+     *  @return list of all network addresses */
+    public InetAddress[] getNetAddresses() { return netAddresses; }
+
+    /** Get the map of all attachments.
+     * @return map of all attachments */
+    public HashMap<Integer, AttachmentLocal> getAttachments() { return attachments; }
+
+    /** Has this object been told to kill all spawned threads?
+     * @return <code>true</code> if this object has been told to kill all spawned threads  */
+    public boolean killAllThreads() { return killAllThreads; }
+
+    /** Get array for storing system information for distribution.
+     * @return rray for storing system information for distribution  */
+    public byte[] getInfoArray() { return infoArray; }
+
+    /** Get length (number of bytes) of valid data in array storing system information.
+     * @return length (number of bytes) of valid data in array storing system information */
+    public int getDataLength() { return dataLength; }
+
+   
+
+    /** Starts the ET system running. If the system is already running, nothing
+     * is done. */
+    synchronized public void startUp() {
+        if (running) return;
+
+        // make grandcentral
+        gcStation = createGrandCentral();
+
+        // fill GC with standard sized events
+        EtEventImpl ev;
+        int index = 0, count = 0;
+        ArrayList<EtEventImpl> eventList = new ArrayList<EtEventImpl>(config.getNumEvents());
+
+        for (int i=0; i < config.getNumEvents(); i++) {
+            ev = new EtEventImpl(config.getEventSize());
+            ev.setId(i);
+
+            // assign group numbers
+            if (count < 1)
+                count = (config.getGroups())[index++];
+            ev.setGroup(index);
+            count--;
+
+            eventList.add(ev);
+            // add to hashTable for future easy access
+            events.put(i, ev);
+        }
+
+        // synchronization not necessary here as we're just starting up
+        gcStation.getInputList().putInLow(eventList);
+        // undo statistics keeping for inital event loading
+        gcStation.getInputList().setEventsIn(0);
+
+        // run tcp server thread
+        SystemTcpServer tcpServer = new SystemTcpServer(this);
+        tcpServer.start();
+
+        // run udp listening thread
+        SystemUdpServer udpServer = new SystemUdpServer(this);
+        udpServer.start();
+
+        running = true;
+    }
+
+
+    /** Stops the ET system if it is running. All threads are stopped.
+     * If the system is not running, nothing is done. */
+    synchronized public void shutdown() {
+        if (!running) return;
+        // tell threads to kill themselves
+        killAllThreads = true;
+        // sockets on 2 second timeout so wait
+        try {Thread.sleep(2500);}
+        catch (InterruptedException ex) {}
+        // delete file
+        File etFile = new File(name);
+        etFile.delete();
+
+        // clear everything
+        stations       = null;
+        attachments    = null;
+        events         = null;
+        netAddresses   = null;
+        stationLock    = null;
+        killAllThreads = false;
+        running        = false;
+    }
+
+    //---------------------------------------------------------------------------
+    // Station related methods, mainly to manipulate the linked lists of stations
+    //---------------------------------------------------------------------------
+
+    /**
+     * This method locks the stopTransfer locks of all existing stations which ensures no events
+     * are currently being moved.
+     */
+    private void lockAllStationTransferLocks() {
+        for (StationLocal mainListStation : stations) {
+            // lock station in main linked list
+            mainListStation.getStopTransferLock().lock();
+            // if this station is the head of a parallel linked list, grab all their locks too
+            if (mainListStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                // skip first element in parallel list as it is identical to mainListStation
+                StationLocal parallelListStation;
+                for (ListIterator iter = mainListStation.getParallelStations().listIterator(1); iter.hasNext();) {
+                    parallelListStation = (StationLocal) iter.next();
+                    parallelListStation.getStopTransferLock().lock();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * This method unlocks the stopTransfer locks of all existing stations which means events
+     * are now allowed to be moved.
+     */
+    private void unlockAllStationTransferLocks() {
+        for (StationLocal mainListStation : stations) {
+            // unlock station in main linked list
+            mainListStation.getStopTransferLock().unlock();
+            // if this station is the head of a parallel linked list, release all their locks too
+            if (mainListStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                // skip first element in parallel list as it is identical to mainListStation
+                StationLocal parallelListStation;
+                for (ListIterator iter = mainListStation.getParallelStations().listIterator(1); iter.hasNext();) {
+                    parallelListStation = (StationLocal) iter.next();
+                    parallelListStation.getStopTransferLock().unlock();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Method used to add a new station to all the relevant linked lists of stations.
+     *
+     * @param newStation station object
+     * @param position the desired position in the main linked list of stations
+     * @param parallelPosition the desired position of a parallel station in the
+     *      group of parallel stations it's being added to
+     * @throws EtException
+     *     if trying to add an incompatible parallel station to an existing group
+     *     of parallel stations or to the head of an existing group of parallel
+     *     stations.
+     */
+    private void insertStation(StationLocal newStation, int position, int parallelPosition) throws EtException {
+
+        // If GRAND_CENTRAL is only existing station, or if we're at
+        // or past the end of the linked list, put station on the end
+        if ((stations.size() < 2) ||
+                (position >= stations.size()) ||
+                (position == EtConstants.end)) {
+
+            stations.add(newStation);
+            if (newStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                newStation.getParallelStations().clear();
+                newStation.getParallelStations().add(newStation);
+            }
+        }
+        // else, put the station in the desired position in the middle somewhere
+        else {
+            StationLocal stat = stations.get(position);
+
+            // if the station in "position" and this station are both parallel ...
+            if ((newStation.getConfig().getFlowMode() == EtConstants.stationParallel) &&
+                    (stat.getConfig().getFlowMode() == EtConstants.stationParallel) &&
+                    (parallelPosition != EtConstants.newHead)) {
+
+                // If these 2 stations have incompatible definitions or we're trying to place
+                // a parallel station in the first (already taken) spot of its group ...
+                if (!EtStationConfig.compatibleParallelConfigs(stat.getConfig(), newStation.getConfig())) {
+                    throw new EtException("trying to add incompatible parallel station\n");
+                }
+                else if (parallelPosition == 0) {
+                    throw new EtException("trying to add parallel station to head of existing parallel group\n");
+                }
+
+                // Add this parallel station in the "parallelPosition" slot in the
+                // parallel linked list or to the end if parallelPosition = Constants.end.
+                if ((parallelPosition == EtConstants.end) ||
+                        (parallelPosition >= stat.getParallelStations().size())) {
+                    stat.getParallelStations().add(newStation);
+                }
+                else {
+                    stat.getParallelStations().add(parallelPosition, newStation);
+                }
+            }
+            else {
+                stations.add(position, newStation);
+                if (newStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    newStation.getParallelStations().clear();
+                    newStation.getParallelStations().add(newStation);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Method used to remove a station from all relevant linked lists of stations.
+     * @param station station object
+     */
+    private void deleteStation(StationLocal station) {
+        // The only tricky part in removing a station is to remember that it may not
+        // be in the main linked list if it is a parallel station.
+
+        // if the station is in the main linked list ...
+        if (stations.contains(station)) {
+
+            // remember where the station was located
+            int index = stations.indexOf(station);
+
+            // remove it from main list
+            stations.remove(station);
+
+            // if it's not a parallel station, we're done
+            if (station.getConfig().getFlowMode() == EtConstants.stationSerial) {
+                return;
+            }
+
+            // if the station is parallel, it's the head of another linked list.
+            station.getParallelStations().removeFirst();
+
+            // if no other stations in the group, we're done
+            if (station.getParallelStations().size() < 1) {
+                return;
+            }
+
+            // If there are other stations in the group, make sure that the linked
+            // list of parallel stations is passed on to the next member. And put
+            // the new head of the parallel list into the main list.
+            StationLocal nextStation = station.getParallelStations().getFirst();
+            nextStation.getParallelStations().clear();
+            nextStation.getParallelStations().addAll(station.getParallelStations());
+            station.getParallelStations().clear();
+            stations.add(index, nextStation);
+        }
+
+        // else if it's not in the main linked list, we'll have to hunt it down
+        else {
+            // loop thru all stations in main list
+            for (StationLocal nextStation : stations) {
+                // If it's a parallel station, try to remove "station" from the
+                // list of parallel stations registered with it.
+                if (nextStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    if (nextStation.getParallelStations().remove(station)) {
+                        // we got it
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Method for use by {@link #createStation(org.jlab.coda.et.EtStationConfig, String)}
+     * to grab all stations'
+     * transfer locks and stop all event transfer before adding a new station to
+     * the ET system's linked lists of stations.
+     *
+     * @param newStation station to add
+     * @param position the desired position in the main linked list of stations
+     * @param parallelPosition the desired position of a parallel station in the
+     *     group of parallel stations it's being added to
+     * @throws EtException
+     *     if trying to add an incompatible parallel station to an existing group
+     *     of parallel stations or to the head of an existing group of parallel
+     *     stations.
+     */
+   private void addStationToList(StationLocal newStation, int position, int parallelPosition) throws EtException {
+        lockAllStationTransferLocks();
+        try {
+            insertStation(newStation, position, parallelPosition);
+            // since we locked all stations' transfer locks, do so with the new one too
+            newStation.getStopTransferLock().lock();
+        }
+        finally {
+            unlockAllStationTransferLocks();
+        }
+    }
+
+
+    /**
+     * Method for use by {@link #removeStation(int)} to grab all stations'
+     * transfer locks and stop all event transfer before removing a station from
+     * the ET system's linked lists of stations.
+     * 
+     * @param station station to remove
+     */
+    private void removeStationFromList(StationLocal station) {
+        lockAllStationTransferLocks();
+        try {
+            deleteStation(station);
+            // since we will unlock all stations' transfer locks, do so with the new one too
+            station.getStopTransferLock().unlock();
+        }
+        finally {
+            unlockAllStationTransferLocks();
+        }
+    }
+
+
+    /**
+     * Method for use by {@link #removeStationFromList(StationLocal)} to grab all stations'
+     * transfer locks and stop all event transfer before moving a station in
+     * the ET system's linked lists of stations.
+     *
+     * @param station station to move
+     * @param position the desired position in the main linked list of stations
+     * @param parallelPosition the desired position of a parallel station in the
+     *      group of parallel stations it's being added to
+     * @throws EtException
+     *     if trying to move an incompatible parallel station to an existing group
+     *     of parallel stations or to the head of an existing group of parallel
+     *     stations.
+     */
+    private void moveStationInList(StationLocal station, int position, int parallelPosition) throws EtException {
+        lockAllStationTransferLocks();
+        try {
+            deleteStation(station);
+            insertStation(station, position, parallelPosition);
+        }
+        finally {
+            unlockAllStationTransferLocks();
+        }
+    }
+
+
+    /**
+     * Method for use by {@link #deleteStation(StationLocal)} and {@link #detach(AttachmentLocal)}
+     * to grab all stations' transfer locks and stop all event transfer before changing a station's status.
+     *
+     * @param station station to set status on
+     * @param status the desired status of the station
+     */
+    private void changeStationStatus(StationLocal station, int status) {
+        lockAllStationTransferLocks();
+        try {
+            station.setStatus(status);
+        }
+        finally {
+            unlockAllStationTransferLocks();
+        }
+    }
+
+    
+    //
+    // Done with station manipulation methods
+    //
+
+
+    /**
+     * Creates a new station placed at the end of the linked list of stations.
+     *
+     * @param stationConfig   station configuration
+     * @param name            station name
+     *
+     * @return the new station object
+     *
+     * @throws EtException
+     *     if the select method's class cannot be loaded
+     * @throws EtExistsException
+     *     if the station already exists but with a different configuration
+     * @throws EtTooManyException
+     *     if the maximum number of stations has been created already
+     */
+    StationLocal createStation(EtStationConfig stationConfig, String name)
+            throws EtException, EtExistsException, EtTooManyException {
+        synchronized(stationLock) {
+            return createStation(stationConfig, name, stations.size(), EtConstants.end);
+        }
+    }
+
+
+    /**
+     * Creates a new station at a specified position in the linked list of
+     * stations. Cannot exceed the maximum number of stations allowed in a system.
+     *
+     * @param stationConfig   station configuration
+     * @param name            station name
+     * @param position        position in the linked list to put the station.
+     *
+     * @return                the new station object
+     *
+     * @throws EtException
+     *     if the select method's class cannot be loaded
+     * @throws EtExistsException
+     *     if the station already exists but with a different configuration
+     * @throws EtTooManyException
+     *     if the maximum number of stations has been created already
+     */
+    StationLocal createStation(EtStationConfig stationConfig, String name,
+                               int position, int parallelPosition)
+            throws EtException, EtExistsException, EtTooManyException {
+
+
+        int id = 0;
+        StationLocal station;
+
+        // grab station mutex
+        synchronized (stationLock) {
+            // check to see if hit maximum allowed # of stations
+            if (stations.size() >= config.getStationsMax()) {
+                throw new EtTooManyException("Maximum number of stations already created");
+            }
+            else if (position > stations.size()) {
+                position = stations.size();
+            }
+
+            // check to see if it already exists
+            StationLocal listStation;
+            try {
+                listStation = stationNameToObject(name);
+                EtStationConfig listStationConfig = listStation.getConfig();
+                // it's got the same name, let's see if it's defined the same
+                if ((listStationConfig.getFlowMode()    == stationConfig.getFlowMode())    &&
+                    (listStationConfig.getUserMode()    == stationConfig.getUserMode())    &&
+                    (listStationConfig.getBlockMode()   == stationConfig.getBlockMode())   &&
+                    (listStationConfig.getSelectMode()  == stationConfig.getSelectMode())  &&
+                    (listStationConfig.getRestoreMode() == stationConfig.getRestoreMode()) &&
+                    (listStationConfig.getPrescale()    == stationConfig.getPrescale())    &&
+                    (listStationConfig.getCue()         == stationConfig.getCue())         &&
+                    (Arrays.equals(listStationConfig.getSelect(), stationConfig.getSelect()))) {
+
+                    if ((listStationConfig.getSelectClass() != null) &&
+                            (!listStationConfig.getSelectClass().equals(stationConfig.getSelectClass()))) {
+                        throw new EtExistsException("Station already exists with different configuration");
+                    }
+                    // station definitions are the same, use listStation
+                    return listStation;
+                }
+                throw new EtExistsException("Station already exists with different configuration");
+            }
+            catch (EtException ex) {
+                // station does NOT exist, continue on
+            }
+
+            // find smallest possible unique id number
+            search:
+            for (int i = 0; i < stationCount + 1; i++) {
+                for (ListIterator j = stations.listIterator(); j.hasNext();) {
+                    listStation = (StationLocal) j.next();
+                    if (listStation.getStationId() == i) {
+                        continue search;
+                    }
+                    if (listStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                        for (ListIterator k = listStation.getParallelStations().listIterator(1); k.hasNext();) {
+                            listStation = (StationLocal) k.next();
+                            if (listStation.getStationId() == i) {
+                                continue search;
+                            }
+                        }
+                    }
+                }
+                // only get down here if "i" is not a used id number
+                id = i;
+                break;
+            }
+
+            // create station
+            station = new StationLocal(this, name, stationConfig, id);
+
+            // start its conductor thread
+            station.start();
+            // give up processor so thread can start
+            Thread.yield();
+
+            // make sure the conductor is started or we'll get race conditions
+            while (station.getStatus() != EtConstants.stationIdle) {
+                if (config.getDebug() >= EtConstants.debugInfo) {
+                    System.out.println("Waiting for " + name + "'s conductor thread to start");
+                }
+                // sleep for minimum amount of time (1 nsec haha)
+                try {
+                    Thread.sleep(0, 1);
+                }
+                catch (InterruptedException ex) {
+                }
+            }
+
+            // put in linked list(s) - first grabbing stopTransfer mutexes
+            addStationToList(station, position, parallelPosition);
+            // keep track of the total number of stations
+            stationCount++;
+        } // release station mutex
+
+        return station;
+    }
+
+
+    /**
+     * Creates the first station by the name of GRAND_CENTRAL and starts its
+     * conductor thread.
+     *
+     * @return GRAND_CENTRAL station's object
+     */
+    private StationLocal createGrandCentral() {
+        // use the default configuration
+        EtStationConfig gcConfig = new EtStationConfig();
+        StationLocal station = null;
+        // create station
+        try {
+            station = new StationLocal(this, "GRAND_CENTRAL", gcConfig, 0);
+        }
+        catch (EtException ex) {}
+
+        // put in linked list
+        stations.clear();
+        stations.addFirst(station);
+
+        // start its conductor thread
+        station.start();
+
+        // keep track of the total number of stations
+        stationCount++;
+        return station;
+    }
+
+    
+    /**
+     * Removes an existing station.
+     *
+     * @param   statId station id
+     * @throws EtException
+     *     if attachments to the station still exist or the station does not exist
+     */
+    void removeStation(int statId) throws EtException {
+        StationLocal stat;
+        // grab station mutex
+        synchronized(stationLock) {
+            stat = stationIdToObject(statId);
+            // only remove if no attached processes
+            if (stat.getAttachments().size() != 0) {
+                throw new EtException("Remove all attachments before removing station");
+            }
+
+            // remove from linked list - first grabbing stopTransfer mutexes
+            removeStationFromList(stat);
+
+            // kill conductor thread
+            stat.killConductor();
+            stat.interrupt();
+
+            // set status
+            stat.setStatus(EtConstants.stationUnused);
+
+            // keep track of the total number of stations
+            stationCount--;
+            return;
+        }
+    }
+
+
+    /**
+     * Changes the position of a station in the linked lists of stations.
+     *
+     * @param statId     station id
+     * @param position   position in the main linked list of stations (starting at 0)
+     * @param parallelPosition position of a parallel station in a group of
+     *     parallel stations (starting at 0)
+     * @throws EtException
+     *     if the station does not exist, or
+     *     if trying to move an incompatible parallel station to an existing group
+     *     of parallel stations or to the head of an existing group of parallel
+     *     stations.
+     */
+    void setStationPosition(int statId, int position, int parallelPosition) throws EtException {
+        StationLocal stat;
+        // grab station mutex
+        synchronized(stationLock) {
+            stat = stationIdToObject(statId);
+            // change linked list - first grabbing stopTransfer mutexes
+            moveStationInList(stat, position, parallelPosition);
+        }
+    }
+
+    /**
+     * Gets the position of a station in the main linked list of stations.
+     *
+     * @param statId   station id
+     * @return         the position of a station in the linked list of stations
+     * @throws EtException
+     *     if the station does not exist
+     */
+    int getStationPosition(int statId) throws EtException {
+        // GrandCentral is always first
+        if (statId == 0) return 0;
+        int position = 0;
+
+        synchronized (stationLock) {
+            for (StationLocal stat : stations) {
+                if (stat.getStationId() == statId) {
+                    return position;
+                }
+                if (stat.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    for (StationLocal stat2 : stat.getParallelStations()) {
+                        if (stat2.getStationId() == statId) {
+                            return position;
+                        }
+                    }
+                }
+                position++;
+            }
+        }
+        throw new EtException("cannot find station");
+    }
+
+
+    /**
+     * Gets the position of a parallel station in its linked list of
+     * parallel stations.
+     *
+     * @param statId   station id
+     * @return         the position of a parallel station in its linked list
+     *      of parallel stations, or zero if station is serial
+     * @throws EtException
+     *     if the station does not exist
+     */
+    int getStationParallelPosition(int statId) throws EtException {
+        // parallel position is 0 for serial stations
+        if (statId == 0) return 0;
+        int pposition;
+
+        synchronized (stationLock) {
+            for (StationLocal stat : stations) {
+                if (stat.getStationId() == statId) {
+                    return 0;
+                }
+                if (stat.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    pposition = 1;
+                    for (StationLocal stat2 : stat.getParallelStations()) {
+                        if (stat2.getStationId() == statId) {
+                            return pposition;
+                        }
+                        pposition++;
+                    }
+                }
+            }
+        }
+        throw new EtException("cannot find station");
+    }
+
+
+    /**
+     * Tells if an attachment is attached to a station.
+     *
+     * @param statId   station id
+     * @param attId    attachment id
+     * @return         <code>true</code> if an attachment is attached to a station
+     *                 and <code>false</code> otherwise
+     * @throws EtException
+     *     if the station does not exist
+     */
+    boolean stationAttached(int statId, int attId) throws EtException {
+        StationLocal stat;
+        synchronized (stationLock) {
+            stat = stationIdToObject(statId);
+            for (AttachmentLocal att : stat.getAttachments()) {
+                if (att.getId() == attId) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+
+    /**
+     * Tells if a station exists.
+     *
+     * @param station station object
+     * @return <code>true</code> if a station exists and
+     *         <code>false</code> otherwise
+     */
+    boolean stationExists(StationLocal station) {
+        synchronized (stationLock) {
+            if (stations.contains(station)) {
+                return true;
+            }
+            for (StationLocal listStation : stations) {
+                if (listStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    if (listStation.getParallelStations().contains(station)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Tells if a station exists.
+     *
+     * @param    name station name
+     * @return   <code>true</code> if a station exists and
+     *           <code>false</code> otherwise
+     */
+    boolean stationExists(String name) {
+        try {
+            stationNameToObject(name);
+        }
+        catch (EtException ex) {
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Gets a station's object representation.
+     *
+     * @param    name station name
+     * @return   a station's object
+     * @throws EtException
+     *     if the station does not exist
+     */
+    StationLocal stationNameToObject(String name) throws EtException {
+        synchronized (stationLock) {
+            for (StationLocal listStation : stations) {
+                if (listStation.getStationName().equals(name)) {
+                    return listStation;
+                }
+                if (listStation.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    for (StationLocal listStation2 : listStation.getParallelStations()) {
+                        if (listStation2.getStationName().equals(name)) {
+                            return listStation2;
+                        }
+                    }
+                }
+            }
+        }
+        throw new EtException("station " + name + " does not exist");
+    }
+
+
+    /**
+     * Given a station id number, this method gets the corresponding
+     * StationLocal object.
+     *
+     * @param     statId station id
+     * @return    the station's object
+     * @throws EtException
+     *     if the station does not exist
+     */
+    StationLocal stationIdToObject(int statId) throws EtException {
+        synchronized (stationLock) {
+            for (StationLocal stat : stations) {
+                if (stat.getStationId() == statId) {
+                    return stat;
+                }
+                if (stat.getConfig().getFlowMode() == EtConstants.stationParallel) {
+                    for (StationLocal stat2 : stat.getParallelStations()) {
+                        if (stat2.getStationId() == statId) {
+                            return stat2;
+                        }
+                    }
+                }
+            }
[truncated at 1000 lines; 966 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et/system
SystemTcpServer.java added at 1.1
diff -N SystemTcpServer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SystemTcpServer.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,1801 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.util.*;
+import java.util.Map.*;
+import java.io.*;
+import java.net.*;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+
+import org.jlab.coda.et.exception.*;
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Modify;
+import org.jlab.coda.et.enums.Priority;
+import org.jlab.coda.et.enums.DataStatus;
+
+/**
+ * This class implements a thread which listens for users trying to connect to
+ * the ET system. It starts another thread for each tcp socket connection
+ * established to a user of the system.
+ *
+ * @author Carl Timmer
+ */
+
+class SystemTcpServer extends Thread {
+
+    /** Port number to listen on. */
+    private int port;
+
+    /** Et system object. */
+    private SystemCreate sys;
+
+    /** Et system config object. */
+    private SystemConfig config;
+
+
+    /** Createes a new SystemTcpServer object.
+     *  @param sys ET system object */
+    SystemTcpServer(SystemCreate sys) {
+        this.sys = sys;
+        config   = sys.getConfig();
+        port     = config.getServerPort();
+    }
+
+
+    /** Start thread to listen for connections and spawn off communication
+     *  handling threads. */
+    public void run() {
+        if (config.getDebug() >= EtConstants.debugInfo) {
+            System.out.println("Running TCP Server Thread");
+        }
+
+        // use the default port number since one wasn't specified
+        if (port < 1) {
+            port = EtConstants.serverPort;
+        }
+
+        // let exceptions propagate up a level
+
+        // open a listening socket
+        try {
+
+            // Direct buffer for reading 3 magic ints with nonblocking IO
+            int BYTES_TO_READ = 12;
+            ByteBuffer buffer = ByteBuffer.allocateDirect(BYTES_TO_READ);
+
+            // Create channel and bind to port. If that isn't possible, exit.
+            ServerSocketChannel serverChannel = ServerSocketChannel.open();
+            serverChannel.socket().setReuseAddress(true);
+            serverChannel.socket().setSoTimeout(2000);
+            if (config.getTcpRecvBufSize() > 0) {
+                serverChannel.socket().setReceiveBufferSize(config.getTcpRecvBufSize());
+            }
+            serverChannel.socket().bind(new InetSocketAddress(port));
+
+            while (true) {
+                // socket to client created
+                SocketChannel channel;
+                Socket sock;
+                while (true) {
+                    try {
+                        // accept the connection from the client
+                        channel = serverChannel.accept();
+                        sock = channel.socket();
+                        break;
+                    }
+                    // server socket accept timeout
+                    catch (InterruptedIOException ex) {
+                        // check to see if we've been commanded to die
+                        if (sys.killAllThreads()) {
+                            return;
+                        }
+                    }
+                }
+                // Set reading timeout to 1/2 second so dead clients
+                // can be found by reading on a socket.
+                sock.setSoTimeout(500);
+                // set send buffer size, receive buffer size is set above in server socket
+                if (config.getTcpSendBufSize() > 0) {
+                    sock.setSendBufferSize(sys.getConfig().getTcpSendBufSize());
+                }
+                // Set tcpNoDelay so no packets are delayed
+                if (config.isNoDelay()) {
+                    sock.setTcpNoDelay(config.isNoDelay());
+                }
+
+                // Check to see if this is a legitimate client or some imposter.
+                // Don't want to block on read here since it may not be a real client
+                // and may block forever - tying up the server.
+                int bytes, bytesRead=0, loops=0;
+                buffer.clear();
+                buffer.limit(BYTES_TO_READ);
+                channel.configureBlocking(false);
+
+                // read magic numbers
+                while (bytesRead < BYTES_TO_READ) {
+//System.out.println("  try reading rest of Buffer");
+//System.out.println("  Buffer capacity = " + buffer.capacity() + ", limit = " + buffer.limit()
+//                    + ", position = " + buffer.position() );
+                    bytes = channel.read(buffer);
+                    // for End-of-stream ...
+                    if (bytes == -1) {
+                        channel.close();
+                        continue;
+                    }
+                    bytesRead += bytes;
+//System.out.println("  bytes read = " + bytesRead);
+
+                    // if we've read everything, look to see if it's sent the magic #s
+                    if (bytesRead >= BYTES_TO_READ) {
+                        buffer.flip();
+                        int magic1 = buffer.getInt();
+                        int magic2 = buffer.getInt();
+                        int magic3 = buffer.getInt();
+                        if (magic1 != EtConstants.magicNumbers[0] ||
+                                magic2 != EtConstants.magicNumbers[1] ||
+                                magic3 != EtConstants.magicNumbers[2])  {
+//System.out.println("SystemTcpServer:  Magic numbers did NOT match");
+                            channel.close();
+                        }
+                    }
+                    else {
+                        // give client 10 loops (.1 sec) to send its stuff, else no deal
+                        if (++loops > 10) {
+//System.out.println("SystemTcpServer:  Client taking too long to send 3 ints, terminate connection");
+                            channel.close();
+                            continue;
+                        }
+                        try { Thread.sleep(10); }
+                        catch (InterruptedException e) { }
+                    }
+                }
+
+                // change back to blocking socket
+                channel.configureBlocking(true);
+
+                // create thread to deal with client
+                ClientThread connection = new ClientThread(sys, channel.socket());
+                connection.start();
+            }
+
+        }
+        catch (SocketException ex) {
+        }
+        catch (IOException ex) {
+        }
+        return;
+    }
+
+}
+
+
+/**
+ * This class handles all communication between an ET system and a user who has
+ * opened that ET system.
+ *
+ * @author Carl Timmer
+ */
+
+class ClientThread extends Thread {
+
+    /** Tcp socket. */
+    private Socket sock;
+
+    /** ET system object. */
+    private SystemCreate sys;
+
+    /** ET system configuration object. */
+    private SystemConfig config;
+
+    /** Data input stream built on top of the socket's input stream (with an
+     *  intervening buffered input stream). */
+    private DataInputStream  in;
+
+    /** Data output stream built on top of the socket's output stream (with an
+     *  intervening buffered output stream). */
+    private DataOutputStream out;
+
+    /** Client is 64 bits? */
+    boolean bit64;
+
+
+    /**
+     *  Create a new ClientThread object.
+     *  @param sys ET system object.
+     *  @param sock TCP socket.
+     */
+    ClientThread(SystemCreate sys, Socket sock) {
+        this.sys  = sys;
+        this.sock = sock;
+        config = sys.getConfig();
+    }
+
+
+    /** Start thread to handle communications with user. */
+    public void run() {
+
+        try {
+            // buffered communication streams for efficiency
+            if (config.getTcpRecvBufSize() > 0) {
+                in  = new DataInputStream(new  BufferedInputStream(sock.getInputStream(),
+                                                                   config.getTcpRecvBufSize())
+                                         );
+            }
+            else {
+                in  = new DataInputStream(new  BufferedInputStream(sock.getInputStream(), sock.getReceiveBufferSize()));
+            }
+
+            if (config.getTcpRecvBufSize() > 0) {
+                out = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(),
+                                                                    config.getTcpSendBufSize())
+                                          );
+            }
+            else {
+                out = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream(), sock.getSendBufferSize()));
+            }
+
+            int endian = in.readInt();
+            int length = in.readInt();
+            int b64    = in.readInt();
+            bit64      = b64 == 1;
+            in.readLong();
+
+            byte[] buf = new byte[length];
+            in.readFully(buf, 0, length);
+            String etName = new String(buf, 0, length - 1, "ASCII");
+
+            // see if the ET system that the client is
+            // trying to connect to is this one.
+            if (!etName.equals(sys.getName())) {
+                if (config.getDebug() >= EtConstants.debugError) {
+                    System.out.println("Tcp Server: client trying to connect to " + etName);
+                }
+                // send error to client
+                out.writeInt(EtConstants.error);
+                out.flush();
+                return;
+            }
+
+            // send ET system info back to client
+            out.writeInt(EtConstants.ok);
+            out.writeInt(EtConstants.endianBig);
+            out.writeInt(config.getNumEvents());
+            out.writeLong(config.getEventSize());
+            out.writeInt(EtConstants.version);
+            out.writeInt(EtConstants.stationSelectInts);
+            out.writeInt(EtConstants.langJava);
+            out.writeInt(EtConstants.bit64);
+            out.writeInt(0);
+            out.flush();
+
+            /* wait for and process client requests */
+            commandLoop();
+
+            return;
+        }
+        catch (IOException ex) {
+            if (config.getDebug() >= EtConstants.debugError) {
+                System.out.println("Tcp Server: IO error in client etOpen");
+            }
+        }
+        finally {
+            // we are done with the socket
+            try {
+                sock.close();
+            }
+            catch (IOException ex) {
+            }
+        }
+    }
+
+
+    /**  Wait for and implement commands from the user. */
+    private void commandLoop() {
+
+        // Keep track of all the attachments this client makes
+        // as they may need to be detached if the client dies
+        // without cleanly disconnecting itself. Detaching
+        // takes care of all events that were sent to clients
+        // as events to be modified, but were never put back.
+
+        // for efficiency, keep local copy of constants
+        final int selectInts   = EtConstants.stationSelectInts;
+        final int dataShift    = EtConstants.dataShift;
+        final int priorityMask = EtConstants.priorityMask;
+        final int dataMask     = EtConstants.dataMask;
+        final int modify       = EtConstants.modify;
+        final int ok           = EtConstants.ok;
+
+        int command;
+        EtEventImpl[] evs = null;
+        HashMap<Integer, AttachmentLocal> attachments =
+                new HashMap<Integer, AttachmentLocal>(sys.getConfig().getAttachmentsMax() + 1);
+        // buffer for sending events to users
+        byte[] buffer = new byte[65535];
+        // buffer for reading command parameters (6 ints worth)
+        byte[] params = new byte[32 + 4 * selectInts];
+
+        // The Command Loop ...
+        try {
+            while (true) {
+                // First, read the remote command. Remember, the
+                // socket has a read timeout of 1/2 second.
+                while (true) {
+                    try {
+                        command = in.readInt();
+                        break;
+                    }
+                    // socket read timeout
+                    catch (InterruptedIOException ex) {
+                        // check to see if we've been commanded to die
+                        if (sys.killAllThreads()) {
+                            return;
+                        }
+                    }
+                }
+
+                // Since there are so many commands, break up things up a bit,
+                // start off with commands for local clients for use in Linux
+                // or other non-mutex sharing operating systems.
+
+                if (command < EtConstants.netEvGet) {
+                    // No local Linux stuff in Java implementation
+                    if (config.getDebug() >= EtConstants.debugError) {
+                        System.out.println("No Java support for local Linux");
+                    }
+                    throw new EtReadException("No Java support for local Linux");
+                }
+
+                else if (command < EtConstants.netAlive) {
+
+                    switch (command) {
+
+                        case EtConstants.netEvGet: {
+                            in.readFully(params, 0, 20);
+                            int err = ok;
+                            int attId = EtUtils.bytesToInt(params, 0);
+                            int mode  = EtUtils.bytesToInt(params, 4);
+                            int mod   = EtUtils.bytesToInt(params, 8);
+                            int sec   = EtUtils.bytesToInt(params, 12);
+                            int nsec  = EtUtils.bytesToInt(params, 16);
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            try {
+                                if (mode == EtConstants.timed) {
+                                    int uSec = sec * 1000000 + nsec / 1000;
+                                    evs = sys.getEvents(att, mode, uSec, 1);
+                                }
+                                else if (mode == EtConstants.sleep) {
+                                    // There's a problem if we have a remote client that is waiting
+                                    // for another event by sleeping and the events stop flowing. In
+                                    // that case, the client can be killed and the ET system does NOT
+                                    // know about it. Since this thread will be stuck in "getEvents",
+                                    // it will not immediately detect the break in the socket - at least
+                                    // not until events start flowing again. To circumvent this, implement
+                                    // "sleep" by repeats of "timed" every few seconds to allow
+                                    // detection of broken socket between calls to "getEvents".
+
+                                    // Store the fact we're trying to sleep - necessary when
+                                    // told to wake up.
+                                    att.setSleepMode(true);
+
+                                    tryToGetEvents:
+                                    while (true) {
+                                        // try a 4 second wait for an event
+                                        try {
+                                            if (att.isWakeUp()) {
+                                                att.setWakeUp(false);
+                                                throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                                            }
+                                            evs = sys.getEvents(att, EtConstants.timed, 4000000, 1);
+                                            // no longer in sleep mode
+                                            att.setSleepMode(false);
+                                            // may have been told to wake up between last 2 statements.
+                                            att.setWakeUp(false);
+                                            break;
+                                        }
+                                        // if timeout, check socket to see if still open
+                                        catch (EtTimeoutException tx) {
+                                            try {
+                                                // 1/2 second max delay on read
+                                                in.readInt();
+                                                // should never be able to get here
+                                                att.setSleepMode(false);
+                                                throw new EtException("communication protocol error");
+                                            }
+                                            // if there's an interrupted ex, socket is OK
+                                            catch (InterruptedIOException ex) { }
+                                        }
+                                    }
+
+                                }
+                                else {
+                                    evs = sys.getEvents(att, mode, 0, 1);
+                                }
+
+                            }
+                            catch (EtException ex) {
+                                err = EtConstants.error;
+                            }
+                            catch (EtBusyException ex) {
+                                err = EtConstants.errorBusy;
+                            }
+                            catch (EtEmptyException ex) {
+                                err = EtConstants.errorEmpty;
+                            }
+                            catch (EtWakeUpException ex) {
+                                err = EtConstants.errorWakeUp;
+                                att.setSleepMode(false);
+                            }
+                            catch (EtTimeoutException ex) {
+                                err = EtConstants.errorTimeout;
+                            }
+
+                            if (err != ok) {
+                                out.writeInt(err);
+                                out.flush();
+                                break;
+                            }
+
+                            EtEventImpl ev = evs[0];
+
+                            // handle buffering by hand
+                            byte[] buf = new byte[4 * (10 + selectInts) + ev.getLength()];
+
+                            // first send error
+                            EtUtils.intToBytes(err, buf, 0);
+                            EtUtils.longToBytes((long)ev.getLength(),  buf,  4);
+                            EtUtils.longToBytes((long)ev.getMemSize(), buf, 12);
+                            EtUtils.intToBytes(ev.getPriority().getValue() |
+                                               ev.getDataStatus().getValue() << dataShift, buf, 20);
+                            EtUtils.intToBytes(ev.getId(), buf, 24);  // skip 4 bytes here
+                            EtUtils.intToBytes(ev.getRawByteOrder(), buf, 32);
+                            // arrays are initialized to zero so skip 0 values elements
+                            int index = 36;
+                            int[] control = ev.getControl();
+                            for (int i = 0; i < selectInts; i++) {
+                                EtUtils.intToBytes(control[i], buf, index += 4);
+                            }
+                            System.arraycopy(ev.getData(), 0, buf, index += 4, ev.getLength());
+
+                            out.write(buf);
+                            out.flush();
+
+                            ev.setModify(Modify.getModify(mod));
+                            if (mod == 0) {
+                                sys.putEvents(att, evs);
+                            }
+                            evs = null;
+                        }
+                        break;
+
+
+                        case EtConstants.netEvsGet: {
+                            in.readFully(params, 0, 24);
+                            int err = ok;
+                            int attId = EtUtils.bytesToInt(params,  0);
+                            int mode  = EtUtils.bytesToInt(params,  4);
+                            int mod   = EtUtils.bytesToInt(params,  8);
+                            int count = EtUtils.bytesToInt(params, 12);
+                            int sec   = EtUtils.bytesToInt(params, 16);
+                            int nsec  = EtUtils.bytesToInt(params, 20);
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            try {
+                                if (mode == EtConstants.timed) {
+                                    int uSec = sec * 1000000 + nsec / 1000;
+                                    evs = sys.getEvents(att, mode, uSec, count);
+                                }
+                                else if (mode == EtConstants.sleep) {
+                                    // There's a problem if we have a remote client that is waiting
+                                    // for another event by sleeping and the events stop flowing. In
+                                    // that case, the client can be killed and the ET system does NOT
+                                    // know about it. Since this thread will be stuck in "getEvents",
+                                    // it will not immediately detect the break in the socket - at least
+                                    // not until events start flowing again. To circumvent this, implement
+                                    // "sleep" by repeats of "timed" every few seconds to allow
+                                    // detection of broken socket between calls to "getEvents".
+
+                                    // Store the fact we're trying to sleep - necessary when
+                                    // told to wake up.
+                                    att.setSleepMode(true);
+
+                                    tryToGetEvents:
+                                    while (true) {
+                                        // try a 4 second wait for events
+                                        try {
+                                            if (att.isWakeUp()) {
+                                                att.setWakeUp(false);
+                                                throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                                            }
+                                            evs = sys.getEvents(att, EtConstants.timed, 4000000, count);
+                                            // no longer in sleep mode
+                                            att.setSleepMode(false);
+                                            // may have been told to wake up between last 2 statements.
+                                            att.setWakeUp(false);
+                                            break;
+                                        }
+                                        // if timeout, check socket to see if still open
+                                        catch (EtTimeoutException tx) {
+                                            try {
+                                                // 1/2 second max delay on read
+                                                in.readInt();
+                                                // should never be able to get here
+                                                att.setSleepMode(false);
+                                                throw new EtException("communication protocol error");
+                                            }
+                                            // if there's an interrupted ex, socket is OK
+                                            catch (InterruptedIOException ex) { }
+                                        }
+                                    }
+
+                                }
+                                else {
+                                    evs = sys.getEvents(att, mode, 0, count);
+                                }
+
+                            }
+                            catch (EtException ex) {
+                                err = EtConstants.error;
+                            }
+                            catch (EtBusyException ex) {
+                                err = EtConstants.errorBusy;
+                            }
+                            catch (EtEmptyException ex) {
+                                err = EtConstants.errorEmpty;
+                            }
+                            catch (EtWakeUpException ex) {
+                                err = EtConstants.errorWakeUp;
+                                att.setSleepMode(false);
+                            }
+                            catch (EtTimeoutException ex) {
+                                err = EtConstants.errorTimeout;
+                            }
+
+                            if (err != ok) {
+                                out.writeInt(err);
+                                out.flush();
+                                break;
+                            }
+/*
+                          // use buffered output
+                          // first send number of events
+                          out.writeInt(evs.length);
+                          int size = evs.length * 4 * (6 + selectInts);
+                          for (int j = 0; j < evs.length; j++) {
+                              size += evs[j].length;
+                          }
+                          out.writeInt(size);
+                          for (int j = 0; j < evs.length; j++) {
+                              evs[j].modify = mod;
+                              out.writeInt(evs[j].length);
+                              out.writeInt(evs[j].memSize);
+                              out.writeInt(evs[j].priority | evs[j].dataStatus << dataShift);
+                              out.writeInt(evs[j].id);
+                              out.writeInt(evs[j].byteOrder);
+                              out.writeInt(0);
+                              for (int i = 0; i < selectInts; i++) {
+                                  out.writeInt(evs[j].control[i]);
+                              }
+                              out.write(evs[j].data, 0, evs[j].length);
+                          }
+                          out.flush();
+*/
+                            // handle buffering by hand
+                            int length, index = 12;
+                            int headerSize = 4 * (6 + selectInts);
+                            int size = evs.length * headerSize;
+                            for (EtEventImpl ev1 : evs) {
+                                size += ev1.getLength();
+                            }
+
+                            EtUtils.intToBytes(evs.length, buffer, 0);
+                            EtUtils.longToBytes((long)size, buffer, 4);
+
+                            Modify mfy = Modify.getModify(mod);
+                            for (EtEventImpl ev : evs) {
+                                ev.setModify(mfy);
+                                length = ev.getLength();
+                                EtUtils.longToBytes((long)length, buffer, index);
+                                EtUtils.longToBytes((long)ev.getMemSize(), buffer, index += 8);
+                                EtUtils.intToBytes(ev.getPriority().getValue() |
+                                                 ev.getDataStatus().getValue() << dataShift, buffer, index += 8);
+                                EtUtils.intToBytes(ev.getId(), buffer, index += 4); // skip 4 bytes here
+                                EtUtils.intToBytes(ev.getRawByteOrder(), buffer, index += 8);
+                                EtUtils.intToBytes(0, buffer, index += 4);
+                                int[] control = ev.getControl();
+                                for (int i = 0; i < selectInts; i++) {
+                                    EtUtils.intToBytes(control[i], buffer, index += 4);
+                                }
+                                index += 4;
+                                if (index + headerSize + length > buffer.length) {
+                                    out.write(buffer, 0, index);
+                                    index = 0;
+                                    if (headerSize + length > buffer.length / 2) {
+                                        out.write(ev.getData(), 0, length);
+                                        out.flush();
+                                        continue;
+                                    }
+                                    out.flush();
+                                }
+                                System.arraycopy(ev.getData(), 0, buffer, index, length);
+                                index += length;
+                            }
+
+                            if (index > 0) {
+                                out.write(buffer, 0, index);
+                                out.flush();
+                            }
+
+                            if (mod == 0) {
+                                sys.putEvents(att, evs);
+                            }
+                            evs = null;
+                        }
+                        break;
+
+
+                        case EtConstants.netEvPut: {
+                            in.readFully(params, 0, 32 + 4 * selectInts);
+
+                            int attId = EtUtils.bytesToInt(params, 0);
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            int id = EtUtils.bytesToInt(params, 4);
+                            EtEventImpl ev = sys.getEvents().get(id);
+                            // skip 4 bytes here
+
+                            long len = EtUtils.bytesToLong(params, 12);
+                            if (len > Integer.MAX_VALUE) {
+                                throw new EtException("Event is too long for this (java) ET system");
+                            }
+                            ev.setLengthFromServer((int) len);
+
+                            int priAndStat = EtUtils.bytesToInt(params, 20);
+                            ev.setPriority(Priority.getPriority(priAndStat & priorityMask));
+                            ev.setDataStatus(DataStatus.getStatus((priAndStat & dataMask) >> dataShift));
+                            ev.setRawByteOrder(EtUtils.bytesToInt(params, 24));
+                            // last parameter is ignored
+
+                            int index = 24;
+                            int[] control = new int[selectInts];
+                            for (int i = 0; i < selectInts; i++) {
+                                control[i] = EtUtils.bytesToInt(params, index += 4);
+                            }
+                            ev.setControl(control);
+                            // only read data if modifying everything
+                            if (ev.getModify() == Modify.ANYTHING) {
+                                in.readFully(ev.getData(), 0, ev.getLength());
+                            }
+
+                            EtEventImpl[] evArray = new EtEventImpl[1];
+                            evArray[0] = ev;
+
+                            sys.putEvents(att, evArray);
+
+                            out.writeInt(ok);
+                            out.flush();
+                        }
+                        break;
+
+
+                        case EtConstants.netEvsPut: {
+                            in.readFully(params, 0, 16);
+                            int attId           = EtUtils.bytesToInt(params, 0);
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+                            int numEvents       = EtUtils.bytesToInt(params,  4);
+                            long size           = EtUtils.bytesToLong(params, 8);
+
+                            long len;
+                            int  id, priAndStat, index;
+                            int  byteChunk = 28 + 4 * selectInts;
+                            evs = new EtEventImpl[numEvents];
+
+                            for (int j = 0; j < numEvents; j++) {
+                                in.readFully(params, 0, byteChunk);
+
+                                id = EtUtils.bytesToInt(params, 0);
+                                evs[j] = sys.getEvents().get(id);
+                                // skip 4 bytes here
+
+                                len = EtUtils.bytesToLong(params, 8);
+                                if (len > Integer.MAX_VALUE) {
+                                    throw new EtException("Event is too long for this (java) ET system");
+                                }
+                                evs[j].setLengthFromServer((int) len);
+
+                                priAndStat = EtUtils.bytesToInt(params, 16);
+                                evs[j].setPriority(Priority.getPriority(priAndStat & priorityMask));
+                                evs[j].setDataStatus(DataStatus.getStatus((priAndStat & dataMask) >> dataShift));
+                                evs[j].setRawByteOrder(EtUtils.bytesToInt(params, 20));
+                                index = 24;
+                                int[] control = new int[selectInts];
+                                for (int i = 0; i < selectInts; i++) {
+                                    control[i] = EtUtils.bytesToInt(params, index += 4);
+                                }
+                                evs[j].setControl(control);
+                                if (evs[j].getModify() == Modify.ANYTHING) {
+                                    // If user increased data length beyond memSize,
+                                    // use more memory.
+                                    if (evs[j].getLength() > evs[j].getMemSize()) {
+                                        evs[j].setData(new byte[evs[j].getLength()]);
+                                        evs[j].setMemSize(evs[j].getLength());
+                                    }
+                                    in.readFully(evs[j].getData(), 0, evs[j].getLength());
+                                }
+                            }
+                            sys.putEvents(att, evs);
+                            out.writeInt(ok);
+                            out.flush();
+                        }
+                        break;
+
+
+                        case EtConstants.netEvNew: {
+                            in.readFully(params, 0, 24);
+                            int  err = ok;
+                            int  attId = EtUtils.bytesToInt(params,  0);
+                            int  mode  = EtUtils.bytesToInt(params,  4);
+                            long size  = EtUtils.bytesToLong(params, 8);
+                            int  sec   = EtUtils.bytesToInt(params, 16);
+                            int  nsec  = EtUtils.bytesToInt(params, 20);
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            if (bit64 && size > Integer.MAX_VALUE/5) {
+                                out.writeInt(EtConstants.errorTooBig);
+                                out.writeLong(0L);
+                                break;
+                            }
+
+                            try {
+                                if (mode == EtConstants.timed) {
+                                    int uSec = sec * 1000000 + nsec / 1000;
+                                    evs = sys.newEvents(att, mode, uSec, 1, (int)size);
+                                }
+                                else if (mode == EtConstants.sleep) {
+                                    // There's a problem if we have a remote client that is waiting
+                                    // for another event by sleeping and the events stop flowing. In
+                                    // that case, the client can be killed and the ET system does NOT
+                                    // know about it. Since this thread will be stuck in "getEvents",
+                                    // it will not immediately detect the break in the socket - at least
+                                    // not until events start flowing again. To circumvent this, implement
+                                    // "sleep" by repeats of "timed" every few seconds to allow
+                                    // detection of broken socket between calls to "getEvents".
+
+                                    // Store the fact we're trying to sleep - necessary when
+                                    // told to wake up.
+                                    att.setSleepMode(true);
+
+                                    tryToGetEvents:
+                                    while (true) {
+                                        // try a 4 second wait for an event
+                                        try {
+                                            if (att.isWakeUp()) {
+                                                att.setWakeUp(false);
+                                                throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                                            }
+                                            evs = sys.newEvents(att, EtConstants.timed, 4000000, 1, (int)size);
+                                            // no longer in sleep mode
+                                            att.setSleepMode(false);
+                                            // may have been told to wake up between last 2 statements.
+                                            att.setWakeUp(false);
+                                            break;
+                                        }
+                                        // if timeout, check socket to see if still open
+                                        catch (EtTimeoutException tx) {
+                                            try {
+                                                // 1/2 second max delay on read
+                                                in.readInt();
+                                                // should never be able to get here
+                                                att.setSleepMode(false);
+                                                throw new EtException("communication protocol error");
+                                            }
+                                            // if there's an interrupted ex, socket is OK
+                                            catch (InterruptedIOException ex) { }
+                                        }
+                                    }
+
+                                }
+                                else {
+                                    evs = sys.newEvents(att, mode, 0, 1, (int)size);
+                                }
+                            }
+                            catch (EtException ex) {
+                                err = EtConstants.error;
+                            }
+                            catch (EtBusyException ex) {
+                                err = EtConstants.errorBusy;
+                            }
+                            catch (EtEmptyException ex) {
+                                err = EtConstants.errorEmpty;
+                            }
+                            catch (EtWakeUpException ex) {
+                                err = EtConstants.errorWakeUp;
+                                att.setSleepMode(false);
+                            }
+                            catch (EtTimeoutException ex) {
+                                err = EtConstants.errorTimeout;
+                            }
+
+                            if (err != ok) {
+                                out.writeInt(err);
+                                out.writeLong(0);
+                                out.flush();
+                                break;
+                            }
+
+                            evs[0].setModify(Modify.ANYTHING);
+
+                            out.writeInt(err);
+                            out.writeInt(evs[0].getId());
+                            out.writeInt(0); // unused
+                            out.flush();
+                            evs = null;
+                        }
+                        break;
+
+
+                        case EtConstants.netEvsNew: {
+                            in.readFully(params, 0, 28);
+                            int err = ok;
+                            int  attId = EtUtils.bytesToInt(params,  0);
+                            int  mode  = EtUtils.bytesToInt(params,  4);
+                            long size  = EtUtils.bytesToLong(params, 8);
+                            int  count = EtUtils.bytesToInt(params, 16);
+                            int  sec   = EtUtils.bytesToInt(params, 20);
+                            int  nsec  = EtUtils.bytesToInt(params, 24);
+
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            if (bit64 && count*size > Integer.MAX_VALUE/5) {
+                                out.writeInt(EtConstants.errorTooBig);
+                                break;
+                            }
+
+                            try {
+                                if (mode == EtConstants.timed) {
+                                    int uSec = sec * 1000000 + nsec / 1000;
+                                    evs = sys.newEvents(att, mode, uSec, count, (int)size);
+                                }
+                                else if (mode == EtConstants.sleep) {
+                                    // There's a problem if we have a remote client that is waiting
+                                    // for another event by sleeping and the events stop flowing. In
+                                    // that case, the client can be killed and the ET system does NOT
+                                    // know about it. Since this thread will be stuck in "getEvents",
+                                    // it will not immediately detect the break in the socket - at least
+                                    // not until events start flowing again. To circumvent this, implement
+                                    // "sleep" by repeats of "timed" every few seconds to allow
+                                    // detection of broken socket between calls to "getEvents".
+
+                                    // Store the fact we're trying to sleep - necessary when
+                                    // told to wake up.
+                                    att.setSleepMode(true);
+
+                                    tryToGetEvents:
+                                    while (true) {
+                                        // try a 4 second wait for events
+                                        try {
+                                            if (att.isWakeUp()) {
+                                                att.setWakeUp(false);
+                                                throw new EtWakeUpException("attachment " + att.getId() + " woken up");
+                                            }
+                                            evs = sys.newEvents(att, EtConstants.timed, 4000000, count, (int)size);
+                                            // no longer in sleep mode
+                                            att.setSleepMode(false);
+                                            // may have been told to wake up between last 2 statements.
+                                            att.setWakeUp(false);
+                                            break;
+                                        }
+                                        // if timeout, check socket to see if still open
+                                        catch (EtTimeoutException tx) {
+                                            try {
+                                                // 1/2 second max delay on read
+                                                in.readInt();
+                                                // should never be able to get here
+                                                att.setSleepMode(false);
+                                                throw new EtException("communication protocol error");
+                                            }
+                                            // if there's an interrupted ex, socket is OK
+                                            catch (InterruptedIOException ex) { }
+                                        }
+                                    }
+
+                                }
+                                else {
+                                    evs = sys.newEvents(att, mode, 0, count, (int)size);
+                                }
+
+                            }
+                            catch (EtException ex) {
+                                err = EtConstants.error;
+                            }
+                            catch (EtBusyException ex) {
+                                err = EtConstants.errorBusy;
+                            }
+                            catch (EtEmptyException ex) {
+                                err = EtConstants.errorEmpty;
+                            }
+                            catch (EtWakeUpException ex) {
+                                err = EtConstants.errorWakeUp;
+                                att.setSleepMode(false);
+                            }
+                            catch (EtTimeoutException ex) {
+                                err = EtConstants.errorTimeout;
+                            }
+
+                            if (err != ok) {
+                                out.writeInt(err);
+                                out.flush();
+                                break;
+                            }
+
+                            // handle buffering by hand
+                            int index = 0;
+                            byte[] buf = new byte[4 + 4 * evs.length];
+
+                            // first send number of events
+                            EtUtils.intToBytes(evs.length, buf, 0);
+                            for (EtEventImpl ev : evs) {
+                                ev.setModify(Modify.ANYTHING);
+                                EtUtils.intToBytes(ev.getId(), buf, index += 4);
+                            }
+                            out.write(buf);
+                            out.flush();
+
+                            evs = null;
+                        }
+                        break;
+
+
+                        case EtConstants.netEvDump: {
+                            int  attId = in.readInt();
+                            int  id    = in.readInt();
+
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+                            EtEventImpl ev = sys.getEvents().get(id);
+                            EtEventImpl[] evArray = new EtEventImpl[1];
+                            evArray[0] = ev;
+                            sys.dumpEvents(att, evArray);
+
+                            out.writeInt(ok);
+                            out.flush();
+                        }
+                        break;
+
+
+                        case EtConstants.netEvsDump: {
+                            int attId     = in.readInt();
+                            int numEvents = in.readInt();
+                            evs = new EtEventImpl[numEvents];
+                            AttachmentLocal att = attachments.get(new Integer(attId));
+
+                            int id;
+                            byte[] buf = new byte[4 * numEvents];
+                            in.readFully(buf, 0, 4 * numEvents);
+                            int index = -4;
+
+                            for (int j = 0; j < numEvents; j++) {
+                                id = EtUtils.bytesToInt(buf, index += 4);
+                                evs[j] = sys.getEvents().get(id);
+                            }
[truncated at 1000 lines; 805 more skipped]

hps-et-java/src/main/java/org/jlab/coda/et/system
SystemUdpServer.java added at 1.1
diff -N SystemUdpServer.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ SystemUdpServer.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,385 @@
+/*----------------------------------------------------------------------------*
+ *  Copyright (c) 2001        Southeastern Universities Research Association, *
+ *                            Thomas Jefferson National Accelerator Facility  *
+ *                                                                            *
+ *    This software was developed under a United States Government license    *
+ *    described in the NOTICE file included as part of this distribution.     *
+ *                                                                            *
+ *    Author:  Carl Timmer                                                    *
+ *             [log in to unmask]                   Jefferson Lab, MS-12H        *
+ *             Phone: (757) 269-5130             12000 Jefferson Ave.         *
+ *             Fax:   (757) 269-5800             Newport News, VA 23606       *
+ *                                                                            *
+ *----------------------------------------------------------------------------*/
+
+package org.jlab.coda.et.system;
+
+import java.lang.*;
+import java.io.*;
+import java.net.*;
+import org.jlab.coda.et.*;
+
+/**
+ * This class implements a thread which starts other threads - each of which
+ * listen at a different IP address for users trying to find the ET system by
+ * broadcasting, multicasting, or the direct sending of a udp packet.
+ *
+ * @author Carl Timmer
+ */
+
+class SystemUdpServer extends Thread {
+
+    /** Udp port to listen on. */
+    private int port;
+
+    /** ET system object. */
+    private SystemCreate sys;
+
+    /** ET system configuration. */
+    private SystemConfig config;
+
+
+    /**
+     * Createes a new SystemUdpServer object.
+     * @param sys ET system object
+     */
+    SystemUdpServer(SystemCreate sys) {
+        this.sys = sys;
+        config = sys.getConfig();
+        port = config.getServerPort();
+    }
+
+    /** Starts threads to listen for packets at a different addresses. */
+    public void run() {
+        if (config.getDebug() >= EtConstants.debugInfo) {
+            System.out.println("Running UDP Listening Threads");
+        }
+
+        // use the default port number since one wasn't specified
+        if (port < 1) {
+            port = EtConstants.serverPort;
+        }
+
+        // If we're broadcasting, then we use 1 thread with 1 socket,
+        // bound to the wildcard address, to listen to broadcasts from all local
+        // subnets.
+        //
+        // If we're multicasting and the specified multicast port is the same as the
+        // broadcast port, then we use 1 thread to listen to multicasts and broadcasts
+        // on one socket.
+        //
+        // If we're multicasting with a different port than the broadcasting/direct
+        // port, then multicasting is treated separately from everything else and has
+        // its own socket and thread.
+
+        if (config.getMulticastAddrs().size() > 0) {
+            try {
+System.out.println("setting up for multicast on port " + config.getMulticastPort());
+                MulticastSocket sock = new MulticastSocket(config.getMulticastPort());
+                sock.setReceiveBufferSize(512);
+                sock.setSendBufferSize(512);
+                ListeningThread lis = new ListeningThread(sys, sock);
+                lis.start();
+            }
+            catch (IOException e) {
+                System.out.println("cannot listen on port " + config.getMulticastPort() + " for multicasting");
+                e.printStackTrace();
+            }
+
+            if (config.getMulticastPort() == config.getUdpPort()) {
+                // only need to listen on the multicast socket, so we're done
+                return;
+            }
+        }
+
+        try {
+System.out.println("setting up for broadcast on port " + config.getUdpPort());
+            DatagramSocket sock = new DatagramSocket(config.getUdpPort());
+            sock.setBroadcast(true);
+            sock.setReceiveBufferSize(512);
+            sock.setSendBufferSize(512);
+            ListeningThread lis = new ListeningThread(sys, sock);
+            lis.start();
+        }
+        catch (SocketException e) {
+            e.printStackTrace();
+        }
+        catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+    }
+}
+
+
+/**
+ * This class implements a thread which listens on a particular address for a
+ * udp packet. It sends back a udp packet with the tcp server port, host name,
+ * and other information necessary to establish a tcp connection between the
+ * tcp server thread of the ET system and the user.
+ *
+ * @author Carl Timmer
+ */
+
+class ListeningThread extends Thread {
+
+    /** ET system object. */
+    private SystemCreate sys;
+
+    /** ET system configuration object. */
+    private SystemConfig config;
+
+    /** Setup a socket for receiving udp packets. */
+    private DatagramSocket sock;
+
+    /** Is this thread responding to a multicast or broadcast or perhaps either. */
+    private int cast;
+
+    /** Don't know which address the broad/multicast was sent to since we're using
+     * "INADDR_ANY" so just return this. */
+    private String incomingAddress = "0.0.0.0";
+
+
+    /**
+     *  Creates a new ListeningThread object for a UDP multicasts.
+     *
+     *  @param sys ET system object
+     *  @param mSock multicast udp socket
+     */
+    ListeningThread(SystemCreate sys, MulticastSocket mSock) throws IOException {
+        this.sys = sys;
+        config   = sys.getConfig();
+        for (InetAddress address : config.getMulticastAddrs()) {
+            if (address.isMulticastAddress()) {
+                mSock.joinGroup(address);
+            }
+        }
+        sock = mSock;
+        cast = EtConstants.broadAndMulticast;
+    }
+
+
+    /**
+     *  Creates a new ListeningThread object for a UDP broadcasts.
+     *
+     *  @param sys ET system object
+     *  @param sock udp socket
+     */
+    ListeningThread(SystemCreate sys, DatagramSocket sock) throws UnknownHostException {
+        this.sys  = sys;
+        config    = sys.getConfig();
+        this.sock = sock;
+        cast = EtConstants.broadcast;
+    }
+
+
+    /**
+     * Starts a single thread to listen for udp packets at a specific address
+     * and respond with ET system information.
+     */
+    public void run() {
+        // packet & buffer to receive UDP packets
+        byte[] rBuffer = new byte[512]; // much larger than needed
+        DatagramPacket rPacket = new DatagramPacket(rBuffer, 512);
+
+        // Prepare output buffer we send in answer to inquiries:
+        //
+        // (0)  ET magic numbers (3 ints)
+        // (1)  ET version #
+        // (2)  port of tcp server thread (not udp config->port)
+        // (3)  ET_BROADCAST or ET_MULTICAST (int)
+        // (4)  length of next string
+        // (5)    broadcast address (dotted-dec) if broadcast received or
+        //        multicast address (dotted-dec) if multicast received
+        //        (see int #3)
+        // (6)  length of next string
+        // (7)    hostname given by "uname" (used as a general
+        //        identifier of this host no matter which interface is used)
+
+        // (8)  length of next string
+        // (9)    canonical name of host
+        // (10) number of IP addresses
+        // (11)   32bit, net-byte ordered IPv4 address assoc with following address
+        // (12)   length of next string
+        // (13)       first dotted-decimal IPv4 address
+        // (14)   32bit, net-byte ordered IPv4 address assoc with following address
+        // (15)   length of next string
+        // (16)       second dotted-decimal IPv4 address ...
+        //
+        // All known IP addresses are sent here both in numerical & dotted-decimal forms.
+        //
+
+        // buffer for reading ET name
+        byte[] etNameBytes = new byte[EtConstants.fileNameLengthMax];
+
+        // Put outgoing packet into byte array
+        ByteArrayOutputStream baos = null;
+
+        try {
+            InetAddress addr = InetAddress.getLocalHost();
+            String canon = addr.getCanonicalHostName();
+            String hostName = addr.getHostName();
+
+            // the send buffer needs to be of byte size ...
+            int bufferSize = 10*4 + incomingAddress.length() + hostName.length() + canon.length() + 3;
+            for (InetAddress netAddress : sys.getNetAddresses()) {
+                bufferSize += 8 + netAddress.getHostAddress().length() + 1;
+            }
+
+            baos = new ByteArrayOutputStream(bufferSize);
+            DataOutputStream dos = new DataOutputStream(baos);
+
+            // (0) magic #s
+            dos.writeInt(EtConstants.magicNumbers[0]);
+            dos.writeInt(EtConstants.magicNumbers[1]);
+            dos.writeInt(EtConstants.magicNumbers[2]);
+
+            // (1), (2) & (3)
+            dos.writeInt(EtConstants.version);
+            dos.writeInt(config.getServerPort());
+            dos.writeInt(cast);
+
+            // (4) & (5)  incomingAddress = 0.0.0.0 since this is Java
+            dos.writeInt(incomingAddress.length() + 1);
+            dos.write(incomingAddress.getBytes("ASCII"));
+            dos.writeByte(0);
+
+            // (6) & (7) Local host name (equivalent to uname?)
+            dos.writeInt(hostName.length() + 1);
+            dos.write(hostName.getBytes("ASCII"));
+            dos.writeByte(0);
+
+            // (8) & (9) canonical host name
+            dos.writeInt(canon.length() + 1);
+            dos.write(canon.getBytes("ASCII"));
+            dos.writeByte(0);
+
+            // (10) number of addresses to follow
+            dos.writeInt(sys.getNetAddresses().length);
+
+            // Send all addresses (32 bit and dot-decimal) associated with this host
+            int addr32;
+            for (InetAddress netAddress : sys.getNetAddresses()) {
+                // convert array of 4 bytes into 32 bit network byte-ordered address
+                addr32 = 0;
+                for (int j = 0; j < 4; j++) {
+                    addr32 = addr32 << 8 | (((int) (netAddress.getAddress())[j]) & 0xFF);
+                }
+// System.out.println("sending addr32 = " + addr32 + ", IP addr = " + netAddress.getHostAddress());
+                // (11)
+                dos.writeInt(addr32);
+                // (12)
+                dos.writeInt(netAddress.getHostAddress().length() + 1);
+                // (13)
+                dos.write(netAddress.getHostAddress().getBytes("ASCII"));
+                dos.writeByte(0);
+            }
+
+            dos.flush();
+        }
+        catch (UnsupportedEncodingException ex) {
+            ex.printStackTrace();
+            // this will never happen.
+        }
+        catch (UnknownHostException ex) {
+            ex.printStackTrace();
+            // local host is always known
+        }
+        catch (IOException ex) {
+            ex.printStackTrace();
+            // this will never happen since we're writing to array
+        }
+
+        // construct byte array to send over a socket
+        byte[] sBuffer = baos.toByteArray();
+
+        while (true) {
+            try {
+                // read incoming data without blocking forever
+                while (true) {
+                    try {
+//System.out.println("Waiting to receive packet, sock broadcast = " + sock.getBroadcast());
+                        sock.receive(rPacket);
+//System.out.println("Received packet ...");
+                        break;
+                    }
+                    // socket receive timeout
+                    catch (InterruptedIOException ex) {
+                        // check to see if we've been commanded to die
+                        if (sys.killAllThreads()) {
+                            return;
+                        }
+                    }
+                }
+
+                // decode the data:
+                // (1) ET magic numbers (3 ints),
+                // (2) ET version #,
+                // (3) length of string,
+                // (4) ET file name
+
+                ByteArrayInputStream bais = new ByteArrayInputStream(rPacket.getData());
+                DataInputStream dis = new DataInputStream(bais);
+
+                int magic1 = dis.readInt();
+                int magic2 = dis.readInt();
+                int magic3 = dis.readInt();
+                if (magic1 != EtConstants.magicNumbers[0] ||
+                    magic2 != EtConstants.magicNumbers[1] ||
+                    magic3 != EtConstants.magicNumbers[2])  {
+//System.out.println("SystemUdpServer:  Magic numbers did NOT match");
+                    continue;
+                }
+
+                int version = dis.readInt();
+                int length = dis.readInt();
+//System.out.println("et_listen_thread: received packet version =  " + version +
+//                    ", length = " + length);
+
+                // reject incompatible ET versions
+                if (version != EtConstants.version) {
+                    continue;
+                }
+                // reject improper formats
+                if ((length < 1) || (length > EtConstants.fileNameLengthMax)) {
+                    continue;
+                }
+
+                // read all string bytes
+                if (length > etNameBytes.length) {
+                    etNameBytes = new byte[length];
+                }
+                dis.readFully(etNameBytes, 0, length-1);
+                String etName = new String(etNameBytes, 0, length-1, "US-ASCII");
+
+//System.out.println("et_listen_thread: received packet version =  " + version +
+//                                  ", ET = " + etName);
+                if (config.getDebug() >= EtConstants.debugInfo) {
+                    System.out.println("et_listen_thread: received packet from " +
+                            rPacket.getAddress().getHostName() +
+                            " @ " + rPacket.getAddress().getHostAddress() +
+                            " for " + etName);
+                }
+
+                // check if the ET system the client wants is ours
+                if (etName.equals(sys.getName())) {
+                    // we're the one the client is looking for, send a reply
+                    DatagramPacket sPacket = new DatagramPacket(sBuffer, sBuffer.length,
+                                                                rPacket.getAddress(), rPacket.getPort());
+                    if (config.getDebug() >= EtConstants.debugInfo) {
+                        System.out.println("et_listen_thread: send return packet");
+                    }
+                    sock.send(sPacket);
+                }
+            }
+            catch (IOException ex) {
+                if (config.getDebug() >= EtConstants.debugError) {
+                    System.out.println("error handling UDP packets");
+                    ex.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+}
+

hps-et-java/src/main/java/org/jlab/coda/et/test
EmuTest.java added at 1.1
diff -N EmuTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ EmuTest.java	13 Feb 2012 22:43:46 -0000	1.1
@@ -0,0 +1,330 @@
+package org.jlab.coda.et.test;
+
+import org.jlab.coda.et.*;
+import org.jlab.coda.et.enums.Mode;
+import org.jlab.coda.et.enums.Modify;
+import org.jlab.coda.jevio.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Try to mimic what a evio producer, event builder, and evio consumer do in succession
+ * in order to test the chain of events that the emu goes through.
+ */
+public class EmuTest {
+
+    public EmuTest() {
+    }
+
+
+     private static void usage() {
+         System.out.println("\nUsage: java EmuTest -etin <name of input et> -etout <name of output et>\n" +
+                 "                    [-d <delay>] [-host <host>] [-pin <input et port>] [-pout <output et port>]\n\n" +
+                 "      -etin  input  ET system's name\n" +
+                 "      -etout output ET system's name\n" +
+                 "      -pin   port number for input  et udp broadcast\n" +
+                 "      -pout  port number for output et udp broadcast\n" +
+                 "      -d     delay in millisec between getting and putting events\n" +
+                 "      -g     group number of new events to get\n" +
+                 "      -host  host the ET system resides on (defaults to anywhere)\n\n" +
+                 "       This consumer works by making a connection to the\n" +
+                 "       ET system's tcp server port.\n");
+     }
+
+
+    /**
+     * Create a simple evio bank for sending.
+     */
+    public static ByteBuffer evioBytes() throws EvioException {
+
+        // count the events we make for testing
+        int eventNumber = 1;
+
+        // use a tag of 2 for no particular reason
+        int tag = 2;
+
+        // bank of banks
+        EventBuilder eventBuilder = new EventBuilder(tag, DataType.BANK, eventNumber);
+        EvioEvent event = eventBuilder.getEvent();
+
+        // add a bank of ints
+        EvioBank bank = new EvioBank(3, DataType.INT32, 0);
+        eventBuilder.appendIntData(bank, new int[] {1,2,3, 0, -1, -2, -3});
+        eventBuilder.addChild(event, bank);
+
+        event.setAllHeaderLengths();
+
+        // write the event
+        ByteBuffer buf = ByteBuffer.allocate(event.getTotalBytes());
+        event.write(buf);
+        buf.flip();
+
+        //System.out.println("Event = \n"+ event2.toXML());
+        return buf;
+    }
+
+
+    /**
+     * Main program for testing.
+     */
+    public static void main(String[] args) {
+
+         String etNameIn = null, etNameOut = null, host = null;
+         int portIn = EtConstants.serverPort, portOut = EtConstants.serverPort;
+         int group = 1;
+         int delay = 0;
+         int size = 32;
+
+         try {
+             for (int i = 0; i < args.length; i++) {
+                 if (args[i].equalsIgnoreCase("-etin")) {
+                     etNameIn = args[++i];
+                 }
+                 else if (args[i].equalsIgnoreCase("-etout")) {
+                     etNameOut = args[++i];
+                 }
+                 else if (args[i].equalsIgnoreCase("-host")) {
+                     host = args[++i];
+                 }
+                 else if (args[i].equalsIgnoreCase("-pin")) {
+                     try {
+                         portIn = Integer.parseInt(args[++i]);
+                         if ((portIn < 1024) || (portIn > 65535)) {
+                             System.out.println("Input port number must be between 1024 and 65535.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper input port number.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-pout")) {
+                     try {
+                         portOut = Integer.parseInt(args[++i]);
+                         if ((portOut < 1024) || (portOut > 65535)) {
+                             System.out.println("Output port number must be between 1024 and 65535.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper output port number.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-s")) {
+                     try {
+                         size = Integer.parseInt(args[++i]);
+                         if (size < 1) {
+                             System.out.println("Size needs to be positive int.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper size.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-g")) {
+                     try {
+                         group = Integer.parseInt(args[++i]);
+                         if ((group < 1) || (group > 10)) {
+                             System.out.println("Group number must be between 0 and 10.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper group number.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else if (args[i].equalsIgnoreCase("-d")) {
+                     try {
+                         delay = Integer.parseInt(args[++i]);
+                         if (delay < 1) {
+                             System.out.println("delay must be > 0.");
+                             usage();
+                             return;
+                         }
+                     }
+                     catch (NumberFormatException ex) {
+                         System.out.println("Did not specify a proper delay.");
+                         usage();
+                         return;
+                     }
+                 }
+                 else {
+                     usage();
+                     return;
+                 }
+             }
+
+             if (host == null) {
+                 host = EtConstants.hostAnywhere;
+                 /*
+                 try {
+                     host = InetAddress.getLocalHost().getHostName();
+                 }
+                 catch (UnknownHostException ex) {
+                     System.out.println("Host not specified and cannot find local host name.");
+                     usage();
+                     return;
+                 }
+                 */
+             }
+
+             if (etNameIn == null || etNameOut == null) {
+                 usage();
+                 return;
+             }
+
+             ///////////////////////////////////////////////////////////
+             // INPUT
+             ///////////////////////////////////////////////////////////
+
+             // make a direct connection to ET system's tcp server
+             EtSystemOpenConfig configIn = new EtSystemOpenConfig(etNameIn, host, portIn);
+
+             // create ET system object with verbose debugging output
+             EtSystem sysIn = new EtSystem(configIn, EtConstants.debugInfo);
+             sysIn.open();
+
+             // get GRAND_CENTRAL station object
+             EtStation gcIn = sysIn.stationNameToObject("GRAND_CENTRAL");
+
+             // attach to grandcentral
+             EtAttachment gcAttIn = sysIn.attach(gcIn);
+
+             // default configuration of a new station
+             EtStationConfig statConfig = new EtStationConfig();
+
+             // create new station
+             EtStation statIn = sysIn.createStation(statConfig, "in", 1, 0);
+
+             // attach to new station
+             EtAttachment attIn1 = sysIn.attach(statIn);
+
+             ///////////////////////////////////////////////////////////
+             // OUTPUT
+             ///////////////////////////////////////////////////////////
+
+             EtSystemOpenConfig configOut = new EtSystemOpenConfig(etNameOut, host, portOut);
+             EtSystem sysOut              = new EtSystem(configOut, EtConstants.debugInfo);
+             sysOut.open();
+             EtStation gcOut              = sysOut.stationNameToObject("GRAND_CENTRAL");
+             EtAttachment gcAttOut        = sysOut.attach(gcOut);
+             EtStation statOut            = sysOut.createStation(statConfig, "out", 1, 0);
+             EtAttachment attOut1         = sysOut.attach(statOut);
+
+             ///////////////////////////////////////////////////////////
+
+             // arrays of events
+             EtEvent[] mevsIn, mevsOut;
+
+             int chunk = 1, count = 0;
+             long t1, t2, counter = 0, totalT = 0, totalCount = 0;
+             double rate, avgRate;
+             int[] con = {1, 2, 3, 4};
+             String s;
+
+             // keep track of time for event rate calculations
+             t1 = System.currentTimeMillis();
+
+             for (int i = 0; i < 50; i++) {
+                 while (count < 300000L) {
+                     // get array of new events from input ET
+                     mevsIn = sysIn.newEvents(gcAttIn, Mode.SLEEP, 0, chunk, 512);
+
+                     if (delay > 0) Thread.sleep(delay);
+
+                     // put data into events
+                     if (true) {
+                         for (EtEvent aMevsIn : mevsIn) {
+                             ByteBuffer buf = evioBytes();
+                             aMevsIn.getDataBuffer().put(buf);
+                             int len = buf.position();
+                             //aMevsIn.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+                             aMevsIn.setLength(len);
+                         }
+                     }
+
+                     // put events back into input ET system
+                     sysIn.putEvents(gcAttIn, mevsIn);
+
+                     ///////////////////////////////////////////////////////////
+                     // now transfer events from one ET system to another
+                     ///////////////////////////////////////////////////////////
+
+                     // get array of events from input ET
+                     mevsIn  = sysIn.getEvents(attIn1, Mode.SLEEP, Modify.NOTHING, 0, chunk);
+
+                     // get array of new events from output ET
+                     mevsOut = sysOut.newEvents(gcAttOut, Mode.SLEEP, 0, mevsIn.length, 2048);
+
+                     if (mevsIn.length != mevsOut.length) {
+                         System.out.println("NON-matching lengths!!!");
+                     }
+
+                     for (int j=0; j < mevsOut.length; j++) {
+                         ByteBuffer buf = mevsIn[j].getDataBuffer();
+                         mevsOut[j].getDataBuffer().put(buf);
+                         int len = buf.position();
+                         mevsOut[j].setLength(len);
+                     }
+
+                     // put events back into input & output ET systems
+                     sysIn.putEvents(attIn1, mevsIn);
+                     sysOut.putEvents(gcAttOut, mevsOut);
+
+                     ///////////////////////////////////////////////////////////
+                     // now look at events from output ET system
+                     ///////////////////////////////////////////////////////////
+
+                     // get array of events from input ET
+                     mevsOut = sysOut.getEvents(attOut1, Mode.SLEEP, Modify.NOTHING, 0, chunk);
+
+                     System.out.println("event's data buffer is " + mevsOut[0].getDataBuffer().order() + ", limit = " + mevsOut[0].getDataBuffer().limit() +
+                     ", capacity = " + mevsOut[0].getDataBuffer().capacity());
+                     System.out.println("swap = " + mevsOut[0].needToSwap());
+
+                     ByteParser parser = new ByteParser();
+                     EvioEvent ev = parser.parseEvent(mevsOut[0].getDataBuffer());
+                     System.out.println("Event = \n"+ev.toXML());
+
+                     sysOut.putEvents(attOut1, mevsOut);
+                     
+                     if (delay > 0) Thread.sleep(delay);
+                     count++;
+                 }
+
+                 // calculate the event rate
+                 t2 = System.currentTimeMillis();
+                 rate = 1000.0 * ((double) count) / ((double) (t2 - t1));
+                 totalCount += count;
+                 totalT += t2 - t1;
+                 avgRate = 1000.0 * ((double) totalCount) / totalT;
+                 System.out.println("rate = " + String.format("%.3g", rate) +
+                                    " Hz,   avg = " + String.format("%.3g", avgRate));
+                 count = 0;
+                 t1 = System.currentTimeMillis();
+             }
+             System.out.println("End of program, now close et systems");
+             sysIn.close();
+             sysOut.close();
+         }
+         catch (Exception ex) {
+             System.out.println("Error using ET system as emu test");
+             ex.printStackTrace();
+         }
+     }
+
+
+}
CVSspam 0.2.12


Use REPLY-ALL to reply to list

To unsubscribe from the LCD-CVS list, click the following link:
https://listserv.slac.stanford.edu/cgi-bin/wa?SUBED1=LCD-CVS&A=1