Declare resource
The place to put resource configuration is WEB-INF/gatein-resources.xml file in any deployed web application.
Simple JavaScript resources
<module>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
<scripts>
<name>second_resource</name>
<script>
<name>DEF_script</name>
<path>/def.js</path>
</script>
</scripts>
Above XML element defines two simple resources named first_resource and second_resource wrapping two lists of physical JavaScript files whose paths (relative to the root directory of actual web application) are given in the <path> elements.
We notice that configurations for first_resource and second_resource are different in term of outer tag (<module> vs <scripts>). The two tags <module> and <scripts> determines resource's fetch-mode, a concept that we discuss later.
In addition to resource including local JavaScript files (deployed to the server), there is possibility to define a remote resource holding a single JavaScript file from external world.
remote JavaScript resource
<module>
<name>remote_resource</name>
<url>http:/ /jquery.com/releases/jquery-1.7.1.js</url>
</module>
Extra information on syntax of remote resource could be found in the schema gatein_resources_1_2_1.xsd.
That a resource is remote or local is made transparent to resource controlling in GateIn.
Scope
The sharing ability of resource is characterized by its scope. The three resource scope are SHARED, PORTAL and PORTLET.
-
SHARED: The resource might involve in the rendering of any web page in portal.
-
PORTAL: The resource might involve in the rendering of any web page belonging to a specified portal site.
-
PORTLET: The resource might involve in the rendering of any web page containing window of a specified portlet.
Example of SHARED scope resource
<module>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
<scripts>
<name>second_resource</name>
<script>
<name>ABCXYZ_script</name>
<path>/abcxyz.js
</script>
</scripts>
Example of PORTAL scope resources
<portal>
<name>classic_site</name>
<module>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
</portal>
<portal>
<name>acme_site</name>
<module>
<url>http:/ /abcxyz/foo.js</url>
</module>
</portal>
<portal>
<name>custom_site</name>
<scripts>
<script>
<name>ABCXYZ_script</name>
<path>/abcxyz.js</path>
</script>
</scripts>
</portal>
Example of PORTLET scope resources
<portlet>
<name>first_portlet</name>
<module>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
</portlet>
<portlet>
<name>second_portlet</name>
<module>
<url>http:/ /abcxyz/bar.js</url>
</module>
</portlet>
<portlet>
<name>third_portlet</name>
<scripts>
<script>
<name>ABCXYZ_script</name>
<path>/abcxyz.js</name>
</script>
<script>
<name>ABCXYZT_script</name>
<path>/abcxyzt.js</path>
</script>
</scripts>
</portlet>
Notice: GateIn will not allow name duplication of resources in the same SCOPE, any duplicated scripts or modules will not be added to GateIn managed resources
Fetch Mode
The resource fetch mode indicates how JavaScript code under it is loaded into the browser.
IMMEDIATE
Resource with IMMEDIATE fetch mode is loaded synchronously into browser before the moment where DOMContentLoaded event is fired
Resources with IMMEDIATE fetch mode
<scripts>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
</scripts>
<portlet>
<name>portlet_resource</name>
<scripts>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</scripts>
</portlet>
<portal>
<name>classic_resource</name>
<scripts>
<script>
<name>ABCXYZ_script</name>
<path>/abcxyz.js</path>
</script>
</scripts>
</portal>
ON-LOAD
Resource with ON-LOAD fetch mode is loaded asynchronously thanks to the 'async' attribute of <script> element (most of modern browsers support that attribute). JavaScript code not required for HTML rendering could be loaded after DOMContentLoaded event and that increase the HTML displaying speed.
Resources with ON-LOAD fetch mode
<module>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
</module>
<portlet>
<name>portlet_resource</name>
<module>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
</portlet>
<portal>
<name>classic_site</name>
<module>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
</portal>
Dependency
Like artifact dependency model in Maven, GateIn introduces the concept of dependency between JavaScript resources that responds to the requirement of managing loading order of JavaScript code. For each dependency relation, both dependent resource and its dependency are forced to have the same fetch mode.
With such rule on dependency relation, the whole set of JavaScript resources makes up two no-cycled directed graphs. One graph whose vertices are IMMEDIATE resources, and the other consists of ON-LOAD resources.
ON-LOAD resource dependencies example
<module>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
<module>
<name>second_resource</name>
...
</module>
<!-- Notice the element <module> under <depends> -->
<portal>
<name>classic_site</name>
<module>
<depends>
<module>first_resource</module>
</depends>
<depends>
<module>second_resource</module>
</depends>
</module>
<portal>
IMMEDIATE resource dependencies example
<scripts>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</scripts>
<scripts>
<name>second_resource</name>
...
</scripts>
<!-- Notice the element <scripts> under <depends> -->
<portal>
<name>classic_site</name>
<scripts>
<depends>
<scripts>first_resource</scripts>
</depends>
<depends>
<scripts>second_resource</scripts>
</depends>
</scripts>
<portal>
It is important to keep in mind that among the set of SHARED, PORTAL and PORTLET resources, only the SHARED resources are eligible to be dependencies.
Use resource
With configuration in gatein-resources.xml, the _new_resource resource is managed on the server side. Anyway, we need extra work to make its JavaScript code available in the hypertext sent back to client.
Denote a resource available if its JavaScript code takes part in the rendering portal page. GateIn resource controller assures:
-
PORTLET resource is available if rendering portal page contains a window of portlet associated with that resource
-
PORTAL resource is available if rendering portal page belongs to the site associated with that resource
-
As one resource is available, all of its dependencies (either direct or indirect) are made available
Resource could be made available in either declarative or programmatic manner.
Declarative
PORTLET resource
Resource for portlet A
<portlet>
<name>A</name>
<module>
...
</module>
</portlet>
As mentioned previously, the resource configuration is enough to make PORTLET resource available. However, there are two constraints upon PORTLET resource:
PORTAL resource
Resource for classic_site site
<portal>
<name>classic_site</name>
<module>
...
</module>
</portal>
classic_site resource is available in any page from classic_site site.
SHARED resource
The only declarative way to make SHARED resource available is to configure it as dependency (direct or indirect) of available resource.
Direct dependency to make SHARED resource available
<portlet>
<name>A</name>
<module>
<depends>
<module>new_resource</module>
</depends>
</module>
</portlet>
<module>
<name>new_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
Indirect dependency to make SHARED resource available
<portlet>
<name>A</name>
<module>
<depends>
<module>first_resource</module>
</depends>
</module>
</portlet>
<module>
<name>first_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<depends>
<module>second_resource</module>
</depends>
</module>
<module>
<name>second_resource</name>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
Programmatic
JavascriptManager
The single-request object JavascriptManager is an entry to interact with JavaScript stuff in the scope of one HTTP request. The object exposes methods that enables us to make resource available.
org.exoplatform.web.application.JavascriptManager
public void loadScriptResource(String name) //load a SHARED resource
public void loadScriptResource(ResourceScope scope, String name)
During portal page rendering phase, if there is call to loadScriptResource for resource new_resource, the resource will take part in final hypertext.
Example of Groovy template that makes new_resource _available_
JavascriptManager jsmanager = _ctx.getRequestContext().getJavascriptManager();
jsmanager.loadScriptResource("new_resource");
Portlet API
In a particular use case where we need SHARED resources for a portlet window, GateIn provides alternative and better solution using JSR 168/286 API.
Make resource _available_ to portlet via JSR 168/286 API
public void render(RenderRequest req, RenderResponse resp) throws PortletException, IOException {
resp.addProperty("org.gatein.javascript.dependency", "first_resource");
resp.addProperty("org.gatein.javascript.dependency", "second_resource");
}
As we could learn from above code, the work consists of customizing GateIn's two predefined portlet response properties during render phase of portlet.
Loading order
The loading order here refers to the order by which JavaScript code is loaded into the browser of clients.
Script ordering
Loading order of scripts wrapped in a resource is determined by top-to-bottom order of <script> elements. Following configuration ensures that abc.js is loaded before xyz.js, that is crucial in case xyz.js requires abc.js.
<module>
<name>new_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
</module>
Resource ordering
As resource A depends on resource B (either directly or recursively), JavaScript code from resource A is loaded after that from resource B.
<module>
<name>new_resource</name>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
</script>
<script>
<name>XYZ_script</name>
<path>/xyz.js</path>
</script>
<depends>
<module>dependency_resource</module>
</depends>
</module>
<module>
<name>dependency_resource</name>
<script>
<name>UVW_script</name>
<path>/uvw.js</path>
</script>
</module>
Localization
GateIn offers the possibility to link JavaScript code with localization defined in properties/xml files.
<module>
<name>new_resources</name>
<supported-locale>de</supported-locale>
<supported-locale>en</supported-locale>
<supported-locale>fr</supported-locale>
<supported-locale>ru</supported-locale>
<supported-locale>vi</supported-locale>
<script>
<name>ABC_script</name>
<path>/abc.js</path>
<resource-bundle>file_path</resource-bundle>
</script>
</module>
As the server retrieves content of /abc.js, it detects pattern ${key_expression} and replaces matched subsequences with the value from L10n files under file_path whose key is key_expression.
abc.js
weekdays : [
"${weekdays.sun}",
"${weekdays.mon}",
"${weekdays.tue}",
"${weekdays.wed}",
"${weekdays.thu}",
"${weekdays.fri}",
"${weekdays.sat}"
]
At runtime, the content of abc.js depends on the local.
abc.js as locale is fr
weekdays : [
"Lundi",
"Mardi",
"Merdcredi",
"Jeudi",
"Vendredi",
"Samedi",
"Dimanche"
]
Unlike the value of <path> element, the file_path is not required to be in the same web application as actual gatein-resources.xml file. Anyway, the file_path must be visible to the merged class loader of Portal Container.