If you read my other post on creating custom view handlers in Sun IdM, you might have noticed my mixed feelings towards the system’s built-in interface.
I know its main task is not to look good, and that it is best at what it is supposed to be good at, but there really is no point in a system that no user would use – unless Sun wants other companies to take the market lead.
It is not only that it is hard to make proper customizations on the CSS layer due to the nested-tables-in-nested-tables-in…-nested-tables-we-do-not-know-how-to-properly-use-ids-or-classes-and-enjoy-the-font-tag-and-br-tags-for-space-HTML generated by code written by someone stuck in the 1990s, but also that a lot of the components look quite old fashion, so to speak.
Have a look at the built in date picker for instance:
![]()

Lovely? No? Nor did our customer think.
Luckily, it is not very hard to write custom HTML components for Sun IdM (or Display Classes, as they are known by on the XPress side). With the help of jQuery UI, we created a much, much slicker one:

(Of course, when it comes to look and feel, this one is 100% customizable – it’s styled using CSS, not font tags.)
Custom Display Classes in Sun IdM
Writing a custom component in Sun IdM does not require the help of magicians. The simplest case would be to create a new Java class that extends the com.waveset.ui.util.html.Component class. In order to create a MySpan display class that prints <span class="some-class" id="some-id">value</span>, we could for example implement the class in the example below.
package com.waveset.ui.util.html;
import java.util.*;
/**
* @author Trond K. Pettersen
*/
public class MySpan extends Component {
private String _id;
private String _cssClass;
public MySpan() {
super();
}
public void setId(String id) {
this._id = id;
}
public void setClass(String cssClass) {
this._cssClass = cssClass;
}
@Override
public void render(Renderer r) {
r.append("<span");
if(_id != null) {
r.append(" id=\"" + _id + "\"");
}
if(_cssClass != null) {
r.append(" class=\"" + _cssClass + "\"");
}
r.append(">");
r.append(getStringValue());
r.append("</span>");
}
}
We are now able to use this class as part of our XPress code:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE Configuration PUBLIC 'waveset.dtd' 'waveset.dtd'> <Configuration id='#ID#UserForm:MyCorp-MyCustomForm' name='MyCorp-MyCustomForm' wstype='UserForm'> <Extension> <Form noDefaultButtons='true'> <Field> <Display class="MySpan"> <Property name="value" value="some test value" /> <Property name="class" value="class1 class2 class3" /> </Display> </Field> </Form> </Extension> <MemberObjectGroups> <ObjectRef type='ObjectGroup' id='#ID#Top' name='Top' /> </MemberObjectGroups> </Configuration>
When this form is displayed, the output will include our new span:
<span class="class1 class2 class3 ">some test value</span>
Creating a Modern DatePicker Display Class
Luckily, creating a more modern date picker does not require much more work than in our MySpan example above.
This is of course partly thanks to jQuery, whose DatePicker widget I decided to use, but also because the only thing we have to do, is to extend the built-in DatePicker class. Here’s how such a class might look:
package com.waveset.ui.util.html;
import com.waveset.util.Util;
import java.util.*;
/**
* @author Trond K. Pettersen
*/
public class ModernDatePicker extends DatePicker {
// Whether or not to display a calendar button next to the input field
private boolean _displayButton= true;
// We still want to use these...and keep a
// local ref. for feeding our JavaScript.
private String _selectAfter = "";
private String _selectBefore = "";
// The format of our dates
private String _format = "yyyy-MM-dd";
// Constructor that might be called by IdM
public ModernDatePicker() {
super();
}
// Constructor that might be called by IdM
public ModernDatePicker(String title, String name) {
super(title, name);
}
// Constructor that might be called by IdM
public ModernDatePicker(String title, String name, Date date) {
super(title, name, date);
}
public void setDisplayButton(String val) {
this._displayButton = Boolean.parseBoolean(val);
}
public void setSelectAfter(String after) {
this._selectAfter = after;
super.setSelectAfter(after);
}
public void setSelectBefore(String before) {
this._selectBefore = before;
super.setSelectBefore(before);
}
@Override
public void setFormat(String format) {
this._format = format;
super.setFormat(format);
}
@Override
public void toHTML(Renderer b) {
String htmlClassName = _required ? "date required" : "date";
String enableOrDisable = _disabled ? "disabled" : "enabled"; // this can be set on the DatePicker class
long selectAfter = "".equals(this._selectAfter) ? 0L : getSelectAfterDate().getTime();
long selectBefore = "".equals(this._selectBefore) ? 0L : getSelectBeforeDate().getTime();
// Create a random XML id ... have experienced problems
// in IE6 if there is no ID set on the element (due to the
// common naming scheme of fields representing values on
// generic objects in IdM, e.g. test[example].toDate ).
String id = Util.generateGUID().replaceAll("[^:alnum:]", "");
b.append("\n<div class=\"datepicker " + enableOrDisable + "\">\n");
// The text input field to turn into a date picker
b.append("<input type=\"text\" ");
b.append(" id=\"id-" + id + "\"");
b.append(" name=\"" + _name + "\" ");
b.append(" value=\"" + getDateValueAsString() + "\"");
b.append(" class=\"" + htmlClassName + "\"");
if(_disabled) {
b.append(" disabled=\"disabled\" ");
}
b.append(">\n");
// selectAfter and selectBefore dates for use by our JavaScript
// (minDate and maxDate in jQuery).
b.append("<input type=\"hidden\" ");
b.append(" class=\"selectAfter\"");
b.append(" value=\"" + selectAfter + "\"");
b.append(">\n");
b.append("<input type=\"hidden\" ");
b.append(" class=\"selectBefore\"");
b.append(" value=\"" + selectBefore + "\"");
b.append(">\n");
b.append("</div>\n");
}
private Date getSelectAfterDate() {
Date date = null;
if(!"".equals(this._selectAfter)) {
try {
date = Util.stringToDate(this._selectAfter, this._format);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return date;
}
private Date getSelectBeforeDate() {
Date date = null;
if(!"".equals(this._selectBefore)) {
try {
date = Util.stringToDate(this._selectBefore, this._format);
} catch (java.text.ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return date;
}
private String getDateValueAsString() {
Date dateValue = ((Date) getValue());
String dateAsStr = "";
if (dateValue != null) {
try {
dateAsStr = Util.dateToString(dateValue, _format);
} catch (Exception e) {
e.printStackTrace(); // TODO log errors
}
}
return dateAsStr;
}
}
And here’s an example of how we could use both the old and the new datepickers in our XPress code:
<Field>
<Display class="DatePicker">
<Property name="format" value="yyyy-MM-dd" />
<Property name="selectAfter" value="2009-01-10" />
<Property name="selectBefore" value="2009-01-15" />
</Display>
</Field>
<Field>
<Display class="ModernDatePicker">
<Property name="format" value="yyyy-MM-dd" />
<Property name="selectAfter" value="2009-01-10" />
<Property name="selectBefore" value="2009-01-15" />
</Display>
</Field>
Adding the jQuery JavaScript
Now, unless we want the above DatePicker to be a simple text input field, we also have to add some JavaScript to our pages, binding the jQuery DatePicker widget to our ModernDatePickers.
The sourcecode for doing so is listed below, and should of course be stored as part of a separate .js file which is included through a HTML script-tag; for instance in setStylesheetsAndTitle.jsp (sometimes you just have to edit some of the built in files), along with a jQuery UI build that includes the DatePicker widget.
jQuery(document).ready(function() {
jQuery('div.datepicker.enabled').each( function() {
var mandatoryVal = jQuery(':text', this).hasClass('required');
var minDateVal = null;
var maxDateVal = null;
var selectAfter = jQuery('.selectAfter', this).val();
var selectBefore = jQuery('.selectBefore', this).val();
if (selectAfter > 0) {
minDateVal = new Date();
minDateVal.setTime(selectAfter);
}
if (selectBefore > 0) {
maxDateVal = new Date();
maxDateVal.setTime(selectBefore);
}
jQuery(':text', this).datepicker( {
firstDay :1,
dateFormat :'yy-mm-dd',
mandatory :mandatoryVal,
minDate :minDateVal,
maxDate :maxDateVal,
yearRange :'-0:+30'
});
jQuery('<input type="button" class="calendar" />').insertAfter(jQuery(':text', this));
});
jQuery('.datepicker.enabled .calendar').click( function() {
jQuery(this).prev().trigger('focus');
return false;
});
});
The result of our effort is shown in the images below — much better than the built in datepicker, and so much easier to customize!
![]()

Scott Jehl
/ 21/01/2009Great post. I wanted to let you know that jQuery UI has been updated recently and features an even slicker new CSS framework and theming tool for styling your datepicker.
You can find out more here: http://ui.jquery.com/demos/datepicker
and try out ThemeRoller (the jQuery UI theming tool) here: http://ui.jquery.com/themeroller/
Trond
/ 22/01/2009@Scott. I noticed the new version of the datepicker. It looks very good.
Right now, I’m sticking to the tested production quality verison, but we’ll probably switch later. ThemeRoller! That’s a great advancement
Trond
/ 23/02/2009Update: as the ThemeRoller turned out to be very cool and backward compatible, I ended up “implementing” the Redmond theme.
Murat
/ 07/08/2009Hey Trond,
Im working now for a new customer and we had also trouble with the datepicker and searched with google to find a alternative and then found this. I readed a part and said to myself “sun, idm, jquery hey you know that…” and later on I found your name
hope your well. By chance I found your website
Great work, hope all guys are also well, last time I heard from Mtri that you want to leave the project…
Cheers,
Murat
Trond
/ 12/08/2009Hi Murat,
Hehe … cool
I’ll be joining another project which is more in line with my experience and skills, that is true. Someone more interested in identity management will be filling my spot.
Hope everything is going good in Germany and that there are lots of interesting IdM projects for you out there!