SRMDataReader.java revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*
*/
/**
* This class works out the protocol layer of the unidirectional data interface
* between the rds and the client. The protocol contains a header with a lists
* of data. Each list has a header and some elements, which have again a header
* and some fields of data:
* protocol = { pheader, n * list }
* pheader == { "@RDS-MAG@", PROTV, LISTN }
* PROTV == { protocol version }
* LISTN == { number of lists }
* list == { lheader, n * element }
* lheader == { LISTT, ELEMN }
* LISTT == { type of the list }
* ELEMN == { number of elements in the list }
* element == { eheader, field }
* eheader == { ELMID, FILDN }
* ELMID == { element id, like pid, uid, project name }
* field == { KEY, VALUE }
* All protocol elements has a key and a value separated by one space.
* The value begins after the first space and ends at the new line character.
* Protocol keys are: "@RDS-MAG@", PROTV, LISTN, LISTT, ELEMN ELMID, FILDN,
* RDERR. The special key RDERR can occur in any line indicates error condition,
* where the VALUE is the error message from rds.
* @author Sun Microsystems, Inc.
* @version 1.1 08/31/01
*/
class SRMDataReader {
// Protocol keys
// RDS commands
private Process p;
private int exitV;
private PrintWriter pw;
// Timeout for waiting for the first line from rds after its start.
// Since rds can be busy for a long time reading and scanning its
// persistence file, this time must set be relative high.
// Default timeout for reading RDS responses
// If rds is too busy to respond, wait this long before retrying
// Retry and rds command no more than this many times
private static final int MAX_RDS_RETRIES = 140;
protected int readTimeout = DEFAULT_READTIMEOUT;
private long charsRead = 0;
/**
* Constructor.
* @param dm data model that reads and interprets the protocol data
* fields.
*/
// initialize the response timeout according to resource property
try {
} catch (Exception e) {
}
}
}
/**
* Start the by cmdArgs defined rds, and check the protocol header.
* @param cmdArgs contains the path of rds and the arguments to use.
* @exception SRMProtocolException if a protocol violation has occurred.
*/
}
/**
* Send exit command to rds and close the rds pipe.
*/
public void closeRDS() {
}
/**
* Close the rds pipe and shutdown the rds procces.
*/
public void shutdownRDS() {
}
/**
* Start the udpate.
* If parse returns an error code it is assumed that rds is busy.
* The request will then be retried.
*
* @param option defines the rds command opion, -S -p ...
* @exception SRMProtocolException if a protocol violation has occurred.
*/
}
/**
* Force the RDS to keep alive by sending the ALIVE command
* @exception SRMProtocolException if a protocol violation has occurred.
*/
public void alive() throws SRMProtocolException {
}
/**
* Start the by cmdArgs defined rds, and check the protocol header.
* This method is called by the worker thread.
* @param cmdArgs contains the path of rds and the arguments to use.
* @exception SRMProtocolException if a protocol violation has occurred.
*/
try {
readHeader();
} catch (SRMProtocolException e) {
shutdownRDS();
throw e;
}
}
/**
* Send exit command to rds and close the rds pipe.
* This method is called by the worker thread.
*/
private void _closeRDS() {
/*
* First we try to close rds carefully by sending an exit command.
* If it failed we will destroy the rds process. In both cases
* we will wait for its termination.
*/
try {
checkPrompt();
"waiting for rds to terminate");
p.waitFor();
close();
} catch (SRMProtocolException e) {
shutdownRDS();
} catch (InterruptedException e) {
}
}
/**
* Close the rds pipe and shutdown the rds procces.
* This method is called by the worker thread.
*/
private void _shutdownRDS() {
/*
* First check if it is still running if so destroy it and wait
* for its termination.
*/
if (checkRDSrunning()) {
p.destroy();
try {
"waiting for rds to terminate");
p.waitFor();
} catch (InterruptedException e) {
}
}
close();
}
/**
* Start the udpate.
* This method is called by the worker thread.
* If parse returns an error code it is assumed that rds is busy.
* The request will then be retried.
*
* @param option defines the rds command opion, -S -p ...
* @exception SRMProtocolException if a protocol violation has occurred.
*/
int numRetries = MAX_RDS_RETRIES;
do {
break;
try {
} catch (InterruptedException x) {
;
}
} while (numRetries-- > 0);
if (numRetries == 0) {
throw new SRMProtocolException(
} else {
}
}
/**
* Force the RDS to keep alive
* This method is called by the worker thread.
* @exception SRMProtocolException if a protocol violation has occurred.
*/
private void _alive() throws SRMProtocolException {
}
/**
* Start the rds and create a BufferedReader input stream.
* @param cmdArgs contains the path of rds and the arguments to use.
*/
}
}
try {
is = p.getInputStream();
errs = p.getErrorStream();
os = p.getOutputStream();
} catch (IOException e) {
throw new SRMProtocolException("Cannot start 'rds', " +
e.getMessage());
}
if (!checkRDSrunning()) {
throw new SRMProtocolException("Cannot start 'rds', " +
"rds terminated with exit code =" + exitV);
}
} // end open
/**
* Close the data stream to rds.
*/
private void close() {
try {
} catch (IOException e) {
}
} // end close
/**
* Read the data stream and wait for RDS protocol header, check version.
* @exception SRMProtocolException if a protocol violation has occurred.
*/
private void readHeader() throws SRMProtocolException {
int protv;
try {
// Waiting for header with the magic value @RDS-MAG@
continue;
break;
}
throw new SRMProtocolException(
"Unexpected end of RDS input stream");
}
// Check the protocol version
} else {
if (PROT_VERSION != protv) {
throw new SRMProtocolException(
"Unsupported RDS protocol version: ex:" +
}
}
} catch (IOException e) {
dumpStdErr();
throw new SRMProtocolException("Cannot read RDS protocol header, " +
e.getMessage());
}
} // end readHeader
/**
* Parse the data stream from rds, evaluate and strip the protocol elements.
*
* Returns 0 if OK, 1 if rds responded 'busy'
*
* @exception SRMProtocolException if a protocol violation has occurred.
*/
private int parse() throws SRMProtocolException {
try {
// fetch the number of lists (or maybe it's busy)
} else {
}
// read the type of the list
} else {
}
// read the number of elements in the list
} else {
}
}
}
} catch (NumberFormatException e) {
} catch (SRMProtocolBusyException b) {
return 1;
}
return 0;
} // end parse
/**
* Parse the fields in a element of a list of type listt. The client
* should know the how to interpret the fields of a element of a particular
* list type.
* @param listt the type of the list.
* @exception SRMProtocolException if a protocol violation has occurred.
*/
int fieldn;
} else {
// get the consumer of fields of this element.
throw new SRMProtocolException(RDS_PV_ERR +
"wrong list type: " + line);
}
}
} else {
}
// The provider data model will take the value and set its property
}
} // end parseElement
/**
* Parse one line of the input stream and split it into a KEY
* and VALUE. The read line is stored in the class field line,
* the KEY in key and VALUE in value. These fields should
* remains unchanged till the next call of this method. Since they
* are used in several places in this class.
* @exception SRMProtocolBusyException if the key is "busy"
* @exception SRMProtocolException if a protocol violation has occurred.
*/
private void parseKeyValue() throws SRMProtocolException {
int idx;
try {
throw new SRMProtocolBusyException("RDS busy");
} else {
}
}
}
} catch (IOException e) {
throw new SRMProtocolException("Cannot read 'rds' input, " +
e.getMessage());
}
} // end parseKeyValue
/**
* To synchronize the protocol wait for RDS prompt and then send
* a given command to RDS.
* @param cmd defines the rds command, -S -p ...
* @throws SRMProtocolException if a protocol violation has occurred.
*/
if (checkPrompt()) {
} else {
throw new SRMProtocolException(
}
} // end wrCmd
/**
* Read the data stream and wait for RDS prompt. This will synchronize
* the protocol flow.
* @throws SRMProtocolException if a protocol violation has occurred.
*/
private boolean checkPrompt() throws SRMProtocolException {
int tries = 1000;
int idx;
try {
while (tries-- > 0) {
return true;
} else {
continue;
}
} else {
return false;
} else {
continue;
}
}
} else {
throw new SRMProtocolException("Cannot read 'rds' prompt");
}
}
} catch (IOException e) {
throw new SRMProtocolException("Cannot read 'rds' prompt," +
e.getMessage());
}
return false;
} // end checkPrompt
/**
* Check if rds is still running
*/
private boolean checkRDSrunning() {
try {
return false;
} catch (IllegalThreadStateException e) {
return true;
}
}
/**
* Dump remianders from rds stderr stream.
*/
private void dumpStdErr() {
try {
}
} catch (IOException e) {
}
}
throws IOException {
}
/**
* This thread carries out the public methods start, update,
* alive, close and shutdown in its own execution thread. The caller
* of these methods waits for the results the from him specified timeout.
*/
// internal code method calls
private final static int START_METHOD = 1;
private final static int UPDATE_METHOD = 2;
private final static int ALIVE_METHOD = 3;
private final static int CLOSE_METHOD = 4;
private final static int SHUTDOWN_METHOD = 5;
// last method's exception is end in ran method and checked
// in
private SRMProtocolException methodException;
// method to be called in run
private int methodToRun;
private boolean methodFinished = false;
// args to be passed in run
// All clients should check this flag before calling notifyAll().
// If false, the client should call wait() and wait till this
// thread is executing its run() method.
private boolean readyToRun = false;
public SRMWorker() {
super("SRMWorker");
}
throws SRMProtocolException {
}
throws SRMProtocolException {
}
}
try {
} catch (SRMProtocolException e) {};
}
try {
} catch (SRMProtocolException e) {};
}
public synchronized void run() {
readyToRun = true; // synchronize with posible clients
notifyAll();
try {
while (true) {
wait(); // wait for task
try {
switch (methodToRun) {
case ALIVE_METHOD: _alive(); break;
case CLOSE_METHOD : _closeRDS(); break;
case SHUTDOWN_METHOD : _shutdownRDS(); break;
default : methodException =
new SRMProtocolException("unknown method: " +
}
} catch (SRMProtocolException e) {
// pass it to the caller
methodException = e;
}
methodFinished = true;
notifyAll();
}
} catch (InterruptedException e) {};
}
throws SRMProtocolException {
methodFinished = false;
try {
// wait till this thread has reached its run method.
if (readyToRun == false) {
}
notifyAll(); // kick it off
} catch (InterruptedException e) {
return;
}
// pass an exception if any
if (methodException != null)
throw methodException;
// check if the call was finished in the given time
if (methodFinished == false)
throw new
SRMProtocolException("can't execute rds command, timeout");
}
}
/**
* An exception thrown by the parsing code if rds reports 'busy'.
*/
class SRMProtocolBusyException extends SRMProtocolException {
public SRMProtocolBusyException(String s) {
super(s);
}
} // end class SRMProtocolBusyException
} // end class SRMDataReader