Get up to 80 % extra points for free! More info:

Lesson 2 - Java Server - Server Parameters

In the previous lesson, Java Server - Introduction, we prepared the basic structure of the project. In today's tutorial, we're going to start with the server part, specifically process its parameters. All the classes we're going to create will relate to the server module unless specified otherwise.

Server Parameters

The server will be a simple console application, so we'll have to pass all settings as parameters when we start the program. Over time, we'll add a simple interactive control panel as well.

The parameters will be as follows:

  • port number: defines the port on which our server will listen
  • number of clients: the maximum number of connected clients that will actively communicate with the server
  • waiting queue size: if there's the maximum number of clients on the server, others will be queued

Individual parameters in the command line will be separated by commas. Each parameter will consist of a -name=value pair. The resulting format will be as follows:

-port=6298, -clients=2, -max_waiting_queue=5

Once we have defined what the server parameters will look like, we can implement them in a class that takes care of parsing parameters from the command line. We'll create a new package named cmd and create an IParameterProvider interface in it. This interface will define the methods we'll use to get the parameters:

package cz.stechy.chat.cmd;

public interface IParameterProvider {

    String DEFAULT_STRING = "";
    int DEFAULT_INTEGER = -1;

    default String getString(String key) {
        return getString(key, DEFAULT_STRING);
    }

    String getString(String key, String def);

    default int getInteger(String key) {
        return getInteger(key, DEFAULT_INTEGER);
    }

    int getInteger(String key, int def);
}

We defined a total of 4 methods in the interface. Two to get text and two to get a number. We use the possibility of default methods in the interface so that we don't have to implement all the methods unnecessarily.

Now in the same package we'll create a class that will implement this interface, we'll name it CmdParser. Let's define constants representing names of individual parameters:

public static final String PORT = "port";
public static final String CLIENTS = "clients";
public static final String MAX_WAITING_QUEUE = "max_waiting_queue";

Next we'll define a Map that will store all the parameters:

private final Map<String, String> map = new HashMap<>();

We'll create a class constructor that accepts input arguments from the command line as a parameter:

public CmdParser(String[] args) {
    for (String arg : args) {
        arg = arg.replace("-", "");
        String[] raw = arg.split("=");
        map.put(raw[0], raw[1]);
    }
}

We process the individual parameters in the constructor. First we get rid of the - character before each parameter name, then we split the individual name=value pairs into an array of two values. Then we insert these values into the map.

Finally, we need to implement the methods that the IParameterProvider interface requires:

@Override
public String getString(String key, String def) {
    final String s = map.get(key);
    return s == null ? def : s;
}

@Override
public int getInteger(String key, int def) {
    final String s = map.get(key);
    return s == null ? def : Integer.parseInt(s);
}

The implementation is very simple. A value is obtained from the map that should match the key. If this value doesn't exist, we return the default value, otherwise we return the value that was obtained from the map.

Testing

To verify that our class works as expected, we'll write a simple unit test. To create tests we have the test/ folder ready. In the folder test/java/ we'll create the appropriate package, i.e: cz.stechy.chat.cmd. Here we'll create a new ParametersTest class. First we'll define a constant that will represent test parameters as they come from the command line:

private static final String[] PARAMETERS = {
    "-port=6298", "-clients=5", "-max_waiting_queue=5", "name=test"
};

Next, we'll create a variable of the IParameterProvider type:

private IParameterProvider parameterProvider;

In the setUp() method, we'll initialize this variable:

@Before
public void setUp() throws Exception {
    parameterProvider = new CmdParser(PARAMETERS);
}

Now we can test that we've implemented the interface correctly. So we'll create four test methods. Two to get the text and two to get the number:

@Test
public void getStringTest() {
    final String key = "name";
    final String name = "test";
    assertEquals("Error, server name value mismatch.", name, parameterProvider.getString(key));
}

@Test
public void getStringNegativeTest() {
    final String key = "unknown";
    final String value = CmdParser.DEFAULT_STRING;
    assertEquals("Error, wrongly defined default value.", value, parameterProvider.getString(key));
}

@Test
public void getIntegerTest() {
    final String key = "port";
    final int value = 6298;
    assertEquals("Error, port value mismatch.", value, parameterProvider.getInteger(key));
}

@Test
public void getIntegerNegativeTest() {
    final String key = "unknown";
    final int value = CmdParser.DEFAULT_INTEGER;
    assertEquals("Error, wrongly defined default value.", value, parameterProvider.getInteger(key));
}

The first method contains a positive test for obtaining text based on the key. The second method contains a negative test, which tests whether we get the default value if the key isn't found. The tests for obtaining a number are similar.

That would be all for today. In the next lesson, Java Server - Google Guice, we'll implement dependency management using the Google Guice library.


 

Previous article
Java Server - Introduction
All articles in this section
Server for Client Applications in Java
Skip article
(not recommended)
Java Server - Google Guice
Article has been written for you by Petr Štechmüller
Avatar
User rating:
2 votes
Activities