stytex Blog

topics all around development, DevOps and more

Building a Image Endpoint for Geo Markers in Spring Boot

| Comments

Introduction

Today we had a funny task for our company internal Google Maps powered system. We should show simple geo markers on a map, having specific colors. So our designer created markers for three colors. However, we needed markers for a lot of more colors, which an admin can configure. So should we let our designer draw a geo marker every time an admin adds new colors?

We found a more elegant way how to solve that little problem:

Idea

We need an API which produces an image containing a geo marker. A basic idea would be to control colors using GET parameters, such as marker.png?color=ff0000, or include the color in the image name, like marker-ff0000.png. Another task was, to have the color of the inner dot of the marker stating ‘online’, ‘offline’, or something different. For example green for ‘online’ and red for ‘offline’.

So we built a Spring Boot application with a single controller action called marker-{fillColor}-{state}-{scale}.png, which draws and outputs an image. A few notes on the convention:

  • we don’t use a leading dash (#) in fillColor, as that is a URI specific char
  • state can be ‘online’ for green, ‘offline’ for red, or yellow for all other values
  • scale is an integer factor which is applied to all sizes. The default image height should be 30x40.

Implementation

First, we use start.spring.io (or the corresponding project initializer in IntelliJ) to generate a simple Spring Boot Application

Returning images in Spring Boot

Usually we can specify a return type of an controller action like this

1
2
3
4
@GetMapping
public String greet(@PathVariable String greeter) {
  return "Hello, " + greeter;
}

However, given the case, we want to return a PNG image, we don’t return anything, but write our content to the output buffer stream of our response by:

1
2
3
4
5
@GetMapping(value = "image.png", produces = MediaType.IMAGE_PNG_VALUE)
public void image(HttpServletResponse response) {
  // ...
  StreamUtils.copy(imgFile.getInputStream(), response.getOutputStream());
}

Draw graphics in Java

For this simple task, we didn’t use any third party image library, but used only Java native tools like java.awt.image.BufferedImage and java.awt.Graphics2D.

Using Graphics2D, we built our geo marker generator using the following controller action:

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
@GetMapping(value = "/marker-{fillColor}-{state}-{scale}.png", produces = MediaType.IMAGE_PNG_VALUE)
public void drawMarker(
        @PathVariable String fillColor,
        @PathVariable String state,
        @PathVariable Integer scale,
        HttpServletResponse response
) throws IOException {
    BufferedImage bufferedImage = new BufferedImage(30 * scale, 40 * scale, BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = bufferedImage.createGraphics();

    // set transparent background
    g2d.setComposite(AlphaComposite.Clear);
    g2d.fillRect(0, 0, 30 * scale, 40 * scale);
    g2d.setComposite(AlphaComposite.Src);

    // draw marker body
    g2d.setColor(parseColor(fillColor));
    g2d.fillOval(0, 0, 30 * scale, 30 * scale);

    QuadCurve2D q = new QuadCurve2D.Float();
    q.setCurve(1 * scale, 20 * scale, 15 * scale, 60 * scale, 29 * scale, 20 * scale);
    g2d.fill(q);

    // draw outer white circle as border
    g2d.setColor(Color.white);
    g2d.fillOval(7 * scale, 7 * scale, 16 * scale, 16 * scale);

    // draw inner state circle
    g2d.setColor(getColorByState(state));
    g2d.fillOval(10 * scale, 10 * scale, 10 * scale, 10 * scale);


    // Disposes of this graphics context and releases any system resources that it is using.
    g2d.dispose();

    // set content type and write image to output stream
    response.setContentType(MediaType.IMAGE_PNG_VALUE);
    ImageIO.write(bufferedImage, "png", response.getOutputStream());
}

private Color getColorByState(String state) {
    switch (state) {
        case "online":
            return Color.green;
        case "offline":
            return Color.red;
        default:
            return Color.yellow;
    }
}

private Color parseColor(String hex) {
    return new Color(
            Integer.valueOf(hex.substring(0, 2), 16),
            Integer.valueOf(hex.substring(2, 4), 16),
            Integer.valueOf(hex.substring(4, 6), 16));
}

We used a simple quadratic curve to make a round bottom corner. The resulting API can now produce images like these:

calling marker-012345-online.png will produce

calling marker-ff5555-online-10.png will produce

Conclusion

This is my first article since a very long time, in particular about Java and Spring Boot. It was a funny little project on this very hot day at work (33 °C are not easy!!), and I hope someone might find this useful.

Cheers

How to Setup & Recover a Self-hosted Kubeadm Kubernetes Cluster After Reboot

| Comments

introduction

In this article I will cover the quick setup of a self-hosted Kubernetes 1.9 cluster using kubeadm, with the ability to recover after a power cycle (e.g., reboot)

I started playing around with kubeadm again for a new project and was especially interested in the self-hosting feature, which is in alpha state. In short, self-hosted clusters host their control plane (api-server, controller-manager, scheduler) as a workload. Compared to the universe of compilers, self-hosting is when a compiler can correctly compile the source code of itself. In term of kubernetes, this simplifies upgrading clusters to a new version and more in-depth monitoring

Modernization

| Comments

Hello 2018!

I had a long break since my last article. So it’s time to say hello here and announce some little things.

Blog modernization

I was thinking of migrating to Hugo for some while, but end up with staying on octopress. The main reason is that I actually don’t want a big change on how my blog looks and feels. Especially I’m interested in all the paths, which are already deep inside Google’s index.

The main feature is, that I learned to use the <!-- more --> separator, which makes my new index page doesn’t look like a mile of full blog articles one after each other. A bit of coloring, a new About Me page and some automation for my blog deploy process. Everything bundled in a little repo :)

Upcoming topics

Here is the roadmap of topics I’m going to cover in my upcoming articles.

  • Tutorial: Deploy HA Kubernetes cluster on bare-metal with Rancher - the story of my 300$ Cluster with bunch of resources
  • JHipster + RabbitMQ + Kubernetes - How to use JHipster to stream data over RabbitMQ and operate deployments on Kubernetes
  • Bitflow4J on Kubernetes: self-healing pipeline for Kubernetes clusters

Feel free to suggest topics in the comments section :)

The Ultimate Kubernetes Private Cloud Deployment Comparison

| Comments

~ 13 minutes to read

introduction

In my recent article on K8S deployment I described my first approach on building a working K8S cluster on a private cloud. Despite this was a working setup, it was simplified to make the setup easier. However my personal aim was more about:

How to deploy a production ready kubernetes cluster on a private cloud?

To be more precise, what I try to achieve:

I don’t want to use AWS/Azure/GKE for some reasons

I am using a non wide known cloud provider like ProfitBricks, or own virtual solutions, such as KVM, VMWare

I want to know a generic way for turn key clusters, agnostic to the underlying infrastructure

I want to have load balancing and storage administration running out of the box