Flip A new way to build web applications.

<dependency org="com.github.gkutiel" name="flip-apt" rev="4-RELEASE"/>

Note for latest version see http://search.maven.org/#search|ga|1|flip-apt

package main;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;

public class Main {
	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd
	public int add(final int a, final int b) {
		return a + b;
	}
}

Testing

Open the page http://localhost:8080/add?a=10&b=5 in your favorite browser.

Flip is a powerful, extendible, lightweight, annotation based, web framework. In the core of the flip framework is the flip-processor - an annotation processor plug-in. Flip has 4 built-in annotations:

The @Cmd annotation tells flip how to route HTTP requests to methods. For example, the following code will route requests to the url /example to the method foo

public class Example{
	@Cmd("/example")
	public void foo(){
		System.out.println("foo");
	}
}

So when the user sends request to http://localhost:8080/example the flip framework will invoke the foo method.

Note if the @Cmd annotation is used without a value, the framework will use the method name as a path.

Handling Request Parameters

When a commands handler has parameters in the method signature, the flip framework map the parameters in the query string to the command handler parameters. For example the following command handler

public class Example{
	@Cmd("/example")
	public void foo(String msg){
		System.out.println(msg);
	}
}

When invoked with the URL http://localhost:8080/example?msg=Hello will print Hello

Note The value of the parameters need to be a valid JSON string.

Response

By default, a command handler sends back a JSON response, for example, the following code will send a JSON representation of a person, when accessed via http://localhost:8080/me

package eg;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;

public class Main {

	static class Person {
		final String name;
		final int age;

		public Person(final String name, final int age) {
			this.name = name;
			this.age = age;
		}
	}

	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd
	public Person me() {
		return new Person("Gilad", 33);
	}
}

The format of the response can be changed, by setting the response property of the @Cmd annotation, for example, the following code will return an XML representation of a person:

package eg;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;
import com.github.gkutiel.flip.res.Xml;

public class Main {

	static class Person {
		final String name;
		final int age;

		public Person(final String name, final int age) {
			this.name = name;
			this.age = age;
		}
	}

	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd(response = Xml.class)
	public Person me() {
		return new Person("Gilad", 33);
	}
}

The @Path annotation tells flip to prefix all commands in a class with the specified path, example:

@Path("/bar")
public class Example{
	@Cmd
	public void foo(){
		System.out.println("foo");
	}
}

So now when the user ask for the URL http://localhost:8080/bar/foo the framework will invoke the foo method.

A filter is a method that is being invoked before any command handler is invoked. A filter handler accepts the same parameters as any command handler, so for example, the following code

public class Example{
	Integer n;
	
	@Filter
	public void bar(Integer n){
		this.n = n;
	}
	
	@Cmd("/example")
	public void foo(String msg){
		for(int i = 0; i < n; i++)System.out.println(msg);
	}
}

When invoked with the following URL http://localhost:8080/example?n=3&msg=Hello will print Hello 3 times.

Note You can add as many filters as you want to the same class. The order in which those filters are invoked, however, is not guaranteed.

flip framework looks for static content in the web folder under the working directory. index.html and index.xml are set as welcome files.

So far we have gone through the core of the flip framework. What we have seen so far is very simple, yet, thanks to the extendible design of the framework, incredibly powerful.

flip-web

flip-web is a (powerful) extension to flip framework.

Installation

<dependency org="com.github.gkutiel" name="flip-web" rev="18-RELEASE"/>

Note for latest version see http://search.maven.org/#search|ga|1|flip-web

General

flip-web extends the flip framework in three aspects:

Reusable Response Classes

flip-web provides the following response classes

Text

The class com.github.gkutiel.flip.web.res.Text returns a simple textual response, for example the following code

package eg;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;
import com.github.gkutiel.flip.web.res.Text;

public class Main {

	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd(response = Text.class)
	public String me() {
		return "Gilad, 33";
	}
}

Will return a simple textual response to the request URL http://localhost:8080/me

Bin

The class com.github.gkutiel.flip.web.res.Bin returns a binary response, for example the following code

package eg;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;
import com.github.gkutiel.flip.web.res.Bin;

public class Main {

	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd(response = Bin.class, mime = "image/png")
	public byte[] circle(final int radius) throws IOException {
		final BufferedImage bufferedImage = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);

		final Graphics2D g = bufferedImage.createGraphics();
		g.setColor(Color.RED);
		g.fillOval(0, 0, radius, radius);

		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ImageIO.write(bufferedImage, "png", baos);

		return baos.toByteArray();
	}
}

Will generate a red circle with a radius defined by the user, example http://localhost:8080/circle?radius=100

Note When using the com.github.gkutiel.flip.web.res.Bin response, the command method must returns a byte[] and a mime property must be specified

Handling Common Tasks

To make use of the methods provided by flip-web, one should inherit the com.github.gkutiel.flip.web.Web class, example

public class Example extends Web {}

The methods exposed by the Web class are

In addition the Web class expose the HttpRequest and HttpResponse objects, so further extension of this class is easy to make.

Note The com.github.gkutie.flip.web.To class provides static methods to build redirection URLs

Remote Method Invocation

The flip-web extension enable the invocation of JavaScript methods directly from the server in a very simple way.

To demonstrate this feature, we will start with a short example, this example consists of two files:

index.html

<html>
  <body>
    <script src="/_.js"></script>
      <script>
        _("/_home", {
          pop : function(msg){
            alert(msg);
          }
        });
      </script>
    </body>
</html>

In line 3 we include the script "/_.js" which is embedded in the flip-web framework.

In lines 5 - 9 we register the function pop on the server so it can invoke it whenever it needs. The registration function _ takes 3 parameters:

Main.java

package eg;

import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Cmd;
import com.github.gkutiel.flip.web.Remote;
import com.github.gkutiel.flip.web.Web;

public class Example extends Web {

	interface Home {
		public void pop(String msg);
	}

	static final Remote HOME = Remote.bind(Home.class, "/_home");

	public static void main(final String[] args) {
		new Flip(8080).start();
	}

	@Cmd
	public void pop(final String msg) {
		HOME.at().pop(msg);
	}
}

In lines 10 - 12 we define the interface the we want to use remotely.

In line 14 we we create the remote interface and in line 10 we register this interface at the path "/_home".

The command pop in lines 20 - 23 simply test that this remote interface works, so when the user go to url http://localhost:8080/pop?msg=hi for example, the remote methods will be invoked.

Note the path is used to bind an interface to a path while the key is used to identify groups that share the same interface, so, for example, if you design a chat application then all the rooms should have the same interface but each room should have its own key.

Ask me