Lesson 1 - Java Server - Introduction
Welcome to the Java tutorial to learn how to create a server for client applications. In this case, we'll focus on a chat server, but the base will be the same for other uses as well. In this lesson, we're going to set out the goals we want to achieve, describe the technologies used, and set up a project.
Goals
As mentioned in the introduction, this course aims to show that writing a quality server in Java is not as difficult as it may seem. In the first half of the course, we'll implement basic parts that can be used for any server application, from chat to a simple game server. The other half will focus on the chat itself.
Server Functions
The server will provide the following features:
- client management
- establish direct communication
- queue waiting clients
- the waiting queue will be used in case there are too many clients on the server
- easy searching for the server in local network
- easy extensibility with plugins
- interactive communication with the server administrator
Final App
Below you can see the resulting chat client. There's the number of unread messages shown next to contacts. In addition, the "typing" indicator appears in the tab when the person is typing a message. If the conversation is longer, a scrollbar appears.
Technologies Used
Since this is a course in the Java section, we're going to write the entire application in Java. Gradle will manage the project and dependencies and Google Guice will provide the dependency injection.
Creating the Project
We'll start by setting up the project. I recommend using a reasonable IDE for programming. I will use IntelliJ IDEA throughout the course.
We'll click on the File -> New -> Project ... button in the application menu. In this window, check that you want Gradle to take care of the project. If there's no Gradle option, you need to activate the plugin in the settings: File -> Settings -> Plugins opens the plugin settings window. In the search box enter the name of the plugin - "Gradle", check the checkbox, click the apply and ok buttons. Gradle will be active when the environment restarts. Select Java as the language (should be selected by default). Click Next to continue.
In the next window we need to fill in the GroupId and ArtifactId fields.
GroupId is a package that typically represents the
business/institution/individual behind the application. I usually use
cz.stechy
here. ArtifactId is the name of the application we are
trying to create. In this case, we simply enter chat
. There's also
a Version field. This indicates the version of the application. Leave the field
filled with the default value and continue with the Next button.
The next window contains the Gradle settings. Leave everything by default and check the Use auto-import checkbox. Continue with the Next button.
The last window in which you set the project root directory follows. When you are satisfied with the location of the project, click Finish to complete it.
As soon as the project is created, Gradle will start initializing.
Project Structure
The structure of our project is shown in the following image:
There are two hidden folders in the project directory: .gradle/
and .idea/
. There are configuration files for gradle and idea in
these folders, ignore them. There are also folders:
gradle/
, containing a wrapper for Gradle.src/
, which is empty.
Do not delete or edit any of these components. We'll not use the
src/
folder. The files include:
build.gradle
, a configuration file containing information about building the mainchat
module.- The
settings.gradle
file containing the project name information. - The
gradlew
andgradlew.bat
files are startup files for Gradle.
However, we aren't satisfied with this structure because we want to create a
client-server application. So we'll create modules representing the client,
server, and the shared part. We'll right-click on the root folder
(chat/
) and select New -> Module. We'll see the same window as
when creating a new project. Again, we'll choose that we want Gradle to take
care of the dependencies. Next, we'll select that we want Java and continue with
the Next button.
The next window contains the GroupId and ArtifactId settings. GroupId is
already pre-filled and we won't change it. As ArtifactId we'll type the name of
the new module. First, we'll create a module for the client, so fill in
client
and continue with the Next button.
The last window displays the module location settings. We'll leave default
values for everything and click Finish to finish creating the first module. Now
create the server
and share
modules using the same
approach.
The resulting project structure is shown in the following image:
Each module has the src/main/java/
folder into which we're going
to write the source code. The resources/
folder is used for any
additional files such as images, translations, etc. The test/
folder contains the same folders as main/
, but is intended for
testing the application.
Setting Dependencies
Now we'll set dependencies between the modules. The share
module
will contain classes that will be common to both the client and the server.
In the client
module, we'll open the build.gradle
file and add a dependency on the share
module by using the
compile project(':share')
command at the place where
dependencies
are set. We'll put the same command into the
server
module as well.
Individual modules can be compiled with the command:
client: gradlew :client:compileJava server: gradlew :server:compileJava share: gradlew :share:compileJava
The commands are executed in the command prompt. There's a terminal plugin in IntelliJ that makes the command line available directly in the environment. If you have the plugin active, you can display the terminal by clicking on the terminal tab at the bottom of the IDE. Otherwise, it's necessary to enable the plugin in the plugin settings in File -> Settings -> Plugins. In the window, enter the name of the terminal plugin in the search box and check the checkbox. After confirming the changes and restarting the IDE, the terminal will be active and ready for use.
Now, if you run the client compilation, the share
module will be
compiled first and then the client
module will.
We'll stick with the client
module and build.gradle
for a while. To be able to run the client easily, it's necessary to add a plugin
that takes care of it. Add the application plugin to the plugins definition at
the beginning of the file:
plugins { id 'java' id 'application' }
This plugin also needs to define the name of the main class including all the
packages in which the class is located. Therefore, we'll create a new variable
that won't be in any block and name it mainClassName
:
mainClassName = 'cz.stechy.chat.SimpleClient'
Let's move to the server
module to the build.gradle
file again. We'll run the server with parameters in the future. To be able to
pass these parameters to the JVM easily, we need to create our own task:
task run (type: JavaExec, dependsOn: classes){ if(project.hasProperty('arg')){ args(arg.split(',')) } main = "cz.stechy.chat.Server" classpath = sourceSets.main.runtimeClasspath jvmArgs = [ "-Dkey=value" ] standardInput = System.in }
We'll start the client and server as follows:
client: gradlew :client:run server: gradlew :server:run -Parg=-port=21298
That would be all for the introductory lesson. Next time, in lesson Java Server - Server Parameters, we'll start creating the server part of the chat.