NameNotFoundExceptions during start up of ATG application on JBoss

When you start up your ATG application on JBoss and see NameNotFoundExceptions like the following it could be because you did not configure your ATG datasources correctly.

Unable to start service "/atg/dynamo/service/jdbc/JTDataSource":
 atg.nucleus.ServiceException:
 Unable to resolve reference to JNDI component:
 java:/atgcore_ds
ERROR [nucleusNamespace.atg.dynamo.service.jdbc.JTDataSource]
javax.naming.NameNotFoundException: atgcore_ds not bound

To properly configure it create an atg-oracle-ds.xml file. I have a sample one below. atgcore_ds is the datasource for most of the ATG repositories. You will probably need to configure datasources for Catalog A and Catalog B if you are doing eCommerce, e.g. atgcataloga_ds and atgcatalogb_ds. The atg-oracle-ds.xml file will go into your server’s configuration, e.g. <jboss>/server/betweengo/deploy.

<?xml version="1.0" encoding="UTF-8"?>
<datasources>
 <local-tx-datasource>
  <jndi-name>atgcore_ds</jndi-name>
  <!-- <connection-url>jdbc:oracle:oci:@Dynamo</connection-url> -->
  <connection-url>jdbc:oracle:thin:@localhost:1521:orcl</connection-url>
  <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
  <user-name>foo</user-name>
  <password>bar</password>
  <min-pool-size>1</min-pool-size>
  <max-pool-size>4</max-pool-size>
 </local-tx-datasource>
</datasources>

Note that the connection URL should be the same as what you configured in your tnsnames.ora file.  If you installed Oracle with a Microsoft Loopback Adapter and pointed the host in your tnsnames.ora configuration to the loopback connection, e.g. 192.168.1.200, then you should do the same in your atg-oracle-ds.xml file.

For further reading please see Getting Started with ATG – jBoss and Oracle and Create Additional JBoss Application Server Configurations.

Could Not Install ATG 2007.1

Today I began a contract with Bell Canada on an eCommerce project.  This project is using ATG 2007.1 with Oracle 10g (supported environments for ATG 2007.1).

I downloaded the installer from ATG’s product downloads page which is only available if you have purchased a Standard or Premium Support contract.  Previously this page was publicly available but now it is hidden.  Fortunately I found the link at ATG’s Google group ATG_Tech where they announced that ATG 2007.1 is available.

ATG Support quickly responded to my email to support@atg.com and within a few hours fixed the installer and made available a new installer on the product downloads page.

Lesson learned: Contact ATG Support.  They’re good.

Recurring Illegal Access Errors in JBoss when running ATG

illegal access

I recently installed ATG 2007.1 with no patches on JBoss 4.0.5.GA.  When I started it up I continually saw these illegal access errors.

16:01:24,296 INFO  [WebappClassLoader] Illegal access: this web application instance has been stopped already.  Could not load org.apache.log4j.Level.
  The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
java.lang.IllegalStateException
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1241)
        at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1201)
        at org.apache.commons.logging.impl.Log4jProxy$1.run(Log4jProxy.java:66)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.commons.logging.impl.Log4jProxy.threadContextClassLoader(Log4jProxy.java:88)
        at org.apache.commons.logging.impl.Log4jProxy.(Log4jProxy.java:94)
        at org.apache.commons.logging.impl.Log4JLogger.(Log4JLogger.java:39)
        at sun.reflect.GeneratedConstructorAccessor22.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
        at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:529)
        at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:235)
        at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:372)
        at atg.nucleus.logging.commons.CommonsLoggingLogListener.logEvent(CommonsLoggingLogListener.java:106)
        at atg.nucleus.GenericService.sendLogEvent(GenericService.java:291)
        at atg.nucleus.GenericService.logInfo(GenericService.java:737)
        at atg.nucleus.GenericService.logInfo(GenericService.java:715)
        at atg.ui.j2edit.model.CachingJ2eeArchiveDirectoryAgent.updateCacheData(CachingJ2eeArchiveDirectoryAgent.java:513)
        at atg.ui.j2edit.model.CachingJ2eeArchiveDirectoryAgent.performScheduledTask(CachingJ2eeArchiveDirectoryAgent.java:573)
        at atg.service.scheduler.ScheduledJob.runJobs(ScheduledJob.java:441)
        at atg.service.scheduler.Scheduler$2handler.run(Scheduler.java:760)

Fortunately this is a common problem and there are many support incidents about it.  Problem Report #144586 says that the problem occurs if:

  1. say “Yes” to deploying Quincy Fund during installation
  2. use startDynamoOnJBoss to run any other application

The work around is to remove Quincy Funds.ear from the JBoss deployment directory.  Or just don’t install Quincy Funds.

If you need to run the Quincy Funds demo then the Error running Quincy Funds demo on JBoss document suggests:

  1. stop the server
  2. delete the ATGDAF.ear from the JBoss installation
  3. start JBoss with the run.bat|sh command; the Quincy Funds demo is automatically started

For further reading please see How to use the startDynamoOnJBOSS script and JBoss configurations to run an application.  You may need to have an active ATG support contract to view these and other ATG support documents referenced in this article.

DynamicBeanMap

Previously I posted about using the atg.beans.DynamicBeanMap class to wrap a RepositoryItem so that it is accessible via JSTL.  However it turns out this is not a great solution.

If we want to access a simple property in a RepositoryItem wrapped in a DynamicBeanMap it is relatively straightforward.  For example,

${user.name}

However if we want to access a RepositoryItem property like this,

${user.address}

then we end up getting a StackOverflowError as the DynamicBeanMap spins going back forth between the user RepositoryItem and the address RepositoryItem.

Interestingly enough accessing a simple property from the RepositoryItem property works fine.

${user.address.city}

One solution is to set the recursive argument to false when creating the DynamicBeanMap.

DynamicBeanMap itemBean = new DynamicBeanMap(pValue, false);

When you do this the following will work correctly.

${user.address}

However this no longer works.

${user.address.city}

We ended up abandoning the DynamicBeanMap and creating a library of strongly typed repository item wrapper proxy objects.

ATG Support helped me tremendously to figure out what was going on. They suggested an alternative which we never tried because of the large impact it would have on our JSP.

What I determined in looking at this further is that the DynamicBeanMap class is not really documented for customer use, but there is a DSP/DSPEL tag called “tomap” that uses this class that we do document. See the appendix in our 2006.3 Page Developer’s guide.

So, this tag would avoid this problem since it does have an undocumented “recursive” attribute that defaults to “false”, but I think it might be preferable to set it to “true” and use another undocumented option. After using the “tomap” tag with recursive=true, you can then use a _realObject property to unwrap your “final” object being accessed.

So if your tag is:

<dspel:getvalueof var="address" param="user.address" />

You can change it to use:

<dspel:getvalueof var="address" param="user.address._realObject" />

Or if you were doing:

<dspel:valueof param="user" />

you could use:

<dspel:valueof param="user._realObject" />

Basically you just unwrap whatever end/final object you’re trying to get to with _realObject.  Since we can’t see exactly what code called hashCode that caused the StackOverflowError, I can’t be certain this will avoid the StackOverflowError, but I suspect it will.

This solution will have the benefit of having minimal impact on your ability to access properties with JSTL.

I’ve entered a PR #155848 about some of these properties not being documented.

Also PR #81771 was submitted requesting the ability to recursively access repository items in JSTL.

Trim White Space from JSP

Untitled | FlickrSometimes the resultant HTML from JSP files has too much white space.  This is because a lot of JSP logic will result in only a few lines of actual HTML code and the rest is white space.

One efficient way to get rid of white space is to add this configuration to your web.xml on Tomcat/JBoss as described in this article, Trim Spaces in your JSP’s HTML.

/jboss/jboss-eap-4.2/jboss-as/server/atg/deploy/jboss-web.deployer/conf/web.xml
OR
/jboss/jboss-eap-5.1/jboss-as/server/atg/deployers/jbossweb.deployer/web.xml

<servlet>
    <servlet-name>jsp</servlet-name>
    ...

    <init-param>
        <param-name>trimSpaces</param-name>
        <param-value>true</param-value>
    </init-param>

    ...
</servlet>


However this sometimes has undesired side-effects. For example this DSP:

<div class="foo">
  <dspel:valueof param="displayName" />
</div>


causes this undesired result:

<div class="foo"/>
  Frank Kim


The work around is to do this.

<dspel:getvalueof  var="displayName" param="displayName" />
<div  class="foo"><c:out  value="${displayName}"/></div>

Update 06-09-2010: The above problem might have been happening because we were running with a version of ATG that is for Servlet 2.3. When we run with a version of JBoss that runs with Servlet 2.4, e.g.  ATG 9.1 with JBoss EAP 4.2, we no longer see this problem.

There is another tip on removing white space in this JSP FAQ: Why I am getting extra whitespace in the output of my JSP?  In our code we had one file which included a bunch of tag libraries.  It originally looked like this.

<%/** Taglibs.jsp: include to pull in all taglibs */%>

<%@ taglib uri="/dspELTaglib" prefix="dspel" %>
<%@ taglib uri="/jstlCoreTaglib" prefix="c" %>
<%@ taglib uri="/struts-bean" prefix="bean" %>
<%@ taglib uri="/struts-tiles" prefix="tiles" %


When we changed it to this we saved about 5% in terms of page size in bytes.

<%@ taglib uri="/dspELTaglib" prefix="dspel"
%><%@ taglib uri="/jstlCoreTaglib" prefix="c"
%><%@ taglib uri="/struts-bean" prefix="bean"
%><%@ taglib uri="/struts-tiles" prefix="tiles" %>


You can use this tip with a DSP page and maintain indentation.

<dspel:page    ><dspel:droplet name="/betweengo/droplet/Foo"      ><dspel:oparam name="output"        >Name: <dspel:valueof param="name"      /></dspel:oparam    ></dspel:droplet
></dspel:page>

Sets cannot be used as property types

I create a JavaBean with a Set property because I wanted to enforce that there were only unique values in that Set.  However when I tried to use this JavaBean with a properties file, Nucleus complained it could not resolve the elements of the Set property.  When I changed the property to be a List or a String [] Nucleus had no problem.

Here is the properties file.

$class=com.betweengo.droplet.VerifyImages
$scope=request

# supported image dimensions
supportedImageDimensions=75x90,88x31,120x90

ATG Support pointed me to the Property Types subsection of the Using Nucleus
section of the ATG Programming Guide.  Specifically only these simple types are supported.  I am not sure why Set was excluded.

boolean
byte
char
short
int
long
float
double
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.String
java.util.List
java.util.Map
java.util.Locale

Repository creating tables automatically

Recently we noticed while running some ATG unit tests that tables were being created by the ATG repository if they had not already been created by our SQL scripts.  This was a functionality that I was unaware of but apparently it is not unique, Hibernate does this too.  I could not find any documentation about this nor could I determine how to turn it off.

The ATG repository creates these tables using the repository definition and the defaults for column width and data type.  It does not seem to warn that it is creating these tables.