...

Enriching Portal user experience using Dojo toolkit support in IBM®... Application Developer v8 for IBM® WebSphere® Portal

by user

on
Category: Documents
52

views

Report

Comments

Transcript

Enriching Portal user experience using Dojo toolkit support in IBM®... Application Developer v8 for IBM® WebSphere® Portal
Enriching Portal user experience using Dojo toolkit support in IBM® Rational®
Application Developer v8 for IBM® WebSphere® Portal
Summary:
Learn how to create Portlet applications for Websphere Portal for enhanced user
experience leveraging the powerful UX capabilities of Dojo Toolkit using IBM® Rational®
Application Developer v8. In this article you will explore the various considerations involved
in developing such a dojo enabled portlet for portal run-time, their solutions along with
various useful tips and tricks to help you in portlet project development. You will also find a
walkthrough of various RAD portlet tools which assist you in your overall project
development life cycle.
Introduction:
The paradigm of internet based applications today is shifting mostly towards Web2.0.
The businesses demand exceptional user experience for their customers. Hence the relevance
of applications having Ajax behaviors and client side capabilities is increasing by the day.
Dojo toolkit provides a strong object oriented JavaScript framework, Ajax capabilities and a
rich set of reusable UI widgets. A developer can leverage these capabilities of Dojo toolkit to
quickly create rich, interactive and highly responsive web applications.
The Portal toolkit in IBM Rational Application Developer provides enhanced tooling
support of the Dojo toolkit for portlet projects. It aids the programmers developing
applications for WebSphere Portal with the help of a series of wizards, auto-code generations,
views, editors, drag & drop features etc. The toolkit can also assist you in implementing the
best practices that take care of JavaScript issues in a portal environment like namespacing
issues.
The Architecture of a Web2.0 application:
The modern Web2.0 based applications have a little different architecture than
classical web applications. The clients of a Web2.0 application do much more than just
rendering the view. Unlike normal MVC or MVC2 architecture, the controller of Rich internet
applications is off-loaded to the clients instead of the server. The focus of such applications is
on componentizing a use-case as much as possible by creating rich set of client side UI
components called widgets. These widgets can handle and multiply many tasks like layout
management, client side data validation, client side state saving, DOM manipulation etc. This
approach gives greater client and server independence and in some use-cases has the
advantage that the servers can focus mainly on data generation and manipulation, while
leaving the rendering work to the clients.
Use-case:
Lets start with a simple use-case to create a JSR286 based Dojo enabled portlet project.
The portlet project consists of a single portlet. It displays the continents of the world and some
of their most populous countries in a tree structure. Clicking on a tree node displays the
information about that continent or country in a Data grid (fig.1).
Fig.1
To make the usecase simple, the data for both the Tree and a DataGrid is fetched from
a static JSON file present on server inside a data folder of portlet’s contextroot. The data in a
real world portlet application can be fetched in multiple ways, one of the ways can be through
a serveResource method call of a portlet’s lifecyle, which can delegate its responsibility of
data fetching and processing to a Session bean. Session bean may connect to a database using
JPA. And the database itself can be present on any networked web server.
Dojo toolkit on WebSphere Portal run-time:
Like many JavaScript toolkits Dojo toolkit creates global object namespaces named
dojo, dijit and dojox. Different versions of dojo toolkit do the same. Dojo’s module system
manages the loading of a particular resource based on if it has already been loaded or not.
Hence, if we try to load multiple versions of dojo, only the dojo that is loaded first would be
effective throughout the page. In a portal environment if each portlet try to load its own dojo,
some of the portlets may not work, one because the dojo version loaded earlier may not work
for a portlet loaded after it which is based on a later version of dojo, other reason may be
because each portlet may try to reinitialize djConfig object while loading its own dojo.
Dojo1.1 or later helps resolve this issue through the use of scopeMap which enables
developers to provide their custom namespaces for dojo, dijit and dojox. However usage of
scopeMap has few known issues, also loading of multiple versions of dojo toolkit in a portal
page, may cause serious performance degradations. To avoid these issues, it is recommended
to load dojo once from inside a portal theme and all the portlets should reuse this “already
available” dojo. Interestingly all the standard WebSphere Portal themes comes with bundled
dojo, and also initializes dojo for a page. Hence a portlet developer can make use this
capability to create dojo based Web2.0 portlets.
Creating the Sample Portlet project
To create this application, start with creating a portlet project having Dojo Toolkit on
WebSphere Portal capability enabled. To achieve this execute the following steps:
1- From File menu Select New > Portlet Project.
2- Select WebSphere Portal 6.1 or WebSphere Portal 7.0 as the target run-time.
3- Select Configuration as JSR286 basic (fig.2).
4- Click on the Modify… for Web 2.0 Features .
5- Select Dojo toolkit in the “Modify Portlet Project Web 2.0 features dialog” (fig.2).
6- Click OK.
Fig.2
7- Click Next >
8- Again Click Next >
9- Uncheck the “Add action listener to portlet to handle action requests” (fig.3), since we
want to generate a plain JSP.
Fig.3
10- Click Finish.
This will generate a portlet project with the structure as shown in fig 4, which has been
enabled to make use of Dojo toolkit available on the WebSphere Portal server run-time.
Fig.4
Developing the Dojo use-case in Portlet jsp
Now that we have created the Portlet project we would develop the sample so that the
Portlet jsp contains the dojo widgets.
Open the Portlet jsp.
Open the Palette view. It should have Dojo drawers (see fig.5) populated with the dojo
widgets present in the WebSphere Portal 6.1 or WebSphere Portal 7.0 server run-time
(based on the run-time you selected during project creation).
Fig.5
We would want to show both Tree and DataGrid side by side in our portlet view (see fig.
1). Hence we will divide the portlet view in two vertical panes, left and right. The left pane
will contain tree while the right pane will contain the Data grid showing the details of the
selected continent or country. Dojo Layout containers provide the facility for easy crossbrowser layout management.
To use the Layout container in the portlet view, execute the following steps:
1- Open the Dojo Layout Widgets drawer from the palette view.
2- Drag and drop the BorderContainer widget onto the portlet jsp.
Since this is a very first time we dnd a dojo widget on portlet jsp, there would be a Dojo
Settings dialog shown. This dialog helps us generate a project specific JavaScript
namespace and portlet helper JavaScript code which enables us in writing the logic
corresponding to a portlet view in external JavaScript file. The generated code would also
be grouped in some distinct files so that the same code can be reused among multiple files
across multiple portlets of the project.
Select the following configuration in the Dojo Settings For Portlet Project dialog (see fig,
6):
1- Leave the Generate in external .jspf file along with the file path as is. (This jspf file
will have the JavaScript logic for parsing the dojo widgets. This file will then be
included in the portlet jsp using jsp include tag. Multiple portlets can include this file
without a need to rewrite the same logic again and again.
2- Leave the Generate portlet helper JavaScript classes in portlet application checkbox
selected.
3- Enter the Namespace for JavaScript classes as com_ibm_portlet_dojo.
Fig.6
Best Practice: Since a portlet is just a fragment that gets aggregated on a portal page, a
portlet which creates variable names in global namespace, may collide with the variables
of the same names in some other portlet present on the same portal page. To avoid this
issue we should make sure that we instantiate all of the JavaScript variables for our portlet
inside a unique namespace. Hence we keyed-in a fully qualified namespace prefix in the
dialog.
Tip: We could have also provided this namespace prefix using the dot notation like
com.ibm.portlet.dojo, but some of browsers are very slow in finding an object from inside
this nested namespace on run-time. In-fact the lesser the cascading (nesting), better would
be the performance in executing your JavaScript code. For this reason we use an
alternative yet better performing fully qualified namespace.
4- Click OK.
The following artifacts (see fig.7) will be generated after this operation:
Fig.7
Here is the description of the artifacts that get created
1- A folder named js inside the context root of the portlet application
2- A folder named com_ibm_portlet_dojo inside the js folder
3- The folder com_ibm_portlet_dojo contains one Portlet.js file, which has two
JavaScript class declarations, one named com_ibm_portlet_dojo.Portlet and another
named com_ibm_portlet_dojo.PortletHelper. The class
com_ibm_portlet_dojo.Portlet helps us initialize our commonly used jsp variables
like portlet namespace, contextpath etc. inside a JavaScript variable so that these can
be used inside any external JavaScript file, through that JavaScript variable. This class
also provides few functions for accessing namespaced elements in a portlet DOM.
Another class com_ibm_portlet_dojo.PortletHelper just keeps a reference of
com_ibm_portlet_dojo.Portlet object. Multiple classes from a portlet can extend this
class to make use of the above object.
4- The folder com_ibm_portlet_dojo also contains one more folder named
portlethelper.
5- The folder portlethelper keeps the JavaScript file of similar names as the portlet view
jsp, which denotes that, this file works like a code behind file to write the custom
JavaScript logic pertaining to a particular jsp. This JavaScript file declares a class
which extends com_ibm_portlet_dojo.PortletHelper, hence it can automatically
make use of the object of class com_ibm_portlet_dojo.Portlet and hence the
variables stored in it.
6- The follwing diagram depicts the relation between the various javascript classes.
7- The dojo_init.jspf file is generated in the context root of the portlet as specified in the
Dojo Settings for Portlet project dialog. This file contains the parsing logic to parse
dojo widgets. This file also registers the namespace com_ibm_portlet_dojo, so that all
the files inside this folder can be loaded using the dojo module loading system by just
having dojo.require(“filename”). Finally it initializes an object of class
com_ibm_portlet_dojo.Portlet.
8- The DojoPortletView.jsp contains the bare minimum code to connect all the above
pieces together.
a. It includes dojo_init.jspf file
b. It imports file com_ibm_portlet_dojo.portlethelper.DojoPortletView.js
using dojo.require
c. Creates an object of the above class and initializes it with
portlet_<portlet:namespace/> object created above in the dojo_init.jspf.
This completes the code externalization and portlet helper code generation. Remember we
Drag and drop BorderContainer dojo widget on the portlet jsp. Hence the declarative
markup for this widget is also generated along with its dojo.require
(“dojit.layout.BorderContainer”) statement.
The WebSphere Portal 6.1 and above themes by default have djConfig.parseOnLoad set
to false due to performance reasons. Hence if we only place the declarative widget markup
in the portlet jsp, these widgets would not be parsed after the portlet finishes its loading.
To solve this scenario a root widget container with id
widgetContainer_<portlet:namespace/> is generated, which contains all of our
declarative widgets. The code inside dojo_init.jspf parses this root widget container
which runs after the portlet finishes loading its markup and required resources.
Now drag & drop ContentPane widget from Dojo Layout Widgets category twice
over the BorderContainer widget that was added to the Portlet jsp earlier.
The complete code should read like this
<div dojoType="dijit.layout.BorderContainer" id="borderContainer_<portlet:namespace/>"
design="headline" style="height: 500px; width: 1000px">
<div dojoType="dijit.layout.ContentPane" region="left" style="width: 300px"></div>
<div dojoType="dijit.layout.ContentPane" region="center"></div>
</div>
The above code basically creates a BorderContainer with two content panes. One
which resides in left and the other one that resides in center
Now we need to insert Tree and DataGrid in the left and center pane of the
BorderContainer respectively. Both the widgets are databound widgets. We would use
ItemFileReadStore and ItemFileWriteStore as local stores which fetch data from the
server. To achieve this execute the following steps:
1- Copy the countries.json and population.json files to a data folder inside WebContent
folder of the portlet project.
2- Insert ItemFileReadStore inside the widgetContainer with the url attribute
<div dojoType="dojo.data.ItemFileReadStore"
jsId="countriesStore_<portlet:namespace/>"
url='<%=renderResponse.encodeURL( renderRequest.getContextPath() + "
datacountries.json" ); %>'>
</div>
3- Insert dojo.require(“dojo.data.ItemFileReadStore”); inside a script tag.
4- Drag & Drop a dijit Tree widget from inside a Dojo Application Widgets drawer onto
the portlet jsp inside the “left” content pane.
5- Set the store of the tree as the ItemFileReadStore declared above.
6789-
<div dojoType="dijit.Tree" id="tree_<portlet:namespace/>"
store="countriesStore_<portlet:namespace/>" query="{type:'continent'}"
labelAttr="name" label="Continents"></div>
Run the application on server.
The application should show a tree in the left pane of the border container.
Now Open the portlet jsp.
Insert ItemFileReadStore inside the widgetContainer with the url attribute
<divdojoType="dojo.data.ItemFileReadStore"jsId="populationStore_<portlet:namespace/>"
url='<%=renderResponse.encodeURL( renderRequest.getContextPath() + "/data/
population.json" ); %>'></div>
10- Drag & drop the Dojo Data Gridwidget from the DojoX Widgets drawer (it might be
present in Dojo Data Widgets drawer) onto the portlet jsp inside the “center” content
pane..
11- Uncheck the Generate JavaScript to populate the grid.
12- Add the Heading labels and corresponding JavaScript properties as shown in the image
below.
Fig.8
13- Press Finish.
14- The markup for the widget along with its dojo.require(“dojox.grid.DataGrid”)
statement and required CSS files is inserted in the portlet jsp.
15- Now we would need to show the data inside grid on the selection of a row in the Tree.
16- To achieve this, insert the following code, inside the tree markup
<script type="dojo/method" event="onClick" args="item">
portletHelper_<portlet:namespace/>.updateGrid(item);
</script>
17- To separate the concerns of designing the portlet and providing business logic for it,
we should generally delegate the responsibility of writing all the business logic of this
portlet jsp to the DojoPortletView.js. Which is what we have done in the code above,
instead of providing the inline code, we have cleanly put that out to the
DojoPortletView.js.
18- Now we would need to create a function inside the DojoPortletView.js with the name
updateGrid. Make sure to put comma ‘,’ after every function declaration except the last
one.
19- Write the logic inside the function:
//update the grid on the selection of a node of tree
updateGrid : function(args){
//get the countriesStore object
var countriesStore = this.portlet.getObject("countriesStore");
//get the name of the selected row in the tree
var name = countriesStore.getValue(args, "name");
//get the populationStore object
var populationStore = this.portlet.getObject("populationStore");
//callback handler for fetch method.
var gotItems = dojo.hitch(this,function(items, request){
var item = items[0];//since id is unique, only one row should return
//get the name and population
var name = populationStore.getValue(item,"name");
var type = populationStore.getValue(item,"type");
var population = populationStore.getValue(item,"population");
var data = new dojo.data.ItemFileWriteStore( {data: {identifier:'name', items:
[]} } );
data.newItem({name:name, type:type, population: population});
});
var grid = this.portlet.byDijitId("dataGrid");
grid.setStore(data);
//fetch data from the population store depending upon the query.
populationStore.fetch({query: {name: name} , onComplete:gotItems});
}
20- Notice the usage of this.portlet.getObject and this.portlet.byDijitId functions used in it.
We can directly access the namespaced JavaScript or Dijit objects inside this class,
without need to worry about providing the namespaces attached to them.
21- Also notice the use of dojo.hitch. dojo.hitch(context, function(){}) function binds the
function to a context, which is very useful for the time when your function is meant to
run as a callback function. And you would almost always require it, if you write a code
for the callback function in some non-global namespace.
22- Since we have used dojo.data.ItemFileWriteStore in our logic, we would need to add a
dojo.require(“dojo.data.ItemFileWriteStore”) in this JavaScript file prior to the class
declaration.
23- Run the portlet application again on server.
24- You should see the working application.
25- Clicking on a node in tree instantaneously updates the data on the grid.
Debugging the portlet application:
Firebug plugin for Mozilla Firefox is an excellent plugin for JavaScript code debugging
which can allow breakpoint setting, run-time value inspection etc.
Since we are reusing the Dojo toolkit loaded by theme, we can’t easily set breakpoints in
our DojoPortletView.js where we have written our code.
Fig.9
To enable proper debugging or to set breakpoints we would either need to change the
djConfig variable of the theme or we can directly replace the dojo.js and dijit.js with their
uncompressed versions like dojo.js.uncompressed.js and dijit.js.uncompressed.js. dojo.js
and dijit.js are generally loaded in the js.jsp file of the theme. If you are using WebSphere
Portal 615, and running the default EnhancedPortalTheme, You can find js.jsp file at
[server installion location]\wp_profile\installedApps\[nodeName]\Enhanced_Theme.ear
\wp.theme.enhancedtheme.war\themes\html\Enhanced\js\js.jsp
After this refresh your browser and you can easily set breakpoints in your
DojoPortletView.js file.
Fig.10
Conclusion:
The article demonstrates how we can easily leverage the UX capabilties provided by the
Dojo toolkit to created Exceptional user experiences for a Portal environment. The article
also demonstrates the tooling capabilities provided by RAD portal toolkit to speed up the
application development while taking care of the best practices.
Fly UP