2
0
Fork 0
mirror of https://github.com/ethauvin/rife2.git synced 2025-04-30 18:48:13 -07:00
Full-stack, no-declaration, framework to quickly and effortlessly create web applications with modern Java. https://github.com/rife2/rife2
Find a file
2022-10-30 20:50:41 -04:00
app Added a README 2022-10-30 20:42:35 -04:00
gradle/wrapper Initial commit 2022-10-01 18:42:06 -04:00
lib Fixed for javadoc generation 2022-10-30 19:27:12 -04:00
standalone Tweaks to gradle scripts and HelloWorld app 2022-10-30 11:36:10 -04:00
war Tweaks to gradle scripts and HelloWorld app 2022-10-30 11:36:10 -04:00
.gitattributes Initial commit 2022-10-01 18:42:06 -04:00
.gitignore Added database and scheduler modules. 2022-10-05 23:32:05 -04:00
gradlew Initial commit 2022-10-01 18:42:06 -04:00
gradlew.bat Initial commit 2022-10-01 18:42:06 -04:00
LICENSE.txt Added informational documents 2022-10-04 21:51:45 -04:00
README.md Center the logo in the readme 2022-10-30 20:50:41 -04:00
rife2_logo.png Added a README 2022-10-30 20:42:35 -04:00
settings.gradle.kts Working template engine 2022-10-02 21:20:46 -04:00

Welcome

RIFE2 is a full-stack, no-declaration, framework to quickly and effortlessly create web applications with modern Java.

RIFE2 is built on the foundations of the original RIFE framework that was popular from 2002-2010. Since then, the world and Java has changed and many of the original RIFE APIs can finally be replaced with pure Java, no-XML, no-YAML, leaving only type-safe expressive code.

NOTE: The documentation and this readme are work-in-progress

Hello World Example

This is how you get started with a Hello World site.

public class HelloWorld extends Site {
    public void setup() {
        get("/hello", c -> c.print("Hello World"));
    }

    public static void main(String[] args) {
        new Server().start(new HelloWorld());
    }
}

The main method spins up the integrated embedded Jetty server, so that you can immediately start coding. The same HelloWorld class can be added as a parameter value to your web.xml, requiring absolute no changes to your code between development and production packaging.

Out-of-container testing is a first-class citizen in RIFE2, directly interacting with your Site class to simulate full request-response interactions, without having to spin up a servlet container.

Let's test the example above with JUnit 5:

class HelloTest {
    @Test void verifyHelloWorld() {
        var m = new MockConversation(new HelloWorld());
        assertEquals("Hello World", m.doRequest("/hello").getText());
    }
}

One of the most brittle aspects of web application development is typing links and URLs as text literals, without anything guaranteeing they remain correct when your routes change or when you deploy your application in different web application contexts. RIFE2's routing API allows all your application links to be generated correctly without any effort on your behalf.

Let's add a new route that contains an HTML link towards the previous Hello World route.

You can see that routes don't have to be created inside the setup() method, but can also be created as part of your Site's construction, allowing the routes to be stored in fields.

public class HelloLink extends Site {
    Route hello = get("/hello", c -> c.print("Hello World"));
    Route link = get("/link", c-> c.print("<a href='" + c.urlFor(hello) + "'>Hello</a>"));

    public static void main(String[] args) {
        new Server().start(new HelloLink());
    }
}

We can now test this as such:

class HelloTest {
    @Test void verifyHelloLink() {
        var m = new MockConversation(new HelloLink());
        assertEquals("Hello World", m.doRequest("/link")
            .getParsedHtml().getLinkWithText("Hello")
            .follow().getText());
    }
}

Bidirectional Logic-Less Templates

The main impetus that had me resume work on RIFE2, was the unique template engine.

RIFE2's templates contain two main concepts:

  • values - that can be filled in with content and data
  • blocks - that will be stripped away and that provide content snippets

Your Java code will compose the final layout by assigning and appending blocks, and by putting data into values. Let's rewrite the HelloLink example above with a template.

In this example, no template manipulation is done in Java yet.

Instead, it introduces the {{v route:hello/}} value tag, which will automatically be replaced with the URL of the route that is available with that field name in your active Site.

public class HelloTemplate extends Site {
    Route hello = get("/hello", c -> c.print("Hello World"));
    Route link = get("/link", c-> c.print(c.template("HelloTemplate")));

    public static void main(String[] args) {
        new Server().start(new HelloTemplate());
    }
}

With HelloTemplate.html being:

<!DOCTYPE html>
<html lang="en">
<body>
<a href="{{v route:hello/}}">Hello</a>
</body>
</html>

Template Manipulation

Let's change the example some more and create a single route that can respond to both get and post requests.

  • the get request will display a form with a single button to click.
  • the post request will receive the form's submission and display Hello World.
public class HelloForm extends Site {
    Route hello = route("/hello", c -> {
        var t = c.template("HelloForm");
        switch (c.method()) {
            case GET -> t.setBlock("content", "form");
            case POST -> t.setBlock("content", "text");
        }
        c.print(t);
    });

    public static void main(String[] args) {
        new Server().start(new HelloForm());
    }
}

With HelloForm.html being:

<!DOCTYPE html>
<html lang="en">
<body>
<!--v content/-->
<!--b form-->
<form action="{{v route:hello/}}" method="post" name="hello">
  <input type="submit" name="Submit">
</form>
<!--/b-->
<!--b text--><p id="greeting">Hello World</p><!--/b-->
</body>
</html>

You can see that the template contains all the pieces to create both pages:

  • the value named content
  • the block named form
  • the block named text

In the Java logic, we simply assign either block to the value, depending on what we want to display.

Another nice benefit is that the template tags can be HTML comments, making them completely invisible. This allows you to work on your HTML design as usual and preview the template file with a regular browser.

Let's include a test for this functionality:

class HelloTest {
    @Test void verifyHelloForm() {
        var m = new MockConversation(new HelloForm());
        var r = m.doRequest("/hello").getParsedHtml()
            .getFormWithName("hello").submit();
        assertEquals("Hello World", r.getParsedHtml()
            .getDocument().body()
            .getElementById("greeting").text());
    }
}