/* Generated by Together */
package multimonster.common.pipe;
import multimonster.common.setting.Setting;
import multimonster.common.setting.SettingDomain;
import multimonster.common.setting.SettingValue;
import multimonster.exceptions.MultiMonsterException;
import multimonster.systemadministration.SettingProxy;
import org.apache.log4j.Logger;
/**
* Transfers Data und Data-Control-Info from one component to the other.
*/
public class Pipe {
/** Logger */
private static Logger log;
private static SettingProxy sproxy;
// TODO use a setting for doSetup
/** decides if a initial setup should be done */
private static boolean doSetup = false;
/** the default number of Channels */
private static int defaultNumberOfChannels = 1;
/** the default id of the data-Channel */
private static int defaultDataChannel = 0;
/** maximum time the pipe will wait for setup */
private static int TIMEOUT = 1000 * 60; //60s
static {
Pipe.log = Logger.getLogger(Pipe.class);
try {
Pipe.sproxy = SettingProxy.getInstance(Pipe.class);
Setting mySetting;
mySetting = new Setting("PIPE_SEGMENT_SIZE", new SettingValue(256*1024), new SettingDomain(1, 100*1024*1024), "segment size to work with the pipe");
Pipe.sproxy.registerSetting(mySetting);
mySetting = new Setting("PIPE_BUFFER_SIZE", new SettingValue(1024*1024), new SettingDomain(1, 100*1024*1024), "the buffer size of the pipe");
Pipe.sproxy.registerSetting(mySetting);
} catch (MultiMonsterException e1) {
Pipe.log.error("Error registering setting.");
}
}
/** the Channels which transfer the data */
private Channel[] channels;
/** the number of Channels actually available in this Pipe */
private int numberOfChannels;
/** flag to decide if the Pipe is closed */
private boolean isClosed;
/** Flag if Pipe-Setup is finished */
private boolean setup = false;
/** for setup the pipe */
private boolean setupWaiterIsNotified = false;
/**
* creates a Pipe with default buffer size
* and default number of channels
*/
public Pipe() {
this(Pipe.defaultNumberOfChannels);
}
/**
* creates a Pipe with the given number of channels.
*
* @param bufferSize
* @param channels
*/
public Pipe(int channels) {
if (channels > 0){
this.numberOfChannels = channels;
} else {
throw new IllegalArgumentException("channels !> 0");
}
this.channels = new Channel[numberOfChannels];
if (defaultDataChannel < this.channels.length) {
// create a BufferedChannel as dataChannel and add it to this pipe:
Channel channel = new BufferedChannel(this, getPipeBufferSize());
setChannel(defaultDataChannel, channel);
}
this.isClosed = false;
if (doSetup) {
// a Pipe-Setup should be done
setup = false;
} else {
// no setup should be done, so Pipe-Setup is finished:
setup = true;
}
//log.debug("CREATED");
}
/**
* Get the size in bytes to read and write with the pipe.
* This value is configurable by a setting.
*
* @return PIPE_SEGMENT_SIZE
*/
public static int getPipeSegmentSize(){
return ((Integer)(sproxy.getValue("PIPE_SEGMENT_SIZE")).getValueCont()).intValue();
}
/**
* Get the size for a pipe buffer.
* This value is configurable by a setting.
*
* @return PIPE_BUFFER_SIZE
*/
private int getPipeBufferSize(){
return ((Integer)(sproxy.getValue("PIPE_BUFFER_SIZE")).getValueCont()).intValue();
}
public Channel getChannel(int id) {
if (id < channels.length){
return channels[id];
} else {
return null;
}
}
/**
* @return the default data channel, where data can get transferred.
*/
public Channel getDataChannel(){
return getChannel(defaultDataChannel);
}
/**
* Sets a channel for the given id.
*
* @param id the id of the channel that should be "overwritten"
* @param channel the channel itself that should be set
*/
public void setChannel(int id, Channel channel) {
if (id <= channels.length){
channels[id] = channel;
} else {
String errorText = "id (" +id +") out of available channels (" +channels.length +").";
log.error(errorText);
throw new IllegalArgumentException(errorText);
}
}
/**
* Adds a channel to the pipe.
*
* @param channel the channel that should be added.
* @return the id of the added channel
*/
public int addChannel(Channel channel) {
int newId = -1;
// TODO implement method
return newId;
}
/**
* If called, the Pipe is set up and ready to serve.
*
* @param setup
*/
public synchronized void setupFinished() {
this.setup = true;
setupWaiterIsNotified = true;
this.notifyAll();
}
/**
* Blocks until the pipe is completly setup.
* Throws a PipeClosedException when the pipe is not setup within a
* timeout interval.
*
*/
public synchronized void waitForPipeSetup() throws PipeClosedException{
while(!setup){
try {
setupWaiterIsNotified = false;
this.wait(TIMEOUT);
if (isClosed) {
throw new PipeClosedException();
}
if (!setupWaiterIsNotified){
log.warn("wait for setup timed out. Closing pipe");
close();
throw new PipeClosedException();
}
} catch (InterruptedException e) {
log.error("problem waiting for pipe-setup");
}
}
}
/**
* @return Returns if the pipe is closed.
*/
public boolean isClosed() {
return isClosed;
}
/**
* close all channels and the pipe itself.
*
*/
public synchronized void close() {
//log.debug("close()");
//close all channels
Channel c = null;
for (int i=0; i<numberOfChannels; i++){
c = getChannel(i);
if (c != null){
c.close();
}
}
// close pipe itself
this.isClosed = true;
this.notifyAll();
}
/**
* @param length -
* the number of bytes to read
*
* Read Data out of the default data-channel.
*
* @return a new byte[] with the length of read bytes
*/
public byte[] read(int length) throws PipeClosedException {
try {
return getDataChannel().read(length);
} catch (ChannelClosedException e) {
throw new PipeClosedException();
}
}
/**
* Writes data in the default data-channel to transfer it.
*
* @param in the data
* @param len the amount to write to the Pipe
* @throws PipeClosedException
*/
public void write(byte[] in, int len) throws PipeClosedException {
try {
getDataChannel().write(in, len);
} catch (ChannelClosedException e) {
throw new PipeClosedException();
}
}
/**
* Writes data in the default data-channel to transfer it.
*
* @param in the data
* @throws PipeClosedException
*/
public void write(byte[] in) throws PipeClosedException {
try {
getDataChannel().write(in);
} catch (ChannelClosedException e) {
throw new PipeClosedException();
}
}
}