Higgs
A modern WebSite and Web services framework with built in Async events, HTTP server,client and WebSocket server,client, all powered by Netty with Jersey/JAX-RS, Shiro, Handlebars and Jackson
Install / Use
/learn @zcourts/HiggsREADME
Higgs Boson
The name shamelessly stolen from the almost mythical Higgs Boson http://en.wikipedia.org/wiki/Higgs_boson .
- Higgs - the name of the library
- Boson - the name of a custom binary protocol
Together with Netty forms a pure JVM (NIO based) high performance, message oriented networking framework. TODO: add answer to question about describing as message oriented as opposed to rpc e.g. explanation http://www-scf.usc.edu/~shailesn/csci-555/mp_vs_rpc.html
Supported protocols
- HTTP/HTTPS (Client and Server)
- WebSocket (Server) -
- Boson - A language independent, object serialization protocol for sending/receiving arbitrary data over the network and performing remote method invocation (RMI/RPC).
Custom Protocols
- One of the biggest wins with Higgs is it provides a simple framework for you to do your own protocol. The advanced section below shows how trivial it is to do so. However, as it stands, Higgs will continue to add support for "standard" protocols. On the to do list are ftp,ssh, sctp, telnet etc (They'll probably be external projects with a dependency on higgs rather than core modules).
- Boson is the actively used/developed custom protocol and is a detailed example of doing your own.
- The Boson protocol is actively used between Node JS and Java/Scala at Fillta
- The library uses the latest version 4 Netty API. Since the netty project had a major refactor between v3 and v4 it is not compatible with previous versions and Netty needs to be built and installed in your local maven REPO using the master branch
- TODO: See if replacing reflection based invocation with code generation via ReflexASM makes a diff.
Features
- Simplicity and Abstraction from the underlying NIO operations & socket handling.
- Extensible - Allowing user supplied protocols, encoders,decoders,client server handlers
- Performant - While it includes an abstraction layer on top of Netty it does not impede or limit the performance you usually get with Netty
- Easily extensible to add custom protocols, binary or otherwise.
- Built on top of Netty
#Modules
- core The Higgs framework. If you want to do a custom protocol without the other modules, add this as a dependency.
- boson An implementation of the Boson Protocol Specification
- http-client A feature rich asynchronous HTTP Client
- http-s3 (Higgs Http Single Site Server [s3] or HS3) Is an HTTP server built for deploying a single site. It is highly configurable and feature rich. Can be used to serve either REST/JSON services,static files (including HTML,images etc) AND dynamic HTML. Dynamic HTML support is made possible by Thymeleaf. Loosely coupled so any feature can be removed or disabled via configurations. Extensible, add custom output or input manager. Annotation based configurations.
- websocket WebSocket server. The server depends on HS3 and inherits all its features. In addition, it allows serving either a plain WebSocket api or mixing HTTP and WebSockets on the same port and using the same or different paths.
- cluster A peer to peer system which enables boson applications to be clustered. It includes features to dynamically load balance with each Node in the cluster having roles. The implementation is still in very early development and experimental use so hasn't be published yet.
- events Events offers a simple mechanism to make thread safe, multi-threaded applications that communicate asynchronously
Getting started
Each protocol comes with a simple client/server demo.
Examples
HTTP
public class Demo {
private static HttpRequestBuilder defaults = new HttpRequestBuilder();
private static Logger log = LoggerFactory.getLogger(Demo.class);
private Demo() {
//configure default builder
defaults.acceptedLanguages("en,fr")
.acceptedMimeTypes("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.charSet("ISO-8859-1,utf-8;q=0.7,*;q=0.7")
.userAgent("Mozilla/5.0 (compatible; HiggsBoson/0.0.1; +https://github.com/zcourts/higgs)")
.connection(HttpHeaders.Values.CLOSE)
//automatically follow redirects when these status codes are returned
.redirectOn(301, 302, 303, 307, 308);
}
public static void main(String[] args) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
}
});
//automatically follow redirects
//disable redirect
HttpRequestBuilder clone = defaults.copy();
// could remove all redirect statuses with copy.redirectOn().clear();
Request req = clone.GET(new URI("http://httpbin.org/relative-redirect/1"),
new PageReader(new Function2<String, Response>() {
public void apply(String s, final Response response) {
System.out.println(s);
}
}));
req.execute();
Request r = clone.GET(new URI("http://httpbin.org/redirect/1"),
new PageReader(new Function2<String, Response>() {
public void apply(String s, Response response) {
System.out.println(s);
System.out.println(response);
}
}));
r.execute();
//keeping all previous settings on r we can make a request to a url on the same host
//by providing a path or to a different host by providing a complete URL
//this will make a request to http://httpbin.org/get
r.url("/get").execute();
//to read an entire page
PageReader page = new PageReader();
page.listen(new Function2<String, Response>() {
public void apply(String data, Response response) {
System.out.println("----------------------------------- SIMPLE GET ----------------------------------");
System.out.println(data);
}
});
//by using copy we create a new instance which keeps the global settings configured on defaults
//and now any operation on the copy is completely independent so default settings can be changed
// without affecting each other
Request request = defaults.copy().GET(new URI("http://httpbin.org/get"), page);
//get the request here
Response response = request.response();
request
//can add headers
.header("some-header", "it's value")
//can add cookies separately
.cookie("cookie-name", "cookie value");
request.execute().
addListener(new GenericFutureListener<Future<Response>>() {
public void operationComplete(Future<Response> future) throws Exception {
//or get the response here
}
});
//to read a url line by line such as a Twitter or other API stream
//use alternative constructor
LineReader lineReader = new LineReader(new Function2<String, Response>() {
public void apply(String line, Response response) {
System.out.println("LINE: " + line);
}
});
defaults.GET(new
URI("http://httpbin.org/get"), lineReader).
execute();
//to download a file
FileReader fileReader = new FileReader(new Function2<File, Response>() {
public void apply(File file, Response response) {
System.out.println("--------------------------------- DOWNLOAD FILE ---------------------------------");
System.out.print("NAME:");
System.out.println(file.getName());
System.out.print("PATH:");
System.out.println(file.getPath());
System.out.print("SIZE:");
System.out.println(file.getTotalSpace());
}
});
defaults.GET(new URI("https://codeload.github.com/zcourts/higgs/zip/master"), fileReader).execute();
//url encoded POST request
PageReader post = new PageReader(new Function2<String, Response>() {
public void apply(String data, Response response) {
System.out.println("------------------------------- URL-ENCODED POST --------------------------------");
System.out.println(data);
}
});
defaults.POST(new URI("http://httpbin.org/post"), post)
.form("abc", 123)
.form("def", 456)
.header("haha", "yup")
.execute();
//multi part http post request
PageReader postReader = new PageReader(new Function2<String, Response>() {
public void apply(String data, Response response) {
System.out.println("----------------------------------- MULTIPART -----------------------------------");
System.out.println(data);
}
});
File tmpFile = Files.createTempFile("upload", ".txt").toFile();
if (tmpFile.exists()) {
tmpFile.delete();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(tmpFile));
writer.write("This is a temporary text file");
//could use HttpFile(String,HttpFile) constructor but that assumes a binary file
HttpFile file = new HttpFile("the-file-name-param");
fi
