Skip to content
This repository has been archived by the owner on Jun 7, 2021. It is now read-only.

Commit

Permalink
Add HTTP POST to the events services
Browse files Browse the repository at this point in the history
  • Loading branch information
lance committed Dec 3, 2015
1 parent 512304f commit 8aba854
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 78 deletions.
54 changes: 39 additions & 15 deletions ribbon/README.md
@@ -1,15 +1,12 @@
# Multiple services plus NetFlixOSS Ribbon

> NOTE: This example will not work yet, as it relies upon a patch
> in the upstream of WildFly not yet available in a released version.
> Please raise any issues found with this example in this repo:
> https://github.com/wildfly-swarm/wildfly-swarm-examples
>
> Issues related to WildFly Swarm core should be raised in the main repo:
> https://github.com/wildfly-swarm/wildfly-swarm/issues
The beginnings of a multi-service example.
## Services

Two services exist:

Expand All @@ -20,27 +17,54 @@ The `time` service simply returns the current time as a JSON map
with fields for hour, minute, second, etc.

The `events` service queries the `time` service, and returns a list of
currently on-going events. Currently, it just generates a list of events
that started at the top of the current hour.
currently on-going events.

Each of these services may be accessed with a simple HTTP `GET` request.
For example, the `time` service:

$ curl http://127.0.0.1:8081
{"s":5,"D":3,"ms":647,"tz":"America/New_York","h":10,"Y":2015,"M":12,"m":37}

In addition, the `event` service will accept an HTTP `POST` request with JSON data
specifying the event type. Every `GET` or `POST` request to the `event` service
generates a new event.

## Front End

There is a simple JAX-RS front end that uses the `ribbon-webapp` fraction to
communicate with the services. The web site displays the current Ribbon topology,
and provides a simple button-based UI to `GET` or `POST` messages to the Ribbon
services.

## Try it Out

Build and run the time service:
First, start up the front end, so you can watch the Ribbon topology get updated
in real time. Open a terminal window.

$ cd frontend
$ mvn wildfly-swarm:run

Then open a browser to `http://127.0.0.1:8080`. There will be nothing to see there
yet. Leave this window open and visible while you bring up the two services.

Open another terminal window to build and run the time service:

$ cd time
$ mvn -Djboss.http.port=8081 wildfly-swarm:run

Maybe run it twice:
You should see the Ribbon topology update in the browser as the time service
comes up. Now, open another terminal window, and run the `time` service again,
but this time give it a different port number. Notice how the web UI updates
itself as the service comes up.

$ cd time
$ mvn -Djboss.http.port=8082 wildfly-swarm:run

Then run the events service, which consumes the time service(s):
Finally, open yet another terminal window and run the events service,
which consumes the time service(s). Again, note the UI changes.

$ cd events
$ mvn wildfly-swarm:run

Then

* http://localhost:8080/

Kill and restart one or both of the `time` services, and witness how stuff
behaves.
Now you can kill and restart one or both of the `time` services, and witness the
UI changes. You can also `GET` time and event service data, and `POST` new events.
@@ -0,0 +1,37 @@
package org.wildfly.swarm.examples.netflix.ribbon.events;

import java.util.Map;

/**
* @author Lance Ball
*/
public class Event {
private int id;
private String name;
private Map timestamp;


public Map getTimestamp() {
return timestamp;
}

public void setTimestamp(Map timestamp) {
this.timestamp = timestamp;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Expand Up @@ -4,22 +4,18 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.netflix.ribbon.Ribbon;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import rx.Observable;

import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.*;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
import java.util.Map;

/**
Expand All @@ -29,17 +25,29 @@
public class EventsResource {

private final TimeService time;
private static final ArrayList<Event> EVENTS = new ArrayList<>();

public EventsResource() {
//this.time = Ribbon.from( TimeService.class );
this.time = TimeService.INSTANCE;
}

@GET
@Produces(MediaType.APPLICATION_JSON)
public void get(@Suspended final AsyncResponse asyncResponse) {
Observable<ByteBuf> obs = this.time.currentTime().observe();
Event event = new Event();
event.setName("GET");
recordEvent(event, asyncResponse);
}

@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public void post(Event event, @Suspended final AsyncResponse asyncResponse) {
recordEvent(event, asyncResponse);
}

private void recordEvent(Event event, @Suspended AsyncResponse asyncResponse) {
Observable<ByteBuf> obs = this.time.currentTime().observe();
obs.subscribe(
(result) -> {
try {
Expand All @@ -48,44 +56,20 @@ public void get(@Suspended final AsyncResponse asyncResponse) {
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(new ByteBufInputStream(result));
Map map = reader.readValue(parser, Map.class);
int hour = (int) map.get( "h" );
int minute = (int) map.get( "m" );
int millis = (int) map.get( "ms" );
String tz = (String) map.get( "tz" );
List<String> events = new ArrayList<>();
for ( int i = 1 ; i <= 10 ; ++i ) {
StringBuffer buffer = new StringBuffer("Event #")
.append(i)
.append(" at ")
.append(hour)
.append(":")
.append(minute)
.append(".")
.append(millis)
.append(" ")
.append(tz);

events.add( buffer.toString() );
}
asyncResponse.resume(events);
event.setTimestamp(map);
event.setId(EVENTS.size());
EVENTS.add(event);
asyncResponse.resume(EVENTS);
} catch (IOException e) {
System.err.println("ERROR: " + e.getLocalizedMessage());
asyncResponse.resume(e);
}
},
(err) -> {
System.err.println("ERROR: " + err.getLocalizedMessage());
asyncResponse.resume(err);
});
}

@OPTIONS
@Path("{path : .*}")
public Response options() {
return Response.ok("")
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD, undefined")
.header("Access-Control-Max-Age", "1209600")
.build();
System.out.println("New event");
}
}
46 changes: 44 additions & 2 deletions ribbon/frontend/src/main/resources/css/app.css
Expand Up @@ -4,13 +4,55 @@ body {
}

.service {
min-width: 500px;
display: block;
float: left;
margin: 1ex;
}

.service h2 {
border-bottom: 1px dotted;
margin: 1ex;
margin: 1ex 0;
padding: 0px;
}

.service .service-address {
margin: 1ex 2ex;
margin: 0px;
}

.btn {
-webkit-border-radius: 6;
-moz-border-radius: 6;
border-radius: 6px;
font-family: Arial;
color: #ffffff;
font-size: 16px;
background: #286e96;
padding: 8px 12px 8px 12px;
text-decoration: none;
}

.btn:hover {
background: #146ec8;
text-decoration: none;
cursor: pointer;
cursor: hand;
}

ul.event {
border: 1px solid #ccc;
padding: 1ex;
list-style: none;
}

ul.event.timestamp {
border: none;
padding: 0;
}

.timestamp {
border: 1px solid #aaa;
padding: 1ex;
margin: 1ex 0;
}

0 comments on commit 8aba854

Please sign in to comment.