Ignore Unavoidable Generic Type Problems in Eclipse

When you use Eclipse by default most generic type problems show up as warnings. Unfortunately this results in lots of warnings when you use ATG code.

You can turn off the warnings that result from ATG code by checking the option “Ignore unavoidable generic type problems”.

Ignore unavoidable generic type problems

Ignore unavoidable generic type problems

For example you might have code like this where getValues() comes from the ATG API:

getValues().put(name, value);

By default Eclipse reports warnings for the above line. But this is unavoidable and with this Ignore option turned on no warning is reported for this line.

Kind of useful and you don’t have to add @SuppressWarnings(“unchecked”) liberally through your ATG code.

Debugging Transaction is not Active

Problems like this happen occasionally and are quite bedeviling.

Caused by: java.lang.RuntimeException: CONTAINER:atg.repository.RepositoryException; SOURCE:org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >)
    at atg.adapter.gsa.GSAItemDescriptor.loadProperty(GSAItemDescriptor.java:5479)
    at atg.adapter.gsa.GSAItem.getPersistentPropertyValue(GSAItem.java:1101)
    at atg.adapter.gsa.GSAItem.getPropertyValue(GSAItem.java:994)
    at atg.adapter.gsa.GSAItem.getPropertyValue(GSAItem.java:1272)
    at atg.repository.RepositoryItemImpl.getPropertyValue(RepositoryItemImpl.java:128)
    at atg.commerce.order.processor.ProcLoadHandlingInstructionObjects.runProcess(ProcLoadHandlingInstructionObjects.java:183)
    at atg.service.pipeline.PipelineLink.runProcess(PipelineLink.java:233)
    at atg.service.pipeline.PipelineChain.runProcess(PipelineChain.java:343)
    ... 17 more
Caused by: CONTAINER:atg.repository.RepositoryException; SOURCE:org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >)
    at atg.adapter.gsa.GSAItemDescriptor.loadProperties(GSAItemDescriptor.java:5431)
    at atg.adapter.gsa.GSAItemDescriptor.loadProperty(GSAItemDescriptor.java:5471)
    ... 24 more
Caused by: org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >)
    at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:96)
    at atg.service.jdbc.WatcherDataSource.getConnection(WatcherDataSource.java:801)
    at atg.service.jdbc.WatcherDataSource.getConnection(WatcherDataSource.java:782)
    at atg.adapter.gsa.GSATransaction.getConnection(GSATransaction.java:744)
    at atg.adapter.gsa.GSAItemDescriptor.getConnection(GSAItemDescriptor.java:2365)
    at atg.adapter.gsa.GSAItemDescriptor.loadProperties(GSAItemDescriptor.java:5345)
    ... 25 more
Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 7f000001:c525:503e32fb:2f2c status: ActionStatus.ABORT_ONLY >
    at org.jboss.resource.connectionmanager.TxConnectionManager.getManagedConnection(TxConnectionManager.java:319)
    at org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:403)
    at org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:850)
    at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:90)
    ... 30 more

I tweeted about issues like this over two years ago.

As I said in the tweet this almost always is not a transaction issue but actually an application issue. The tweet references an excellent article Transaction is not active: tx=TransactionImple < ac, BasicAction in which the author found in his case that the problem was a NullPointerException which caused the transaction to end.

Today I had to debug this issue again. First I checked the transaction in ProcLoadHandlingInstructionObjects before it called getPropertyValue on the shipping group repository item.

GSAItem item = (GSAItem) sgMutItem;
ItemTransactionState state = item.getItemTransactionState(false);
logDebug("state=" + state.mGSATransaction);

I saw in the logs that the status of the transaction was ActionStatus.ABORT_ONLY which meant the transaction was already aborted before getting the property value from the repository which is why the Transaction is not active exception happened.

Next I checked the transaction at the beginning of ProcLoadHandlingInstructionObjects using the order repository item.

GSAItem item = (GSAItem) orderItem;
ItemTransactionState state = item.getItemTransactionState(false);
logDebug("state=" + state.mGSATransaction);

When I confirmed that the status of the transaction was ActionStatus.ABORT_ONLY at the beginning of the processor I went backwards through the pipeline checking all the processors in the same way.

After doing that and confirming the transaction was ActionStatus.ABORT_ONLY at the beginning of the pipeline process I began checking the code that called the pipeline using code like this.

GSAItem orderItem = (GSAItem) order.getRepositoryItem();
ItemTransactionState state = orderItem.getItemTransactionState(false);
try {
  int status = state.mGSATransaction.getTransaction().getStatus();
  if (status == Status.STATUS_MARKED_ROLLBACK) {
    logError("Oh-oh, marked for rollback.");
  }
} catch (SystemException exc) {}

I finally found the problem was that in a previous call to another pipeline an error had occurred and the transaction was marked for rollback. However the code did not check the result of the pipeline call and had continued.

The moral of the story is always check your return values and don’t go down the rat hole of believing it’s a transaction issue.

Alice in front of the rabbit hole

SQL Delete in One Table Based on Values in Another Table

Growing | Flickr

Growing by Simon Peckham

Delete From One Table Whose Values Don’t Appear in Another Table

Sometimes you will find that you have items in a table whose values reference items in another table that no longer exist.  For example in ATG you may have orders that reference profiles that no longer exist.  This could happen if an order is for an anonymous profile that was deleted.

Here is an example of how to delete items in a table whose values reference items in another table that no longer exist, in this case ATG orders whose profiles no longer exist.

DELETE FROM dcspp_order
WHERE profile_id
NOT IN
(
  SELECT id
  FROM dps_user
);

This example does not actually work because of the dependencies on the dcspp_order table so please don’t try it. Smile

Delete From One Table Based on Values in Another Table

Sometimes you want to delete items in one tables based on values in another table.  You can do this similarly to the previous case.

DELETE FROM dcspp_order
WHERE profile_id
IN
(
  SELECT id
  FROM dps_user
  WHERE id LIKE '6%'
);

This example also does not actually work because of the dependencies on the dcspp_order table so please don’t try it. Smile

For further reading please see How to delete records from a SQL Server database and SQL Delete Rows Based on Another Table.

Configuring JBoss for HTTPS

Keys 1 by ~Brenda-Starr~

This is how I configured JBoss to handle HTTPS requests for secure ATG applications.

  1. Create the keystore and private key.
    $ cd /opt/jboss/jboss-eap-4.3/jboss-as/server/atg/conf
    $ keytool -genkey -alias jbosskey -keyalg RSA -keystore server.keystore
  2. Generate and store the certificate.
    $ keytool -export -alias jbosskey -file server.crt -keystore server.keystore
    $ keytool -import -alias jbosscert -file server.crt -keystore server.keystore
  3. Enable HTTPS.
    $ vi /opt/jboss/jboss-eap-4.3/jboss-as/server/atg/deploy/jboss-web.deployer/server.xml

    Uncomment SSL HTTP/1.1 Connector section and edit. For example:

        <Connector port="8443" address="${jboss.bind.address}"
                   protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   clientAuth="false" sslProtocol="TLS"
                   keystoreFile="${jboss.server.home.dir}/conf/server.keystore"
                   keystorePass="letmein" />
  4. Start JBoss with keystore specified. On UNIX you can do this by updating run.conf. For example:
    JAVA_OPTS="-Xms128m -Xmx512m -XX:MaxPermSize=128m -Djavax.net.ssl.trustStore=/opt/jboss/jboss-eap-4.3/jboss-as/server/atg/conf/server.keystore -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -Dsun.lang.ClassLoader.allowArraySyntax=true"

Note that if you are using service bindings (i.e. uncommented service bindings section of conf/jboss-service.xml) then the bindings in the XML configuration file (e.g. sample-bindings.xml) will take precedence. In this case the secure port becomes 8543.

For further reading please see HOWTO Configure JBoss for HTTPS.

Enabling non-XA Resources in JBoss 4.2 with ATG

a dog and it's boss on Flickr
(Photo: a dog and it’s boss by Pixel Addict)

ATG documents how to enable non-XA resources in JBoss 4.2 for SOLID.  We ended up following the same instructions to work with Oracle.

JBoss Note: JBoss 4.2 by default assumes XA drivers, which some ATG applications use; however, there are no XA drivers for SOLID. To enable multiple non-XA resources in JBoss 4.2, add the property to the jbossjta-properties.xml file, under the “arjuna” property tag:

[xml]<property depends="arjuna" name="jta">
<property name="com.arjuna.ats.jta.allowMultipleLastResources" value="true"/>[/xml]

You may still see warnings in your log file, but ATG applications will run correctly. To suppress these warnings, add the following to your jboss-log4j.xml file:

[xml]<category name="com.arjuna.atg.jta.logging">
<priority value="ERROR"></priority>
</category>[/xml]

For further reading please see Starting the SOLID SQL Database document in the Running Nucleus-Based Applications section of the ATG Installation and Configuration Guide.

Running JBoss with Oracle

(Photo: oracle by you are the atman)

Most commercial websites that use JBoss also use Oracle.  To run JBoss with Oracle you simply need to tell JBoss where to find the Oracle JDBC drivers. To do this modify run.bat or run.sh and set the JBOSS_CLASSPATH to include the Oracle JDBC jar file before

set JBOSS_CLASSPATH=C:\oracle\product\10.2.0\db_1\jdbc\lib\ojdbc14.jar

I did this right before run.bat checks to see if JBOSS_CLASSPATH is empty.

rem If JBOSS_CLASSPATH or JAVAC_JAR is empty, don't include it, as this will
rem result in including the local directory in the classpath, which makes
rem error tracking harder.
if not "%JAVAC_JAR%" == "" set RUNJAR=%JAVAC_JAR%;%RUNJAR%
if "%JBOSS_CLASSPATH%" == "" set RUN_CLASSPATH=%RUNJAR%
if "%RUN_CLASSPATH%" == "" set RUN_CLASSPATH=%JBOSS_CLASSPATH%;%RUNJAR%

After doing this you might need to tell your web application how to configure the data sources. I wrote a post about how to configure your data source for ATG web applications.

Update Profile in ATG Commerce

Wolf portrait 3 on Flickr
(Photo: Wolf portrait 3 by Tambako the Jaguar)

ProfileTools provides methods for updating a profile.  In ATG Commerce you can access the ProfileTools via the CommerceProfileTools.

Therefore to update a profile it is as simple as calling the update methods in ProfileTools.

getCommerceProfileTools().updateProperty(propertyName,
                                         property, getProfile());

getCommerceProfileTools().updateProperty(propertyTable, getProfile());

The update methods get the MutableRepositoryItem for the profile, set the property in the MutableRepositoryItem and then update the item in the ProfileRepository.

Pretty simple, eh? 🙂

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>

betweenGo Consults with Cineplex to Release Latest Version of Online Store on ATG

Cineplex Store

On Monday, August 30 Cineplex launched the latest version of its store running on ATG 2007.1 and JBoss 4.0.5.GA.

Cineplex ..:: Gift Cards betweenGo with Bell Canada was proud to be part of this release.  betweenGo implemented the handling of gift cards and product bundles and other eCommerce features.

Specific features we implemented for gift cards and product bundles included:

  • product listing
  • search listing
  • display in cart and throughout checkout
  • handling of taxes and shipping costs
  • promotions
  • inventory status
  • adding gift cards to the cart (required some JavaScript magic

Other features we implemented included:

betweenGo was proud to be part of this enjoyable project.  If you need expert ATG consulting please contact us.

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. 🙂