Debugging a Category’s Bad Child Products

Today I was using the CategoryLookup droplet to find a category’s child products. However when I accessed the child products I would get this JDBC error.

java.lang.NullPointerException
at java.lang.String.(String.java:166)
at oracle.sql.CharacterSet.AL32UTF8ToString(CharacterSet.java:1517)

I realized my product data was corrupted. However this category had over 70 child products. The stack trace wasn’t telling me which one was corrupt and going through each child product to find out which one was corrupt was too painful.

I first queried the database to find all the child product ID’s.

SQL> select child_prd_id from dcs_cat_chldprd where category_id='cat101' order by sequence_num;

I then created a simple JHTML page which would query each child product and output which ones were corrupted.

<java>
final String [] product_ids = { "prod101", "prod102", "prod103" };

for (int ii = 0; ii < product_ids.length; ii++) {
out.print(ii + ". [" + product_ids[ii] + "] ");
try {
</java>
<droplet name="/atg/commerce/catalog/ProductLookup">
<param name="id" value="`product_ids[ii]`">
<oparam name="output">
<valueof param="element.displayName"/><br/>
</oparam>
</droplet>
<java>
} catch (RuntimeException exc) {
out.println(exc + "<br>");
}
}
</java>

Once I knew which child products were bad I removed their mappings to the category in dcs_cat_chldprd.

SQL> delete from dcs_cat_childprd where child_prd_id = 'prod102' and category_id='cat101';

Then I updated the sequence numbers so that they are all consecutive by moving the ones at the end to fill the holes created by the previous deletes.

SQL> update dcs_cat_childprd set sequence_num = 1 where child_prd_id = 'prod103' and category_id='cat101';

Submitting a form with a radio button

Submitting a form from a radio button is not common but it is a nice UI which is even better when done with AJAX.

A typical form with two radio buttons would look something like this.

<form action="test.html">
1 <input type="radio" name="test" value ="1"><br>
2 <input type="radio" name="test" value ="2">
<p><input type="submit" value="submit">
</form>
1
2

But with basic JavaScript you can make a simpler form like this.

<script>
function submitAction( form, absPath ) {
form.action = absPath;
form.submit();
}
</script>
<form action="test.html" id="test">
1 <input type="radio" name="test" value ="1" onchange="submitAction(document.getElementById('test'), 'test.html')"><br>
2 <input type="radio" name="test" value ="2" onchange="submitAction(document.getElementById('test'), 'test.html')">
</form>
1
2

If you are using Struts the above form’s JSP would be:

<html:form action="test.do" styleId="test">
1 <input type="radio" name="test" value ="1" onchange="submitAction(document.getElementById('test'), 'test.do')"><br>
2 <input type="radio" name="test" value ="2" onchange="submitAction(document.getElementById('test'), 'test.do')">
</html:form>

Printing out an array

When printing out an array if you simply do a toString on the array you will get a “fairly useless result such as [C@16f0472”. Consider using Arrays.toString to convert the array into a readable String that gives the contents of the array.” I used to use Arrays.asList followed by toString but Arrays.toString is definitely more efficient and is available as of JDK 1.5.0.

This method is useful when you want to report on the values of an JDK 1.5 enum since the values method returns an array.

The quote is from a FindBugs report.

Accessing JavaBean’s Getters and Setters

A JavaBeans is simply a Java class with a set of properties, each property which has a getter and/or a setter. For example if the Java class has a name property it could be defined like this.

public class Foo {
  private String mName;
  public String getName() { return mName; }
  public void setName(String pName) { mName = pName; }
}

Typically one accesses the property by directly calling its getter and/or setter. But sometimes you may not know the name of the property in advance but still might want to access the getter and/or setter. To do this one can use Java’s beans and reflection packages.

Here is an example of how one would read the value of a property of a JavaBean. Note that the property name should not be capitalized.

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public Object getProperty(MyBean myBean, String propertyName) {

  // get descriptor of property
  PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, myBean.getClass());

  // invoke read method on property of myBean
  Method readMethod = descriptor.getReadMethod();
  return readMethod.invoke(memberSavingsProfile, (Object []) null);
}

Note that if your property only has a getter then you would create the PropertyDescriptor like this.

// get descriptor of property that only has a getter
String readMethodName = "get" + org.apache.commons.lang.StringUtils.capitalize(propertyName);
String writeMethodName = null;
PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, myBean.getClass(), readMethodName, writeMethodName);

Accessing the class from a static method which the class owns

Accessing the class from a static method which the class owns is a bit tricky. From a non-static method accessing the class is as simple as doing this.

Class thisClass = this.getClass(); In a static method there are two different ways to access the class. One way, which I learned from this forum discussion, is to create a stack trace and use the fact that the top of the stack trace will have the class we want.
// get stack trace
StackTraceElement[] stackTrace = new Throwable().getStackTrace();

// get the class name at the top level of the stack trace
StackTraceElement stackTraceTopLevelElem = stackTrace[0];
String thisClassName = stackTraceTopLevelElem.getClassName();

// get the class using the class loader
Class thisClass;
try {
  thisClass = Class.forName(thisClassName);
} catch (ClassNotFoundException exc) {
  // this should never happen
}

The other way is to use Java’s SecurityManager class as described in this article. This way seems preferable because it is not as costly as creating an exception as done in the other way.

Here is some sample code using the SecurityManager. Note that we need to use an inner class because the getClassContext() method is protected.

public static void main(String[] args) {
  Class clazz = new ClassGetter().getClazz();
}

// inner class is necessary since getClassContext is protected
private static class ClassGetter extends SecurityManager {

  protected ClassGetter() {
    // do nothing
  }

  protected Class getClazz() {
    Class [] classes = getClassContext();
    Class clazz = classes[1];
    return clazz;
  }
}

HibernateException: Found two representations of same collection

Sometimes you might stumble upon this confusing exception.

org.hibernate.HibernateException: Found two representations of same collection: com.betweengo.Foos

This could have happened because after clearing a Hibernate session (session.clear()) you updated a property that contains a collection. I found just making sure to clear the session once seemed to fix the problem but that may not be a suitable solution in more complex situations.

More information about this problem can be found at http://forum.hibernate.org/viewtopic.php?p=2231400.

Catching Oracle exceptions

Oracle SQL queries can throw exceptions. For example in this query f there is no data then Oracle will throw a NO_DATA_FOUND exception.

SELECT status_date INTO v_status_date FROM member WHERE member_id = p_member_id_in;

ORA-01403: no data found

If this query is part of a stored procedure and is called from Hibernate you will get this uninformative exception.

org.hibernate.exception.DataException: could not execute query

Oracle SQL, like many languages, has a try catch construct. In this example you could do the following.

BEGIN
  SELECT status_date INTO v_status_date FROM member WHERE member_id = p_member_id_in;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    v_status_date := NULL;
END;

How to Log SQL on JBoss

Edit the log4j.xml in the conf directory as shown below to turn on SQL debugging of the JDBC CMP plugin.

/apps/jboss/server/default/conf :->diff -c log4j.xml~ log4j.xml
*** log4j.xml~  Mon Sep 30 18:09:27 2002
--- log4j.xml   Tue Apr  4 20:41:18 2006
***************
*** 61,73 ****
    <!-- ============================== -->

    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
!     <param name="Threshold" value="INFO"/>
      <param name="Target" value="System.out"/>

      <layout class="org.apache.log4j.PatternLayout">
        <!-- The default pattern: Date Priority [Category] Message\\n -->
        <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>

      </layout>
    </appender>

--- 61,79 ----
    <!-- ============================== -->

    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
!     <!--<param name="Threshold" value="INFO"/>-->
!     <param name="Threshold" value="DEBUG"/>
      <param name="Target" value="System.out"/>

      <layout class="org.apache.log4j.PatternLayout">
        <!-- The default pattern: Date Priority [Category] Message\\n -->
        <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>

      </layout>
+
+     <category name="org.jboss.ejb.plugins.cmp.jdbc">
+       <priority value="DEBUG"/>
+     </category>
+
    </appender>

If you want to log Hibernate SQL statements:

    <category name="org.hibernate.SQL">
      <priority value="DEBUG"/>
    </category>

If you want to log everything Hibernate’s doing, including SQL statements, schema export, transactions, etc.:

    <category name="org.hibernate.SQL">
      <priority value="DEBUG"/>
    </category>

JDBC Plugins for Eclipse

I was previously using DbVisualizer to query and update my Oracle databases and was not completely satisfied with it. I actually prefer PhpMyAdmin but that only works with MySQL.

Since I use Eclipse so much for development I decided to look for a JDBC plugin that is at least as good as DbVisualizer. My goal is to have in one workspace access to my database as well as my source and configuration files.

I went to EclipsePlugins and downloaded the three highest rated JDBC plugins, all which happen to be free (in some cases just for non-commercial use).

  1. DBEdit
  2. QuantumDB
  3. SQLExplorer

I installed DBEdit 1.0.3_1, Quantum DB 3.0.1 (which requires GEF, I installed 3.1.1), SQLExplorer 2.2.4.

Setup was quite simple with DBEdit, just add the JDBC driver to the CLASSPATH, give it the JDBC URL and connect. Setup was almost as simple with Quantum DB though it asks you for the components of the JDBC URL instead of the URL directly. I couldn’t figure out how to setup SQLExplorer within five minutes so I gave up.

DBEdit and Quantum DB have similar interfaces and both are similar to DbVisualizer though Quantum DB’s appealed to me a little more. However Quantum DB’s interface responded much more quickly and querying of tables was much faster. DBEdit has a nice feature, which I did not completely test, of inline editing of cell values which seems quite powerful.

Because of Quantum DB’s speed and responsiveness I am going to continue to use that as my primary JDBC plugin but I will also keep DBEdit on the side to use for its inline editing but also in case I find Quantum DB does something in an unintuitive manner.

Update: Since I posted this less than a month ago I found DBEdit much more useful than Quantum DB. It’s inline editing, inserting feature, and other editing features really make it powerful. Also its filter, scrolling through result sets, etc. are great. I highly recommend DBEdit.

Java allocation is no longer expensive

Beginning in JDK 1.4.2, allocation of new objects is no longer expensive according to this article, Java theory and practice: Urban performance legends, revisited. According to this article.

… allocation in modern JVMs is far faster than the best performing malloc implementations…

The malloc/free approach deals with blocks of memory one at a time, whereas the garbage collection approach tends to deal with memory management in large batches, yielding more opportunities for optimization (at the cost of some loss in predictability).

This “plausibility argument” — that it is easier to clean up a mess in one big batch than to pick up individual pieces of dust throughout the day — is borne out by the data.

So allocate away, never object pool, don’t do strange, non-intuitive things to avoid allocating objects on the heap. Life is good.