ATG Log Error from JSP Page

"The page cannot be displayed" | Flickr

"The page cannot be displayed" by Peter Kaminski

Unlike this IKEA sign, you usually don’t want to display errors on your web pages.  ATG allows you to log errors to the server log from a JSP page.  Below is an example of how to do this.  In this case if we find the price is null we log an error to the server log.

<dsp:getvalueof id="price" idtype="java.lang.Double" param="currentItem.priceInfo.amount">
<%
if (price == null) {
atg.servlet.DynamoHttpServletRequest dreq = atg.servlet.ServletUtil.getDynamoRequest(request);
dreq.logError("price is null!”);
}
%>
</dsp:getvalueof>

Set ATG Property And Popup Window After Clicking on Link

la cuarta ventana on Flickrla cuarta ventana by bachmont 

Sometimes when you click on a link in an ATG JSP/DSP page you want a property of an ATG component to be set as well.  For example:

[xml]<dsp:a href="foo.jsp">Foo
<dsp:property bean="BarFormHandler.baz" paramvalue="index"/>
</dsp:a>[/xml]

What gets tricky is if you also want a popup window to display the contents of this link.

The Wrong Way

I tried adapting the instructions from the tutorial Popup Windows | open new customised windows with JavaScript.

[xml]<dsp:a href="javascript:poptastic(‘foo.jsp’);">Foo
<dsp:property bean="BarFormHandler.baz" paramvalue="index"/>
</dsp:a>[/xml]

This does not work, i.e. the setter for baz in BarFormHandler is never called.

The Brute Force Way

I then reverted to the original DSP and looked at the outputted HTML.  Based on that I updated the DSP like this.

[xml]<% atg.servlet.DynamoHttpServletRequest dreq = atg.servlet.ServletUtil.getCurrentRequest(); %>
<a href="javascript:poptastic(‘foo.jsp?_DARGS=/betweengo/test.jsp_AF&_dynSessConf=<%= dreq.getSessionConfirmationNumber() %>&_D%3A/betweengo/BarFormHandler.baz=+&/betweengo/BarFormHandler.baz=<dsp:valueof param="index" />’);">Foo</a>[/xml]

This works but is grotesque.

The Good Idea That Did Not Work

Then I realized I could just set a parameter in the URL and have the form handler use the value to set the property.

[xml]<a href="javascript:poptastic(‘foo.jsp?index=<dsp:valueof param="index" />’);">Foo</a>[/xml]

And in BarFormHandler

public boolean beforeSet(DynamoHttpServletRequest req,
            DynamoHttpServletResponse res) throws DropletFormException {

  String indexParam = request.getParameter("index");
  setIndex(Integer.parseInt(indexParam));

  return super.beforeSet(request, response);
}

This did not work plus I did not really like it because now I have a beforeSet method that is called for every single request.

The Winner

I then realized I did not read the tutorial Popup Windows | open new customised windows with JavaScript carefully.  There is a more elegant way to call the JavaScript which degrades gracefully for browsers that don’t support JavaScript.

[xml]<dsp:a href="foo.jsp" onclick="poptastic(this.href);return false;">Foo
<dsp:property bean="BarFormHandler.baz" paramvalue="index"/>
</dsp:a>[/xml]

This works, is elegant and requires just adding the onclick attribute to the original DSP.

ATG Date Tag Converter is Buggy

Leaf on my car on Flickr

(Photo: Leaf on my car by exfordy)

The ATG Date Tag Converter is buggy because Java’s DateFormat is inherently unsafe for multithreaded use.  This is documented in ATG PR #123210 DateTagConverter.convertObjectToString() method is not thread safe.

You run into this problem whenever you do something like this.

<dsp:valueof param=”creationDate” converter=”date” date=”M/dd/yyyy”/>

Unfortunately there is no work around.  If using the Date Tag Converter is not causing problems for you, i.e you don’t see a stack trace like below, then you can ignore this bug.

2009-04-17 00:19:08,220 ERROR [nucleusNamespace.atg.dynamo.servlet.dafpipeline.DynamoServlet] java.lang.ArrayIndexOutOfBoundsException: 502
  at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:436)
  at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2081)
  at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:1996)
  at java.util.Calendar.setTimeInMillis(Calendar.java:1071)
  at java.util.Calendar.setTime(Calendar.java:1037)
  at java.text.SimpleDateFormat.format(SimpleDateFormat.java:785)
  at java.text.SimpleDateFormat.format(SimpleDateFormat.java:778)
  at java.text.DateFormat.format(DateFormat.java:314)
  at atg.droplet.DateTagConverter.convertObjectToString(DateTagConverter.java:176)

But if you do see a bug like this then you might need to create a custom droplet to format the date.  The droplet should only use DateFormat instances that are not static.  I usually make my DateFormat instances local.

RQLQueryRange does not sort dates correctly

Roppongi District Desktop on Flickr

(Photo: Roppongi District Desktop by powerbooktrance)

This was bedeviling me for awhile.  I could not figure out why my RQLQueryRange droplet was not sorting by dates correctly.  It turns out this is a known ATG bug which only happens when you are using Oracle, which is 99% of the time.

Considering that this bug has been open since 2003 one can assume ATG is not interested in fixing it.  This is probably because there is a simple work around.

Instead of using the sortProperties parameter, put the the sort directive directly in the RQL statement in the queryRQL parameter.

<dsp:param name="queryRQL" value="ALL ORDER BY creationDate DESC"/>

The Strangely Behaved ATG textarea Tag

Escalera al cielo / Stairway to heaven on Flickr 
(Photo: Escalera al cielo / Stairway to heaven by Davichi)

When I create a DSP textarea tag like this it outputs the value of the bean property in the text area box.

<dsp:textarea bean="MyFormHandler.foo" rows="5" cols="20"/>

Similarly if I create a DSP textarea tag like this I get the same output.

<dsp:textarea bean="MyFormHandler.foo" rows="5" cols="20"></dsp:textarea>

However when I leave some space between the textarea opening and closing tag I get a blank instead of the value of the bean property in the text area box.

<dsp:textarea bean="MyFormHandler.foo" rows="5" cols="20">
</dsp:textarea>

Anyone know why there is a difference?

Anyway after reading the documentation it turns out if I want to control what is output in the text box I can use the default attribute.

<dsp:textarea bean="MyFormHandler.foo" rows="5" cols="20" default="bar"/>

Maybe I should have read the documentation before writing this post. 🙂

Update 2009-09-03: I also found this strange pattern of behavior with the DSP droplet tag.  When I invoked a droplet that took no parameters and had no open parameters like this:

<dsp:droplet name="MyDroplet"/>

or like this:

<dsp:droplet name="MyDroplet"></dsp:droplet>

the droplet would not be invoked.

However when I did this the droplet was invoked.  Strange …

<dsp:droplet name="MyDroplet">
</dsp:droplet>

How to Set an Array Property in an ATG Form

Cool Blue Hive on Flickr
(Photo: Cool Blue Hive by jurvetson)

In the Setting Property Values in Forms section of the ATG Page Developer’s Guide there are two examples for setting values of array properties in forms.

  1. Grouped Checkboxes
  2. Multiple-Selection List Box

Both examples are for a simple form.  But what if you are generating a form using a ForEach droplet and want to set an array property in each iteration of the loop.  Fortunately it turns out to be relatively easy.

Hidden or Text Inputs

<dsp:droplet name="/atg/dynamo/droplet/ForEach">
  <dsp:oparam name="output">
    <dsp:input type="hidden" paramvalue="element.id" bean="MyFormHandler.ids"/>
  </dsp:oparam>
</dsp:droplet>

Select Inputs

<dsp:droplet name="/atg/dynamo/droplet/ForEach">
  <dsp:oparam name="output">
    <dsp:select bean="MyFormHandler.answers">
     <dsp:option value="foo">foo</dsp:option>
     <dsp:option value="bar">bar</dsp:option>
    </dsp:select>
  </dsp:oparam>
</dsp:droplet>

By the way if you try to set the array element directly using the param:index notation as in the following example it will not work.

<dsp:droplet name="/atg/dynamo/droplet/ForEach">
  <dsp:oparam name="output">
    <dsp:select bean="MyFormHandler.answers[param:index]">
     <dsp:option value="foo">foo</dsp:option>
     <dsp:option value="bar">bar</dsp:option>
    </dsp:select>
  </dsp:oparam>
</dsp:droplet>

When submitting the above form you will get this exception.

atg.droplet.DropletException:
  Can't set an element of the array property without a set <name> (int index, Object value) method.

The exception message is a red herring, there is no way you can set the element of an array property no matter what kind of set method you create.  Trust me, I spent many hours delving into the ATG code to verify this. 🙂

ATG Currency Converter Not Working With JSTL c:set

Currency conversion confusion on Flickr!

This JSP code was not outputting the properly formatted amount.

<dspel:valueof value="${dollars}" converter="currency" />

I tried forcing it by specifying the conversion parameters.

<dspel:valueof value="${dollars}" converter="currency" locale="en-CA" format="#.00" currency="$" />

I then debugged atg.droplet.CurrencyTagConverter using Eclipse and found this code being executed.

public String convertObjectToString(DynamoHttpServletRequest pRequest,
                                 Object pValue, Properties pAttributes)
  throws TagConversionException
{
  if ((pValue == null) || (pValue instanceof String))
    return (String)pValue;

It turns out pValue was a String which is why it was never being formatted.  But why is it a String?

Well the code that sets dollars looks like this.

<dspel:tomap var="paymentGroup" param="commerceItem.paymentGroups[1]" />
<c:set var="dollars" value="0" />
<c:if test="${not empty paymentGroup}">
  <c:set var="dollars" value="${paymentGroup.amount}" />
</c:if>

Apparently c:set converts the Double to a String.

To work around this problem I did this.

$<dspel:valueof number="0.00" value="${dollars}" />

For further reading please see Tag Converters in the ATG Page Developer’s Guide.

How to Debug No Output for ATG ForEach

foreach

Today I added a feature in my shopping cart JSP page but nothing was showing up.  This was because the output of ATG ForEach droplet was blanks.

To debug this I did the following steps.

  1. I added an empty oparam to see if the ForEach droplet thought the collection was empty.
    <dsp:oparam="empty">Empty?</dsp:oparam>

    It did not.

  2. I outputted the count in the output oparam to see if it was looping through the collection.
    <dsp:oparam="output"><dsp:valueof param="count"/> <dsp:valueof param="element"/></dsp:oparam>

    It was looping through the collection.

  3. Finally I debugged using Eclipse the ForEach code.  The ForEach code can be found in <ATG>/DAS/src/Java/atg/droplet/ForEach.java

    Using the debugger I realized that the element name of the loop was being set to something else which is why <dsp:valueof param=”element”/> was blank.

It turned out that the ForEach droplet was inside another ForEach droplet and in that droplet they set the element name like this.

<dsp:param name="elementName" value="CommerceItem" />

By setting the elementName parameter to something else in my ForEach droplet and then referencing it properly I was finally able to get the expected output.

<dsp:droplet name="/atg/dynamo/droplet/ForEach">
 <dsp:param name="array" param="CommerceItem.auxiliaryData.productRef.dvds"/>
 <dsp:param name="elementName" value="dvd" />
 <dsp:oparam name="output">
  <dsp:valueof param="dvd.name" />
 </dsp:oparam>
</dsp:droplet>

By the way ATG documentation suggests not using elementName.

elementName and indexName allow you to provide a parameter name other than element and index, respectively. A better way to provide a different parameter name is to use the dsp:setvalue tag.

In our example we would do this instead of setting the elementName param.

 <dsp:setvalue param="dvd" paramvalue="element" />

ATG ForEach Output with Separators Between Items

Pez Collection

Sometimes you want to list each item in the collection with a separator in between like a comma or slash.  However the trick is to have the separator only in between items.

In ATG DSP you can use the ForEach droplet to iterate through each item in a collection.  However to put a separator between each item is not straight-forward with this droplet.  To do this I used JSTL to test if we are at the end of the collection.  If we are then I don’t add the separator, otherwise I do.

Here is an example.

<dspel:droplet name="/atg/dynamo/droplet/ForEach">
 <dspel:param name="array" param="dvds"/>
 <dspel:setvalue param="dvd" paramvalue="element" />
 <dspel:oparam name="outputStart">
  <dspel:getvalueof var="size" param="size" />
 </dspel:oparam>
 <dspel:oparam name="output">
  <dspel:valueof param="dvd.title" valueishtml="true"/>
  <dspel:getvalueof var="count" param="count" />
  <c:if test="${size != count}"> , </c:if>
 </dspel:oparam>
</dspel:droplet>

And here is the output for this example.

The Incredibles, Ratatouille, Cars

Do you have a better or more elegant solution?  Please feel free to let me know in the comments?