This tutorial will show you how to write and configure a simple TCP-based network server using the Dwarf framework. We will implement the TCP-based Quote of the Day service (RFC865). We will also learn how to configure a server application both programmatically and via the XML-based configuration file.
Let's start with an excerpt from the RFC865 protocol definition:
TCP Based Quote of the Day Service One quote of the day service is defined as a connection based application on TCP. A server listens for TCP connections on TCP port 17. Once a connection is established a short message is sent out the connection (and any data received is thrown away). The service closes the connection after sending the quote.
To develop a TCP-based service we will use the SK.gnome.dwarf.tcpip package. The following classes are necessary for us: TCPIPServer and TCPHandler. The first one provides an universal multi-threaded TCP/IP server. The actual protocol handling will be done by an instance of the second class, the TCPHandler, which must be added to the server. Since it is an abstract class, we must extend it and add the specific protocol-handling functionality to it. Let's name the new classes the QuoteServer and QuoteHandler, respectivelly. After we create these classes, we will see how to instantiate and configure the server application in two different ways - programatically as well as via the XML-based configuration.
All classes created in this tutorial will be members of the SK.gnome.dwarf.sample package. You can find them already precompiled in the "lib/dwarf.jar" class library coming with the distribution. The source files can be found in the "src/SK/gnome/dwarf/sample" directory.
We start with the implementation of the QuoteHandler class.
Let's assume first that the QuoteServer class will have a public method with the following signature:
public String getQuote();
Whenever called this method will return a single quote of the day. The handler will call it to obtain a quote string each time it handles a client request.
Assuming this we are able now to implement the handler. It just requires to implement the abstract handle(Socket) method inherited from the TCPHandler abstract class. For the learning purposes we make our handler to implement the Reportable interface as well so the handler will be able to give us a human-readable report of its current activity. See the commented QuoteHandler source code.
The next step is to develop the QuoteServer which will manage the newly created handlers and provide the quote strings to them via the previously assumed getQuote() method.
The QuoteServer must extend the generic TCPIPServer class and implement the previously assumed getQuote() method. In order to do it we must choose a way how to read and store the quote strings. Let's say that the quote strings will be in the format defined by the java.util.Properties class. The property values will represent the quotes and the property keys can be any strings at all. (We use the quotes' author names as the property keys.) The server must therefore declare one more method - setQuotes(java.util.Properties) - to setup the list of the quote strings. The sample quote string database formatted according to the chosen rules can be found in the conf/samples/dwarf/quote/quotes.properties file.
Let's see the commented QuoteServer source code.
In the following section we will configure and execute the server application programmatically.
We create a Main1 class - it is a static class used to instantiate, configure and execute the server application. Instead of running the QuoteServer instance directly we rather use the more suitable MainServer, which gives us some useful features as the server management console and server runtime information, for example. The QuoteServer instance is added to it as one of its nested services. We instantiate and configure also a Console instance for handling console commands and a LogServer instance which collects and routes the log messages to the particular logging adapters. All these objects must be instantiated first, configured and then added to the MainServer instance, of course. Let's see the commented Main1 source code.
All classes used by this tutorial have been precompiled and included in the "lib/dwarf.jar" class library. They are members of the SK.gnome.dwarf.sample package. If you would create your own classes, you should add them to the classpath before executing the main server class. In the case of a JAR file it may be simply placed in the "lib/" subdirectory of the Dwarf installation and the rest will be handled automatically by the executing scripts.
Now it is time to execute the SK.gnome.dwarf.sample.Main1 class. Run one of the batch scripts, according to the system platform (please note the dash before the class name, it is important):
On Windows systems:
C:\Dwarf> run.bat - SK.gnome.dwarf.sample.Main1
On Unix systems:
localhost:/usr/dwarf# ./run.sh - SK.gnome.dwarf.sample.Main1
Run telnet and open connection to host 127.0.0.1 port 17. A single quote of the day should be sent by the server each time you connect to this address and port.
While the application is running you can press Enter at the command prompt to get into the server management console. The help command will give you a list of the available commands.
We have learned how to configure and execute the server application manually. Now we can do the same thing in a more sophisticated and flexible way - via a XML-based configuration file.
We create a Main2 static class first. Instead of manually creating, configuring and adding all the objects we use the XML-based configuration instead. This configuration way is based on the SK.gnome.dwarf.config package with the important XMLConfiguration class. It reads and parses the XML configuration data and instantiates and configures the service tree according to the given XML description.
Let's examine the commented Main2 source code as well as the correspondent XML configuration file. As you can see the XML-based configuration is easier and much more flexible comparing to the previous way.
Now we can execute the SK.gnome.dwarf.sample.Main2 class. All configuration files for this tutorial example reside in the "conf/samples/dwarf/quote/" directory. The main configuration file is named by convention "main.xml".
On a Windows systems:
C:\Dwarf> run.bat conf/samples/dwarf/quote/main.xml SK.gnome.dwarf.sample.Main2
On a Unix systems:
localhost:/usr/dwarf# ./run.sh conf/samples/dwarf/quote/main.xml SK.gnome.dwarf.sample.Main2
You should get the exactly same running application as in the previous example.
(Of course, this application can be also executed by the standard main executable class SK.gnome.dwarf.main.Main, if you invoke the scripts without the second argument. We have created the new SK.gnome.dwarf.sample.Main2 class just for the learning purposes.)
See the XML Configuration Guide for more information about the XML-based configuration, too.
Analogical to the TCP-based services is creating of an UDP-based services. You can view a source of the sample SyslogHandler implementation here. It can work in cooperation with the TCPIPServer and the UDPListener classes. Configuration and running of an UDP-based server is similar to the previous examples.
Return to the main page.