Tag Archive: software development

Ruby best practice: Implementing operator == and ensuring it doesn’t break

March 8, 2019 12:42 pm Published by

In ruby, comparing hashes, strings and objects is a complicated topic. Should you use equal?, eql? or ==? There is plenty of help on this topic, but in this post, we will focus on the interesting behavior of the == operator and how you can make it behave as you need it for your use case.

When comparing Hashes in Ruby, the == operator compares the content of a hash recursively.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
my_hash = {
    :sub_hash => {
        :value => 42
    }
}

my_second_hash = {
    :sub_hash => {
        :value => 42
    }
}

my_third_hash = {
    :sub_hash => {
        :value => 21
    }
}

puts "my_hash == my_second_hash? #{my_hash == my_second_hash}"
puts "my_hash == my_third_hash? #{my_hash == my_third_hash}"

1
2
my_hash == my_second_hash? true
my_hash == my_third_hash? false

Unfortunately, when comparing objects of arbitrary classes, the default operator only compares the object identity.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class MyClass
  def initialize(value)
    @value = value
  end
end

my_object = MyClass.new(42)
my_second_object = MyClass.new(42)

puts "my_object == my_second_object? #{my_object == my_second_object}"

1
my_object == my_second_object? false

If you want to do a deep comparison of objects of your class, you need to implement your own operator == by overriding the existing operator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class MyClass
  attr_reader :value

  def initialize(value)
    @value = value
  end

  def ==(other)
    other.respond_to?("value") && value == other.value
  end
end

my_object = MyClass.new(42)
my_second_object = MyClass.new(42)

puts "my_object == my_second_object? #{my_object == my_second_object}"

1
my_object == my_second_object? true

That was easy. But imagine this was a bigger class and someone else needed to add a property, not being aware of the existence of this operator and some other code depending on it to ensure no public member of the object changed. How can you ensure such a change doesn’t sneak in unnoticed?

I stumbled across the following solution when implementing an operator == for a class in the BOSH code together with my colleague Max.

As BOSH code is written in TDD – and your code should be as well – writing a test that breaks with a change as the one described above should ensure the operator to keep working. But how can such a test look like?

Consider the following change to our code above:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class MyClass
  attr_reader :value
  attr_reader :value_new

  def initialize(value)
    @value = value
    @value_new = value
  end

  def ==(other)
    other.respond_to?("value") && value == other.value
  end
end

my_object = MyClass.new(42)
my_second_object = MyClass.new(42)

puts "my_object == my_second_object? #{my_object == my_second_object}"

To detect the variable @value_new has been added using rspec can be done with a test like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
require './object_compare_op'

describe :MyClass do
  describe 'operator ==' do
    context 'when instance variables are modified' do
      let :obj do
        MyClass.new(42)
      end
      let :other_obj do
        MyClass.new(42)
      end

      all_members = MyClass.new(0).instance_variables.map { |var| var.to_s.tr('@', '') }
      all_members.each do |member|
        it "returns false when #{member} is modified" do
          eval <<-END_EVAL
            class MyClass
              def modify_#{member}
               @#{member} = 'foo'
              end
            end
          END_EVAL
          obj.send("modify_#{member}")
          expect(obj == other_obj).to(
            equal(false),
            "Modification of #{member} not detected by == operator.",
          )
        end
      end
    end
  end
end

The variable @value_new only has an attribute reader, so we cannot simply assign a new value. But this doesn’t stop you from changing the value. Not in Ruby. Using the eval in the test, we add a method for all existing instance variables of MyClass (one in each iteration) that modifies the member.

Afterwards, the newly added method is called to change the value of the member and the expect checks if the operator detects the modification. And – for our code above – will fail. Hence, whenever someone adds a new member to MyClass, he will be reminded to also it to the operator == by this test. Even if the code of test itself might not be as speaking, the output of the failing test is:

 Modification of value_new not detected by == operator.

In some situations you may want to exclude a member from this check as it is just internal or not important to the equality of two objects. To enable this, we added an exclude list for private members to the test. This adds a bit of complexity to adding new members to the class as the test will bother you and you also have to add the member to the exclude list, but it improves the safety of your operator ==.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
require './object_compare_op'

describe :MyClass do
  describe 'operator ==' do
    context 'when instance variables are modified' do
      let :obj do
        MyClass.new(42)
      end
      let :other_obj do
        MyClass.new(42)
      end

      all_members = MyClass.new(0).instance_variables.map { |var| var.to_s.tr('@', '') }
      private_members = %w[value_new]
      public_members = all_members - private_members
      public_members.each do |member|
        it "returns false when #{member} is modified" do
          eval <<-END_EVAL
            class MyClass
              def modify_#{member}
               @#{member} = 'foo'
              end
            end
          END_EVAL
          obj.send("modify_#{member}")
          expect(obj == other_obj).to(
            equal(false),
            "Modification of #{member} not detected by == operator.",
          )
        end
      end
    end
  end
end

With this kind of test, you can easily implement comparison operators for your classes that check for object equality rather than identity and ensure you do not forget to add new members of the class also to the comparison.
You can take a look at productive code in the BOSH code base here. As you may see it’s not much different to what I presented here – it’s a universal approach to solve the problem.

A Christmas Poem

December 19, 2018 7:31 am Published by

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>

/* A CHRISTMAS POEM
*
* Christmas is near,
* brings relaxed atmosphere.
* The devs are staying at home,
* feeling bored like a stone.
*
* Left the winter outside,
* but still not satisfied.
* They are missing their code,
* yet so tired of node.
*
* And if this feels like you -
* here is something to do.
* Celebrate! It's written in C:
* A compilable Christmas tree. */

#
define
o printf
#define O "%c"
int main(){o(O,
77);o(O,101);for(
int l=0;l<2;++l)o(O
,114);o(O,121);o(" ")
;o(O,88);o(O,0x6d);o(O,
0x61);o
(O,115)
;o(O,0x0A);}

Blogpost: CloudFoundry Summit Europe 2018

December 18, 2018 7:31 am Published by

After attending CloudFoundry Summit 2018 in Basel in October, I published an event summary together with my colleagues. This writing summarizes the talks that where interesting from the perspective of us as BOSH developers. You can find the post on the community page of SAP.

Recap and collected replays: Cloud Foundry Summit Europe 2018 — thanks @ManuelDewald and team! #cfsummit @cloudfoundryhttps://t.co/t7b6NjplyN

— SAP Cloud Platform (@sapcp) 6. November 2018

Watch all talks online via the youtube playlist.

Define interfaces in a duck typed language like ruby

October 5, 2018 6:55 am Published by

In Java, it is very intuitive how interfaces are defined and used. You just create an interface in a similar way you would create a class and derive the classes, implementing the interface.

interface Drivable {
public void drive(int meters);
public void stop();
}

class Car implements Drivable {
public void drive(int meters) {
//start the engine
//go for it
}

public void stop() {
//stop the engine
}
}

class Bagger implements Drivable {
public void drive(int meters) {
//start engine
//start left track
//start right track
}

public void stop() {
//stop left track
//stop right track
}
}

class AutomatedDriver {
public void forward(Drivable vehicle, int meters) {
vehicle.drive();
vehicle.stop();
}
}

This results in a exlplicit class structure as depicted in the following class diagram.

However, in languages like ruby, interfaces are defined implicitly, which means that two classes implement the same interface as soon as they respond to the same interface. Take a look at our example as implemented in ruby:

class Car
public void drive(meters)
# start the engine
# go for it
end

def stop
# stop the engine
end
end

class Bagger
def drive(meters)
# start engine
# start left track
# start right track
end

def stop
# stop left track
# stop right track
end
end

class AutomatedDriver
def forward(vehicle, meters)
vehicle.drive();
vehicle.stop();
end
end

The classes Car and Bagger still both implement the Drivable interface. But as in ruby you use the so-called ducktyping, they both implement it implicitly by just responding to the same API, consisting of drive and stop. However, even in duck-typed languages, you might want to define and document your interfaces in a central point to make sure once you change it, all implementing classes do as well. You can do this by implementing unit tests to ensure the interface is fulfilled.

Following is an example of a rspec test to ensure our Drivable interface is implemented correctly.

shared_examples "a Drivable" do
it { expect(subject).to respond_to(:drive).with(1).argument }
it { expect(subject).to respond_to(:stop).with.no_args }
end

describe Car do
it_behaves_like "a Drivable"
end

describe Bagger do
it_behaves_like "a Drivable"
end

If the developer now changes something in the interface Drivable, he does so in the rspec test ensuring the interface. This test will fail for all classes that are expected to implement it but not yet do.

Even if it is not as intuitiv as it is in java, where your code just doesn’t compile if you fail to implement the interface, it is possible to define an interface and ensure it is implemented correctly in duck typed languages.

You might argue that you lose a bit of the flexibility of duck typing if you implement this for all your interfaces, and you are right! But in many cases, for example if the one defining the interface and the ones implementing it are different people, this is a very useful tool.

For example, imagine you are the author of a ruby library. A shared_example is a good and straight forward way to tell the users of your ruby gem what you expect their classes to behave like. Also, this will make them confident that if they upgrade to a newever version of your library, they will notice changes in the API by executing their test suite.

Use Ansible to clone & update private git repositories via ssh

July 7, 2018 7:21 am Published by

One of the first things I wanted to do when I started using Ansible was to clone a git repository on a remote machine as I keep configuration, scripts, and source code in github or gitlab repositories. Things that are not meant for the public, I store in private repositories that I want to clone via ssh. Cloning and updating them I now want to automate with Ansible.

There are different ways to go for this task:

  • Checkout the repo locally and copy it to the server via a Ansible synchronize task
  • Generate an ssh key on the server and allow cloning the repo with that key manually
  • Copy a local ssh key to the server and allow cloning the repo with that key
  • use ssh-agent to load the local key and forward the agent to the server
While it might be tempting to just copy an ssh key via Ansible to the remote server, I find this quite risky,  as it means you copy a secret to a persistent storage on a remote server. Also, if you version your Ansible playbooks in a git repository as well to be able to execute the playbook from somewhere else, the private key has to be versioned along with it.

Using ssh-agent, you can easily load your ssh key prior to provisioning the git repo on the remote server without copying it over, and without allowing access to your repo for a different key than the one you have granted access for development.
Let’s go through this via a simple example. Let’s say you want to run the following playbook, which includes ensuring the git repository github.com/ntlx/my-private-repo is up-to-date.

1
2
3
4
5
6
7
---
- hosts: webserver
  tasks:
      - name: Ensure repo is up-to-date
        git:
            repo: git@github.com/ntlx/my-private-repo.git
            dest: repos/my-private-repo
I assume you added your public ssh key to your github.com repository so you are able to clone and work on the repository locally. To clone the repository on the remote machine, you need to load your ssh-key to ssh-agent with the following command.

ssh-add ~/.ssh/id_rsa

Now we need to enable the forwarding of the ssh agent to the remote machine so we can access the loaded key remotely. There are different ways to do so, but I find it most useful to do it in your ansible.cfg like this:

1
2
[ssh_connection]
ssh_args=-o ForwardAgent=yes

That way, you allow the forwarding for all your Ansible-managed hosts at once.

Now you can go on executing your playbook and should be able to clone the repository on the remote host.

To make it even easier, we can add a task to load the ssh-key before executing the other tasks in the playbook. For this, add the local host to your Ansible inventory:

1
2
[local]
local_machine ansible_connection=local ansible_host=localhost

Now we can add a small shell task to load the ssh-key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
---
- hosts: local
- name: load ssh key
  shell: |
      ssh-add ~/.ssh/id_rsa

- hosts: webserver
  tasks:
      - name: Ensure repo is up-to-date
        git:
            repo: git@github.com/ntlx/my-private-repo.git
            dest: repos/my-private-repo

When you now execute the playbook, you shouldn’t need to load the ssh-key before.

Guest Post on opensource.com: “Try this vi setup to keep and organize your notes”

June 19, 2018 9:14 pm Published by

Today my first blog post on opensource.com has been published, please have a look at it if your are, similar to myself, interested in an easy, intuitive, synchronized way to keep your notes.

You can find it on the opensource.com blog or just by following this link.

Thanks to the opensource.com team for collaboration and editing, I hope I will get the chance to write another one soon!

Thoughts on Members vs. Parameters

May 17, 2018 6:38 am Published by

Yesterday in a longer refactoring session, we stumbled across some open questions when it comes to member variables vs function parameters.

In a function with a huge number of parameters, we decided to create new class(es) to split this mess up a bit. As the new class first contained only one public function – because we moved one function out of a bigger class – we had to decide which of the parameters to choose for the input of the constructor and the actual function call, respectively.
Without being able to judge whether this is a good recipe currently, we split them up by the following classifications:

Does the variable change between calls of the public method?

If this is the case, in our it should be a function parameter. This was hard to decide for many of the input parameters, as in this state of the refactoring, every instance of the new class would be used only once to call the function.

Is the variable a member, a local variable, or a parameter in the caller?

We found it clean to treat all the parameters and local variables of the calling function that need to be passed to the new one as input parameters of this function. This should also make it easier to change the locally created object into a member of the calling class in future. Most of the member variables of the calling class have been turned into a member of the new class (although not all of them, as some could be decided based on earlier mentioned reasons).

Is the variable a pure input parameter, a complex object or subject of change?

We found it useful in our case to classify the variables we had to pass to the new class in three different types:

Pure input parameters

We created some structs to group the huge number of input parameters thematically, which turned out to be a good idea later in the process as we could find subfunctions and classes taking one of those groups and acting upon it. Also, we thought it would be a good idea to put those input only parameters into the interface of the function instead of the class constructor.

Complex Object

Some of the variables to handle are real objects, receiving messages from the new class. We decided to take them as members of the new class to enhance the object-oriented feeling of objects talking to each of their members.

Subjects of Change

There was at least one variable who changed it’s internal state which would be an input parameter to our new class. (We cannot be 100% sure, because we are coding in ruby, where we don’t have the possibility to const our variables and ask our compile, who might try to change it). As this would increase also the state, being held by the newly created class, we decided to put it as input parameter to the new method.

Quick and Dirty Java Service Template

December 25, 2017 1:04 pm Published by

To get a java service running, you don’t always need to start a tomcat and deploy a war file, as described in an earlier blog post. Even if tomcat gives you a number of benefits, such as user management and database connection handling, sometimes you do not need this and just want to start up a small http server to provide a bit of functionality.

The template contents

To get such projects started as fast as possible, I created the quick and dirty java service template, where I collected stuff I find most useful to implement a new java service:

It uses the grizzly http server to provide the web server, which makes starting an http server running java code as easy as executing a jar file.
Often, communication between a web page and a java backend works easiest by sending a JSON document. This is why we include the gson JSON parser in the template.
In addition to some java code, we will also package static content, such as html files or images to the jar package. All this can be accessed via the same URL after starting the jar file.

Checkout the service template at https://github.com/NautiluX/JavaServiceTemplate.

Start up

To build and run the server, we use mvn. So compilation and start can be done using the following two maven commands:

mvn clean install

mvn exec:java

now we can access our small server at localhost:5678.

Customize

Now for some more details to show you where to put server code and static content.
The project is set up using maven. That means all our java code can be found in src/main/java. When we start the server, by executing mvn exec:java, the class org.ntlx.server.Main will be executed, which creates the http server.

package org.ntlx.server;

import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory;
import com.sun.jersey.api.core.*;

import java.io.IOException;

import org.glassfish.grizzly.http.server.*;

public class Main {

  public static void main(String args[])
      throws IllegalArgumentException, NullPointerException, IOException {
    Main main = new Main();
    main.startServer();
  }

  public void startServer() throws IllegalArgumentException, NullPointerException, IOException {
    ResourceConfig rc = new PackagesResourceConfig(“org.ntlx.service”);
    HttpServer myServer = GrizzlyServerFactory.createHttpServer(“http://0.0.0.0:9876/calc/”, rc);
    HttpHandler httpHandler = new CLStaticHttpHandler(HttpServer.class.getClassLoader(), “/ui/”);
    myServer.getServerConfiguration().addHttpHandler(httpHandler, “/”);
    try {
      myServer.start();
      Thread.currentThread().join();
    } catch (Exception e) {
      System.err.println(e);
    } finally {
      myServer.stop();
    }
  }

}

The http server is listening on port 9876 and is searching for service endpoints in the package org.ntlx.service.

GET endpoint

To implement the code for our service, we take a look at the example implementation of the service template. We want our GET endpoint as heartbeat to check if the backend is up and running. Therefore we want it to just return
{
    “getCall”: “succeeded”
}
The code for this simple get endpoint can be found in the class org.ntlx.service.SumService in the function dummyGet:

package org.ntlx.service;

import com.google.gson.*;
import javax.ws.rs.*;

@Path(“sum”)
public class SumService {

  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public String dummyGet() {
    JsonObject result = new JsonObject();
    result.addProperty(“getCall”, “succeeded”);
    return result.toString();
  }

  …
}
We tell the http service, that we want requests that come in to the path /sum to be handled by this class. With the annotation @GET we tell it, that this function shall be called by GET http requests. With the @Produces annotation we get the http response header application/json. To create this simple json string, we use the Gson library.

POST/PUT/…

To create endpoints for other type of requests, we can do the same as for get. Lets have a look at the backend for our summing service, which should sum a list of numbers coming in as JSON.

  @POST
  @Produces(MediaType.APPLICATION_JSON)
  public String dummyPost(String body) {
    CalculatorInput input = new Gson().fromJson(body, CalculatorInput.class);
    JsonObject result = new JsonObject();
    result.addProperty(“result”, input.calculateSum());
    return result.toString();
  }

We tell the server we are listening for POST calls (the same could be done for POST, PUT, DELETE, etc.). We add a String parameter to the function, which will be filled up with the request body of the incoming POST call. To get the input, we again use GSON to instantiate an object of the CalculatorInput class, which executes our – very complex – workload in the function call calculateSum().

Static Content

Static content – like html files – must be located in the class path, so the http server can find it. That means we have to rebuild the jar file any time we want to change our static content. We told the http server where to search for it (/ui/) and where to place it (/). That means we can put our static content into the folder src/main/resources/ui, and they will be included in our jar file automatically and found by the http server under the path /. That’s why we are routed to the file created as src/main/resources/ui/index.html when we visit localhost:9876 after starting the server.

Do Not Use Boolean Parameters

May 31, 2017 7:16 pm Published by

I’m absolutely serious, don’t do it. “But hey”, one may ask, “what’s wrong with boolean parameters?” That’s what I got asked recently when I did a code review. And to all of you who have the same question in mind, here is my answer.
There is only one reason to use a boolean parameter in a function interface, and that’s when it’s the only parameter – in a setter function (and even there one could argue to not use it).

Unreadable Function Calls

Let’s take a look at a first example:

 1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include "concat.h"
#include <string>
#include <vector>

int main ()
{
Concat concat;
std::vector<const std::string> values {"Line One", "Line Two", "Line Three"};
std::cout << concat.concatVector(values, false, true);
return 0;
}

In line 10 you can see a call to the function concatVector which seems to be used to concat all the values of a vector to a single string. But what are those 2 boolean parameters passed? To find out what they are used for you have to take a look at the declaration of that function. (Or, depending on the IDE you are using, at least hover over the function call to see the names of that parameters, while hoping the names are speaking) Here is the corresponding header file:

1
2
3
4
5
6
7
#include <vector>
class Concat {
public:
const std::string concatVector(const std::vector<const std::string> strings, const bool unixStyle, const bool endWithNewline);
private:
const std::string newLine(const bool unixStyle);
};

Okay. Now we know the first one is used to tell the function if it should use unix-style new lines to separate the strings or DOS-style new lines. The second one tells if the string should end with a newline. Took already some time, and it will take that time again when you want to understand it a week later, because you won’t remember at least the order of those parameters.
One first step towards better readability of that code would be to store the parameters first to local variables, so the reader of the code knows what they are used for.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "concat.h"
#include <string>
#include <vector>

int main ()
{
Concat concat;
std::vector<const std::string> values {"Line One", "Line Two", "Line Three"};
bool useUnixStyle = false;
bool endWithNewLine = true;
std::cout << concat.concatVector(values, useUnixStyle, endWithNewLine);
return 0;
}

Okay, now we can at least understand what the code does, without visiting the header or implementation of that function. Great.

Even better would be to make them member of the Concat class, so the user of the class is forced to explicitly spell the usage in the client code:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "concat.h"
#include <string>
#include <vector>

int main ()
{
Concat concat;
std::vector<const std::string> values {"Line One", "Line Two", "Line Three"};
concat.setUseUnixStyle(false);
concat.setEndWithNewline(true);
std::cout << concat.concatVector(values);
return 0;
}

That way, you even can specify suitable defaults for that boolean parameters without setting them in the function definition (which you also shouldn’t do, but that’s a separate topic).

 1
2
3
4
5
6
7
8
9
10
11
#include <vector>
class Concat {
public:
const std::string concatVector(const std::vector<const std::string>& strings);
void setUseUnixStyle(bool _useUnixStyle){useUnixStyle = _useUnixStyle;};
void setEndWithNewline(bool _endWithNewline){endWithNewline = _endWithNewline;};
private:
const std::string newLine();
bool useUnixStyle {false};
bool endWithNewline {false};
};

Multi-purpose functions

Often, boolean parameters are used to specify the behaviour of a function. This indicates that the function in question may serve multiple purposes, which functions should never do. Hence, often it is useful to split those functions up in separate ones, each fulfilling one purpose. This results in a cleaner interface of the functions as well as easier to understand function implementations.
Here is the current implementation of the Concat class.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <string>
#include <sstream>
#include "concat.h"

const std::string Concat::concatVector(const std::vector<const std::string>& strings)
{
std::stringstream str;
for (std::vector<const std::string>::const_iterator it = strings.begin(); it != strings.end(); ++it) {
if (it != strings.begin())
str << newLine();
str << *it;
}
if (endWithNewline)
str << newLine();
return str.str();
}

const std::string Concat::newLine() {
if (useUnixStyle)
return "n";
else
return "rn";
}

We now split it up into two separate functions concatVectorWithNewlineEnding and concatVectorWithoutNewlineEnding (one might come up with better function names).

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <string>
#include <sstream>
#include "concat.h"

const std::string Concat::concatVector(const std::vector<const std::string>& strings)
{
if (endWithNewline)
return concatVectorWithNewlineEnding(strings);
return concatVectorWithoutNewlineEnding(strings);
}

const std::string Concat::concatVectorWithNewlineEnding(const std::vector<const std::string>& strings)
{
const auto& concatWithoutNewline = concatVectorWithoutNewlineEnding(strings);
return appendNewline(concatWithoutNewline);
}

const std::string Concat::concatVectorWithoutNewlineEnding(const std::vector<const std::string>& strings)
{
std::stringstream str;
for (std::vector<const std::string>::const_iterator it = strings.begin(); it != strings.end(); ++it) {
if (it != strings.begin())
str << newLine();
str << *it;
}
return str.str();
}

const std::string Concat::appendNewline(const std::string& string)
{
std::string str(string);
return str.append(newLine());
}

const std::string Concat::newLine() {
if (useUnixStyle)
return "n";
else
return "rn";
}

Now we have separate functions, each serving one purpose only, which play well together. Even though we generated more code now than in the beginning, it is much more readable and every function does exactly what its name promises.

Summary

Here are the main reasons not to use boolean parameters in your functions:
  1. Code which uses your function is easier to read if you find a different way than boolean parameters
  2. Boolean parameters indicate functions with more than one purpose, which you should split up whenever possible
I used a simple example to show how you can improve such code. One can imagine, the effect gets even bigger in a huge code base with long and unreadable functions (and a high amount of function parameters).

Putting tomcat into a container

February 9, 2017 10:37 pm Published by

As soon as you get in touch with software there is no chance to get around one topic these days: Microservices. And wherever you hear this term there is always a second one around the corner: Docker. I myself have only little experience in productively using docker, and this is mostly restricted to the convenience of packaging stuff and installing it somewhere else via a central repository. But already this is quite cool, so why not try to go further and create a small Java service in a docker container if setting up things is so easy with docker. The goal of this post is to document how I achieved a first response of the service – setting up a Java microservice with docker should be almost no work, right? As I haven’t had much contact with tomcat and maven, I learned all this (not much in the end but it took some time) the hard way – fighting all the way through old forum posts, maven repositories, eclipse UIs, tomcat books and documentations. Please let me know if you see any potential improvements.

Setting things up

Here we go. First of all I created a docker-compose file that shows how my microservice-powered project will look like:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
proxy:
image: nginx
links:
- frontend
- backend
volumes:
- ./proxy/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
frontend:
image: nginx
volumes:
- ./frontend:/usr/share/nginx/html
backend:
image: tomcat
links:
- database
volumes:
- ./backend/tomcat-users.xml:/usr/local/tomcat/conf/tomcat-users.xml
database:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=topsecret
- MYSQL_DATABASE=mydb
- MYSQL_USER=mydbuser
- MYSQL_PASSWORD=

I know container-links are not the most modern way to go in the docker universe, but for the ease of use and to show how things are tangled together, I still use them for this small project. As you can see, we have four different containers. One for the frontend, containing the great UI of our application. A second one containing the database with all the data the application will need to run. Don’t worry, I won’t bother you with boring database setup in this blog post. It’s only about the third thing: the tomcat container. For this container we add a link to the database, of course, and we mount a local file to override the user configuration of the tomcat.
This is needed to be able to show the manager application and to deploy remotely to the tomcat server. Here is the config file as I created it. (I copied it out of the container and adjusted it, maybe you should do the same to make sure it’s compatible with your version of tomcat. And, for productive usage, of course you should use a password for the admin user. But configuring maven is more complicated then, so for now it’s ok without for me.)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version='1.0' encoding='utf-8'?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<!--
NOTE: By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary. It is
strongly recommended that you do NOT use one of the users in the commented out
section below since they are intended for use with the examples web
application.
-->
<!--
NOTE: The sample user and role entries below are intended for use with the
examples web application. They are wrapped in a comment and thus are ignored
when reading this file. If you wish to configure these users for use with the
examples web application, do not forget to remove the <!.. ..> that surrounds
them. You will also need to set the passwords to something appropriate.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
<role rolename="manager-script"/>
<user username="admin" password="" roles="manager-script"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="topsecret" roles="manager-gui"/>
</tomcat-users>

The last container is used to reverse-proxy the requests of the application either to the frontend or to the backend, depending on the URL. In this example, I configured nginx to lead all the requests starting with /backend (http://localhost/backend) or /manager to the backend container (make sure to set it to the correct port of tomcat, 8080) and all others to the frontend container. So we need to make sure the servlet we are going to create is available under /backend, so they can be routed through the reverse proxy correctly.
We run docker-compose up -d as usual and some seconds later the containers are up and running. If you now go to http://localhost/backend you should already see tomcat greeting you with a 404 error page. Installing tomcat has never been so easy.

Deploying to tomcat

Next, we want to be able to deploy a servlet to the tomcat running in the docker container. To do this, I decided to use maven to build and deploy the project. To get the initial setup, I ran maven with the following command line:
mvn archetype:generate -DgroupId=com.ntlx -DartifactId=backend -DarchetypeArtifactId=maven-archetype-webapp
After the execution of this command you will find your self in a folder structure, containing all the files and folders you always wondered where they come from, and who knows where to put them:

./pom.xml
./src
./src/main
./src/main/resources
./src/main/webapp
./src/main/webapp/index.jsp
./src/main/webapp/WEB-INF
./src/main/webapp/WEB-INF/web.xml

The pom.xml now needs some further adjustments because we want to deploy to a remote tomcat server. Here is the complete file, as it looks for me:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ntlx</groupId>
<artifactId>backend</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>backend Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>


</dependencies>
<build>
<finalName>backend</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>true</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost/manager/text</url>
<server>TomcatServer</server>
<path>/backend</path>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>6.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

It already contains the plugins needed to deploy a servlet and it contains the information to deploy onto a remote tomcat. In our case the remote tomcat is localhost, port 80 (remember: reverse-proxied to port 8080 in the tomcat container). /manager/text is needed to deploy our service. That’s why we also created a reverse-proxy for this URL.

That’s nearly it. If we now run
mvn tomcat7:deploy
it should be able to deploy our web application to the tomcat server. Go to http://localhost/backend again to see the hello world page, maven created earlier.

Adding a servlet

To provide our RESTful service in the end, we want to use a servlet. Therefore, we need to create a .java file for our servlet class at the right place: src/main/java. Create this folder, add some subfolders for your package like com/ntlx/ and add a Java Servlet file there. I myself copied the example from the eclipse wizard for servlet creation:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
package com.ntlx;

/**
* Servlet implementation class FirstTest
*/
@WebServlet("/FirstTest")
public class FirstTest extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public FirstTest() {
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}

}

As you can see, we set the URL to /FirstTest. This is the relative address where the servlet will be found. So, after a run of 
mvn tomcat7:redeploy

you should see the response of the servlet at http://localhost/backend/FirstTest

That’s it, now we can start developing the service! I think this is quite handy as you can deploy the same tomcat on a different machine, like the productive one instead of your developer notebook, and it will work as before. Of course we have to think of a process to package the servlet with the docker container, but this shouldn’t be too much effort.