www.exoplatform.com - eXo Portal team presents Juzu 1.0 and how to develop nice Juzu portlets for eXo Platform.
eXoers on the Grill aims to provide some incentive & fresh air for our staff in order to constantly re-think our methods, spread good practices, promote some technology or tools, generate ideas, etc... All the teams are invited to contribute by picking up some hot topics of their choice and spread to other teams.
5. JUZU What…?
Copyright 2015 eXo Platform
Juzu is a Web Framework base on MVC
concepts for developing powerful web/portlets
applications
6. But… WHY Juzu ? (Too many MVC web framework?)
Copyright 2015 eXo Platform
7. WHY Juzu ? (Why don’t use existing one)
Copyright 2015 eXo Platform
● All framework target for developing web app
● Too Complex in configuration with XML
● Play framework is simple and good but does not follow JavaEE
standard
Juzu combine idea of Play framework with JavaEE standard
and target for developing both Portlet and Web application.
8. History and technology
Copyright 2015 eXo Platform
● Inspired from Play framework
● Base on MVC concepts
● Modular oriented
● Integrates with IoC frameworks
● Groovy and Mustache template engine
13. Simplicity
Copyright 2015 eXo Platform
@Inject
@Path("index.gtmpl")
Template index;
@View
public Response.Content index() {
return index.ok();
}
<action name="hello"
class="com.tutorialspoint.struts2.HelloWorldAction"
method="execute">
<result name="success">/HelloWorld.jsp</result>
</action>● No more XML
● Use Annotation
14. Typesafe (Detect error at Compile time)
Copyright 2015 eXo Platform
@Inject
@Path("index.gtmpl")
package.template.index index;
@View
public Response.Content index() {
return index.with().location("Ha Noi").ok();
}
@View
public Response.Content more() {...}
#{param name=location/}
You are at ${location}.
<a href="@{Controller.more()}">get more information</a>
15. Typesafe (Detect error at Compile time)
Copyright 2015 eXo Platform
@Inject
@Path("index.gtmpl")
package.template.index index;
@View
public Response.Content index() {
return index.with().location("Ha Noi").ok();
}
@View
public Response.Content more() {...}
#{param name=myLocation/}
You are at ${location}.
<a href="@{Controller.more()}">get more information</a>
compile error
16. Extensibility (Easy to develop and deliver plugin)
Copyright 2015 eXo Platform
public class AjaxService extends ApplicationService {...}
ajax-plugin.jar
org.exoplatform.commons.juzu.ajax.AjaxService
META-INF/services/juzu.impl.plugin.application.ApplicationService
uses the java.util.ServiceLoader discovery mechanism for
finding plugin services
17. How to develop nice
JUZU PORTLET
for eXo Platform
Copyright 2015 eXo Platform
18. Develop Juzu portlet
Copyright 2015 eXo Platform
● Create new Juzu project
● Controller
● Business service and Injector
● Template
● Asset manager
● Plugin: Ajax, WebJar
23. Juzu Controller (simple controller)
Copyright 2015 eXo Platform
public class JuZcretApplication {...}
@View
public Response.Content index() {
return Response.ok("Hello world!!!");
}
@Application(defaultController = org.juzu.tutorial.JuZcretApplication.class)
package org.juzu.tutorial;
package-info.java
24. Juzu Service
Copyright 2015 eXo Platform
public interface SecretService {...}
@Application(defaultController = ...)
@Bindings({
@Binding(
value = org.juzu.tutorial.services.SecretService.class,
implementation = org.juzu.tutorial.services.SecretServiceMemImpl.class
)
})
package org.juzu.tutorial;
package-info.java
public class SecretServiceMemImpl implements SecretService {...}
25. Juzu Service (inject to controller)
Copyright 2015 eXo Platform
public interface SecretService {...}
public class JuZcretApplication {
@Inject
SecretService secretService;
@Inject
@Path("secretWall.gtmpl")
templates.secretWall secretWall;
...
}
@View
public Response.Content index() {
return secretWall.with()
.secretList(secretService.getScretsList()).ok();
}
26. Juzu Template
Copyright 2015 eXo Platform
public class JuZcretApplication {
...
@Inject
@Path("secretWall.gtmpl")
org.juzu.tutorial.templates.secretWall secretWall;
...
}
@View
public Response.Content index() {
return secretWall.with().secretsList("My list of secret").ok();
}
#{param name=secretsList/}
Here is my secret list:
${secretsList}
secretWall.gtmpl
31. Asset manager (@Stylesheet and Less plugin)
Copyright 2015 eXo Platform
Less plugin will take care of compiling automatically the Less file to CSS file during the maven
compilation
<dependency>
<groupId>org.juzu</groupId>
<artifactId>juzu-plugins-less4j</artifactId>
<version>1.0.0-cr1</version>
</dependency>
@Less(@Stylesheet("styles/juzcret.less"))
@Stylesheets({@Stylesheet(value = "styles/my.css")})
@Assets("*")
package org.juzu.tutorial;
package-info.java
38. Internalization and Localization
Copyright 2015 eXo Platform
Juzu support i18n natively in the core. We just need to modify all the labels in all our
templates.
<form action="@{JuZcretApplication.enableComment()}" method="POST" role="form">
<h5>&{label.configuration}</h5>
<input type="checkbox" name="enableComment" <%=enableComment ? "checked" : "" %>/>
&{label.enableComment}
<button type="submit">&{label.save}</button>
</form>
@Inject
ResourceBundle bundle;
Controller.java
template.gtmpl
46. Juzu 1.0 New Features (asset minification)
Copyright 2015 eXo Platform
@Scripts(@Script(value = "jquery.js", minified = "jquery.min.js"))
package my.application;
@Scripts(@Script(value = "jquery.js"), minifier = NormalizeJSMinifier.class),
package my.application;
Juzu allows to provide a minified version of an asset that will be used in prod run mode
@Scripts(@Script(value = "jquery.js"), minifier = ClosureMinifier.class),
package my.application;
On-the-fly minification
Generate minified
version at runtime
47. Juzu 1.0 New Features (asset minification - Less plugin)
Copyright 2015 eXo Platform
In Less plugin: a minify option can be used to minify generated css file.
This option will trim the white-space when processing the file
@Less(@Stylesheet(value = "stylesheet.less", minify = true))
package my.application;
48. Juzu 1.0 New Features (Request parameter type)
Copyright 2015 eXo Platform
@Action
@Route("/login")
public Response login(@Mapped User user) {
...
}
@Action
public Response.Content sum(Integer left, int right) {
...
}
@View
public Response.Content show(@Format("yyyy.MM.dd G 'at' HH:mm:ss z") Date date) throws Exception {
...
}
@View
public Response.Content sum(int[] values) {
...
}
Primary type
Date time
Bean type Multivalued type
49. Juzu 1.0 New Features (JSON Responding - too complex in 0.6)
Copyright 2015 eXo Platform
private Response.Content<Stream.Char> createJSONResponse(final Map<String, String> data) {
return new Response.Content<Stream.Char>(200, Stream.Char.class) {
@Override
public String getMimeType() { return "application/json"; }
@Override
public void send(Stream.Char stream) throws IOException {
stream.append("{");
Iterator<Map.Entry<String, String>> i = data.entrySet().iterator();
while (i.hasNext()) {
Map.Entry<String, String> entry = i.next();
stream.append(""" + entry.getKey() + """).append(":").append(""" + entry.getValue() + """);
if (i.hasNext()) { stream.append(","); }
}
stream.append("}");
}
};
}
}
50. Juzu 1.0 New Features (JSON Responding - very easily in 1.0.0)
Copyright 2015 eXo Platform
@Resouces
public Response.Content getResources() {
JSONObject json = new JSONObject();
parameters.put("key", "value");
…
return Response.ok(json.toString()).withMimeType("application/json");
}
51. Juzu 1.0 New Features (Jackson plugin)
Copyright 2015 eXo Platform
@Action
public void post(com.fasterxml.jackson.databind.JsonNode tree) {
...
}
@Action
@Route("/post")
public Response.View action(@Jackson MyObj obj) throws IOException {
...
}
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.
52. Juzu 1.0 New Features (Jackson plugin - response JSON)
Copyright 2015 eXo Platform
Producing a JSON response can done using the Jackson plugin. It can encode a native JsonTree or
an object using the Jackson mapper.
@View
@MimeType.JSON
@Jackson
public MyObj index() {
return new MyObj("Hello World");
}
@View
@MimeType.JSON
public TreeNode index() {
JsonNodeFactory factory = JsonNodeFactory.instance;
return factory.factory.textNode("Hello World");
}
53. Juzu 1.0 New Features (Validation)
Copyright 2015 eXo Platform
@View
public Response.Content doSomething(@javax.validation.constraints.NotNull String s) {
return Response.ok("The parameter 's' should never be null");
}
Juzu provides controller handler parameter validation via the Bean Validation framework.
54. Juzu 1.0 New Features (Application error handler)
Copyright 2015 eXo Platform
public class ErrorHandler implements Handler<Response.Error, Response> {
@Override
public Response handle(Response.Error argument) {
return Response.content(500, "An error occured");
}
}
@Application(errorController = ErrorHandler.class)
package my.application;
@View
public Response.Content doSomething(@javax.validation.constraints.NotNull String s) {
return Response.ok("The parameter 's' should never be null");
} If validation error
package-info.java
56. Controller method
Copyright 2015 eXo Platform
Controller method must return Response object
@View
public void index() {
index.render(parameters);
}
@View
public Response index() {
return index.ok(parameters);
}
57. Template#render() is removed
Copyright 2015 eXo Platform
use method juzu.template.Template#ok()
@View
public void index() {
index.render(parameters);
}
@View
public Response index() {
return index.ok(parameters);
}
58. RenderContext is removed
Copyright 2015 eXo Platform
If you want to use these context objects:
juzu.request.ApplicationContext
juzu.request.UserContext
juzu.request.SecurityContext
….
Just inject them into controller method
@View
public Response.Content index(ApplicationContext applicationContext,
SecurityContext securityContext, UserContext userContext){...}
60. class *Plugin is renamed to *Service
Copyright 2015 eXo Platform
public class AjaxService extends ApplicationService {...}
ajax-plugin.jar
org.exoplatform.commons.juzu.ajax.AjaxService
META-INF/services/juzu.impl.plugin.application.ApplicationService
ApplicationPlugin
rename to
META-INF/services/juzu.impl.plugin.application.ApplicationPlugin
rename to