Juzu is a web framework based on MVC concepts for developing applications. Juzu is an open source project developed on GitHub licensed under the Apache 2 License.
Build, deploy, run and test
We will study in this chapter the life cycle of a Juzu application: Build, Deploy, Run and Test!
Introduction
Building a Juzu application is usually done in two steps:
-
Compile the application to classes
-
Package the application as a web application (war file)
Compiling an application requires a few jars to be present on the compilation classpath:
-
The Juzu core jar for the Juzu API
-
The JSR-330 jar for the @Inject API
-
Any Juzu extension jar such as plugins or additional template engines
After compilation, the compiled classes are packaged as a web application archive (war) and then deployed in a server. We will show several ways to package your Juzu application.
Juzu dependencies
Let’s start by looking at the dependencies required by Juzu, there are several types of dependencies:
-
compilation time dependencies used during the compilation of the application: for instance the Less plugin transforms a less file into a css
-
runtime dependencies used when the application is running
-
provided by server like the @Inject jar provided by an EE server but not by a Servlet Container
-
embedded in the application like Groovy
-
Juzu core dependendencies
Juzu is built on top of a plugin architecture allowing to reduce the number of dependencies to the minimum for the core of the framework.
GAV | Compilation | Servlet Container | Java EE Server | |
---|---|---|---|---|
Juzu |
org.juzu:juzu-core |
☑ |
☑ |
☑ |
Groovy |
org.codehaus.groovy:groovy-all |
☐ |
☑ |
☑ |
@Inject |
javax.inject:javax.inject |
☑ |
☑ |
☐ |
Injection Container dependendencies
Juzu leverages an Injection Container (IOC) at runtime for wiring the various objects managed by the framework. Several implementations can be used and you should configure the correct dependencies according to the container you are using:
-
Spring 3
-
Google Guice 3
-
Context and Dependency Injection
-
CDI provided by the server
-
Weld the CDI implementation managed by Juzu
-
Context and Dependency Injection specification is an extension (JSR 299) of the @Inject specification (JSR-330) |
These implementation jars are never required at compilation time, unless you use specific classes in your project, such
as the @Autowire
annotation of Spring, or the @Produces
annotation of CDI.
At runtime the jars you needs depends on the implementation you use:
Servlet Container | Java EE Server | |
---|---|---|
Spring |
☑ |
☑ |
Google Guice |
☑ |
☑ |
Weld |
☑ |
☐ |
CDI |
☑ |
☐ |
When using CDI with a Servlet Container, you need to chose an implementation of CDI and configure it specifically for the Servlet Container, for instance you can configure the Weld implementation for Tomcat 7. |
Packaging a Juzu application
Packaging a Juzu application is quite easy to achieve when you know which dependencies Juzu and the runtime expect or provide. Juzu jars are deployed in the Maven Central repository.
When packaging your application you can follow:
Compilation | Servlet Container | EE Container | |
---|---|---|---|
|
☑ |
☑ |
☑ |
|
☑ |
☑ |
☑ |
|
☑ |
☑ |
☐ |
Guice |
☐ |
☑ |
☑ |
Spring |
☐ |
☑ |
☑ |
CDI |
☐ |
☑ |
☐ |
Build
Every Juzu application is just a web application, any build system or IDE cab achieve it easily. We are going to cover the cases of Maven and Gradle builds as well as a few IDEs.
Build with Maven
The Maven war packaging is a convenient way for building a web application with Maven. In the following examples we will show the Maven configuration for a couple of examples, all the configurations are listed in the appendix of this guide:
we don’t need to depend on the Groovy jar as it is a compile dependency of org.juzu:juzu-core artifact and it will be present thanks to dependencies transitivity |
Example 1: Spring in a Servlet Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
Example 2: CDI
CDI is supported natively by an EE container and requires specific integration for a servlet container like tomcat
CDI for an EE container
Here are the dependencies for an EE container.
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
CDI for a Servlet container
Using CDI with the Weld reference implementation in a Servlet Container requires extra configuration of the web application described in the Weld manuel, let’s look first at the jar dependencies
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
</dependency>
</dependencies>
We need specific elements in web.xml for integrating CDI with a servlet container:
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
<resource-env-ref>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
In addition we need also a META-INF/context.xml file that contains specific Tomcat configuration:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="BeanManager"
auth="Container"
type="javax.enterprise.inject.spi.BeanManager"
factory="org.jboss.weld.resources.ManagerObjectFactory"/>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>META-INF/context.xml</WatchedResource>
</Context>
Juzu archetype
The following creates a base Juzu application for Tomcat with the Guice injection container:
mvn archetype:generate \ -DarchetypeGroupId=org.juzu \ -DarchetypeArtifactId=juzu-archetype \ -DarchetypeVersion=1.0.0 \ -DgroupId=org.example \ -DartifactId=myapp \ -DpackageName=org.example.myapp \ -Dversion=1.0.0-SNAPSHOT
The generated application is a quickstart ready to can be customized for developing more complex applications that provides out of the box:
-
Arquillian / Selenium tests
-
A preconfigured server to test the application
Selecting the injection container
It is possible to generate the application for a different server and injection container:
mvn archetype:generate \ -DarchetypeGroupId=org.juzu \ -DarchetypeArtifactId=juzu-archetype \ -DarchetypeVersion=1.0.0 \ -DgroupId=org.example \ -DartifactId=myapp \ -DpackageName=org.example.myapp \ -Dversion=1.0.0-SNAPSHOT \ -DjuzuServer=servlet \ -DjuzuInject=spring
Valid juzuServer values are servlet, ee or gatein. Valid juzuInject values are guice, spring or cdi.
Running the application
The application can be executed in Maven with the Tomcat7 Maven Plugin or the JBoss AS7 Deployment Plugin depending on the selected server.
> mvn tomcat7:run ... [INFO] Running war on http://localhost:8080/myapp [INFO] Using existing Tomcat server configuration at /Users/julien/java/tmp/myapp/target/tomcat [INFO] create webapp with contextPath: /myapp Nov 12, 2013 9:38:00 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-bio-8080"] Nov 12, 2013 9:38:00 AM org.apache.catalina.core.StandardService startInternal INFO: Starting service Tomcat Nov 12, 2013 9:38:00 AM org.apache.catalina.core.StandardEngine startInternal INFO: Starting Servlet Engine: Apache Tomcat/7.0.37 Nov 12, 2013 9:38:03 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-bio-8080"] Nov 12, 2013 9:38:12 AM juzu.impl.common.JUL send INFO: Using inject implementation guice Nov 12, 2013 9:38:12 AM juzu.impl.common.JUL send INFO: Starting Application
Likewise it is possible to run the application with JBoss AS7 (or later)
> mvn jboss-as:run ...
Running in Live Mode
The live mode allows you to edit the application while it is running, in this mode Juzu recompiles the application on the fly when it is detecting changes (see Run modes), the archetype comes with a preconfigured live Maven profile:
> mvn tomcat7:run -Plive ...
live mode works only for Tomcat server at the moment |
Build with Gradle
Building a Juzu application with Gradle is very easy with the war Gradle plugin, here is an example of build.gradle file:
apply plugin: 'war' repositories { mavenCentral() } dependencies { compile group: 'org.juzu', name: 'juzu-core', version: '1.0.0' compile group: 'org.juzu', name: 'juzu-plugins-servlet', version: '1.0.0' compile group: 'javax.inject', name: 'javax.inject', version: '1' providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' runtime group: 'org.springframework', name: 'spring-web', version: '3.2.4.RELEASE' }
Eclipse support
Eclipse IDE provides the best support for annotation processing among all IDEs. Annotation processing is integrated natively at the heart of Eclipse incremental compiler providing an high level of interaction between the developer and its project.
In this section we will see how to import the Maven based Juzu sample in Eclipse and configure it for annotation processing.
Importing the Maven project
Let’s first import our Maven application in Eclipse.
At this point the project should be imported in Eclipse.
Compiler configuration
Now we need to configure annotation processing in the compiler configuration.
Set the generated source directory to target/generated-sources/annotations to share it with the Maven build.
Enable the project specific settings and add the Juzu core jar by clicking on Add Variable…
Then click on Extend…
Processing annotations
Our project is now properly configured
The target/generated-sources/annotations is now recognized by Eclipse as a source folder.
Let’s add a process controller method
Eclipse will update the Controller_
class transparently just after we save the Controller
class.
Maven m2e-apt plugin
If you want to make your life easier you can install the m2e-apt plugin, this plugin will automatically configure the Eclipse project as we have seen before.
installing this plugin is optional, it is however nice to use with annotation processing |
You can get this plugin by adding http://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt in the Install panel.
Intellij support
Juzu uses Annotation Processing Tool to perform many tasks at compilation time. APT is a standard extension of a Java compiler. All Java IDE (Eclipse, Intellij and Netbeans) provide good support for APT, we will show in the section how to configure and uses APT within those IDEs.
IDEs provide also Maven support, we will focus in this section on using APT without the Maven support. Indeed the APT support may work differently when using Maven in your project, the Maven and APT support within IDEs has a dedicated section.
In this Intellij walkthrough we will work with project called myapp that was created by the Juzu Maven archetype.
Importing the Maven project
Let’s first import our Maven project in Intellij.
We can see in the target directory the generated annotations folders, it contains several classes generated
by Juzu such as Application
or Controller_
but also other files like templates
The generated annotations folders should be visible from the project.
you should build the project before importing it, this will help Intellij to detect the target/generated-sources/annotations and target/generated-sources/test-annotations folder and configure those as source folders of the project. If you don’t do that then you will have to do it manually in the Project Structure screen. In the screenshot we can see that all folders of target have been excluded except the generated annotations sources. |
Compiler configuration
Integration of Juzu in your IDE requires to properly configure and activate the Java compiler for using the Juzu annotation processor.
Java compiler configures requires to disable the external build feature that does not support annotation processing.
After that, the Juzu annotation processor shall be configured to juzu.processor.MainProcessor
.
Processing annotations
When using annotation processing it is important to keep your generated sources in sync with your code. There are two ways to achieve it in our case: - let Maven do the job for you either via the IDE integration or command line - ask Intellij to process the sources
In this part we are going to study how annotation generation work within the IDE with the Controller
class. The
controller compagnion Controller
looks like after the initial generation:
Let’s add a new controller method process
in our controller.
Now let’s generate the new source code via the IDE.
After generate our Controller
class has been updated.
We can see that a new method_1
field in Controller_
reflects the process
method we added in Controller
.
Run modes
Juzu defines three modes for running an application, called run modes:
-
Production (prod): error reporting is minimal
-
Development (dev): provides verbose error reporting
-
Live (live): allow to develop the application live with verbose error reporting. It provides a live recompilation of the sources at runtime providing an increased productivity.
Run mode is configured via the servlet context parameters for Servlet or Portlet applications this the scope of the run mode is for the entire bridge.
<context-param>
<param-name>juzu.run_mode</param-name>
<param-value>dev</param-value>
</context-param>
live mode is experimental and you may experience issues when using it. When this happens recompile your application with your build system and redeploy it, this will reinitialize the runtime and you can use live mode again. |
Testing
Juzu applications are web applications, so you can test your application like any other web application. The Juzu tutorial provides an extensive chapter that covers an example of testing an application with the JUnit, Arquillian and Selenium.
Hello World
The first section Build, deploy, run and test of this guide covers the entire life cycle of an application, this section will teach you about the structure of a basic Hello World application written with Juzu. The goal of this chapter is not to show you an entire Juzu application, since the Juzu tutorial already serves this purpose, instead the goal is to show you how to write the most basic application as any Hello World app does.
We suppose you have setup already the application structure, which means you have a Java project with the correct dependencies for compiling the Juzu application.
Step 1: application package
The first step is to decide the application package name. Indeed a Juzu application belongs to a single Java
package and its subpackages, allowing several applications in the same unit of compilation. Let’s name our
application examples.helloworld
. That’s how Juzu identifies an application, by its package name.
Let’s create this package and most importantly the Java named package: the named package is a file named
package-info.java that resides a the package folder, it can be used for documenting a package but also
to annotating a package. Indeed Java packages can be annoated and Juzu use the @juzu.Application
package
annotation for declaring an application:
@Application
package examples.helloworld;
import juzu.Application;
Step 2: hello world controller
Juzu follows the MVC paradygm for creating application and thus we need to provide at least one controller to handle web requests, let’s create one!
import juzu.View;
import juzu.Response;
public class HelloWorldController {
@View
public Response index() {
return Reponse.ok("Hello World");
}
}
That’s it, our application will now say Hello World to any incoming request. The @View
annotation defines
a Juzu view and the method name index
is a special name that catches any unmatched request. It returns
a response object that contains the markup of the page.
Step 3: adding a template
Let’s wrap up this by adding a template for the view. We need to create first an helloworld.gtmpl template in
the templates
sub package:
Hello Wolrd
This template can then be used by injecting it in the controller using dependency injection:
package examples.helloworld;
import juzu.Path;
import juzu.Response;
import juzu.View;
import juzu.template.Template;
import javax.inject.Inject;
public class HelloWorldController {
@Inject
@Path("helloworld.gtmpl")
Template helloworld;
@View
public Response index() {
return helloworld.ok();
}
}
Step 4: declaring the application
Finally our application must be declared when it is deployed in a war file. The runtime in which the application executes is called the bridge and we can declare it either as a servlet application or as a portlet application.
Servlet application
Declaring as a servlet application is easy to do via the Servlet plugin: the @Servlet
annotation annotates our
application package, pretty much like the @Application
does:
@Application
@Servlet("/")
package examples.helloworld;
This will generate a servlet running the application on the / path. If you like you can declare the application directly in the web.xml file, see Servlet bridge.
Portlet application
Declaring as a portlet application can only be done via the portlet.xml file since portlet containers don’t support annotation based configuration. The Portlet bridge chapter covers the configuration of such portlet, in our case the describe is:
<?xml version="1.0" encoding="UTF-8"?>
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<display-name xml:lang="EN">Hello World Application</display-name>
<portlet-class>juzu.bridge.portlet.JuzuPortlet</portlet-class> 1
<init-param>
<name>juzu.app_name</name> 2
<value>examples.helloworld</value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>Hello World</title>
<keywords>juzu,sample</keywords>
</portlet-info>
</portlet>
1 | The JuzuPortlet will run the application |
2 | Configured with the juzu.app_name init parameter |
Phases
Request life cycle is the most important concept to get right when developping a web application, whether it is a Juzu application or not. Juzu maps a request to a phase, in this chapter we will explain the phase concept and its importance.
Phases
Juzu request life cycle is composed of four phases, we will explain three of them in this chapter, the last one will be explained in another chapter of this guide.
-
The view phase : invoke the application to produce markup output aggregated within a page
-
The action phase : invoke the application to process an action
-
The resource phase : invoke the application to produce any kind of output as a full response (i.e not in a page)
During the execution of a phase, parameters are provided by Juzu to execute the phase. Those parameters are set by the application itself, for instance when it creates a link. The scope of the parameters (i.e when the validity of the parameters) depends on the phase.
View phase
The view phase invokes the application for the purpose of creating markup. This phase is indempotent, it means that repeated invocation of the same phase with the same parameters should produce the same markup (supposing than the application does not depend on some other state, like a database that could change over time).
View parameters are associated with the current URL, it means that they are somehow persistent. For instance you interact with an application to change its view parameters on each request and then you interact with another application on the same page: the view parameters will remain the same accross the invocation of the view phase of the application when the second application is used.
Action phase
The action phase invokes the application for processing an action. During the invocation, action parameters are provided and their validity is limited to the current action phase being executed, after they will not be anymore available.
The action phase is not idempotent, invoking several times an action phase could have side effects such as inserting several times the same data in a database.
Juzu does not expect markup returned during this phase, however it provides the opportunity to configure the view parameters of the next view phase.
Interactions
Now that we have an overview of the phase, it is time to connect them and explain the interactions between the phases.
-
An action phase is invoked by an URL produced during a view phase, this URL contains the action parameters
-
After an action phase a view phase is executed and the view parameters are updated
-
A resource phase is invoked by anURL produced during a view phase, this URL contains the resource parameters
Mapping onto HTTP
As said before, phases and interactions have a natural mapping with the HTTP protocol. It is worthy to explain it because it will help you to understand fully the interations managed by Juzu.
View phase
View phases are mapped on GET requests:
-
The view phase is idempotent like GET
-
View parameters are identified to query parameters
-
The response returned by a GET request should remain identical for the same parameters
During a view phase, the application produces URL which can invoke any application phase.
In this example the view phase produce markup parameterized by the color
parameter having the red value.
Action phase
Action phase are created from view phase by processing a link that was found in the markup response. The action phase is mapped on POST requests:
-
Both action phases and POST request are not idempotent
-
Action parameters are identified to form parameters
-
Action phase and POST requests should not be invoked more than one time
Now let’s update our example and suppose that the application returns markup with a form that invokes
an action phase. When the user submits the form it triggers the action phase, which in returns updates the color
view
parameter of the next view phase to the value blue.
The HTTP redirection will update the browser to show the next view phase with the expected view parameters.
During the action phase, the application configures the parameters of the next view phase. When the invocation of the phase is over, the server redirects the browser (with an HTTP temporary redirection) to the next view phase URL. This URL contains the view parameters. This mechanism is well known as Redirect After Post pattern and is often used to ensure that a POST request is not triggered several times when the refresh button of the browser is used.
Controllers
Controllers play an essential role in a Juzu application: they contain the code executed when Juzu processes a request, this chapter provides an in depth study of Juzu controllers.
Overview
Juzu controllers are simply annotated methods of the application, here is the most basic controller declaration:
public class Controller {
@View public Response.Content index() {
return Response.render("hello world");
}
}
The annotation @juzu.View
declares a view controller, the name index
has a special meaning as it will
be used when no other controller is specifed in a Juzu request.
Controller methods can declare parameters for receiving request parameters:
public class Controller {
@View public Response.Content index(String person) {
return Response.ok("Hello " + person == null ? "world" : person);
}
}
Like previously, the index
controller returns the hello world value when it is called the first time. When
the controller is called with the person
parameter it returns the hello string personalized with the corresponding
parameter value: Juzu use the declared method parameter name to match against the request parameters, in our case
the person
request parameter.
Any controller class (any class containing at least one controller method) generates a companion class during the compilation of the project. Such companion class extends the original controller class to provider companion methods for the controller method. The companion class has the same name than the original class appended with the _ character:
public class Controller_ {
public static Dispatch index() { /* Generated code */ }
public static Dispatch index(String person) { /* Generated code */ }
}
Each index
methods generated a corresponding index
method companion. When any index
method is invoked
it returns an juzu.Dispatch
object that generates the URL dispatching to the corresponding phase when
the toString()
method is invoked. When parameters are provided they will be encoded in the generated URL.
@View public Response.Content index() {
return Response.ok("Hello word. <a href='" + Controller_.index("Juzu") + "'>Say hello to Juzu</a>";
}
URL companion methods have the same signature of the originating method.
Request routing
During a request, Juzu routes the request to the correct controller method. Previously we have seen
that any unmatched view phase request will be handled by the index
controller method.
In this section we cover the binding of a controller method to a specific request. This binding is not the same whether you are writing an application that deploys as a servlet or as a portlet.
The main difference between the two environements are the request and responses: servlets interacts with the http protocol whereas the portlets interacts with the portal (which can turns into the WSRP prococol in the case of a remote portlet).
In practice the main difference between servlet and portlet is the routing of the request: with a servlet the controller methods needs to be bound to route.
Http request routing
When Juzu handles an http request it routes this request to a controller based on the request path. Request routing is based on a set of route declarations, each declaration binds a route to a controller method.
Default controller
Before discussing routing configuration, we shall remind the default controller method: the index
view
controller method of the default controller will handle any unmatched request:
@View
public void index() {
// Handle unmatched request
}
When the application has a single controller class, the default controller is this controller. When there
are more than one controller, there is an ambiguity. In this situation the default controller should be specified
in the @Application
annotation:
@Application(defaultController = Controller.class)
Declaring a route
The @Route
annotation declares the route for a controller with a path
and an optional priority
:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Route {
/**
* The route path.
*
* @return the route path
*/
String value();
/**
* The route priority.
*
* @return the route priority
*/
int priority() default 0;
}
Controller method should declare an @Route
annotation, in practice with http the
annotations @View
, @Action
and @Resource
are associated with an @Route
annotation.
@View @Route("/show")
public void show() {
...
}
The request /show will be dispatched to the show()
method.
Route parameters
Route can declare parameters:
@View @Route("/show/{id}")
public void show(String id) {
...
}
In this example the route parameter id
will match the controller method parameter id
and a request like
/show/123 will invoke the show(String id)
method with the 123 value.
Route parameter pattern matching
Optionally, route parameters can match regular expression. This can be achieved with the @Param
annotation:
@View @Route("/show/{id}")
public void show(@Param(pattern="[0-9]+") String id) {
...
}
Route overloading
The same route can bound to different phases, the dispatch behavior depends on the http method:
-
in a GET method the phases priority are view, action, resource
-
in a POST method the phases priority are action, view, resource
@View @Route("/show")
public void showWithView() {
...
}
@Action @Route("/show")
public void showWithAction() {
...
}
With such rules:
-
A GET request on the /show path will invoke the
showWithAction()
method -
A POST request on the /show path will invoke the
showWithView()
method
Route priorities
When several routes match the same request, the router will use the first route found. The priority
parameter of the @Route
annotation can be used to increase the priority of a route. This can
be useful, specially when a route contains a parameter that could match another route instead.
@View @Route("/show/status", priority = 1)
public void showStatus() {
...
}
@View @Route("/show/{name}")
public void show(String name) {
...
}
In the example, the showStatus()
controller will be invoked when the route /show/status is requested.
Without this higher priority, the show(String name)
controller might be invoked instead. When no priority is
specified, the default priority is 0.
Redirect after post
As explained in the Phases chapter, an action never produces markup, instead an action phase is followed by a view phase that will return a markup response. Juzu handles this interaction with an http redirection to the next view phase via the [redirect_after_post] pattern.
This behavior is good for the user because the browser will be updated with an URL of the view phase that is bookmarkable and safely refreshable (i.e the user an refresh the page safely).
However Juzu does not enforce this behavior and it can be changed to have the view phase immediatly invoked after the action phase.
@Action
@Route("/process")
public Response.View process() {
return Controller_.index().withNo(PropertyType.REDIRECT_AFTER_ACTION);
}
@juzu.View
@Route("/show")
public void show() {
//
}
Portlet request routing
Unlike the http protocol, the portlet request routing does not require the @Route
annotation
because portlet requests are managed by the portal and have no concept of path mapping.
To achieve request routing, the portlet uses a special portlet request parameter
named juzu.op . This parameter determines which controller should be called
during a phase. When the juzu.op parameter is not present, Juzu will look for the index
view controller.
Controller phases
There are several kinds of controllers bound to a request phase:
-
View controllers annoted with the
@juzu.View
annotation -
Action controllers annotated with the
@juzu.Action
annotation -
Resource controllers annotated with the
@juzu.Resource
annotation -
Event controllers annotated with the
@juzu.Event
annotation (not yet implemented)
View controllers
A view controller method produces aggregated markup for the application, the invocation of the method should produce markup that will be aggregated in larger page, therefore it should not care about the overall HTML structure.
View parameters describe the current parameters of the view, they are often used for navigation purpose in the application. Juzu supports simple data types such as string or integers, structured data types modelled by Java objects.
-
Simple data types can be the following types
String
,List<String>
andString[]
. Later this will be expanded to more simple types such as number, etc.. -
Structured data types which are distinguished from other parameters by annotating the controller handler parameter annotation with the the
@juzu.Mapped
annotation
View controller method should return a juzu.Response
object that is the content produced by the method. To be more precise
it should return a Response.Body
or Response.Content
object (the latter being a subclass of the former) that contains
everything Juzu needs to display the application.
During the view phase a controller can generate URLs to other phases (except the event phase) by using controller companion
methods. Companion methods returns a juzu.Dispatch
object to represent the URL. The final
URL is returned by the toString()
method of the dispatch object.
Action controllers
Action controller are executed during the action phase of a Juzu application. Usually action methods perform two tasks
-
implement the logic of the application processing, for instance inserting an entity in the database
-
configure the next view phase: setting the next view controller to display and configuring its view parameters of the method when they exist
In the following example, the controller method createUser
creates a user and
returns a Response.View
object that will tell Juzu to use the showUser
view controller during the next view phase:
@Action
public Response.View addUser(String userName, String password) {
orgService.createUser(userName, password);
return Controller_.showUser(userName);
}
showUser
is a companion view method that creates a +Response.View_ object configured with the
controller and arguments to use. Like url companion methods, view companion methods are generated during
the compilation of the project by Juzu.
Resource controllers
Resource controllers are similar to view controllers, however the resource has full control over the target page. It means that a resource controller must produce the entire resource and it can also chose the mime type returned. Resource controllers have several use cases:
-
Implement ajax resource serving
-
Produce an application resource, such as an image, a script, etc…
Resource controllers are by default bound to all HTTP methods. The @Resource
annotation can be used to restrict
the http methods a resource controller can handle:
@Route("/users/{uid}");
@Resource(method = { Method.GET })
public Response get(String uid) {
...
}
@Route("/users/{uid}");
@Resource(method = { Method.PUT })
public Response put(String uid) {
...
}
@Route("/users/{uid}");
@Resource(method = { Method.DELETE })
public Response delete(String uid) {
...
}
resource controller HTTP method routing only works for HTTP bridges. In case of the portlet bridge routing is done with the controller method and therefore the HTTP method does not play a role. |
Request parameters
Juzu supports request parameter mapping with:
-
Plugable value types with support for various primitive types,
java.util.Date
type -
Multivalued list and array types
-
Bean types
Primitive type
Primitive types can be mapped to request parameters, Juzu will do automatically the conversion between the types
and the request parameters. Most primitive types can be used, the only exception is the char
type, as it could be
ambiguously mapped to the char codepoint or the char value, String
or numeric types shall be used instead. Those types
can be used under their boxed type or their primitive type.
@Action
public Response.Content sum(Integer left, int right) {
if (left != null) {
return Response.ok("sum = " + (left + right));
} else {
return Response.error("Missing input");
}
}
when the parameter of a primitive value is not present in the request, the default primitive value is used |
Date type
The java.util.Date
type can also be mapped, in addition it can be formatted with a specific pattern thanks to the
juzu.Format
annotation:
@View
public Response.Content show(@Format("yyyy.MM.dd G 'at' HH:mm:ss z") Date date) throws Exception {
...
}
Multivalued type
Multivalued types can be used under the form of a Java array or a generic java.util.List
easily:
@View
public Response.Content sum(int[] values) {
...
}
or
@View
public Response.Content sum(List<Integer> values) {
...
}
Bean type
Juzu is able to map a set of request parameters, to the properties of a simple bean:
public class User {
public String username;
public String password;
public String name;
public User() {}
public User(String name, String password, String username) {
this.name = name;
this.password = password;
this.username = username;
}
}
The controller handler needs to declare the parameter using this type with the @Mapped
annotation:
@Action
@Route("/login")
public Response login(@Mapped User user) {
...
}
The properties can either be:
-
public fields
-
getters/setters
Request entity processing
When the request provides an HTTP entity, Juzu can decode it and make it available to your controllers. Such kind of requests can be:
-
a HTTP request targetting any phase
-
a Portlet request targetting an action or a resource phase
In such case, the entity may be decoded by Juzu otherwise it is available to your controllers via the
juzu.request.ClientContext
interface.
By default Juzu handles application/x-www-form-urlencoded requests, decodes the associated form and map it to the controllers parameters. Other requests can be processed by an entity unmarshaller which is a pluggable unmarshaller for mapping the entity to controller parameters.
File upload plugin
The file upload plugin integrates Apache Commons FileUpload in Juzu. This unmarshaller decodes multipart requests as file objects and can inject them as controller method parameters. It works with the servlet bridge and the portlet bridge.
The plugin can be used in your Maven build using a simple dependency:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugin-upload</artifactId>
<version>1.0.0</version>
</dependency>
File upload in an action phase
File upload can be handled during an action of a portlet or a servlet:
@Action
@Route("/upload")
public void upload(org.apache.commons.fileupload.FileItem file) {
if (file != null) {
// Handle the file upload
}
}
The @Route annotation is only meaningfull for the servlet bridge. In case of a portlet, the URL
is managed by the portal.
|
File upload in a resource phase
File upload can also be handled in a resource phase.
@Resource
@Route("/upload")
public Response.Content upload(org.apache.commons.fileupload.FileItem file) {
if (file != null) {
// Handle the file upload
}
return Response.ok("Upload is done");
}
Handling upload in a resource phase can be used when the file is uploaded via Ajax: the application does not want a view phase to be triggered after the upload.
Json processing
The Jackson plugin decodes json entities using the Jackson framework. It can decode to a Jackson native tree or perform mapping to Java object using Jackson mapper.
The plugin can be used in your Maven build using a simple dependency:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugin-jackson</artifactId>
<version>1.0.0</version>
</dependency>
Decoding to a Json tree
@Action
@Route("/post")
public void post(com.fasterxml.jackson.databind.JsonNode tree) {
...
}
Decoding to a Java object
Jackson provides a powerful mapper for creating java objects from Json documents, it can of course be used with this plugin.
@Action
@Route("/post")
public Response.View action(@Jackson MyObj obj) throws IOException {
...
}
The obj
argument mapped to the java objects must be annotated with the @juzu.plugin.jackson.Jackson
annotation
so the unmarshaller can recognize it.
Controller classes
Controller methods belongs to Java classes known as controller classes. Controller classes are ordinary java classes, any class can be turned into a controller by declaring a controller method. Controller classes are registered in the IOC container of the Juzu application, we will study later the benefits.
Controller life cycle
We will study in this section the complete life cycle of a controller object. Juzu relies on the IOC container
for managing the life cycle of controller objects, based on the @javax.inject.Inject
annotation. If the
controller desires, it can receive life cycle callbacks thanks to the @javax.annotation.PostConstruct
and @javax.annotation.PreDestroy
annotations.
Let’s have a look at the complete life cycle of a controller object during a Juzu request:
-
Juzu begins the request, it will need an controller instance for the request and asks the IOC container an instance
-
The IOC container creates a fully operational controller instance in several stesp
-
It gets a controller object instance either by creating a new instance by using the default constructor or the constructor annotated with @Inject
-
It injects the controller declared dependencies by the @Inject annotation
-
It invokes any method annotated with @PostConstruct
-
-
Juzu obtains a valid controller instance and that method on the controller
-
After the invocation, Juzu releases the controller instance and delegates it to the IOC container again
-
It invokes any method annotated with @PreDestroy
-
It makes the instance available to the garbage collector
-
-
Juzu ends the request and use the Response objet returned by the controller method
Request lifecycle
The bare minimum Juzu will do when dispatching to a controller method is to invoke this method with the proper arguments and use the optionally returned object as a response for the request.
When the controller wants to deal with the dispatch in a generic manner (i.e detyped), it can implement the
juzu.request.RequestLifeCycle
interface that allows to:
-
Be aware of the request life cycle around (i.e before and after) the controller method dispatch
-
Control the response for the current request
public interface RequestLifeCycle {
/**
* <p>Signals to the controller that a request begins. During the invocation of this method,
* if a {@link juzu.Response} is set on the request context, the request will be considered
* as terminated.</p>
*
* <p>When this method throws a runtime exception, a {@link juzu.Response.Error} response will
* be set on the request context, thus terminating the request.</p>
*
* @param context the request context
*/
void beginRequest(RequestContext context);
/**
* <p>Signals to the controller that a request ends. During the invocation of this method,
* the response set during the dispatch of the request is available via the
* {@link juzu.request.RequestContext#getResponse()} method, this method is free to override
* it and provide a new response instead.</p>
*
* <p>When this method throws a runtime exception, a {@link juzu.Response.Error} response
* will be set on the request context, thus terminating the request.</p>
*
* @param context the request context
*/
void endRequest(RequestContext context);
}
-
The
beginRequest
method is invoked before the controller method invocation and theendRequest
is invoked after the controller method invocation. -
The
RequestContext
object provides a read/write access to ajuzu.Response
object that is set with the response returned by the controller method invocation. The controller method can declare no return type and instead set the response directly with theRequestContext#setResponse(juzu.Response)
method. -
When the controller method invocation throws an exception, the
endRequest
method will be invoked with ajuzu.Response.Error
response set on theRequestContext
. -
The
beginRequest
invocation can optionally set of response on theRequestContext
, when it does the dispatch will stop here and the provided response will be the request response. -
The
endRequest
invocation can optionally set a response on theRequestContext
, when it does this overrides the previous response provided during the dispatch to the controller method.
Responses
Each request produces a response object: a subclass of the juzu.Response
class.
Response objects are returned by method processing phases, the class of the object determines the kind of response sent to the client. A response object may carry additional objects such as assets (css or script).
Response object are created thanks to the static factory methods of the juzu.Response
class. The Response
class is abstract and it has several subclasses that form a possible hierarchy of response adapted to the phase
being processed.
Content responses
A content response is a markup or binary data, it can be created with the ok
static method:
public static Response.Content<Stream.Char> ok(CharSequence content) { ... }
It can be used during a view or resource phase to return markup:
@View
public Response.Content index() {
return Response.ok("Hello World");
}
Render response
A render response extends a content response, it specializes it for aggregated markup, i.e a response where the application manages only one portion of the full page such as a portal:
@View
public Response.Content index() {
return Response.ok("Hello World").withTitle("The Hello");
}
Response mime type
The response mime type can be set on using the response properties with PropertyType.MIME_TYPE
property:
@View
public Response.Content index() {
return Response.ok("Hello World").with(PropertyType.MIME_TYPE, "text/html");
}
This can also be achieved with the @MimeType
annotation:
@View
@MimeType("text/html")
public Response.Content index() {
return Response.ok("Hello World");
}
or the MimeType.HTML
can be used as a shortcut:
@View
@MimeType.HTML
public Response.Content index() {
return Response.ok("Hello World");
}
JSON response
Producing a JSON response can done using the _Jackson+ plugin. It can encode a native JsonTree or an object using the Jackson mapper. The plugin can be used in your Maven build using a simple dependency:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugin-jackson</artifactId>
<version>1.0.0</version>
</dependency>
View response
View response is returned after the action phase to configure the next view phase. Usually view responses are not created directly using static factory methods, instead they are created using controller companion static methods, this is explained in the controller chapter.
Redirect response
Redirect responses are returned during an action phase to redirect the user agent to an URL, its usage is simple:
@Action
public Response.Redirect process() {
return Response.redirect("http://www.host.com/");
}
Error response
Error response can be returned during any phase to signal an application error. This kind of response is different from a content response with a 5xx status code, however it can be turned into a 5xx response to the client.
@View
public Response index() {
try {
...
} catch(IOException e) {
return Response.error(e);
}
}
An error response can also be generated by the controller method by declaring the exception in its throw clause, so the previous example is equivalent to:
@View
public Response index() throws IOException {
...
}
Bridges
The bridge is the runtime in which Juzu executes, until now Juzu provides two bridges:
-
The servlet bridge executes a Juzu application in a servlet container like Tomcat
-
The portlet bridge executes a Juzu application in a portlet container inside a portal
Servlet bridge
The servlet bridge exposes a Juzu application as a servlet in a Servlet Container.
Juzu servlet
The first step for using the servlet bridge is to configure the juzu.bridge.servlet.JuzuServlet
servlet for
the application. There is a one to one mapping between a Juzu application and a Juzu servlet. Therefore
if you project contains several applications, you should configure a Juzu servlet for each.
Servlet configuration
Declaring a Juzu servlet is done in the web.xml file of the web application or using annotations. Annotation based is described in the Servlet plugin chapter.
<servlet>
<servlet-name>JuzuServlet</servlet-name>
<servlet-class>juzu.bridge.servlet.JuzuServlet</servlet-class>
<init-param>
<param-name>juzu.app_name</param-name>
<param-value>my.application</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JuzuServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
The juzu.app_name init parameter tells Juzu the package of the application to use. The servlet is bound on the / pattern as the default servlet of the web application.
In case of several applications, each can be configured with a path mapping in addition of the default servlet:
<servlet-mapping>
<servlet-name>JuzuServlet</servlet-name>
<url-pattern>/myapplication/*</url-pattern>
</servlet-mapping>
Any other kind of url-pattern than the default servlet (/) or path mapping is not supported and will raise an error during startup. |
Portlet bridge
The portlet bridge exposes a Juzu application as a portlet in a Portlet Container.
Juzu portlet
The first step for using the portlet bridge is to configure the juzu.bridge.portlet.JuzuPortlet
portlet for
the application. There is a one to one mapping between a Juzu application and a Juzu portlet. Therefore
if you project contains several applications, you should configure a Juzu portlet for each.
Portlet configuration
Declaring a Juzu portlet is done in the portlet.xml file of the portlet application:
<portlet>
<portlet-name>JuzuPortlet</portlet-name>
<display-name xml:lang="EN">Juzu Portlet Application</display-name>
<portlet-class>juzu.bridge.portlet.PortletBridge</portlet-class>
<init-param>
<param-name>juzu.app_name</param-name>
<param-value>my.application</param-value>
</init-param>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>Portlet Application</title>
</portlet-info>
</portlet>
The juzu.app_name init parameter tells Juzu the package of the application to use.
Bridge configuration
Bridge can be configured via the the servlet context parameters of the web application or the servlet/portlet init parameters:
Parameter | Name | Description | Scope | Bridge | Interpolation |
---|---|---|---|---|---|
Application name |
juzu.app_name |
application package name |
init param |
servlet/portlet |
none |
Run mode |
juzu.run_mode |
prod, dev or live |
context param |
servlet/Portlet |
system properties |
Request encoding |
juzu.request_encoding |
charset name for decoding post requests |
init param |
servlet |
system properties |
Injection container |
juzu.inject |
injection container name |
init param/context param |
servlet/portlet |
none |
When interpolation occurs, the interpolation format allows to define a default value when the value cannot be resolved:
<context-param>
<param-name>juzu.run_mode</param-name>
<param-value>${my_run_mode:prod}</param-value>
</context-param>
Inversion of Control
Juzu provides native support for Injection of Control (known as IOC) and relies on the specification JSR 330 (known as @Inject).
Although the JSR-330 is quite small it provides the necessary ground for building Juzu applications. Juzu relies on the injection container for wiring the entire Juzu runtime (controllers, templates, plugins, etc…).
We will explain how Juzu uses IOC for its runtime, we suppose the reader is familliar with IOC and with the @Inject
specification, in particular the notion of injection, scope and qualifier should be familliar.
Containers
At the moment Juzu supports three containers implementing the JSR 330:
-
Context and Dependency Injection also know as CDI implemented by the Weld project
CDI is a specification that extends the @Inject specification: CDI provides more features than @Inject, however this specification is only implemented by Weld. Nevertheless if your choice is to use CDI you will be leverage its specific features in your Juzu application |
Juzu can run with any of those implementation and leaves you the choice of the IOC implementation you want to use. The container to selection is done via the servlet context parameter juzu.inject:
-
guice for Google Guice
-
spring for Spring
-
CDI
-
cdi when the container is provided by the server such as Tomcat configured for CDI or a Java EE server
-
weld when the CDI container is managed by Juzu
-
<context-param>
<param-name>juzu.inject</param-name>
<param-value>spring</param-value>
</context-param>
When no IOC container is specified, Juzu will look for the available implementations and use the first available in the list among Guice, Spring, CDI and Weld. |
Inversion Of Control
Beans
Beans are simply object managed by the IOC container, any bean can be injected other beans:
@java.inject.Inject
Service service;
Scopes
Scopes define how a instances of a bean are managed by the IOC container: for a given bean, shall it be instantiated only one time and shared or shall it instantiated everty time it is required ? that’s the kind of question that scope answers.
Juzu provides 4 scopes to use within your application:
-
@javax.inject.Singleton
scope: a single bean instance is the same for the whole application -
@juzu.RequestScoped
scope: the bean is instantiated once per request -
@juzu.SessionScoped
scope: the bean is instantiated once per session -
@juzu.FlashScoped
scope: the bean is instantiated once per request but is reused if it was instantiated during an action request in the next render request and only in the first one
Qualifiers
Qualifier are designed to distinguish several instances of a same bean. How does a bean differ from another bean ? it’s not really possible to tell, qualifiers simply answer this question, allowing to:
-
distinguish beans based upon the qualifier members
-
configure the bean instance for a particular usage
The JSR-330 specification provides the @Named
qualifier whose purpose is to give a name to a bean, for instance
@Named("john")
@Inject Person john;
@Named("peter")
@Inject Person peter;
Beans in action
Beans are simply the objects managed by the IOC engine. In a Juzu applications we have several kind of beans:
-
Controllers
-
Template
-
Application beans
-
Plugin beans
Template beans
Every template has a corresponding juzu.template.Template
class at runtime. The template class allows
applications to interact with templates, most of the time for creating a controller ok response:
template.ok();
A template bean is always qualified by the @Path
qualifier. The path qualifier is simply the value of the path
relative to the templates package, for instance index.gtmpl is a valid qualifier value. The qualifier allows
to have several Template
instances and distinguish them.
Templates have the @Singleton
scope: a single instance of the template object is created and shared in the IOC
container.
Controller beans
Each controller class is turned into a bean, that’s how controllers can be injected with other beans. As soon
as Juzu finds a class annotated by @View
, @Action
or @Resource
, it is automatically turned into a bean.
Controller have the Request
scope by default: every time a controller instance is required it will be created
for the duration of the request. It is possible to change the scope of a controller by annotating it with another
scope annotation managed by Juzu:
@SessionScoped
public class Controller {
@View
public void index() { }
}
Application beans
Application beans model the custom logic of an application, they are normally injected in controller beans that use them when they process requests. The binding plugin allows an application to declare custom beans that can be used in the application.
POJO bean binding
Binding a Plain Old Java Object (POJO) is a very simple task to accomplish:
@Bindings(@Binding(Mailer.class))
package myapplication;
The bean will be entirely managed by the IOC container, the binding plugin will just declare it in the IOC container. The POJO will be created when needed, for instance when it is inserted in a controller.
public class MyController {
@Inject Mailer mailer;
@Action
public void sendMail(String recipient, String subject, String message) {
mail.send(recipient, subject, message);
}
}
Abstract bean binding
Binding an abstract class or an interface type is also possible with the implementation
member of the @Binding
annotation:
@Bindings(@Binding(value=Mailer.class,implementation=MailerImpl.class))
package myapplication;
Binding with a provider
Sometimes the implementation cannot be created by the IOC container, for instance it may not have a correct
constructor, it can only be retrieved using a factory or it should be configured before being used. For such scenarios
the implementation can specify a class implementing the javax.inject.Provider
interface.
public class ConfiguredMailerProvider implements javax.inject.Provider<Mailer> {
private String email
private String password;
public ConfiguredMailerProvider() {
this.email = System.getProperty("mailer.email");
this.password = System.getProperty("mailer.password");
}
public Mailer get() {
return new MailerImpl(email, password);
}
}
Thanks to the provider, we have a Mailer
provider that returns a MailerImpl
configured before usage.
Scoped binding
The @Binding
annotation provides room for declaring a bean scope:
@Bindings(@Binding(value=Mailer.class,scope=Scope.SINGLETON))
When the scope is not specified, the scope is determined from the bean or implementation that should be annotated with a scope annotation. When it is specified, it overrides the annotation scope the bean could declare.
Qualifying provider
A provider implementation can declare qualifiers on the get
method they implement in order to set the qualifiers
of the returned bean:
public class MailerProvider implements Provider<Mailer> {
@Named("mailer")
public Mailer get() {
return new MailerImpl();
}
}
This is useful for declaring qualifiers on a class that is not annotated by qualifiers, because it is not possible
to declare qualifiers in an @Binding
annotation due to limitations of the Java language.
Provided container
Sometimes a Juzu application needs to run with a provided container, i.e a container whose life cycle is not managed by the framework, allowing Juzu to integratte with existing runtimes.
Provided Spring
A Juzu application can reuse an existing container scoped to a web application. In this case Juzu will create its own container with the provided container as parent, as a result, all beans available in the provided container will be available in the Juzu application.
During the startup of the application, the web application attribute org.springframework.web.context.WebApplicationContext.ROOT
is looked up, this is the provided container when it is not null. Such container is usually created by a Spring servlet
or listener, for example:
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
This usually start the beans declared in the /WEB-INF/applicationContext.xml.
when using a bean from a provided container, you should not declare it with the @Binding annotation or
the bean will be duplicated and you will use the wrong bean instance
|
Provided CDI
Provided CDI is supported since Juzu 0.7.0, it provides an integration managed by the server:
-
in case of a Java EE server, CDI is provided natively.
-
in case of a Servlet Container, the Weld CDI implementation supports the integration in Tomcat or Jetty.
In both case you need to comply to CDI applications rules such as having a beans.xml file in your WEB-INF directory.
Templating
Templating is the View part of a Model View Controlle architecture. We will study in this chapter how the templating system interacts with the Juzu, at compilation time and at runtime, both aspects are very important.
The templating engines
Juzu can use several templating engines, it provides a native template engine as well as the Mustache templating engine. Those engines are not competing, instead they should be seen as alternatives: the native Groovy engine provides the goodness of the Groovy languages, however sometimes some people prefer logic-less templates and Mustache is a template engine they should use. Let’s introduce them briefly.
The native template engine
The native template engine extends the Groovy templating system: it can include snippet of Groovy code or resolve Groovy expressions:
Expressions
Expressions are simply Groovy expressions wrapped with the ${…}
syntax:
The sky is ${color}
Scriplets
Groovy code can also literaly be used with the scriplet syntax: <% … %>
. Within a scriptlet the out
implicit object
can be used for outputting markup:
<ul> <% ["red","green","blue"].each { color -> out.print("<li>The sky is ${color}</li>") } %> </ul>
The scriplet syntax <%= … %>
can also be used:
The sky is <%= color %>
Controller urls
Controller urls is natively supported by the engine, it allows to create controller URL with a short and compact syntax
@{…}
:
<a href="@{index()}">Home</a>
URL expressions can contain parameters and they must be named:
<a href="@{purchase(product=1)}">Purchase</a>
The purchase method refers to a controller method, when the application has several controllers, the controller name can be used to prefix the url expression and remove the ambiguity:
<a href="@{Controller.purchase(product=1)}">Purchase</a>
Under the hood the controller URL syntax uses the controller compagnion for creating the URL: the Controller.purchase(product=1)
will uses the controller compagnion Controller_#purchase(String product)
.
Messages
You can resolve a message in resource bundles in a template with the &{…}
syntax:
<label>&{color}</label> <input type="text" name="color">
When the message is not found, no output will be done. The resource bundle is resolved with the current user locale. The Internationalization section explains resource bundle configuration.
Taglib
#{title value=Hello/}
Tag parameter values
-
can be quoted with simple quotes or double quotes or not quoted at all
-
are transformed to Groovy string, so they can reference variables with the
${…}
syntax
#{title value="${theTitle}"/}
A taglib of predefined tags are explained in the Taglib, the application can also provide Simple tags which are tags made from templates.
Groovy template compilation
During the compilation phase, the native template engine transforms the gtmpl templates into groovy files. Such files are valid Groovy scripts and they need to be compiled sometime into bytecode before execution at runtime. By default there is nothing to do, since Juzu will compile the groovy file when it is needed, however you can compile the templates ahead of time with your build if you want, doing it provides two advantages:
-
since compilation is done before runtime, it will save a bit of time when the template is used since loading a mere class is significanly cheaper than compiling a Groovy template. (note we are talking of a few milliseconds here)
-
if your templates contains Groovy code, this code will be validated before execution, this is probably a more valid reason than the previous one
Maven builds can use the gmaven-plugin to achieve this:
<!-- Precompile the template class in maven (this is optional) -->
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sources>
<fileset>
<directory>${project.build.outputDirectory}</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</fileset>
</sources>
</configuration>
</execution>
</executions>
</plugin>
The Mustache template engine
The Mustache template engine uses logic-less templates based on Mustache.java the Java port of Mustache. Mustache is very easy to use, you can read the documentation, however we will have a quick overview of how it can be used in Juzu:
Using templates
A template as seen by an application is a bean managed by the IOC container.
Template declaration
Applications use a template by injecting a juzu.template.Template
object in its controllers qualified by the
juzu.Path
annotation:
public class Controller {
@Inject
@Path("index.gtmpl") // 1
Template index;
@View
public Response.Content index() {
index.ok(); // 2
}
}
1 | Declares the template path |
2 | Returns a content response from the template |
The @Path
declares the template to use, the value is usually a path relative to the templates
package. The value
can also be absolute like /my/application/templates/index.gtmpl
.
The @Inject
annotation instructs the injection container the inject the template at runtime, so it can be used
by the controller.
The render
method of a template returns a juzu.Response.Content
response which can also be returned
by the controller method.
The juzu.Path annotation is a qualifier annotation managed by the IOC container. It is very much like the
@javax.inject.Named qualifier, but it has a special meaning for Juzu for processing the template.
|
Template reuse
Template can be shared between applications: one application can reuse the templates of another application by using an absolute path value instead of a relative path value:
@Inject
@Path("/my/other/application/templates/index.gtmpl")
Template index;
There are a few things to keep in mind when using external templates:
-
templates will not be compiled by the current application.
-
relative templates references (such as inclusion) are relative to the initial compilation directory, so don’t expect this behavior to be dynamic (since it would break compile time safety).
Type safe parameters
Template type safe parameters brings more type safety in your applications. Templates can declare parameters and they
are made available on a subclass of the juzu.template.Template
class.
Parameters are declared using the taglib support of the native template engine
#{param name=color/} The sky is ${color}.
or the pragma support of the Mustache engine
{{%param color}} The sky is {{color}}.
When the template is declared in a controller, a subclass of juzu.template.Template
can be used:
package weather;
public class Controller {
@Inject
@Path("sky.gtmpl")
weather.templates.sky sky; // 1
@View
public Response.Content index() {
sky.with().color("blue").ok(); // 2
}
}
1 | The weather.templates.sky typed template class |
2 | Use the sky template color parameter |
The weather.templates.sky
class does not exist in the original source but it is available when the application
is compiled because it will be generated by Juzu compiler integration. The sky
templates provides a fluent
syntax to bind parameters: sky.with().color("blue").ok()
.
Expression resolution
When we studied the templating engine syntax but we did not mentioned exactly how expression are resolved.
Single name expressions
Both templating system provides a syntax for resolving single name expressions:
-
${…}
for Groovy -
{{…}}
for Mustache
Resolution is performed against template parameters or bean named with the javax.inject.Named
qualifier.
@javax.inject.Named("color")
public class Color {
public String toString() {
return "red";
}
}
index.with().set("color", "red").ok(); // 1
index.with().color("red").ok(); // 2
1 | Detyped version |
2 | Type safe version |
Compound expressions
Compound expressions are resolved the same way for the first name and the expression resolve will attempt to navigate the rest of the expressions from this object:
-
${weather.color}
for Groovy -
{{#weather}}{{color}}{{/weather}}
for Mustache
@javax.inject.Named("weather")
public class Weather {
private String color;
public Weather(String color) {
this.color = color;
}
public Weather() {
this.color = "red";
}
public String getColor() {
return color;
}
}
index.with().set("weather", new Weather("blue")).ok(); // 1
index.with().color(new Weather("blue")).ok(); // 2
1 | Detyped version |
2 | Type safe version |
Taglib
A tag library is an essential component of a templating system, allowing to enrich a templating by encapsulating reusable programmable logic.
Taglib syntax
Like most taglib syntaxes, Juzu provides two syntaxes for invoking a tag:
#{foo}bar#{/foo}
A tag can also be empty:
#{foo/}
A tag can also be invoked empty with the #{foo/}
syntax.
Include tag
The include tag simply includes a template inside the current template. The inclusion is dynamic and not static, meaning that the content of the included template is not inserted in the calling template, instead when inclusion is performed the control is passed to the included template.
#{include path=dispatched.gtmpl/}
The path attribute determines the template to include, the path value is relative to the templates package.
Decorate / Insert tag
The decorate tag allows the content of the decorating template to wrap the content of the template invoking the tag. The insert tag should be used in the decorating template to specify the place where to insert the markup produced by the template to decorate.
#{decorate path=box.gtmpl/}
<div style="border: 1px solid black"> #{insert/} </div>
Title tag
The title tag specifies a title to insert in the juzu.Response.Content
object the template will produce.
#{title value=Home/}
Param tag
The param tag enhances the type safety of templates, allowing to declare parameters for executing a template. When such a parameter is declared, the generated template class companion will have a fluent parameter for setting the value of the parameter:
#{param name=color/}
@Inject my.templates.index index;
@View
public Content.Response index() {
return index.with().color("red").ok();
}
Custom tags
Since Juzu 0.7.0, custom tags can be implemented, either as Java class or as templates, we will study both ways in this section.
Java tags
Tags can also be implemented with Java code, let’s look at the actual implementation of the title tag:
public class TitleTag extends TagHandler {
public TitleTag() {
super("title");
}
@Override
public void render(TemplateRenderContext context, Renderable body, Map<String, String> args) throws IOException {
String title = args.get("value");
//
if (title != null) {
context.setTitle(title);
}
//
body.render(context);
}
}
-
The class extends the
juzu.template.TagHandler
abstract class -
The constructor must provide the tag name to the
TagHandler
super constructor -
The tag is rendered with the
render
method
Finally the tag must be declared as a Java Service Provider API which is achieved by having the following content in the META-INF/services/juzu.template.TagHandler file:
juzu.impl.tags.TitleTag # the tag service provider
Simple tags
Simple tags allow creation of custom tags with templates located in the tags
package of your application.
My simple tag
Put this content in the tags/mytag.gtmpl file of the application.
Obviously Juzu needs to be aware of the existence of this tag, this is achieved using the @Tag
/@Tags
annotations:
@Application
@Tags(@Tag(name = "mytag", path = "mytag.gtmpl"))
package my.application;
import juzu.Application;
import juzu.template.Tags;
import juzu.template.Tag;
Simple tags are templates so most of the tag syntax applies here, however there are a few differences between application templates and simple tags:
-
Simple tags are in the tags package instead of the templates package
-
Simple tags cannot reference other templates, the tag syntax must be used instead
Simple tag parameters
Simple tags can have parameters, to access them use the implicit parameters
map property in the tag template.
Hello ${parameters.name}
Simple tag body
Simple tags can have a body that can be evaluated within the tag body using the insert
tag (this tag is also be used
by the decorate
tag).
<foo>#{insert/}</foo>
The body can be evaluated as much as you want, allowing to create loop tags.
Turning a simple tag into a reusable tag
A simple tag is usually an applicative tag, it is also nonetheless a Java tag and it can be reused outside of the
application that defined it. A simple tag can be reused by merely declaring it in a META-INF/services/juzu.template.TagHandler
file. The corresponding Java class to declare is created by concatenating the application package, the tags
name and
the tag name. With the previous example it gives us:
my.application.tags.mytag
Internationalization
Application resource bundle
Juzu allows an application to use a resource bundle.
This feature is supported natively by the Portlet API and its configuration occurs in the portlet.xml file:
<portlet>
<portlet-name>MyPortlet</portlet-name>
...
<resource-bundle>MyBundle</resource-bundle>
...
</portlet>
For the servlet bridge a custom implementation is provided by Juzu at the servlet level:
<servlet>
<servlet-name>MyServlet</servlet-name>
...
<init-param>
<param-name>juzu.resource_bundle</param-name>
<param-value>MyBundle</param-value>
</init-param>
...
</servlet>
If you are using the Servlet plugin plugin, the @Servlet
annotation allows to configure, please refer to the Resource bundle declaration
part.
Bundle injection
When you provide a resource bundle along with your application, the bundle object is available for injection:
@Inject
ResourceBundle bundle;
Template messages
The native template engine supports the resolution of Messages from the resource bundle.
Assets
Web assets are resources used over the web such as stylesheet and script files. Using an asset is done in two steps:
-
declare an asset
-
serve this asset
Asset plugin
The asset plugin provides declarative asset configuration. The @Scripts
and + @Stylesheets+ annotations declares a list
of script and stylesheet assets used by an application.
@Scripts({
@Script(id = "jquery", value = "javascripts/jquery-1.7.1.min.js"), // 1
@Script(
id = "jquery-ui", value = "javascripts/jquery-ui-1.7.2.custom.min.js", // 2
depends = {"jquery", "jquery-ui.css"}) // 3
})
@Stylesheets(
@Stylesheet(id = "jquery-ui.css", value = "ui-lightness/jquery-ui-1.7.2.custom.css") // 4
)
package my.application;
1 | declares the jquery asset |
2 | declares the jquery-ui asset composed of the JavaScript source and its associated stylesheet |
3 | depends on jquery and jquery-ui.css assets |
4 | declares the jquery-ui.css asset |
By default script assets are inserted in the head section of the page, obviously they can also be inserted
in the footer as well by setting the header
value to false:
@Scripts(@Script(alue = "myfooterscript.js", header = false))
package my.application;
Configuring assets
Assets can configured for the application with:
-
an id to reference it within the application
-
a location and value for resolving the asset physical resources which can be empty, a single file or several files
-
a list of dependencies referencing other assets that are needed by the asset
For example, the jQuery-UI plugin could be identified by jquery-ui with the dependency onto the jQuery script and
the jQuery-UI stylesheet. Its physical location would be the asset
package with the jquery-ui-1.4.2.min.js
name.
The asset identifier
Assets are identified by a unique id within the application, this value is however optional. When no id is declared , the asset value is used for creating an id from the asset file name:
-
The value
jquery-ui-1.7.2.custom.min.js
produces the samejquery-ui-1.7.2.custom.min.js
id -
The value
js/jquery-ui-1.7.2.custom.min.js
produces thejs/jquery-ui-1.7.2.custom.min.js
id
Application assets
Applications assets can be located anywhere on the application classpath, they can be either absolute or relatives. Relative
assets declared by the asset plugin must be located in the assets
package of the application, for instance
an application packaged under my.application
will have its relative assets located under my.application.assets
.
@Scripts(@Script("myscript.js"))
package my.application;
The location AssetLocation.APPLICATION
is not declared because it is the default one.
Server assets
Server assets are served by the webserver in which the application is deployed. Relative server assets are served from the war file containing the application.
@Scripts(@Script(value = "myscript.js", location = AssetLocation.SERVER))
package my.application;
External assets
External assets declares an opaque URL for Juzu.
@Scripts(@Script(
value = "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js",
location = AssetLocation.URL))
package my.application;
Minified assets
For performance reasons, assets can be minified: an optimized and trimmed down version of the script or stylesheet is served instead of the original file, because it has a smaller size. Juzu allows to provide a minified version of an asset that will be used in _prod+ run mode.
Ahead of time minification
When an assets is already minified, it can be used in addition of regular asset. This is done via the minified
member of the asset annotation.
@Scripts(@Script(
value = "jquery.js",
minified = "jquery.min.js"))
package my.application;
On-the-fly minification
Juzu can minify assets on the fly by providing a minifier in assets declarations:
@Scripts(@Script(value = "jquery.js"), minifier = NormalizeJSMinifier.class),
package my.application;
The NormalizeJS
minifier is simple minifier that strip the comments out of the asset. This minifier is bundled in
Juzu core. While it does not have a great performance concerning minification, it does not require any external
dependency.
The Closure Compiler
plugin provides a very performant minifier based on Google Closure Compiler library, using
it requires a dependency on the plugin:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugin-closurecompiler</artifactId>
<version>1.0.0</version>
</dependency>
Then it can be used as a minifier:
@Scripts(@Script(value = "jquery.js"), minifier = ClosureMinifier.class),
package my.application;
Asset serving
During a request, asset identifiers are added to the response. At the end of the request, Juzu translates the assets into a list of uri to add to the page.
An asset reference is a link to an asset value that is configured externally, thus an asset of any kind will always resolve to a location and an uri. Let’s examine the different possible asset location:
-
AssetLocation.URL
: the value is opaque to Juzu, for instance the a CDN hosted script such as https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js. -
AssetLocation.SERVER
: the asset is served by the same web server in which Juzu is deployed. If the asset value is relative, the final uri will resolve relatively to the web archive context address. -
AssetLocation.APPLICATION
: the asset is served by Juzu asset server (a servlet configured in the web application) and the resource is located on the classpath.
Asset serving can either be done declaratively with the @Assets
annotation or with methods of the juzu.Response.Content
class.
Declarative asset serving
The Assets
annotation tells Juzu to add an asset to a content response, it takes asset ids as arguments:
@Assets("jquery", "bootstrap")
@View
public Response.Content index() {
...
}
The annotation can be declared on controller methods, classes or packages. such declarations are cascaded to the nested controllers:
Declared on | Effective on |
---|---|
Method |
Controller method |
Class |
Controller methods declared in the class |
Package |
Controller classes declared in the current and sub package and sub |
Those rules apply where the @Assets
annotation occurs, in particular it is also valid for overriden methods.
The overriding method will not use the annotations of its current class or packages unless the method redeclares an @Assets
annotation (possibly empty).
Annotating the application package with #WithAsset
will serve all assets declared in the application for all controllers.
If you need finer grained serving, remove it and use it on controller directly.
The @Assets
annotation can use the wildcard value *
to serve all assets declared in the application:
...
@Application
@Assets("*")
package my.application;
Dynamic asset serving
Declarative asset serving is powerful, however is requires you to declare the asset to server at compilation time. When the application does not know the assets to serve at compilation, this behavior can be also dynamic by using the Juzu API.
@View
public Response.Content index() {
...
return content.withAssets("jquery", "bootstrap");
}
The withAssets
method does exactly the same job than the WithAssets
annotation.
The @Assets annotation and the withAssets method are cumulative.
|
Asset caching
Proper asset caching is important for delivering good front end performance. To implement this, Juzu relies on Cache-Control and ETag http response headers.
When an asset is served, the asset server will set an ETag header hashed from the asset name and the asset last modification date. By default, the server will also set the Cache-Control header to the max-age=3600 value. This value can be modified globally:
@Scripts(@Script(value = "javascripts/jquery-1.7.1.min.js"), maxAge = 1000),
package my.application;
It can also be modified for a specific asset:
@Scripts(@Script(value = "javascripts/jquery-1.7.1.min.js", maxAge = 1000)),
package my.application;
In dev or live mode, asset caching is disabled and the served Cache-Control header is set to no-cache, no-store, must-revalidate.
Asset server
For serving classpath assets, Juzu requires the configuration of the asset server as a servlet declaration:
<servlet>
<servlet-name>AssetServlet</servlet-name>
<servlet-class>juzu.impl.asset.AssetServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AssetServlet</servlet-name>
<url-pattern>/assets/*</url-pattern>
</servlet-mapping>
This declaration should be in the web.xml of the application whether it is a servlet or a portlet application.
If you are using Servlet 3.0, this declaration is not necessary as it will be registered by Juzu dynamically
using a javax.servlet.ServletContainerInitializer
|
Asset manager
When an application is deployed, assets are registered against the asset manager. The asset manager has several responsibilities:
-
manage asset dependencies: the order in which assets are literaly declared when they are served. For instance the jquery-ui asset depends on the jquery asset because the jquery script must be loaded before the jquery-ui script.
-
resolve asset references: each asset reference must be resolved and produce a final web url that will produce the resource when it is resolved by the web browsers
Asset controller
The asset controller is a special controller provided by the asset manager for creating application asset urls at runtime.
It can be injected in any bean and provides two methods:
-
the
byPath
method transforms the path of an asset into a URL served by the asset server-
the asset are served from the
assets
package -
the asset controller can provide URL for any kind of asset, such as an image
-
-
the
byId
method transforms the id of an asset into a URL served by the asset server-
the asset can have any location (application, server or external)
-
the minified asset can be used when running in prod mode
-
@Inject
juzu.plugin.asset.AssetController assetController;
@View
public Response.Content index() {
String jqueryURL1 = assetController.byPath("jquery.js");
String jqueryURL2 = assetController.byId("jquery");
...
}
The asset controller can also be used in templates as it is bound under the Assets
name:
<script type="application/javascript" src="@{Assets.url(path='jquery.js')}"></script>
<script type="application/javascript" src="@{Assets.url(id='jquery')}"></script>
Javascript modularity
The AMD plugin provides declarative support for JavaScript modules using annotations. It relies on the Asynchronous Module Definition specification implemented by the RequireJS project.
Introduction to modules
JavaScript does not provide a natural way for namespacing, the notion of module was designed to solve this problem. This natural lack of namespacing can be perceived as a lack, instead it should be seen as an advantage as modules provide namespacing and more: indeed the module pattern allows to create dependencies between modules and resolve them at runtime enabling on demand and parallel loading of JavaScript resources.
This guide will not explain modules because we haven’t designed a module system for Juzu. Instead Juzu uses the RequireJS library and integrates it. Therefore the best documentation you can read about modules is the RequireJS documentation you can also read the excellent article about modules in depth.
In the essence the notion of module can be viewed as:
-
An identifier
-
A list of dependencies on the modules required by the module to work properly
-
The code packaged usually expressed as a self-executing function
-
The product which is an object produced by the module that is usually consumed by other modules
At runtime the dependency system defines a graph of function to execute, the product of each module being injected in the other modules. It can be seen as a simple dependency injection system able to load modules in an asynchronous and parallel fashion providing parallel loading, namespacing and dependency management.
Declaring a module
The @Modules
and @Module
are used to declare JavaScript modules as defined by the AMD specification:
@Modules(@Module(id="Foo", value="foo.js"))
@Assets("Foo")
package my.application
foo.js
moduledefine("Foo", function() {
return {
text: "Hello"
};
});
Modularity allows to define dependencies accross modules, the @Module
annotation depends
member can be used
for declaring those dependencies. It is not formally require in the client side to define such dependencies as they
are already declared in the JavaScript module itself, Juzu needs to be aware of those dependencies in order to
compute the specific _require.js+ configuration when serving a page.
@Modules({
@Module(id="Foo", value="foo.js"),
@Module(@id="Bar", value="bar.js", depends={"Foo"})
})
@Assets("Bar")
bar.js
moduledefine("Bar", ["Foo"], function(foo) {
return {
text : foo.text + " World"
};
});
The module identifiers declared inside the JavaScript modules must match the identifiers declared in the depends
and id
annotation declarations.
Dependency aliases
Sometimes a dependency id declared by a JavaScript module does not fit the application and it needs to be changed to another value.
For example let’s say that the Foo dependency should be renamed foo in the bar.js
module
bar.js
moduledefine("Bar", ["foo"], function(foo) {
return {
text : foo.text + " World"
};
});
In this case dependency ids can be aliased by the @Module
annotation:
@Modules({
@Module(id="Foo", value="foo.js"),
@Module(id="Bar", value="bar.js", depends={"Foo"}, aliases={"foo")})
})
@Assets("Bar")
The Juzu AMD definition provides dependency aliasing only for JavaScript located at AssetLocation.APPLICATION .
|
Module adapters
The AMD plugin allows to provide custom adapter for adapting JavaScript files to the expected format. It allows to turn non JavaScript files into proper JavaScript modules. Thanks to the adapter feature we can reuse the jQuery without any change:
(function(window, undefined) {
...
})(window);
The main issue with this construct is that it will bind jQuery to the window but most importantly it will not return any value as expected by the dependency system. Thanks to the custom adapter we can integrate it easily:
@Module(
id="jquery",
value="jquery-1.7.1.js",
adapter="(function() { @{include} return jQuery.noConflict(true);})();"
)
of the original jQuery script in the resulting module:
define("jquery", [], function() {
return (function() {
(function(window, undefined) {
})(window);
return jQuery.noConflict(true);
})();
});
The Juzu AMD definition adapts only the JavaScript located at AssetLocation.APPLICATION .
|
Error handling
Juzu provides a central error handling mechanism, allowing to handle error that may occur at runtime in controllers or plugins (entity marshalling/unmarshalling, validation, etc…).
An error handle is a special controller that must implement the Handler<Response.Error, Response>
interface:
import juzu.Handler;
import juzu.Response;
public class ErrorHandler implements Handler<Response.Error, Response> {
@Override
public Response handle(Response.Error argument) {
return Response.content(500, "An error occured");
}
}
The error handler controller must be declared in the @Application
interface:
@Application(errorController = ErrorHandler.class)
The error handler can return any type of response as it is a controller like others, therefore it can also be injected with application beans, templates, etc…
Validation plugin
Juzu provides controller handler parameter validation via the Bean Validation framework.
Controller parameter validation
The usage of Bean Validation for validating method parameters is very easy:
public class Controller {
@View
public Response.Content doSomething(@javax.validation.constraints.NotNull String s) {
return Response.ok("The parameter 's' should never be null");
}
}
When a controller handler
Handling validation errors
When a controller validation fails, Juzu will not call the method however it can invoke other controllers that can
handle the validation error better than the default mechanism. The validation plugin uses the
juzu.plugin.validation.ValidationError
response (which is a subclass of juzu.Response.Error
). The ValidationError
object gives access to the bean violations.
Using request life ycle
When the controller implements the juzu.request.RequestLifeCycle
the endRequest
method will be invoked with the bean
validation error.
@Inject
@Path("error.gtmpl")
Template errorTemplate;
@Override
public void endRequest(RequestContext context) {
Response response = context.getResponse();
if (response instanceof ValidationError) {
ValidationError error = (ValidationError)response;
Set<ConstraintViolation<Object>> violations = error.getViolations();
context.setResponse(errorTemplate.ok());
}
}
See Request lifecycle to learn more about the request lifecycle feature.
this works only with the request lifecycle of the bean that is requested. If you need a more centralalized handler, you can make your controller beans extend the same class and perform the handling at this place or use an application error handler as explained below |
Using error handler
The application error handler can also be used to achieve the same result:
public class ErrorHandler implements Handler<Response.Error, Response> {
@Inject
@Path("error.gtmpl")
Template errorTemplate;
@Override
public Response handle(Response.Error argument) {
if (argument instanceof ValidationError) {
ValidationError error = (ValidationError)response;
Set<ConstraintViolation<Object>> violations = error.getViolations();
argument = errorTemplate.ok();
}
return argument;
}
}
See Error handling to learn more about application error handling.
Less plugin
Juzu Less Plugin
LESS is a dynamic stylesheet language which extends CSS with dynamic behavior such as variables, mixins, operations and functions. LESS is easy to learn thanks to the online documentation.
Juzu provides a LESS plugin that takes care of compiling a LESS stylesheet into a CSS stylesheet which are then served by the Asset plugin. This chapter explains how to use LESS and combine it with the Assets plugin.
Usage
The LESS plugin operates at compilation time only because the only task he has to do is to transform a LESS source code into a CSS stylesheet. The runtime part is usually done by the Asset plugin.
The @Less
annotation annotates a package containing an assets
package. This assets
package should contain
the LESS files to be compiled.
@Less("stylesheet.less")
@Application
package myapp;
import juzu.plugin.less.Less;
The stylesheet.less file will be located in the myapp.assets
package. The assets
child package of the
annotated package should contain the stylesheet, this is done on purpose to coincide exactly with the
assets
package used by the Asset plugin. During the compilation phase the stylesheet.less will be compiled
to the stylesheet.css. If we want this file to be served with the application we simply add the corresponding
@Stylesheets
annotation:
@Less("stylesheet.less")
@Stylesheets({
@Stylesheet(value = "stylesheet.css", location = AssetLocation.CLASSPATH)
})
@Application
package myapp;
import juzu.Application;
import juzu.asset.AssetLocation;
import juzu.plugin.less.Less;
import juzu.plugin.asset.Assets;
import juzu.plugin.asset.Stylesheet;
By default LESS will use a default formatting for the generated CSS. To achieve smaller CSS size, a minify option
can be used, this option will trim the whitespace when processing the file : @Less(value = "stylesheet.less", minify = true)
.
WebJars plugin
WebJars are client-side web libraries (e.g. jQuery & Bootstrap) packaged into jar files. WebJars allow to declaratively set the version, use a consistent version across an application, and easily deal with transitive dependencies.
Juzu provides a WebJars plugin that copies resources in jar libraries to application assets and then served by the Asset plugin or the AMD plugin.
Usage
@Application
@WebJars(@WebJar("jquery"))
package myapp;
import juzu.Application;
import juzu.plugin.webjars.WebJars;
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>1.10.2</version>
</dependency>
The plugin will copy the content of the jquery webjar content to the application assets
directory, they will be available as
any other asset. For this example the jquery/1.10.2/jquery.js and jquery/1.10.2/jquery.min.js files will be
in the myapp.assets
package.
If we want this file to be served with the application we simply add the corresponding @Scripts
annotation:
@Application
@WebJars(@WebJar("jquery"))
@Scripts(@Script("jquery/1.10.2/jquery.js"))
package myapp;
import juzu.Application;
import juzu.plugin.asset.Scripts;
import juzu.plugin.asset.Script;
import juzu.plugin.webjars.WebJars;
You don’t need to specify the WebJar version because the WebJars plugin will find it automatically (by examining the Maven metadata stored in the jar). However some jars have files that don’t correspond to the WebJar version (usually patch releases), in that case you can specify the version to help the plugin find the files:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>angular-ui-bootstrap</artifactId>
<version>0.7.0-1</version>
</dependency>
For this particular version 0.7.0-1 the effective version to use it 0.7.0. This can be achieved by examining the jar:
> cd .m2/repository/org/webjars/angular-ui-bootstrap/0.7.0-1/ > jar -tvf angular-ui-bootstrap-0.7.0-1.jar 0 Fri Dec 06 08:50:36 CET 2013 META-INF/ 125 Fri Dec 06 08:50:34 CET 2013 META-INF/MANIFEST.MF 0 Fri Dec 06 08:50:30 CET 2013 META-INF/resources/ 0 Fri Dec 06 08:50:30 CET 2013 META-INF/resources/webjars/ 0 Fri Dec 06 08:50:30 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/ 0 Fri Dec 06 08:50:34 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/ 230 Fri Dec 06 08:50:30 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/webjars-requirejs.js 51488 Fri Dec 06 08:50:34 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/ui-bootstrap-tpls.min.js 122931 Fri Dec 06 08:50:34 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/ui-bootstrap-tpls.js 40129 Fri Dec 06 08:50:34 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/ui-bootstrap.min.js 109195 Fri Dec 06 08:50:34 CET 2013 META-INF/resources/webjars/angular-ui-bootstrap/0.7.0/ui-bootstrap.js 0 Fri Dec 06 08:50:36 CET 2013 META-INF/maven/ 0 Fri Dec 06 08:50:36 CET 2013 META-INF/maven/org.webjars/ 0 Fri Dec 06 08:50:36 CET 2013 META-INF/maven/org.webjars/angular-ui-bootstrap/ 5217 Fri Dec 06 08:50:26 CET 2013 META-INF/maven/org.webjars/angular-ui-bootstrap/pom.xml 118 Fri Dec 06 08:50:34 CET 2013 META-INF/maven/org.webjars/angular-ui-bootstrap/pom.properties
In this special case, we need to tell the version to the plugin:
@Application
@WebJars(@WebJar(value = "angular-ui-bootstrap", version = "0.7.0"))
package myapp;
Building
Add the WebJars plugin jar to your compilation classpath.
In Maven it can achieved by adding the WebJars plugin dependency to your POM:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugins-webjars</artifactId>
<version>1.0.0</version>
</dependency>
Shiro plugin
The Apache Shiro is a powerful and easy-to-use Java security framework. Juzu provides a Shiro plugin that integrates Apache Shiro core to allow a Juzu application to easily perform authentication and authorization. This plugin works both the servlet bridge and portlet bridge.
Configuration
The Shiro configuration can be loaded from .ini files, to load a INI file to initialize its SecurityManager:
@juzu.Application
@juzu.plugin.shiro.Shiro(config = @juzu.plugin.shiro.Configuration("/shiro.ini"))
package org.sample.shiro;
@juzu.Application
@juzu.plugin.shiro.Shiro(config = @juzu.plugin.shiro.Configuration("/WEB-INF/shiro.ini"), location = juzu.asset.AssetLocation.SERVER)
package org.sample.shiro;
Otherwise the plugin will initialize a DefaultSecurityManager for each applications:
@juzu.Application
@juzu.plugin.shiro.Shiro
package org.sample.shiro;
Authentication
This plugin uses @juzu.plugin.shiro.Login
and @juzu.plugin.shiro.Logout
annotations to declare the controller methods which
perform login or logout. The @juzu.plugin.shiro.Login
configures the username
, password
, rememberMe
parameter names to use
within the application:
@Action
@Login(username="uname", password="pwd", rememberMe="remember")
public void doLogin(String uname, String pwd, String remember, AuthenticationException e)
{
....
}
Then those parameters can be used for doing the programming login:
<form action="@{Controller.doLogin()} method="POST">
Username:<input type="text" name="uname" />
Password:<input type="password" name="pwd" />
<input type="checkbox" name="remember" />Remember Me
<input type="submit" value="Submit" />
</form>
Those paramerers
The plugin will throw an AuthenticationException when authentication failed. Such exception can be caught as corresponding contextual parameter. |
@Action
@Login(username = "uname", password = "passwd")
public Response login(AuthenticationException failure) {
// Authentication failed and we get the failure as a contextual parameter
...
}
Otherwise the AuthenticationException will be thrown as a Juzu error.
Authorization
The plugin uses annotations provided by Apache Shiro to perform
authorization. The @RequiresGuest
, @RequiresUser
, @RequiresAuthentication
can be used on controllers methods. The
@RequiresRoles
and @RequiresPermissions
can be used on controllers methods as well.
@View
@RequiresUser @RequiresRoles("foo")
public void foo(AuthorizationException e) {
...
}
Remember Me
The plugin reuse the CookieRememberMeManager to perform remember subject. Currently, this is only supported for Juzu servlet application as a Portlet environment would not be able to handle it.
@juzu.Application
@juzu.plugin.shiro.Shiro(rememberMe = true)
package org.sample.shiro;
<form action="@{Controller.doLogin()} method="POST">
Username:<input type="text" name="uname" />
Password:<input type="password" name="pwd" />
<input type="checkbox" name="remember" />Remember Me
<input type="submit" value="Submit" />
</form>
@Action
@Login(username="uname", password="pwd", rememberMe="remember")
public void doLogin(String uname, String pwd, String remember, AuthenticationException e)
{
...
}
----
Multiple Realms
The plugin provides an easy way to add extra realms to the current SecurityManager
with the @Ream
annotation. This
allow to implement a custom Shiro AuthorizingReam
:
public class SimpleRealm extends AuthorizingRealm {
@Inject MyServicer service;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
...
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
...
}
}
Such realms are Juzu beans, so they are subject to injection and can be injected any bean within your application.
If the application use Guice
or Spring
, it should use more @Bindinds
to bind the realms.
@juzu.plugin.binding.Bindings(@Binding(SimpleRealm.class))
The realm are declared in the Shiro
configuration.
@juzu.Application
@juzu.plugin.shiro.Shiro(realms = {
@Realm(value = SimpleRealm.class, name = "simple"),
@Realm(value = OtherRealm.class, name = "other")
})
package plugin.shiro.realms;
Authz plugin
The Authz plugin provides a lightweight implementation of the javax.annotation.security
annotations @DenyAll
,
@RolesAllowed
and @PermitAll
. Those annotations were originally created for Java EE containers in which authorization
is done based on the current user roles. Juzu implements a lightweight authorization manager that performs access
enforcement based on these three annotations.
Authorization is performed on the user roles, provided by the underlying bridge via the juzu.request.SecurityContext
interface.
The plugin jars needs to be on the classpath of the application:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugin-authz</artifactId>
<version>1.0.0</version>
</dependency>
Granting access to specific roles
The @RolesAllowed
annotation can be used to restrict the access to a set of specific roles.
@View
@Route("/admin")
@RolesAllowed("manager")
public Response Response admin() { ... }
Granting access
The @DenyAll
annotation can be used to restrict the access to anyone.
@View
@Route("/admin")
@DenyAll("manager")
public Response Response nevercallme() { ... }
Denying access
The @PermitAll
annotation can be used to grant the access to anyone.
@View
@Route("/admin")
@PermitAll
public Response Response index() { ... }
This annotation is not really useful, however it is implemented by Juzu. Note that the first version of the annotation can only annotated a method and the last version allows also to annotation a class which allows to make all handlers of a controller denied.
Cascading
The security annotations can also be used on controller classes to restrict the access on a the controller handlers.
@RolesAllowed("manager")
public class MyController {
@View
@Route("/admin")
public Response Response admin() { ... }
}
Class scoped declarations can of course be overriden on a per method basis:
@RolesAllowed
declaration on the index
handler@RolesAllowed("manager")
public class MyController {
@View
@PermitAll
public Response index() { ... }
@View
@Route("/admin")
public Response Response admin() { ... }
}
Servlet plugin
The servlet plugin enhance Juzu servlet applications.
Servlet declaration
A Juzu servlet application is managed by a JuzuServlet configured with the application name. Since Servlet 3.0, configuration can be easier thanks to servlet annotations. Juzu leverages this capability and is able to generate a servlet for an application with the juzu.plugin.servlet.Servlet annotation:
@Application
@Servlet("/") // 1
package my.application;
1 | The application url-pattern |
Resource bundle declaration
The @Servlet
annotation allows to declare a resource bundle:
@Application
@Servlet(value = "/", resourceBundle = "MyBundle")
package myapp;
Asset server automatic registration
The jar of the servlet plugin contains a web-fragment.xml that automatically declares the asset servlet simplifying further more the configuration of the application.
Portlet plugin
The portlet plugin enhance Juzu portlet applications.
Portlet class generation
A Juzu portlet application is managed by a JuzuPortlet
configured with the application name. The
@juzu.plugin.portlet.Portlet
annotation can be used to generate a subclass of the JuzuPortlet
that configures
the application name for you, easing the configuration of the portlet.xml corresponding section.
@Portlet
package my;
<portlet>
<portlet-name>MyApplication</portlet-name>
<display-name xml:lang="EN">My Application</display-name>
<portlet-class>myapp.MyPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>My Application</title>
</portlet-info>
</portlet>
The plugin will generate the portlet using the application name with the first letter capitalized and the Portlet suffix.
In our example the my application generates the MyPortlet
class. If you don’t like it you can change the name of the
generated class in the application:
@Portlet(name "MyGreatPortlet")
package my;
<portlet>
<portlet-name>MyApplication</portlet-name>
<display-name xml:lang="EN">My Application</display-name>
<portlet-class>myapp.MyGreatPortlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>My Application</title>
</portlet-info>
</portlet>
Portlet preferences injection
- During the various phase of an application, the current portlet preferences can be injected
-
.Injecting portlet preferences
@Inject javax.portlet.PortletPreferences preferences;
The same restriction defined in the portlet specification applies to the provided preferences object: i.e saving preferences can only be performed during an action phase. |
Resource bundle injection
During the various phase of an application, the portlet resource bundle for the current locale can be injected:
@Inject java.util.ResourceBundle bundle;
This is equivalent of doing:
Locale locale = request.getLocale();
ResourceBundle bundle = portlet.getConfig().getResourceBundle(locale);
This resource bundle can be configured in the portlet.xml deployment descriptor.
Building
Add the Portlet plugin jar to your compilation classpath.
In Maven it can achieved by adding the Less plugin dependency to your POM:
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugins-portlet</artifactId>
<version>1.0.0</version>
</dependency>
Appendix
Maven configurations
Guice for a Servlet Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
</dependencies>
Spring for a Servlet Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
CDI for a Servlet Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
</dependency>
</dependencies>
Guice for an EE Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
</dependencies>
Spring for an EE Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
CDI for an EE Container
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Guice for GateIn Portal
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Spring for GateIn Portal
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
CDI for GateIn Portal
<dependencies>
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-core</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-core</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
</dependency>
</dependencies>