Class Channel
- All Implemented Interfaces:
Runnable,ZDispenser<String>
public abstract class Channel extends Object implements Runnable
Spiderwiz framework comes out of the box with implementations of predefined communication channels, such as TCP/IP
sockets, WebSockets and disc files (the latter is helpful for offline debugging). The type of the channel to use is configured in the
application's configuration file. These are all implemented by extending the Channel
class.
In addition to the predefined channels users can write plugins with their own custom channel implementation. You develop a custom
channel by extending Channel, and use your implementation class by assigning its fully qualified name to the
class tag in the configuration file.
There are two ways to use this base class for implementing a custom channel. The first relies on its builtin mechanism of using
InputStream and OutputStream. If you go this way all you have to do is provide your extensions to
these classes in getInputStream() and getOutputStream(). The other way is to provide your own i/o access code.
In this case you will need to override open(), readLine(), writeLine(),
close() and maybe also flush().
In many cases channels are used in a client-server architecture, in which the client side of the channel applies
for a connection to a configured server address, while the server accepts the requests and opens the server side of the channel.
The Channel class should be used for both ends of the connection. At the client side, the channel is configured by
configure() method that you must implement.
If you implement a custom Channel in client-server architecture, you shall also provide a custom implementation of
ServerChannel that will accept requests from your client implementation and open its server side.
Here is a full example taken from Spiderwiz implementation of a TCP/IP socket:
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Map;
import org.spiderwiz.core.Channel;
import org.spiderwiz.core.Main;
import org.spiderwiz.zutils.ZUtilities;
public class TcpSocket extends Channel{
private Socket socket = null;
private String ip;
private int port;
@Override
protected boolean configure(Map<String, String> initParams, int type, int n) {
return init(
initParams.get("ip"), ZUtilities.parseInt((initParams.get("port"))), type, n);
}
private boolean init(String ip, int port, int type, int n) {
final String NO_TCP_PARAMS = "No IP address or port number specified for %1$s-%2$d";
final String TYPES[] = {"import", "producer", "consumer"};
if (ip == null || port == 0) {
Main.getInstance().sendExceptionMail(null, String.format(NO_TCP_PARAMS, TYPES[type], n), null, true);
return false;
}
this.ip = ip;
this.port = port;
return true;
}
@Override
protected boolean open() throws UnknownHostException, IOException {
socket = new Socket(InetAddress.getByName(ip).getHostAddress(), port);
return true;
}
@Override
protected void close() throws IOException {
if (socket != null)
socket.close();
socket = null;
}
@Override
protected InputStream getInputStream() throws IOException {
return socket == null ? null : socket.getInputStream();
}
@Override
protected OutputStream getOutputStream() throws IOException {
return socket == null ? null : socket.getOutputStream();
}
@Override
public String getRemoteAddress() {
return ip + (port == 0 ? "" : ":" + getPort());
}
}- See Also:
ServerChannel
-
Constructor Summary
Constructors Constructor Description Channel()Class constructor. -
Method Summary
Modifier and Type Method Description protected voidclose()Closes this channel.protected abstract booleanconfigure(Map<String,String> configParams, int type, int n)Configures the channel.voiddisconnect(String reason)Disconnects the channel.voiddispense(String line, boolean flush)Implementation ofZDispenser.dispense().protected booleandontReconnect()Returnstrueif this is a client channel that shall not try to reconnect automatically if disconnected.protected voidflush()Flushes any remaining data in the output buffer.protected abstract InputStreamgetInputStream()Returns the channel input stream.protected longgetKeepAliveInterval()Returns the time interval that the framework writes an empty string to the channel to keep it alive.protected abstract OutputStreamgetOutputStream()Returns the channel output stream.abstract StringgetRemoteAddress()Returns the address of the endpoint this channel is connected to, or null if it is unknown.voidhandleException(Exception ex)Handles an exception occurred while processing the associatedZBufferobject.protected booleanisCompressable()ReturnstrueifZIPalgorithm shall be used to compress the data on this channel.booleanisFileChannel()Returnstrueif this channel reads from a disk file.protected booleankeepAliveOnEndOfData()Returnstrueif the channel should be considered connected after the end of data has been reached.protected voidonError(Throwable ex)Reports an exception.protected booleanopen()Opens the channel for communication.protected StringreadLine()Reads a line of text.voidrun()Implementation ofRunnable.run().protected voidwriteLine(String line)Writes a line of text.
-
Constructor Details
-
Channel
public Channel()Class constructor.
-
-
Method Details
-
configure
Configures the channel.An abstract method that you must implement to configure a client channel from parameters specified by
producer-n,consumer-norimport-nproperties in the application's configuration file. The values of these properties must be a list of pairs key=value concatenated by a semicolon. For instance, let's say you implement a custom TCP/IP socket, then its configuration may look something like:class=com.mydomain.myplugins.MyTcpIp;ip=192.185.6.24;port=31415The framework will then instantiate your classcom.mydomain.myplugins.MyTcpIpand call itsconfigure()method with a map inconfigParamscontaining the following pairs (order not guarantee):class=com.mydomain.myplugins.MyTcpIp ip=192.185.6.24 port=31415- Parameters:
configParams- a map of key=value configuration parameters.type- type of channel - 0: import, 1:producer, 2:consumer.n- the n value of import-n, producer-n or consumer-n.- Returns:
- true if and only if configuration is successful.
-
getInputStream
Returns the channel input stream.An abstract method you must implement to provide the input stream of the channel. If you do, this is the only method you need to implement for that purpose. Alternatively you can return
nullin this method and implement direct input by overridingreadLine(),open()andclose().- Returns:
- the
InputStreamobject used by your implementation, or null if you implement direct input. - Throws:
Exception
-
getOutputStream
Returns the channel output stream.An abstract method you must implement to provide the output stream of the channel. If you do, this is the only method you need to implement for that purpose. Alternatively you can return
nullin this method and implement direct output by overridingwriteLine(),open()andclose().- Returns:
- the
OutputStreamobject used by your implementation, or null if you implement direct input. - Throws:
Exception
-
open
Opens the channel for communication.Override this method to provide code for opening the channel, if needed. This method is called before
getInputStream()andgetOutputStream()are called. The default implementation of this method does nothing and returnstrue.See the example in the class description.
- Returns:
- true if and only if the operation is successful.
- Throws:
Exception
-
readLine
Reads a line of text.Override this method if and only if your implementation of
getInputStream()returnsnull.- Returns:
- the read line, not including any line-termination characters, or null if the end of the data has been reached.
- Throws:
IOException
-
writeLine
Writes a line of text.Override this method if and only if your implementation of
getOutputStream()returnsnull.- Parameters:
line- the line to be written.
-
flush
protected void flush()Flushes any remaining data in the output buffer.Override this method if and only if your implementation of
getOutputStream()returnsnull. -
close
Closes this channel.Override this method to provide code for closing the channel, if needed. This method is called after the streams returned by
getInputStream()getOutputStream()are closed. The default implementation of this method does nothing.See the example in the class description.
- Throws:
Exception
-
getRemoteAddress
Returns the address of the endpoint this channel is connected to, or null if it is unknown.This is an abstract method that you must implement to provide the endpoint address of this channel, for instance a remote IP address.
See the example in the class description.
- Returns:
- an address representing the remote endpoint of this channel, or null if it is unknown.
-
isFileChannel
public boolean isFileChannel()Returnstrueif this channel reads from a disk file.Override this method if this is a file channel. The default implementation returns
false.- Returns:
- true if any only if this is a file channel.
-
isCompressable
protected boolean isCompressable()ReturnstrueifZIPalgorithm shall be used to compress the data on this channel.This method is relevant only if you implement
getInputStream()andgetOutputStream()to return non-null values. If the method returnstruedata written to the output stream will be compressed before, and data read from the input stream will be decompressed after. The method has no effect if those methods returnnull.The default implementation returns
trueif any only if this is not a file channel. Override the method to provide a different implementation.- Returns:
- true if any only if ZIP algorithm shall be used to compress the data on this channel.
-
dontReconnect
protected boolean dontReconnect()Returnstrueif this is a client channel that shall not try to reconnect automatically if disconnected.If this method returns
false, the framework will try repeatedly to reconnect the channel whenever it is disconnected. The method affects only client channels. If a server channel is disconnected, the server would just wait for the client to reconnect.By default the method returns the value returned by
isFileChannel(). Override it to provide a different behavior.- Returns:
- true if this is a client channel that shall not try to reconnect automatically if disconnected.
-
getKeepAliveInterval
protected long getKeepAliveInterval()Returns the time interval that the framework writes an empty string to the channel to keep it alive.There are scenarios in which if no output is written to a communication channel for a certain amount of time the system treats the channel as idle and disconnects it. If your implementation involves this scenario, you can use this method to set the time interval that the framework checks whether the channel is idle and sends an empty string to it to keep it alive.
The default value that the method returns is one minute. Override it to provide a different value in milliseconds, or zero if "keep alive" is not needed.
- Returns:
- the time interval in milliseconds that the framework will write an empty string to the channel to keep it alive, or zero if this is not needed.
-
keepAliveOnEndOfData
protected boolean keepAliveOnEndOfData()Returnstrueif the channel should be considered connected after the end of data has been reached.In some cases there is a need to consider the channel connected even though reading from it has reached the end of data. For instance, if this is a file channel that uses one file for input and one file for output, even though the end of data from the input file has been reached the channel should stay connected so that output to the output file shall continue to be written.
By default the method returns the value returned from
isFileChannel(). Override it to provide a different behavior.- Returns:
- true if and only if the channel should be considered connected after the end of data has been reached.
-
disconnect
Disconnects the channel.Call this method if your implementation detects a disconnection state that cannot be detected by the framework. The
reasonparameter should be a free textual description of the reason that caused the disconnection, used for logging purposes. Anullvalue will yield the generic text"Channel closed by other peer".- Parameters:
reason- a textual description of the reason that caused the disconnection.
-
onError
Reports an exception.Call this method if your implementation catches an exception that could not be caught by the framework.
- Parameters:
ex- the exception object caught by your implementation.
-
run
public final void run()Implementation ofRunnable.run().Used internally by the framework. Do not call or override.
-
dispense
Implementation ofZDispenser.dispense().Used internally by the framework. Do not call or override.
- Specified by:
dispensein interfaceZDispenser<String>- Parameters:
line- Line to dispense.flush- Flush buffered data if set totrue.
-
handleException
Description copied from interface:ZDispenserHandles an exception occurred while processing the associatedZBufferobject.Implement this method to handle exceptions in the associated buffer.
- Specified by:
handleExceptionin interfaceZDispenser<T>- Parameters:
ex- the exception.
-