/* 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(); } } }