REST asleep – how to construct an HTTP server in Java

REST? What? An HTTP server to „communicate“ with via URLs? Yes, why not. In certain use cases a valid solution for various different tasks. Especially for the idea of displaying more or less ’static‘ information on a display.

In my case such a server handles tasks such as

  • fetching the next x entries in a (google) calendar
  • retrieving and preprocessing actual weather data from openweathermap
  • retrieving and preprocessing the weather forecast for the upcoming hours/days from openweathermap

Other examples of useful information could be financial data such as

  • exchange rates of different currencies or
  • stock market information.

Interesting could also be the information which dustbin should be standing outside next for garbage disposal in the morning.
Perhaps flight information for frequent flyers, train times (and delays) for rail travellers, even momentary fuel prices in the region (if only they were not changing so quickly as in Germany) is helpul.

For sure there are more ideas which data could be retrieved and prepared by a server for display! But back to the server itself.

HTTP Server Construction

An HTTP server in Java is basically a runnable jar file that is launched on a machine within a (local) network. The required libraries include http, httpclient, httpcore, … .

Functionality

When a GET request is received from a client the appropriate routine is launched. For each ‚digestible‘ URL a different Java class handles the request.
In case of fetching the next x entries from a Google calendar the specific Java class handles the authentication, the retrieval and the processing of the calendar entries into the JSON format. In Java this is more simple and faster than computing directly on an Arduino.

The entry point of the server may be constructed like this:

import com.sun.net.httpserver.HttpServer;
...
public static void main(String[] args) {
	try {
	    HttpServer server = HttpServer.create(new InetSocketAddress(12345), 0);
	    server.createContext("/calendar", new RequestCalendarHandler());
	    server.createContext("/weather", new RequestOWMWeatherHandler());
	    server.createContext("/forecast", new RequestOWMWeatherForecastHandler());
	    server.setExecutor(null); // creates a default executor
	    server.start();
	    System.out.println("Server running on host " + server.getAddress().getHostString());
	} catch (IOException e) {
	    System.err.println(e.getMessage());
	}
}

Openweathermap

For weather data/weather forecast retrieval from openweathermap it is not necessary to reimplement the wheel. An excellent Java library already exists: owm-japis. It can be used in a different Java class to process appropriate HTTP GET requests.

The handler for fetching weather data by openweathermap may look similar to this:

import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;

import net.aksingh.owmjapis.CurrentWeather;
import net.aksingh.owmjapis.OpenWeatherMap;
import net.aksingh.owmjapis.OpenWeatherMap.Units;
...
static class RequestOWMWeatherHandler implements HttpHandler {
	@Override
	public void handle(HttpExchange http) throws IOException {
		System.out.println("URI received: " + http.getRequestURI().toString());

	String[] request = http.getRequestURI().toString().split("/");
	if( request.length>1 ) {
		// Handle read requests
		if( request[1].equals("weather") ) {
		try{
			OpenWeatherMap owm = new OpenWeatherMap("APIKEY");
			owm.setUnits(Units.METRIC);

			// getting current weather data for the location
			CurrentWeather cwd = owm.currentWeatherByCityCode(CITYCODE_OWM);

			// checking data retrieval was successful or not
			if (cwd.isValid()) {
				DateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
				Date now = cwd.getDateTime();
				String dateNow = dateFormatter.format(now);
				DateFormat timeFormatter = new SimpleDateFormat("HH:mm");
				String timeNow = timeFormatter.format(now);

				System.out.println(cwd.getRawResponse());
				System.out.println("Post weather result in JSON format (raw)");
				// wrap parcels of byte size 4096
				int BUFFER_SIZE = 4096;
				http.sendResponseHeaders(200, 0);
				try (BufferedOutputStream out = new BufferedOutputStream(http.getResponseBody())) {
					try (ByteArrayInputStream bis = new ByteArrayInputStream(response.getBytes())) {
						byte [] buffer = new byte [BUFFER_SIZE];
						int count ;
						while ((count = bis.read(buffer)) != -1) {
							out.write(buffer, 0, count);
						}
					}
				}
			}
		} catch (Exception e) {
			System.err.println(e.getMessage());
		}
	}
}

Client to Server

A client requests data from the HTTP server by a GET request. An example URL to fetch the weather data looks like this:
http://localhost:12345/weather
Such an URL consisting of hostname:port can be tested in a browser on the machine where the server is running. Otherwise an IP or hostname must replace localhost.

Server to Clients

As soon as the HTTP server received a request it analyses the URL and launches the appropriate handler. In the example above the weather data will be retrieved from openweathermap (API key and location ID required).

How to read from a google calendar in Java is explained on google’s developer pages. Authentication for the desired calendar must be set up in advance following the manual.

The results can be preprocessed into a desired format to be posted for the client.
A common format is the JSON format. Data in this format can be read and processed further by a client.

Example Client: Arduino / ESP8266

The client I use is an Adafruit Huzzah microcontroller with an ESP8266 WiFi chip.
(Just in case: the hardware setup, the pin changes in the epd library and the code to parse weather data are described in previous blog posts) .
The source code in this blog post illustrates how to act as an HTTP client. To decode a reply in JSON format the library ArduinoJson is used.
Any display can be attached to the microcontroller to show the results from the HTTP GET request to the HTTP server. At the moment I strongly prefer an e-Ink display. 😉

calendar_currentweather

Links

https://developers.google.com/google-apps/calendar/quickstart/java

http://openweathermap.org/api

https://bitbucket.org/akapribot/owm-japis/overview

https://github.com/bblanchon/ArduinoJson

http://www.waveshare.com/4.3inch-e-paper.htm

http://www.waveshare.com/wiki/4.3inch_e-Paper

Advertisements

android cardboard app using camera and OpenGL ES

Some time ago I started to program Android apps for my smartphone. This year I got my hands on a cardboard. My first idea was to use the smartphones camera. Stereo vision with a single camera is a fake, but still it was tempting.

I was searching for examples of cardboard apps and stumbled across this example. For a start this was very useful. The example app shows how to create a stereo view and how to display a live camera image. The app is using Open GL ES which won’t work on all smartphones.

After having played around a little with the app I realized that if I want to change the live image only the fragment shader has to be replaced. This can happen  while clicking on the display (difficult when the smartphone is in the cardboard) or when using the magnet switch.

cardboardView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        switchShader();
    }
});


@Override
public void onCardboardTrigger() {
    vibrator.vibrate(50);
    switchShader();
}

Excerpt of switchShader():

private void switchShader() {
    shader_selection++;
    if (shader_selection > 31)
        shader_selection = 0;

    if (shader_selection == ORIG)
        overlayView.show3DToast("Shader: original. " +     shader_selection);
    else if (shader_selection == NEG)
        overlayView.show3DToast("Shader: negative. " +     shader_selection);
    ...
}

To display a negative image the fragment shader looks like this:

#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 textureCoordinate;
uniform samplerExternalOES s_texture;
void main() {
    vec4 color = texture2D( s_texture, textureCoordinate );
    float inverted = 1.0 - color.r;
    vec4 inverted_vec = vec4( vec3(inverted), 1.0);
    gl_FragColor = clamp(inverted_vec, 0.0, 1.0);
}

To invert RGB images:

#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 textureCoordinate;
uniform samplerExternalOES s_texture;
void main() {
	vec4 color = texture2D( s_texture, textureCoordinate );
    float invertedr = 1.0 - color.r;
    float invertedg = 1.0 - color.g;
    float invertedb = 1.0 - color.b;
    vec4 inverted_vec = vec4( vec3(invertedr, invertedg, invertedb), 1.0);
    gl_FragColor = clamp(inverted_vec, 0.0, 1.0);
}


A nice sepia effect:

#extension GL_OES_EGL_image_external : require
#ifdef GL_ES
precision mediump float;
#endif

varying vec2 textureCoordinate;
uniform samplerExternalOES s_texture;

void main()
{
    vec4 color = texture2D( s_texture, textureCoordinate );
    vec4 sepia = texture2D( s_texture, textureCoordinate );
    sepia.r = (color.r * .393) + (color.g *.769) + (color.b * .189);
    sepia.g = (color.r * .349) + (color.g *.686) + (color.b * .168);
    sepia.b = (color.r * .272) + (color.g *.534) + (color.b * .131);
    
    gl_FragColor = vec4(sepia.rgb, 1);
}

Several good examples for shaders which can be adapted I found here:

http://littlecheesecake.me/blog1/2013/08/15/pretty-geeky-codes.html
http://littlecheesecake.me/blog1/2013/04/19/more-filters.html
http://littlecheesecake.me/blog1/2013/01/31/image-processing.html

It is quite important to stop the camera when the app is paused. Otherwise other apps could not use the camera in the meantime.

    @Override
    public void onPause() {
        super.onPause();
        stopCamera();
    }

    private void stopCamera() {
        if( camera!=null ) {
            camera.stopPreview();
        }
    }

The result looks like this (computer mouse in negative mode):

androidcardboardnegativemouse

The smartphone gets pretty warm while using the app…