 |
December 2006 Archives
Adding Dynamic Faces Support to a jMaki widget
Posted by edburns on December 07, 2006 at 09:09 AM | Permalink
| Comments (1)
In this entry, I show how I added Dynamic Faces support to the Dojo
Inline Editor widget in jMaki.
Background and History
If you've read my blog before, you know that I think JSF is a good
fit for handling the motherhood
and apple pie requirements of web applications. What you may not
know is that jMaki intentionally
leaves the work of satisfying these requirements as an exercise for the
developer. No problem, just use jMaki and JSF together. This is indeed
a valid answer, but there is a subtlety that bears clarification.
When using jMaki + JSF under J2EE 1.4 (the default target audience
for jMaki), you miss out on the following features:
Ability to have the jMaki widget POST back to the faces
page while preserving the JSF view state.
Ability to use jMaki widgets that represent components
that accept user input within an iterating component such as
dataTable.
Ability to attach valueChangeListeners to jMaki
components in the view.
Ability to attach converters and validators to jMaki
components in the view.
Ability to attach action and/or actionListeners to
jMaki components in the view.
These deficiencies stem both from missing features in the built-in
jMaki JSF support and from missing features in JSF 1.1 commonly used
with J2EE 1.4.
The story about jMaki and Dynamic Faces
By using jMaki with Dynamic Faces on top of
JavaEE 5, however, all of these deficiencies can be addressed (with the
exception of the last two, and issues have been
filed
for these features). This section discusses how using jMaki and Dynamic
Faces addresses all of the deficiencies mentioned above.
- Ability to have the jMaki widget POST back to the faces page while
preserving the JSF view state.
-
This is the big one, and it was at the heart of the JavaOne
presentation in which I participated. The lack of this feature in
many Ajax + JSF solutions is what prompted us to title the session,
"Ajax done right". When you do not have the JSF view state, you
cannot do any of the things that JSF does well. Including
the JSF View state in the Ajax transaction is essential.
By using Dynamic Faces to send and receive Ajax transactions from
the browser to the JSF view, the JSF view state is correctly
preserved, allowing the entire JSF lifecycle to be used, including
conversion, validation, events, etc.
- Ability to use jMaki widgets that represent components
that accept user input within an iterating component such as
dataTable.
-
This one is near and dear to Jacob Hookom's heart.
Not only do you need the JSF view state, but you need a way to apply
individual values to an individual components within a composite
component (such as a table or tree). This capability did not exist in
JSF until version 1.2, and Dynamic Faces takes full advantage of it.
- Ability to attach valueChangeListeners to jMaki
components in the view.
This didn't exist in jMaki until issue 3
was fixed. However, even though you can add a valueChangeListener to a
jMaki component now, you still need to preserve the JSF view state in
order for it to ever have a chance of being invoked. Again, Dynamic
Faces is the answer.
Ability to attach converters and validators to jMaki
components in the view.
Ability to attach action and/or actionListeners to
g jMaki components in the view.
As with valueChangeListener, these two need to be first
implemented in jMaki, then they need to be used with Dynamic Faces.
How To
The whole point of jMaki is to put today's hot JavaScript widget
libraries in the hands of Java web application developers. Each widget
library has different ways of doing things, and indeed, each widget
within each library does too. jMaki solves this by having specific
files with each widget. Therefore, adding Dynamic Faces support to each
widget involves making some modifications to the widget specific files.
Currently, the only widgets that have been modified are the Dojo FishEye and Inline Editor, and the Scriptaculous Inplace Editor. This section shows some high
level guidelines for how to add Dynamic Faces support to an arbitrary
jMaki widget.
The widget specific files for a jMaki widget are:
| File Name
|
Purpose
|
| component.css
|
Any CSS style associated with an instance of this widget.
|
| component.htm
|
The markup that will be included in the page an instance of this
widget.
|
| component.js
|
The JavaScript adapter file for this widget. This adapts between
the widget library specific way of doing things and the jMaki server
side framework. This is also the easiest place where Dynamic Faces
support can be added.
|
| widget.json
|
Any name/value pairs that aid in the configuration of an instance of
this widget.
|
In general, you'll probably just need to modify component.js to add
Dynamic Faces support. Please follow Jennifer's Tutorial for how to get
started with jMaki and Dynamic Faces. Once you've done that, you need
to make sure to include the Dynamic Faces taglib and script tag in the
page on which you are using the jMaki widgets.
Syntax highlighting courtesy of http://www.nopaste.com/.
Listing 1, the JSP Page
<%@ taglib prefix="a" uri="http://java.sun.com/jmaki-jsf" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib prefix="jsfExt" uri="http://java.sun.com/jsf/extensions/dynafaces"%> <h2>Editor Using JSF </h2> <f:view> <jsfExt:scripts /> <h:form prependId="false"> <h:dataTable id="table" rows="10" binding="#{ResultSetBean.data}" value="#{ResultSetBean.list}" var="customer"> <h:column> <f:facet name="header"> <h:outputText value="Account Id"/> </f:facet> <h:outputText id="accountId" value="#{customer.accountId}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Customer Name"/> </f:facet> <a:ajax name="dojo.inlineedit" value="#{customer.name}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Symbol"/> </f:facet> <h:outputText id="symbol" value="#{customer.symbol}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Total Sales"/> </f:facet> <h:outputText id="totalSales" value="#{customer.totalSales}"/> </h:column> </h:dataTable> </h:form> </f:view>
Line 4 has the taglib for Dynamic Faces, line 11 uses the scripts
tag. Line 29 has the use of the jMaki ajax component.
Let's take a look at the component.js for the Dojo Inline Edit
widget, before Dynamic Faces support was added.
Listing 2, the component.js before Dynamic Faces is added
dojo.require("dojo.widget.*"); dojo.require("dojo.widget.InlineEditBox"); dojo.require("dojo.event.*"); var container = document.getElementById(widget.uuid); var w = dojo.widget.createWidget(container); w.getValue = function() { return w.textValue; } // add a saveState function if (typeof widget.valueCallback != 'undefined') { w.onSave = function(newValue, oldValue) { // we need to be able to adjust this var url = widget.valueCallback; dojo.io.bind({ url: url + "?cmd=update", method: "post", content: { "value" : newValue }, load: function (type,data,evt) { // do something if there is an error } }); } } w.saveState = w.onSave; jmaki.attributes.put(widget.uuid, w);
On lines 1 - 3 we have the dojo includes: uninteresting. Line 5 of
listing 2 is interesting. The "widget" refererred to is this instance
of this widget in the page. In this case, it's the widget on line 29 of
Listing 1. However, keep in mind that line 29 of listing 1 is inside of
a dataTable, therefore, there will be 10 instances of this widget in the
page, each corresponding to an actual JavaScript object in the
JavaScript VM. Therefore, the value of widget.uuid will be
different for each widget, and will, most importantly, correspond to the
JSF Client Id for the widget in the JSF view. This is important because
in order to address the widget in the JSF view, you need its client
id.
For example, the widget.uuid values for this page happen
to be table:n:j_id_id34 where n is the
numbers 0 to 9.
Returning to line 5 of listing 2, the actual DOM element returned by
the call to document.getElementById is what jMaki renders
based on the content of the component.htm file. For the
dojo inline editor, this file is:
<div id="${uuid}" dojoType="inlineEditBox" class="dInlineEdit">${value} </div>
The jMaki AjaxWrapperRenderer will cause the
component.htm file to be rendered like this in the page
from listing 1.
<div id="table:0:j_id_id34" dojoType="inlineEditBox" class="dInlineEdit">name_0 </div>
Therefore, when line 5 of listing 2 executes, the value of
container is the div element with id
table:n:j_id_id34, where n, of course, is the
current row in the table.
Line 6 of listing 2 uses the dojo createWidget to create
an instance of the inline edit box inside of the container
element.
Lines 14 - 25 of listing 2 declares the JavaScript function that will
be called when the user presses the "save" button in the widget UI.
Now, let's take a look at the changes to component.js necessary to
add Dynamic Faces support, expressed as a diff.
Listing 3, the diffs to component.js to add Dynamic Faces support
--- component-pre-DF.js 2006-12-07 10:32:25.000000000 -0500 +++ component.js 2006-12-07 10:31:19.000000000 -0500 @@ -12,6 +12,16 @@ // add a saveState function if (typeof widget.valueCallback != 'undefined') { w.onSave = function(newValue, oldValue) { + + if (typeof _globalScope.DynaFaces != 'undefined') { + DynaFaces.fireAjaxTransaction(container, + { + execute: widget.uuid, + render: "none", + postBody: widget.uuid + "=" + newValue + }); + } + else { // we need to be able to adjust this var url = widget.valueCallback; dojo.io.bind({ @@ -22,7 +32,8 @@ // do something if there is an error } }); + } } } w.saveState = w.onSave; -jmaki.attributes.put(widget.uuid, w); \ No newline at end of file +jmaki.attributes.put(widget.uuid, w);
The only change is a conditional within the onSave
function. jMaki defines a _globalScope global variable
that allows you to access all things globally defined in the page. It
so happens that the scripts included by virtue of line 11 of listing 1
define a global variable called DynaFaces. This JavaScript
object has all the functions exposed by the Dynamic Faces JavaScript
library. Therefore, you can safely test for the existing of Dynamic
Faces in a page as shown on line 8 of listing 3. If Dynamic faces is
not being used in the page, then the normal jMaki operation of the
widget takes place, as shown on lines 17 - 23 of the diff.
Lines 9 - 14 of listing 3 cause a Dynamic Faces Ajax transaction to
be made back to the JSF page currently being viewed in the browser.
This transaction includes all the view state for the current
f:view. The first argument to
fireAjaxTransaction is the DOM element from which the
transaction should be fired. It is important that this be the DOM
element that corresponds to the actual JSF UIComponent in
the view. The second argument to fireAjaxTransaction is a
JavaScript associative array. In this case, we're saying three things:
do the 'execute' portion of the JSF lifecycle just on
the JSF UIComponent for this widget instance.
do not re-render anything to the browser (in this case,
Dojo handles it).
In the HTTP POST body of the request, include the name
value pair for the currently entered value of the widget.
Note that newValue, on line 6 of listing 3, is an
argument to the onSave function. It is the new value
entered by the user.
For more information on the JavaScript functions exposed from Dynamic
Faces, see the
Dynamic Faces Reference.
Summary
jMaki gives you cool widgets. Dynamic Faces + jMaki gives you cool
widgets you can use in a real enterprise web application.
Technorati Tags: edburns
Knoppix, Partimage, VMware, mmmm
Posted by edburns on December 04, 2006 at 05:56 AM | Permalink
| Comments (0)
I had been doing the multi-boot thing on my Toshiba Satellite
5205-S703 since I bought it in late 2002. It came factory installed
with Windows XP Home Edition (monopoly anyone?) on an NTFS partition.
Thanks to Partition Magic 7.0, I soon ended up with the following
partition table:
Physical Geometry: 7,926 Cyls, 255 Hds, 63, Sects
Drive: C:
Partition Type: 07 (Hex) NTFS
Serial Number: F8CD:F94F
Total Physical Sectors: 80,080,632 (3,945.6 MB)
Drive: E:
Partition Type: 08 (Hex) FAT32
Serial Number: None
Total Physical Sectors: 8,353,800 (4,079.0 MB)
Drive: Extended
Partition Type: 0F (Hex) ExtendedX
Serial Number: None
Total Physical Sectors: 100,775,745 (49,206.9 MB)
Drive: F:
Partition Type: 08 (Hex) FAT32
Serial Number: None
Total Physical Sectors: 78,605,982 (38,381.8 MB)
Drive: SWAPSPACE2
Partition Type: 82 (Hex) Linux Swap
Serial Number: None
Total Physical Sectors: 2,120,517 (1,035.4 MB)
Drive: Linux Ext2
Partition Type: 83 (Hex) Linux Ext2
Serial Number: None
Total Physical Sectors: 20,049,057 (9,789.6 MB)
C: contained the factory Windows XP, E: contained Windows 2000
Professional, where I did most of my production work, including work on
mozilla.org
side
projects. In the GNU/Linux partition, I ran Sun Java Desktop System
Linux. I used GRUB as my bootloader, but somehow managed to have the
Windows bootloader in there as well (like a sub-menu) to choose between
Win XP and 2k, once "Windows" had been chosen from the main menu. I
never bothered to fix that.
At the JAOO
2006 conference, VMware was giving out free licenses to their VMware
workstation 5.5 product. Seeing an opportunity to free myself from the
shackles of a multi-boot existence, I took one. Several months later, I
began the long and arduous process of converting my multi-boot machine
into one that just boots the factory installed OS (since that's the only
thing officially supported by the manufacturer anyway) and uses VMs for
the other OSes.
I wanted to convert the OSes installed in my real hard disk
partitions into VMs. Here is the high level process I will use.
Install VMware Workstation 5.5 under the Windows XP OS,
using an external disk for extra space and to contain the VMs
for the guest OSes.
For each OS on a real partition on my disk
Use a Knoppix 3.7
CD I had made years ago to boot the Toshiba laptop. Once
booted into Knoppix, use partimage to create partition images
of all the OS partitions on the mahcine. Swap partitions
needn't be imaged, for obvious reasons, and data partitions
needn't be imaged because they can simply be copied. I stored
the partimage files on an external disk.
Create a VM for that OS, storing it on an external
disk.
Boot the VM into Knoppix
Install VMware tools into the running Knoppix instance
so I can access the partimage files using the "shared folders"
feature of VMware.
Use partimage to restore the OS partition into the
virtual hard disk of the VM.
Re-install the appropriate boot loader for that OS to
enable that OS to boot.
Once VMs had been created, on an external disk, for all
the OSes on real partitions, completely and totally wipe,
defrag, and re-install from factory media the laptop. After
the factory restore has completed, run Windows update however
many times I need to get the machine totally up to snuff and
current. Re-install virus protection software and other
essential goodies. Note, on the core, non virtual OS, I plan
to install very little real software, just stuff that
absolutely has to have access to the real hardware.
Create the new VM using VMware.
Set the guest OS type to be the type of the OS stored in your
partimage files.
Make sure the hard drive types (IDE or SCSI) match what is in
the partimage files. I chose to pre-allocate space. Not sure
if this is necessary.
Make the same amount of disk space is allocated in the VM as was in
the partition from which the partimage files were made.
Because you are using the Knoppix live CD, you need to mount a second
CDROM drive from the linux.iso file, located in the install
directory of VMware. Make sure to assign IDE 1.1 to this virtual CDROM
drive.
Use the VMware shared folders feature to expose your partimage files
to the VM.
Boot knoppix and install VMware tools into the running
Knoppix instance.
Download the vmware-knoppix-overlay.tar.gz to a real
machine on which an FTP server is running. In fact, this can be the
VMware host machine, but it needn't be.
With the Knoppix CD in the drive, start the VM, pressing escape
during the VMware startup screen to enter the boot menu. Select
CDROM.
When Knoppix starts up, get root access: su - , then
cd /tmp
tar -zxf /mnt/cdrom1/VMwareTools-5.5.3-34685.tar.gz
Use FTP to transfer the
vmware-knoppix-overlay.tar.gz file to /tmp in Knoppix.
cd /
tar -zxf /tmp/vmware-knoppix-overlay.tar.gz
cd /tmp/vmware-tools-distrib
./vmware-install.pl
This will run the modified VMware installer for Knoppix. When it
asks "In which directory do you want to install the binary files?"
answer /ramdisk/bin.
Accept the defaults for the rest of the questions until it asks,
"What is the location of the directory of C header files that match your
running kernel?" Answer
/ramdisk/lib/modules/2.4.27/build/include.
When done with these scripts, you should have access to your shared
folders under the path /mnt/hgfs.
Use fdisk under knoppix to partition the
virtual disk, most likely it will be /dev/hda, in
such a way that it is equivalent to the partimage files you
are going to restore. For example, if the partimage files
were created from a JFS filesystem, use JFS as
the partition type in fdisk. If you need to
create a swap partition, make sure to do that as
well.
Use partimage to restore the image files under
/mnt/hgfs to the new virtual disk.
Lastly, you need to make sure that the boot loader has
been restored. It's very unlikely that you can use the
bootloader that happened to be installed in the partimage
files. Of course, bootloaders are a matter of preference, but
I used GRUB. Here's what I had to do in my case.
Back at the root prompt in Knoppix:
mkdir /mnt/hda1
mount /dev/hda1 /mnt/hda1
cd /mnt/hda1/boot
cp -r grub grub.orig
rm -rf grub
grub-install --no-floppy --root-directory=/mnt/hda1 --recheck /dev/hda
At this pount the guest OS should boot.
Of course, your mileage may vary, but hopefully there is some useful
information here. It was a PITA for me to figure this out so I thought
I ought to share it once I did.
Technorati Tags: edburns
(near) Zero (re-)Deployment Time for JSF
Posted by edburns on December 01, 2006 at 06:52 PM | Permalink
| Comments (4)
One oft cited complaint about Java Web Applications is the slow
and laborious deployment
step. This step seriously undermines the ability to get into a
flow
state and is generally a major buzz kill. The absense of a
deployment step is one reason why people like Ruby on Rails so
much.
JSF-Extensions Design Time brings good news for
flow-impaired Java Web application Developers: the JMX
PhaseListener.
The implementation of this was really simple. I just took Jean-Francios
Arcand's JMXDeploy class, modded it ever so slightly, as you
can see in the
source code, and called it from a
PhaseListener.
I did a screencast about it too.
Technorati Tags: edburns
|