{"id":7920,"date":"2014-11-20T05:55:43","date_gmt":"2014-11-20T13:55:43","guid":{"rendered":"http:\/\/localhost\/exoblog\/?p=7920"},"modified":"2023-06-05T16:49:42","modified_gmt":"2023-06-05T14:49:42","slug":"developing-juzu-portlets-step-2-viewing-and-posting-secrets","status":"publish","type":"post","link":"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-2-viewing-and-posting-secrets\/","title":{"rendered":"Developing Juzu portlets &#8211; Step 2: viewing and posting secrets"},"content":{"rendered":"<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series.jpg\" alt=\"02-Juzu-tutorial-series\" width=\"650\" height=\"220\" class=\"aligncenter size-full wp-image-7945\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series.jpg 650w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-300x102.jpg 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-500x169.jpg 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-360x122.jpg 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-200x68.jpg 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-100x34.jpg 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/02-Juzu-tutorial-series-70x24.jpg 70w\" sizes=\"(max-width: 650px) 100vw, 650px\" \/><\/a><\/p>\n<p><em>Previous step:<br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/learn-how-to-develop-great-juzu-portlets-for-exo-platform\/\">Learn how to develop great Juzu portlets for eXo Platform!<\/a><\/em><\/p>\n<p>In the <a href=\"https:\/\/www.exoplatform.com\/blog\/learn-how-to-develop-great-juzu-portlets-for-exo-platform\/\">previous blog post, you learned how to start a simple Juzu project and deploy it in eXo Platform<\/a>.<\/p>\n<p>In this blog post, we will start to play with Juzu and add some functionality to our application.<br \/>\n<!--more--><\/p>\n<h2>Introduction<\/h2>\n<p>It\u2019s time to tell you a little bit more about the <strong>JuZcret application<\/strong>.<\/p>\n<p>First of all we have secret. A secret is a <strong>simple message<\/strong> but it can also be enhanced by an <strong>image<\/strong> (to illustrate the secret better).<\/p>\n<p>Our application will manage a list of secrets and display them. Of course any user can also <strong>share<\/strong> their secrets using an <strong>add<\/strong> secret button.<\/p>\n<p>In later steps, we will allow connected users to <strong>like and comment on secrets<\/strong>, but these features are not included in Step 2.<\/p>\n<h2>Create our model<\/h2>\n<p>This does not require any Juzu stuff. We just need to create a <strong>simple Secret bean<\/strong> containing a default constructor with getters and setters.<\/p>\n<p>In the org.juzu.tutorial package, add a new package named models. In this new package, create a <strong>Secret class<\/strong> as below:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/01-model.png\"><img decoding=\"async\" loading=\"lazy\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/01-model.png\" alt=\"01-model\" width=\"270\" height=\"111\" class=\"aligncenter size-full wp-image-7922\"><\/a><\/p>\n<h3>Secret<\/h3>\n<pre class=\"lang:default decode:true \">package org.juzu.tutorial.models;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\npublic class Secret implements Serializable {\n\n   private String message;\n\n   private String imageURL;\n\n   private Date createdDate;\n\n   public Secret() {}\n\n   public String getMessage() { return message; }\n\n   public void setMessage(String message) { this.message = message; }\n\n   public String getImageURL() { return imageURL; }\n\n   public void setImageURL(String imageURL) { this.imageURL = imageURL; }\n\n   public Date getCreatedDate() { return createdDate; }\n\n   public void setCreatedDate(Date createdDate) { this.createdDate = createdDate; }\n}<\/pre>\n<h2>Create our service<\/h2>\n<p>We need to create an application bean to manage all the secrets: the <strong>SecretService<\/strong>!<\/p>\n<p>The SecretService bean will contain all the logic for our application, like getting the list of secrets and adding a secret.<\/p>\n<p>In the <span class=\"navCode\">org.juzu.tutorial<\/span> package, add a new package named services. In this new package, create the interface SecretService and its implementation <span class=\"navCode\">SecretServiceMemImpl<\/span> as below:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/02-service.png\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/02-service.png\" alt=\"02-service\" width=\"306\" class=\"aligncenter size-medium wp-image-7923\"><\/a><\/p>\n<h3>The SecretService interface<\/h3>\n<pre class=\"lang:default decode:true \">package org.juzu.tutorial.services;\n\nimport java.util.List;\n\nimport org.juzu.tutorial.models.Secret;\n\npublic interface SecretService {\n\n    List&lt;Secret&gt; getSecrets();\n\n    void addSecret(String message, String imageUrl);\n}<\/pre>\n<h3>The SecretService implementation<\/h3>\n<p><em>Note: In step 2, we will implement a simple in-memory data-saving implementation for simplicity. Real persistence is only for real aspirant Juzu developers not for rookies \ud83d\ude09 and will be covered later in step 5.<\/em><\/p>\n<pre class=\"lang:default decode:true \">package org.juzu.tutorial.services;\n\nimport org.juzu.tutorial.models.Secret;\n\nimport java.util.Date;\nimport java.util.List;\n\npublic class SecretServiceMemImpl implements SecretService {\n\n    private List&lt;Secret&gt; secretsList;\n\n    @Override\n    public List&lt;Secret&gt; getSecrets() {\n    return secretsList;\n    }\n\n    @Override\n    public void addSecret(String message, String imageUrl) {\n    Secret secret = new Secret();\n    secret.setMessage(message);\n    secret.setImageURL(imageUrl);\n    secret.setCreatedDate(new Date());\n    secretsList.add(secret);\n    }\n}<\/pre>\n<h2>Display secrets<\/h2>\n<p>Now that our SecretService application bean is ready, we would like to use it.<\/p>\n<p>But as before, we first need to declare it. And declaring a custom bean in Juzu is very simple.<\/p>\n<h3>Binding the application bean<\/h3>\n<p>Remember step 1, when I told you about the configuration file for our application named package-info.java.<\/p>\n<p>This Java file is the home for the <strong>package level annotation<\/strong>. This is where we will declare our new application bean. Replace the file <span class=\"navCode\">package-info.java<\/span> with:<\/p>\n<pre class=\"lang:default decode:true \">@juzu.Application\n@Bindings({\n        @Binding(value = org.juzu.tutorial.services.SecretService.class, implementation = org.juzu.tutorial.services.SecretServiceMemImpl.class, scope = Scope.SINGLETON)\n})\npackage org.juzu.tutorial;\n\nimport juzu.Scope;\nimport juzu.plugin.binding.Binding;\nimport juzu.plugin.binding.Bindings;<\/pre>\n<p>In a Juzu application, we can have several kinds of bean: <strong>controllers, templates, plugins and application services<\/strong> (don\u2019t worry, each of these will be covered in a different step).<\/p>\n<p>All these different types of bean are managed by the <strong>container<\/strong>, which means that it is the job of the <strong>IOC container<\/strong> to manage the service lifecycle (instantiation, inject dependencies, \u2026) and to inject them where you need them.<\/p>\n<p>For instance, you can directly inject and use a template in a controller by adding the <strong>@Inject annotation<\/strong> when you declare it:<\/p>\n<pre class=\"lang:default decode:true \">@Inject\n@Path(\"index.gtmpl\")\nTemplate index;<\/pre>\n<p>However, if you want to use a custom bean, like our SecretService, you first need to declare it in the <span class=\"navCode\">package-info.java<\/span> using the <strong>@Binding annotation<\/strong>.<\/p>\n<p>And that\u2019s it. Now we can use the SecretService bean anywhere in our application, simply by using the <span class=\"navCode\">@Inject<\/span> annotation.<\/p>\n<h3>Scoped binding<\/h3>\n<p>It\u2019s time for a lesson! Let\u2019s talk a little bit about <strong>scoped binding in Juzu<\/strong>.<\/p>\n<p>As you can see, we have declared our service as a <strong>singleton<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">scope = Scope.SINGLETON<\/pre>\n<p>By declaring the <strong>service bean<\/strong> as a <strong>singleton<\/strong> in <span class=\"navCode\">package-info.java<\/span>, I have overridden the <strong>scope annotation<\/strong> the bean could declare.<\/p>\n<p>The annotation scope is optional in <span class=\"navCode\">package-info.java<\/span>. If the scope is not specified, it is determined from the bean, which should be annotated with a scope.<\/p>\n<p>For instance, in our case, the following declaration in <span class=\"navCode\">package-info.java<\/span>:<\/p>\n<pre class=\"lang:default decode:true \">@Bindings({\n        @Binding(value = org.juzu.tutorial.services.SecretService.class, implementation = org.juzu.tutorial.services.SecretServiceMemImpl.class, scope = Scope.SINGLETON)\n})<\/pre>\n<p>will give us the exact same result as this declaration:<\/p>\n<pre class=\"lang:default decode:true \">@Bindings({\n        @Binding(value = org.juzu.tutorial.services.SecretService.class, implementation = org.juzu.tutorial.services.SecretServiceMemImpl.class)\n})\nand add in SecretServiceMemImpl the @Singletion annotation:\n@Singleton\npublic class SecretServiceMemImpl implements SecretService {\n\n...\n}<\/pre>\n<p>It\u2019s recommended to add a scope in package-info.java, since it gives more fine-grained control and on opening the file you have a quick overview of the composition of the project.<\/p>\n<h3>Abstract bean binding<\/h3>\n<p>Let\u2019s have another talk, this time about <strong>abstract bean binding<\/strong> in Juzu.<\/p>\n<p>In our example, we need to set the <strong>implementation member<\/strong> of the @Binding annotation because SecretService is an interface.<\/p>\n<p>If an <strong>application bean<\/strong> doesn\u2019t have an interface, then you don\u2019t need to set the implementation member. For instance, in our case, we may directly use this implementation:<\/p>\n<pre class=\"lang:default decode:true \">@Bindings({\n        @Binding(value = org.juzu.tutorial.services.SecretServiceImpl.class, scope = Scope.SINGLETON)\n})<\/pre>\n<p>Ok, that\u2019s enough explanation. Let\u2019s go back to the code.<\/p>\n<h3>Develop the controller<\/h3>\n<p>We already developed the new application bean, SecretService, and we declared it in package-info.java. Now it\u2019s time to use it with a <strong>new controller<\/strong> named <strong>JuZcretApplication,<\/strong> which will allow us to display a list of secrets.<\/p>\n<p>In the <span class=\"navCode\">org.juzu.tutorial package<\/span>, create a new java class JuZcretApplication:<\/p>\n<pre class=\"lang:default decode:true \">package org.juzu.tutorial;\n\npublic class JuZcretApplication {\n\n}<\/pre>\n<p>The <strong>JuZcretApplication controller bean<\/strong> must be the <strong>default controller<\/strong> for our application. Right now we have two controller beans in our project:<\/p>\n<ul>\n<li><span class=\"navCode\">Controller.java<\/span><\/li>\n<li><span class=\"navCode\">JuZcretApplication.java<\/span><\/li>\n<\/ul>\n<p>There is no problem with this. In Juzu, you can <strong>have as many controllers as you want<\/strong>. But (and there\u2019s always a but\u2026), you need to tell Juzu which one is the <strong>default controller<\/strong>.<\/p>\n<p>Guess where we will define this? Yes, <span class=\"navCode\">package-info.java<\/span>!<\/p>\n<p>Open it and just update the <strong>@Application annotation<\/strong> by setting the <strong>defaultController member<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">@juzu.Application(defaultController = org.juzu.tutorial.JuZcretApplication.class)<\/pre>\n<p>To display a list of secrets, our JuZcretApplication controller needs:<\/p>\n<ul>\n<li>The SecretService application bean<\/li>\n<li>A new template able to display a list of secrets<\/li>\n<\/ul>\n<p>Create a new empty template, <span class=\"navCode\">secretWall.gtmpl<\/span>, in the <span class=\"navCode\">org.juzu.tutorial.templates<\/span> package. The <strong>secretWall template <\/strong>will be responsible for <strong>displaying the list of secrets<\/strong>.<\/p>\n<p>Also create another empty template, <span class=\"navCode\">addSecret.gtmpl<\/span>, in the <span class=\"navCode\">org.juzu.tutorial.templates<\/span> package:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/03-templates.png\"><img decoding=\"async\" loading=\"lazy\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/03-templates.png\" alt=\"03-templates\" width=\"197\" height=\"80\" class=\"aligncenter size-medium wp-image-7924\"><\/a><\/p>\n<p>The <strong>addSecret template<\/strong> will be responsible for <strong>displaying the form used to add a new secret<\/strong>.<\/p>\n<p>We need to inject into JuZcretApplication, our application bean and our template beans:<\/p>\n<pre class=\"lang:default decode:true \">package org.juzu.tutorial;\n\nimport juzu.Path;\nimport org.juzu.tutorial.services.SecretService;\n\nimport javax.inject.Inject;\n\npublic class JuZcretApplication {\n\n    @Inject\n    SecretService secretService;\n\n    @Inject\n    @Path(\"secretWall.gtmpl\")\n    org.juzu.tutorial.templates.secretWall secretWall;\n\n    @Inject\n    @Path(\"addSecret.gtmpl\")\n    org.juzu.tutorial.templates.addSecret addSecret;\n\n}<\/pre>\n<p><em>Note: If you get a \u201ccannot resolve symbol\u201d exception after injecting a newly created template, like this:<\/em><\/p>\n<p><em><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret.png\"><img decoding=\"async\" loading=\"lazy\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret.png\" alt=\"04-addSecret\" width=\"393\" height=\"71\" class=\"aligncenter size-medium wp-image-7925\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret.png 393w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret-300x54.png 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret-360x65.png 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret-200x36.png 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret-100x18.png 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/04-addSecret-70x13.png 70w\" sizes=\"(max-width: 393px) 100vw, 393px\" \/><\/a><\/em><\/p>\n<p><em>then you should recompile your project:<\/em><\/p>\n<p><em><\/em><\/p>\n<p><em><\/p>\n<pre class=\"lang:default decode:true \">$ mvn clean compile<\/pre>\n<p><\/em><em><\/em><em><\/em><em><\/em><em>This will generate the Java class associated with this template and consequently fix the \u201ccannot resolve symbol\u201d exception.<\/em><\/p>\n<p>Now we need to create a <strong>new view controller<\/strong>. A view controller is a method with the <strong>@View annotation<\/strong> and is responsible for <strong>providing the markup<\/strong>. @View will use an injected template to create markup. The @View method delegates the rendering to the template.<\/p>\n<p>In our case, we will create a new <strong>view controller<\/strong> responsible for displaying the list of secrets.<\/p>\n<h3>Type safe parameters<\/h3>\n<p>You can declare <strong>parameters<\/strong> in a template that are <strong>directly available to subclasses<\/strong> of the <span class=\"navCode\">juzu.template.Template<\/span> class.<\/p>\n<p>For instance, open <span class=\"navCode\">secretWall.gtmpl<\/span> and add:<\/p>\n<pre class=\"lang:default decode:true \">#{param name=secretsList\/}\nHere is my secret list:\n${secretsList}\n#{param name=secretsList\/} declare the parameter secretsList\n${secretslist} display the parameter secretsList<\/pre>\n<p>Now add the view into JuZcretApplication.java like this:<\/p>\n<pre class=\"lang:default decode:true \">import juzu.Response;\nimport juzu.View;\n\n...\n\n   @View\n   public Response.Content index() {\n       return secretWall.with().secretsList(\"My list of secret\").ok();\n    }<\/pre>\n<p>You see that we can directly set the parameter secretsList declared in the secretWall template via a <strong>generated method <\/strong>named with the <strong>parameter name<\/strong>. For the secretsList parameter <span class=\"navCode\">#{param name=secretsList\/}<\/span>, we have a <span class=\"navCode\">secretsList()<\/span> method that can be used.<\/p>\n<p>Consequently, if you modify the <span class=\"navCode\">secretWall.gtmpl<\/span> template and change the name of the parameter <span class=\"navCode\">secretsList<\/span>, the <strong>compilation<\/strong> of <span class=\"navCode\">JuZcretApplication.java<\/span> will <strong>fail<\/strong>.<\/p>\n<p>Declaring a parameter in the template and using a generated method in the controller are not mandatory. You can simply use a <strong>HashMap<\/strong> to store parameters passed by the controller to the template:<\/p>\n<pre class=\"lang:default decode:true \">@View\npublic Response.Content index() {\n    Map&lt;String, Object&gt; parameters = new HashMap&lt;String, Object&gt;();\n    parameters.put(\"secretsList\", \"My list of secret\");\n    return secretWall.with(parameters).ok();\n}<\/pre>\n<p>But using a <strong>HashMap<\/strong> means that if a <strong>parameter name changes<\/strong> in the template, the controller will continue to <strong>compile without error<\/strong> because of the generic parameter map, and you will only see the error at runtime. To avoid seeing this situation, it\u2019s better to declare parameters in the template and use the generated methods named with the parameter name.<\/p>\n<h3>Default controller method<\/h3>\n<p>One more thing. In Juzu, <strong>index<\/strong> is a special name that <strong>catches any unmatched request<\/strong>. In other words, the method <strong>index()<\/strong> annotated with @View provides the <strong>default markup<\/strong> for our application.<\/p>\n<h3>Integrating with Platform 4.1<\/h3>\n<p>Guys, after this explanation we need to take a break here because I have something to confess.<\/p>\n<p>Today the <strong>official Juzu version<\/strong> supported by <strong>Platform 4.1<\/strong> is 0.6.2. I don\u2019t want to limit you to 0.6.2. I want to let you discover all of the <strong>Juzu features<\/strong> available in version 1.0.0-cr1. To run a Juzu 1.0.0-cr1 portlet properly in Platform 4.1, we need to <strong>override<\/strong> the implementation that comes from the <strong>eXo commons <\/strong>project. If not, we\u2019ll get an unexpected error due to the conflict in the class version. This problem will be fixed as soon we upgrade Platform with the <strong>newest Juzu version<\/strong>.<\/p>\n<p>This is quick and pretty simple. And because we are nice, notice that we created a specific Juzu helloWorld project for you that already contains all the stuff needed to <strong>create a Juzu portlet for Platform 4.1<\/strong>.<\/p>\n<p>So for your next personal project, I advise you to clone this <a href=\"https:\/\/github.com\/juzu\/portlet-tutorial\/tree\/master\/juzu-plf41-helloworld\" target=\"_blank\" rel=\"noopener\">Juzu Platform 4.1 startup project<\/a>.<\/p>\n<p>But in this tutorial, it\u2019s important to understand what happens so you can become a <strong>real Juzu developer<\/strong> ;). That\u2019s why you need to follow this instruction:<\/p>\n<p>In Platform, the services are managed by <strong>eXo container<\/strong>, thanks to provider factory support. A <strong>provider factory<\/strong> provides pluggability for integrating beans that are not managed natively by the <strong>IOC container<\/strong> but need to be integrated inside the container.<\/p>\n<p>For JuZcret to run properly in Platform now, we need to declare a <strong>KernelProviderFactory<\/strong>.<\/p>\n<p>First, we need to create a new file named <span class=\"navCode\">juzu.inject.ProviderFactory<\/span> in <span class=\"navCode\">src\/main\/resources\/META-INF\/services\/<\/span>.<\/p>\n<p>In this file, we just add a line with the implementation class name:<\/p>\n<pre class=\"lang:default decode:true \">org.exoplatform.commons.juzu.KernelProviderFactory<\/pre>\n<p>Notice that it\u2019s important to <strong>keep the name exactly<\/strong> like that above, as this is a workaround to override the implementation that comes from the eXo commons project.<\/p>\n<p>Second, we create the kernel provider factory class. In the <span class=\"navCode\">org.exoplatform.commons.juzu<\/span> package, add a KernelProviderFactory class:<\/p>\n<pre class=\"lang:default decode:true \">package org.exoplatform.commons.juzu;\n\nimport javax.inject.Provider;\nimport juzu.inject.ProviderFactory;\nimport org.exoplatform.container.PortalContainer;\nimport org.picocontainer.ComponentAdapter;\n\npublic class KernelProviderFactory implements ProviderFactory {\n\n    @Override\n    public &lt;T&gt; Provider&lt;? extends T&gt; getProvider(final Class&lt;T&gt; implementationType) throws Exception {\n        final PortalContainer container = PortalContainer.getInstance();\n        if (container == null) {\n            throw new IllegalStateException(\"Not running in the context of a portal container\");\n        }\n        final ComponentAdapter adapter = container.getComponentAdapterOfType(implementationType);\n        if (adapter != null) {\n            return new Provider&lt;T&gt;() {\n                @Override\n                public T get() {\n                    Object service = adapter.getComponentInstance(container);\n                    if (service == null) {\n                        throw new RuntimeException(\"Could not obtain service \" + implementationType + \" from container \" + container);\n                    }\n                    return implementationType.cast(service);\n                }\n            };\n        } else {\n            return null;\n        }\n    }\n}<\/pre>\n<p>The provider calls the <strong>PortalContainer<\/strong> \u2013 an object from the <strong>eXo kernel library<\/strong> \u2013 and delegates finding the managed bean to it. Juzu will use the returned result to <strong>bind to its container<\/strong>. So we need to add the dependency to eXo kernel lib in the POM of our project:<\/p>\n<pre class=\"lang:default decode:true \">&lt;dependency&gt;\n\t&lt;groupId&gt;org.exoplatform.kernel&lt;\/groupId&gt;\n\t&lt;artifactId&gt;exo.kernel.container&lt;\/artifactId&gt;\n\t&lt;version&gt;2.4.x-SNAPSHOT&lt;\/version&gt;\n\t&lt;scope&gt;provided&lt;\/scope&gt;\n\t&lt;exclusions&gt;\n\t\t&lt;exclusion&gt;\n\t\t\t&lt;artifactId&gt;servlet-api&lt;\/artifactId&gt;\n\t\t\t&lt;groupId&gt;javax.servlet&lt;\/groupId&gt;\n\t\t&lt;\/exclusion&gt;\n\t&lt;\/exclusions&gt;\n&lt;\/dependency&gt;<\/pre>\n<p>That\u2019s it. Now our Juzu 1.0.0-cr1 portlet can work on Platform 4.1.<\/p>\n<p>Remember, for your next project, a <a href=\"https:\/\/github.com\/juzu\/portlet-tutorial\/tree\/master\/juzu-plf41-helloworld\" target=\"_blank\" rel=\"noopener\">Juzu Platform 4.1 startup project<\/a> is available.<\/p>\n<h3>Display secrets<\/h3>\n<p><em>Note: We will now <a href=\"https:\/\/community.exoplatform.com\/portal\/g\/:spaces:juzu\/juzu\/wiki\/Develop_Juzu_Portlet_with_JRebel\" target=\"_blank\" rel=\"noopener\">configure our project to use JRebel<\/a>. This will allow hot redeployment of our portlet without restarting the server.<\/em><\/p>\n<p>Recompile the project:<\/p>\n<pre class=\"lang:default decode:true \">$ mvn clean install<\/pre>\n<p>Copy and paste the WAR file (which replaces the old one) in the web app folder of the Platform server as explained in step 1, start the server and open the JuZcret page created in step 1.<\/p>\n<p>It displays a simple message:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/05-message.png\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/05-message.png\" alt=\"05-message\" width=\"650\" class=\"aligncenter size-medium wp-image-7926\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message.png 1280w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-300x188.png 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-1024x640.png 1024w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-768x480.png 768w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-1250x781.png 1250w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-720x450.png 720w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-500x313.png 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-360x225.png 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-200x125.png 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-100x63.png 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/05-message-48x30.png 48w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>What we really want it to do is to get the list of secrets and display it. Not display a single hard-coded sentence.<\/p>\n<p><em>Note: Remember that we have just configured the portlet to use JRebel. So from now on, we <strong>don\u2019t need to restart the server<\/strong> after a modification. We can just rebuild it using mvn clean compile.<\/em><\/p>\n<p>In <span class=\"navCode\">JuZcretApplication.java<\/span>, modify the index method to pass a list of secrets to the secretWall template instead of a string:<\/p>\n<pre class=\"lang:default decode:true \">@View\n public Response.Content index() {\n\treturn secretWall.with().secretsList(secretService.getSecrets()).ok();\n }<\/pre>\n<p>In <span class=\"navCode\">SecretServiceMemImpl.java<\/span>, we will initialize the list with some fake secrets so that we have something to display for our test:<\/p>\n<pre class=\"lang:default decode:true \">import java.util.LinkedList;\n\n...\n\npublic class SecretServiceMemImpl implements SecretService {\n\n  private List&lt;Secret&gt; secretsList;\n\n  public List&lt;Secret&gt; getSecrets() {\n    if (secretsList == null) {\n      secretsList = new LinkedList&lt;Secret&gt;();\n      addFakeSecrets();\n    }\n    return secretsList;\n   }\n\n...\n\n  private void addFakeSecrets() {\n     addSecret(\"Yesterday I said I missed my PL meeting because I have to many work. In fact I was drinking free beer in Barbetta pub\",\n              \"https:\/\/c1.staticflickr.com\/3\/2385\/2345543856_6d0fbafb66_z.jpg?zz=1\");\n     addSecret(\"I have a master degree but I still use Google to calculate 3*8\",\n              \"https:\/\/yy2.staticflickr.com\/7244\/7245177220_3f17ee9fb8_z.jpg\");\n     addSecret(\"I am in relationship for 2 years. He is awesome, powerful and I never go out without him. His name is Linux\",\n              \"https:\/\/fc02.deviantart.net\/fs71\/f\/2009\/364\/9\/d\/christmas_love_by_skubaNiec.jpg\");\n     addSecret(\"I spent 2 hours a day to train my cat to perform a backflip\",\n              \"https:\/\/fc06.deviantart.net\/fs15\/i\/2007\/008\/e\/b\/colour_cat_wallpaper_by_jellyplant.jpg\");\n     addSecret(\"I pretend to be a spy when I go out. In reality my job is to perform photocopy at the embassy\",\n              \"https:\/\/c2.staticflickr.com\/2\/1230\/5108154392_3cc02cac67_z.jpg\");\n   }\n }<\/pre>\n<p>Finally, we need to update the secretWall.gtmpl template to manage the list of secrets passed by the controller and <strong>display all secrets<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">#{param name=secretsList\/}\n\n&lt;ul class=\"secret-wall-list\"&gt;\n&lt;% secretsList.each { secret -&gt; %&gt;\n    &lt;li&gt;\n        ${secret.message}\n    &lt;\/li&gt;\n&lt;% } %&gt;\n&lt;\/ul&gt;<\/pre>\n<h3>Juzu templating<\/h3>\n<p>The <strong>native Juzu template engine<\/strong> extends the <strong>Groovy templating system<\/strong> so we can include <strong>snippets<\/strong> of Groovy code or resolve Groovy <strong>expressions<\/strong>.<\/p>\n<p>In our case, we use Groovy code with the scriptlet syntax <span class=\"navCode\">&lt;% \u2026 %&gt;<\/span> to perform a simple loop for each secret. Then each secret is added within a <span class=\"navCode\">&lt;li&gt;<\/span> tag using Groovy expressions wrapped with the <span class=\"navCode\">${\u2026}<\/span> syntax.<\/p>\n<h3>See the list of secrets<\/h3>\n<p>Next we rebuild our project, refresh the browser, and here is the result:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/06-secret-list.png\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/06-secret-list.png\" alt=\"06-secret-list\" width=\"650\" class=\"aligncenter size-medium wp-image-7927\"><\/a><\/p>\n<p>You\u2019ll see in the server log something like this:<\/p>\n<pre class=\"lang:default decode:true \">JRebel: Reloading class 'org.juzu.tutorial.JuZcretApplication'.\nJRebel: Reloading class 'org.juzu.tutorial.templates.secretWall'.\nJRebel: Reloading class 'org.juzu.tutorial.services.SecretService'.\nJRebel: Reloading class 'org.juzu.tutorial.models.Secret'<\/pre>\n<p>JRebel reloads the classes, which saves us from having to restart the Tomcat server. But keep in mind that it can only reload a class; it can\u2019t renew an object instance. That means that <strong>attributes of created objects<\/strong> stay the same after the class has been reloaded.<\/p>\n<h2>Add a secret<\/h2>\n<p>We are <strong>close to the end!<\/strong> After displaying the secrets, we want to add a new secret.<\/p>\n<p>We already have a service ready with an addSecret method:<\/p>\n<pre class=\"lang:default decode:true \">@Override\n public void addSecret(String message, String imageUrl) {\n\tSecret secret = new Secret();\n\tsecret.setMessage(message);\n\tsecret.setImageURL(imageUrl);\n\tsecret.setCreatedDate(new Date());\n\tsecretsList.add(secret);\n }<\/pre>\n<p>What is missing is a <strong>form to create a new secret<\/strong> and the logic to manage it. This is what we need to do:<\/p>\n<ul>\n<li>Update the gtmpl template for adding a secret.<\/li>\n<li>Update the gtmpl template to display an add secret form.<\/li>\n<li>Create a new view controller to provide markup for creating a secret using the gtmpl template.<\/li>\n<li>Add some logic to switch between the different views and manage the add secret feature.<\/li>\n<\/ul>\n<h3>Template<\/h3>\n<p>We need to add a link in the <span class=\"navCode\">secretWall.gtmpl<\/span> to switch to the add secret form:<\/p>\n<pre class=\"lang:default decode:true \">#{param name=secretsList\/}\n\n&lt;ul class=\"secret-wall-list\"&gt;\n&lt;% secretsList.each { secret -&gt; %&gt;\n    &lt;li&gt;\n        ${secret.message}\n    &lt;\/li&gt;\n&lt;% } %&gt;\n&lt;\/ul&gt;\n&lt;a href=\"#\" role=\"button\"&gt;Share my secret&lt;\/a&gt;<\/pre>\n<p>For now we will keep the href empty. We will come back to it later.<\/p>\n<p>Then we need to update the <span class=\"navCode\">addSecret.gtmpl<\/span> template so we can display an add secret form:<\/p>\n<pre class=\"lang:default decode:true \">&lt;form action=\"#\" method=\"POST\" role=\"form\"&gt;\n\t&lt;h5&gt;Share my secret&lt;\/h5&gt;\n\tMy secret:\n\t&lt;textarea rows=\"3\" name=\"msg\" placeholder=\"Write your secret here\"&gt;&lt;\/textarea&gt;\n\t&lt;br\/&gt;\n\tImage URL:\n\t&lt;input name=\"imgURL\"  placeholder=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/e\/ee\/Karl_Witkowski_-_Secrets.jpg\"&gt;\n\t&lt;br\/&gt;\n\t&lt;button type=\"submit\"&gt;Share&lt;\/button&gt;\n&lt;\/form&gt;<\/pre>\n<p>We keep the values of both href and the action parameters empty. We will come back to these later.<\/p>\n<h3>View<\/h3>\n<p>We need to create a new view controller to provide markup for adding a new secret in <span class=\"navCode\">JuZcretApplication.java<\/span>.<\/p>\n<p>At the beginning of this step, we have already injected the new template, addSecret:<\/p>\n<pre class=\"lang:default decode:true \">@Inject\n@Path(\"addSecret.gtmpl\")\norg.juzu.tutorial.templates.addSecret addSecret;\nNow we need to create the View method addSecretForm():\n  @View\n   public Response.Content addSecretForm() {\n       return addSecret.ok();\n    }<\/pre>\n<p>Go back to <span class=\"navCode\">secretWall.gtmpl<\/span> to update the href of the link and let <strong>Juzu manage it<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">&lt;a href=\"@{JuZcretApplication.addSecretForm()}\" role=\"button\"&gt;Share my secret&lt;\/a&gt;<\/pre>\n<p><strong>Controller URLs<\/strong> are natively supported in the template. So if you change the path for your view, you don\u2019t need to update your template. Juzu will take care of it.<\/p>\n<h3>Action<\/h3>\n<p>In Juzu, application logic processing is implemented via an <strong>action controller<\/strong>, which is a method annotated with @Action.<\/p>\n<p>In <span class=\"navCode\">JuZcretApplication.java<\/span>, let\u2019s create our first action controller. It will be responsible for <strong>creating a new secret<\/strong>:<\/p>\n<pre class=\"lang:default decode:true \">import juzu.Action;\n\n...\n\n   @Action\n   public Response.View addSecret(String msg, String imgURL) {\n        secretService.addSecret(msg, imgURL);\n       return JuZcretApplication_.index();\n    }<\/pre>\n<p>Now go back to <span class=\"navCode\">addSecret.gtmpl<\/span> and update the submit action of the form:<\/p>\n<pre class=\"lang:default decode:true \">&lt;form action=\"@{JuZcretApplication.addSecret()}\" method=\"POST\" role=\"form\"&gt;\n    &lt;h5&gt;Share my secret&lt;\/h5&gt;\n...\n&lt;\/form&gt;<\/pre>\n<p>Now rebuild the project, refresh the browser, and click on the <em>Share my secret<\/em> link to add a new secret:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form.png\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form.png\" alt=\"07-add-secret-form\" width=\"650\" class=\"aligncenter size-medium wp-image-7928\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form.png 1280w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-300x188.png 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-1024x640.png 1024w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-768x480.png 768w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-1250x781.png 1250w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-720x450.png 720w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-500x313.png 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-360x225.png 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-200x125.png 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-100x63.png 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/07-add-secret-form-48x30.png 48w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p><em>Note: After JRebel reloads our project, our portlet may display an error message instead of the expected screen. If this happens, you need to restart the server.<\/em><\/p>\n<h2>Redirection<\/h2>\n<p><strong>An action never produces markup<\/strong>. Instead an action phase is followed by a <strong>view<\/strong> phase that will <strong>return a markup response<\/strong>. Juzu handles this interaction with an http redirection to the next view phase via the <strong>redirect after post <\/strong>pattern.<\/p>\n<p>What\u2019s JuZcretApplication_? It\u2019s a class generated by Juzu via an annotation of JuZcretApplication.<\/p>\n<p>It\u2019s the <strong>companion class<\/strong> of <strong>JuZcretApplication<\/strong> generated by Juzu during the compilation of the project. In Juzu, all controller classes generate a companion class. The companion class has the <strong>same name<\/strong> as the original class appended <strong>with the _ character<\/strong>.<\/p>\n<p>So, after adding a new secret you are <strong>automatically redirected to the secret wall<\/strong> page:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret.png\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret.png\" alt=\"08-share-secret\" width=\"650\" class=\"aligncenter size-medium wp-image-7929\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret.png 1280w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-300x188.png 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-1024x640.png 1024w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-768x480.png 768w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-1250x781.png 1250w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-720x450.png 720w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-500x313.png 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-360x225.png 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-200x125.png 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-100x63.png 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/08-share-secret-48x30.png 48w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>Now we don\u2019t need <span class=\"navCode\">Controller.java<\/span> and <span class=\"navCode\">index.gtmpl<\/span> any more. You can remove both of them. Your project should look like this:<\/p>\n<p><a href=\"\/blog\/wp-content\/uploads\/2014\/11\/09-project.png\"><img decoding=\"async\" loading=\"lazy\" src=\"\/blog\/wp-content\/uploads\/2014\/11\/09-project.png\" alt=\"09-project\" width=\"335\" height=\"608\" class=\"aligncenter size-medium wp-image-7930\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project.png 335w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-165x300.png 165w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-261x473.png 261w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-181x328.png 181w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-130x236.png 130w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-72x131.png 72w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-50x90.png 50w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/11\/09-project-17x30.png 17w\" sizes=\"(max-width: 335px) 100vw, 335px\" \/><\/a><\/p>\n<p>We now have some <strong>interesting features<\/strong> allowing us to interact with our Juzu portlet, but it still has an ugly design\u2026<\/p>\n<p>In the next blog post, <strong>Step 3 \u2013 Building a sexy secret wall<\/strong>, we will <strong>improve the UI<\/strong> of JuZcret to attract many secret users&#8230; (Edit: <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-3-building-a-sexy-secret-wall\/\">&#8220;Step 3: Building a sexy secret wall&#8221;<\/a> is live!)<\/p>\n<p><em>The final source of step 2 is available for <a href=\"https:\/\/github.com\/juzu\/portlet-tutorial\/tree\/step-2\" target=\"_blank\" rel=\"noopener\">downloading on GitHub.<\/a>.<\/em><\/p>\n<p><em>Previous and next steps:<br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/learn-how-to-develop-great-juzu-portlets-for-exo-platform\/\">Learn how to develop great Juzu portlets for eXo Platform!<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-2-viewing-and-posting-secrets\/\">Step 2: viewing and posting secrets<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-3-building-a-sexy-secret-wall\/\">Step 3: Building a sexy secret wall<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-4-adding-likes-and-comments-for-secret\/\">Step 4: adding Likes and Comments for Secret<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-5-saving-secrets-in-the-jcr\/\">Step 5: Saving Secrets in the JCR<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-6-let-the-whole-world-create-new-secrets\/\">Step 6: Let the whole world create new secrets<\/a><br \/>\n&#8211; <a href=\"https:\/\/www.exoplatform.com\/blog\/developing-juzu-portlets-step-7-finishing-the-job-properly-with-unit-test\/\">Step 7: Finishing the job properly with unit test<\/a><\/em><\/p>\n<p><b><a href=\"https:\/\/community.exoplatform.com\/portal\/dw\/\" target=\"_blank\" rel=\"noopener\">Join the eXo tribe<\/a> by registering for the community and get updates, tutorials, support, and access to the Platform and add-on downloads!<\/b><\/p>\n<p><!--begin adv-events--><\/p>\n<div class=\"adv-events\" style=\"background: #476fad;padding: 30px 20px;color: white\">\n<div class=\"media\">\n<div class=\"pull-right\"><a href=\"#\"><br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-6587 alignright\" src=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2014\/02\/how-to-make-the-most-of-eXo-platform41.png\" alt=\"make-the-most-out-of-eXo-platform4\" width=\"161\" height=\"85\"><br \/>\n<\/a><\/div>\n<div class=\"media-body\">\n<h4 class=\"media-heading\">Make the most out of eXo Platform 4<\/h4>\n<p>Register to the next webinar and get a complete overview of what you can do with eXo Platform 4. <strong><a href=\"https:\/\/www.exoplatform.com\/contact-us\/\">Reserve your seat now!<\/a><\/strong><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!--end adv-events--><\/p>\n","protected":false},"excerpt":{"rendered":"Previous step: &#8211; Learn how to develop great Juzu portlets for eXo Platform! In the previous blog post, you learned how to start a simple Juzu project and deploy it in eXo Platform. In this blog post, we will start to play with Juzu and add some functionality to our application.","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[699],"tags":[],"lang":"en","translations":{"en":7920},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/7920"}],"collection":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/comments?post=7920"}],"version-history":[{"count":0,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/7920\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/media?parent=7920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/categories?post=7920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/tags?post=7920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}