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 void
close()
Closes this channel.protected abstract boolean
configure(Map<String,String> configParams, int type, int n)
Configures the channel.void
disconnect(String reason)
Disconnects the channel.void
dispense(String line, boolean flush)
Implementation ofZDispenser.dispense()
.protected boolean
dontReconnect()
Returnstrue
if this is a client channel that shall not try to reconnect automatically if disconnected.protected void
flush()
Flushes any remaining data in the output buffer.protected abstract InputStream
getInputStream()
Returns the channel input stream.protected long
getKeepAliveInterval()
Returns the time interval that the framework writes an empty string to the channel to keep it alive.protected abstract OutputStream
getOutputStream()
Returns the channel output stream.abstract String
getRemoteAddress()
Returns the address of the endpoint this channel is connected to, or null if it is unknown.void
handleException(Exception ex)
Handles an exception occurred while processing the associatedZBuffer
object.protected boolean
isCompressable()
Returnstrue
ifZIP
algorithm shall be used to compress the data on this channel.boolean
isFileChannel()
Returnstrue
if this channel reads from a disk file.protected boolean
keepAliveOnEndOfData()
Returnstrue
if the channel should be considered connected after the end of data has been reached.protected void
onError(Throwable ex)
Reports an exception.protected boolean
open()
Opens the channel for communication.protected String
readLine()
Reads a line of text.void
run()
Implementation ofRunnable.run()
.protected void
writeLine(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-n
orimport-n
properties 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=31415
The framework will then instantiate your classcom.mydomain.myplugins.MyTcpIp
and call itsconfigure()
method with a map inconfigParams
containing 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
null
in this method and implement direct input by overridingreadLine()
,open()
andclose()
.- Returns:
- the
InputStream
object 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
null
in this method and implement direct output by overridingwriteLine()
,open()
andclose()
.- Returns:
- the
OutputStream
object 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()Returnstrue
if 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()Returnstrue
ifZIP
algorithm 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 returnstrue
data 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
true
if 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()Returnstrue
if 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()Returnstrue
if 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
reason
parameter should be a free textual description of the reason that caused the disconnection, used for logging purposes. Anull
value 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:
dispense
in interfaceZDispenser<String>
- Parameters:
line
- Line to dispense.flush
- Flush buffered data if set totrue
.
-
handleException
Description copied from interface:ZDispenser
Handles an exception occurred while processing the associatedZBuffer
object.Implement this method to handle exceptions in the associated buffer.
- Specified by:
handleException
in interfaceZDispenser<T>
- Parameters:
ex
- the exception.
-