package dataqueue;
import
java.beans.PropertyChangeListener;
import
java.beans.PropertyChangeSupport;
import
java.io.IOException;
import
java.io.UnsupportedEncodingException;
import
com.ibm.as400.access.AS400;
import
com.ibm.as400.access.AS400SecurityException;
import
com.ibm.as400.access.ConnectionDroppedException;
import
com.ibm.as400.access.ErrorCompletingRequestException;
import
com.ibm.as400.access.IllegalObjectTypeException;
import
com.ibm.as400.access.KeyedDataQueue;
import com.ibm.as400.access.KeyedDataQueueEntry;
import
com.ibm.as400.access.ObjectDoesNotExistException;
/**
* Class encapsulating methods to read a data queue from a thread so the caller
* does not wait for the data queue read. The results of the data queue read are
* communicated through PropertyChangeSupport. The varible objects are supplied
* to the class <ul>
* <li>AS400 object for data queue communications</li>
* <li>The IFS path of the iSeries data queue objectg </li>
* <li>The initial RecordFormat object that the model is expected to deliver its output </li>
* </ul>
* The key key value used to identify this view-controller/client to the
* model/server as hex representation of last 3 bytes (least significant
* bytes) of IP address giving a six character key.
* <p>
* @author Bill Blalock
*
*/
public class
ModelOutputDataQueue implements Runnable {
private AS400 as400;
private KeyedDataQueue dq;
private final
PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private String dqKey;
private boolean readDqFlag;
/**
* Construct ModelOutputDataQueue. The parameters are contructed outside this class by the caller to
* make the class independent and reusable.
* @param _as400 Fully instantiated AS400 object who connection has been validated.
* @param dqIseriesPath The IFS path of the data queue object on the iSeries from the root.
* @param _dqKey value of key whose length matches the key
* length defined for the data queue
* @param _dqRecordFormat The initial RecordFormat object to be read from the model output
* data queue. Severally differe RecordFormat could be used during the life of the class that
* represent different data structures sent by the model/server.
*/
public ModelOutputDataQueue(
AS400 _as400, String dqIseriesPath, String _dqKey ) {
dqKey = _dqKey;
System.out.println("Key used
is: " + dqKey);
as400 = _as400;
readDqFlag = true;
dq = new KeyedDataQueue(as400,
dqIseriesPath);
}
/**
* Method to be executed by a Thread.
*/
public void run() {
// Record to be read from the model
output data queue.
KeyedDataQueueEntry keyedDqEntry = null;
// Previous Record read from the model
output data queue.
KeyedDataQueueEntry oldKeyedDqEntry
= null;
// this loop won't end unless an
Exception occurs or the JVM is ended
while (readDqFlag) {
try {
// Wait for
the model response.
keyedDqEntry = dq.read(dqKey, 600, "EQ");
// the
stopReadingDq() method called, setting readDqFlag false, and
// feeding the
model's output data queue a dummy entry.
Since the
// readDqFlag
is false the entry read from the data queue is
// thrown
away, the property change event is not fired and break
// out of the
loop, leaving the run() method.
if( !readDqFlag ) {
// System.out
// .println("...
the readDqFlag is false, breaking out of run() method ... ");
break;
}
// Every 10
minutes the read will time out. Loop and
try again. If something
// has
happened to the data queue (like the System i was IPL'd)
// an
exception will be thrown. Not great but
atleast this Thread
// won't wait
forever for something which can't happen.
if( keyedDqEntry
== null )
continue;
// Pass the
record object to the property change listener.
this.pcs.firePropertyChange("dqRead",
oldKeyedDqEntry, keyedDqEntry);
// save the
record object just read as the old record object
oldKeyedDqEntry =
keyedDqEntry;
} catch
(ConnectionDroppedException e) {
reportException(e);
break;
} catch
(InterruptedException e) {
reportException(e);
break;
} catch
(UnsupportedEncodingException e) {
reportException(e);
break;
} catch
(AS400SecurityException e) {
reportException(e);
break;
} catch
(ObjectDoesNotExistException e) {
reportException(e);
break;
} catch ( ErrorCompletingRequestException
e) {
reportException(e);
break;
} catch (
IllegalObjectTypeException e) {
reportException(e);
break;
} catch ( IOException
e) {
reportException(e);
break;
}
} // end of while(true)
ObjectDoesNotExistException IllegalObjectTypeException
}
/**
* Set boolean to break do loop and write a dummy record to the model's
* output data queue. This class will read it and break the read loop.
*
*/
public void stopReadingDq()
{
readDqFlag = false;
try {
dq.write(dqKey, new String(" ") );
} catch( Exception e )
{
reportException(e);
}
}
/**
* Override the key set for this class in constuctor to identify this
* view-controller/client to the model/server. The length of
* the key passed must match the length of the key defined for
* for data queue.
* @param _dqKey new value of key whose length matches the key
* length defined for the data queue
*/
public void setDqKey(String
_dqKey ) {
dqKey = _dqKey;
}
/**
* Get key used to identify this view-controller/client to the model/server.
* @return Key used to identify this view-controller/client to the model/server.
*/
public String
getDqKey() {
return dqKey;
}
/**
* Report exceptions to user and to the data queue listener. The
* run() method of a thread can't throw exceptions. When implementing
* for real enhance this method to log the exceptions.
* @param e
*/
private void reportException(Exception
e) {
e.printStackTrace();
// Pass the data queue exception to
the property change listener.
this.pcs.firePropertyChange("dqError", null, e);
}
/**
* Add a PropertyChangeListener for bound property using the services of the
* PropertyChangeSupport class.
* @param listener
*/
public void
addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
/**
* Remove a PropertyChangeListener using the services of the
* PropertyChangeSupport class.
* @param listener
*/
public void
removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
}