<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;
}
}
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:
@Cmd@Page@Path@FilterThe @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.
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.
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 @Page annotation is very similar to the @Cmd annotation. The main different is that the default representation of a page is XML.
XML, of course, is not the way you want to present your web-site to your users. In flip, we use XSLT to transform the XML data into viewable HTML, example:
package eg;
import com.github.gkutie.flip.web.Flip;
import com.github.gkutiel.flip.apt.Page;
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();
}
@Page(xsl = "/me.xsl")
public Person me() {
return new Person("Gilad", 33);
}
}
When combined with the following .xsl file (more on static content in a minute)
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <head> <title>Me</title> </head> <body> <h1>Me</h1> <p>Name: <xsl:value-of select="//name"/></p> <p>Age: <xsl:value-of select="//age"/></p> </body> </html> </xsl:template> </xsl:stylesheet>
Will generate an HTML page at http://localhost:8080/me
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 is a (powerful) extension to flip framework.
<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
flip-web extends the flip framework in three aspects:
flip-web provides the following response classes
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
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
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
redirect - send a redirection response.get , set and del- useful for state-less session management.requestUrl - current URL, including the protocol, host, path and query stringIn 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
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 - defines the client view and methods.Main.java - the server implementation.
<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:
path - the path to register the functionsmap - a key value object with all the functions to be registered.key - (Optional) a key to register the functions with, usually useful to create groups or identify a user.
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.
flip-store is a simple, powerful, persistence framework.
Add the following ivy dependency
<dependency org="com.github.gkutiel" name="flip-store" rev="2-RELEASE"/>
Note for latest version see http://search.maven.org/#search|ga|1|flip-store
You can easily store any object with a default constructor as following:
public class Main {
public static void main(final String[] args) {
Store.create(String.class).put("foo");
}
}
To retrieve the objects we store we use one of the get methods, for example:
public class Main {
public static void main(final String[] args) {
final Store<String> store = Store.create(String.class);
store.put("foo");
System.out.println(store.get());
}
}
We can select only specific objects by using the com.github.gkutiel.store.Store.Index annotation, example:
public class Person {
public static void main(final String[] args) {
final Store<Person> store = Store.create(Person.class);
store.put(new Person("Gilad", 33));
store.put(new Person("Uri", 32));
List<Person> gilads = store.get("name = ?", "Gilad");
}
@Index String name;
@Index int age;
public Person(final String name, final int age) {
this.name = name;
this.age = age;
}
}
To prevent duplicates objects and to enable updating existing objects we can use the com.github.gkutiel.store.Store.Key annotation, example:
@Key("name")
public class Person {
public static void main(final String[] args) {
final Store<Person> store = Store.create(Person.class);
store.put(new Person("Gilad", 32));
store.put(new Person("Gilad", 33));
store.put(new Person("Uri", 32));
List<Person> gilads = store.get("name = ?", "Gilad");
}
@Index String name;
@Index int age;
public Person(final String name, final int age) {
this.name = name;
this.age = age;
}
}
We can delete objects by using the del method, example:
Ask me