The Tomcat move: The unexpected which made us think

By Samanth Gunapal – Websites Core Platform team

One of our core products got moved from Weblogic 10.5 to Tomcat 7.0 recently. The older generation of the product was very dependent on a lot of Weblogic application server capabilities like EJBs, clustering, messaging. They were all removed in a planned manner. Once all of that got done, we were in the last leg of the move. When we ran the ported application on Tomcat, we found a lot of unexpected problems related to how things work differently in Tomcat and Weblogic. I would like to share some of the interesting ones, which needed us to make up our mind on how we wanted to handle them.

 

Tag instances are pooled!

One of the first things we noticed that some of our custom tags were broken. When we investigated further, we realized that our tags were getting wrong dependencies. When the tag was used in a particular place, it was getting dependencies from its first usage – dependencies were shared! That’s when we realized that tag instances were pooled in Tomcat and not so in Weblogic. In general, tag pooling seems to be a good practice and it is recommended. However, this didn’t work in our case since we wanted different behavior from the tag based on the different dependencies we provided to it. To give an example,

@Configurable(preConstruction = true)
public class MyTag extends TagSupport {
 @Resource
 private MyDependency dependency; // Depending on different contexts and needs, a different implementation needs to be injected
... 
}
So, we used a workaround to disable pooling by changing $CATALINA_BASE/conf/web.xml.
<servlet>
 <servlet-name>jsp</servlet-name>
 <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
 ...
 <init-param>
  <param-name>enablePooling</param-name>
  <param-value>false</param-value>
 </init-param>
 ...
</servlet>

 

The story of the truncated cookie

We store user preferences in cookies so that we can provide them with a personalized experience. For example, if the user chooses a particular make and model, we store that in a cookie like below.

Name Value Domain
userPreferences make=Chevrolet&model=Camaro http://www.example.com

Once we migrated to tomcat, this started failing. We found that Tomcat doesn’t allow a few characters in cookie values such as white space, brackets, parentheses, equals sign, commas, quotes, question mark etc. unless you explicitly enable it. Here is how the cookie value varies.

//code snippet
System.out.println (cookie.getName() + “ : ” + cookie.getValue());

//output
userPreferences : make=Chevrolet&model=Camaro //In Weblogic
userPreferences : make  //In Tomcat, cookie value got truncated from the character '='
The reason behind this seems that Tomcat by default adheres to version 0 cookie refer here. But since our user preferences were richer in nature and most users are on modern browsers, we decided to keep our richer cookies as is. So, we used the following Tomcat system properties to enable this behavior.
org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE=true
org.apache.tomcat.util.http. ServerCookie.ALLOW_HTTP_SEPARATORS_IN_VALUE=true

 

EL expressions with Java keywords will be stopped!

Few JSPs in our product were broken with javax.el.ELException. When we dug deeper on one of many instances, we found the following snippet in the JSP and the corresponding method in POJO.
//JSP snippet
...
${vehicle.new}
...
//POJO
class Vehicle {
  ...
  public boolean isNew() {
    //returns true if it is a new vehicle.
  }
  ...
}
Weblogic was working fine in this scenario, but Tomcat threw the exception. We then found that Tomcat’s EL parser seems to be stricter than that of Weblogic when it comes to the usage of Java keywords in EL expressions. But in this case, we wanted to preserve the semantics that the method name offered to our domain and code base. So we decided to turn off this check in Tomcat. We achieved the same using the following JVM argument.
-Dorg.apache.el.parser.SKIP_IDENTIFIER_CHECK=true

 

Conclusion

One aspect that jumps at us is that Tomcat seems to be leaning towards being stricter and conservative whereas Weblogic is more lenient and flexible. Generally, such strictness ensures that that the code we write is cleaner and better. That said, the above scenarios illustrate that sometimes it is important to weigh the benefits of following a practice in the context of how it applies to the product.

Sharing Spring JdbcTemplate instance

By Abhijat Upadhyay – Sr. Software Engineer – ADP Cobalt Inventory Platform

Prior to sharing the JdbcTemplate instance in our application, we injected a Datasource object directly into the DAOs and then in the setter method we created an instance of  the JdbcTemplate class.

For example:

@Autowired
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

Then we made the following change to our context xml:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
    <property name="fetchSize" value="200" />
</bean>

And this is how we started injecting the shared instance:

@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate

As per Spring, JdbcTemplate is thread safe once constructed. However, they also mention that the object is stateful but that state is not conversational. This is evident from our declaration in the context.xml above.

Motivation to share JdbcTemplate instance:

  1. To improve performance by reducing the roundtrips that resultset object has to make to fetch the next set of records. We achieve this by setting the fetchSize on JdbcTemplate. Without that the default value of 10 is used by Oracle JDBC driver. For example, if we are fetching 250 records from db with default fetchSize then there will be 25 roundtrips between Java layer and the database. This results in some performance hits. In our case prior to this change we reduced our cache priming time by about 40%. We work with large caches (30 GB+).
  2. We can set config params like fetchSize globally versus having to do inside each DAO.
  3. Object reuse: why to create new ones when it is thread safe… (or may be not, as we found out).

So, what’s the issue we ran into?

The issue is that JdbcTemplate is a “threadsafe” stateful object. In addition to storing fetchSize it also allows us to set maxRows.

From JdbcTemplate.java:

/**
* If this variable is set to a non-zero value, it will be used for setting the
* maxRows property on statements used for query processing.
*/
private int maxRows = 0;

Couple of our DAO classes were setting this value to 30K for business reasons. Since our JdbcTemplate instance is shared, if we set maxRows on it then it impacts all DAOs. Any DAO that is trying to fetch more than that many records will return back truncated resultset. For example if a query returns 45,000 records and the maxRows is set to 30,000 then the JdbcTemplate will return 30,000 records only. Previously, since each DAO had its own instance of JdbcTemplate we were not bitten by this issue.

So, what’s the solution?

Few options that we have on the table:

  1. Do what we were doing previously… meaning each DAO should create its own instance of JdbcTemplate.
  2. Make jdbcTemplate instance a prototype bean. This will ensure that each injected jdbcTemplate instance will be different. Similar to #1 but Spring does creation and injection and we can also set global variables in one place.
  3. Do not set maxRows on jdbcTemplate and “fix” the code that is doing that.
  4. Write a wrapper around JdbcTemplate to disallow modifying the state once it has been created.
  5. Request Spring to make JdbcTemplate safe to be used by shared instances. Meaning state should be assigned only during creation time and once that is done any further modification should generate an exception.

Java Refactoring for Fun and Profit: Interface Arguments

By Greg Larson – Sr. Software Engineer – ADP Cobalt SEO & Blogging Team

Since code duplication is generally agreed to be a Bad Thing, Java programmers often refactor similar methods into a single method with a differentiating argument. A typical case is shown in the following example – methodA and methodB are refactored into methodC with the addition of a boolean argument :

public MyClass methodA(String arg1, int arg2) {
   MyClass myClass = createObjectWithArg1(arg1);
   int intVal = doStuffWithBothValues(arg1, arg2);
   myClass.setValue(doStuffWithIntVal(intVal));
   doMoreStuff(myClass);
   return transform(myClass);
}

public MyClass methodB(String arg1, int arg2) {
   MyClass myClass = createObjectWithArg1(arg1);
   int intVal = doStuffWithBothValues(arg1, arg2);
   if(intVal < 0) {
      myClass.setValue(handleNegative(intVal));
   }
   return transform(myClass);
};

public MyClass methodC(String arg1, int arg2, boolean doOptionA) {
   MyClass myClass = createObjectWithArg1(arg1);
   int intVal = doStuffWithBothValues(arg1, arg2);
   if(doOptionA) {
     myClass.setValue(doStuffWithIntVal(intVal));
     doMoreStuff(myClass);
   } else if(intVal < 0) {
      myClass.setValue(handleNegative(intVal));
   }
   return transform(myClass);
};

The differentiating argument can also be an interface. When the method is called, a concrete implementation of the interface is passed in. In many cases the result is similar to passing a function pointer to a C++ method. For reuse, the implementation should be an instance of an externally defined class. In the case of one-time use, it can be an anonymous implementation inline with the method itself.

This approach is typical when applying the Strategy design pattern; Java’s Collections.sort method provides a good example:

Collections.sort(list, new Comparator<MyClass>(){
    public int compare(MyClass a, MyClass b) {
        // define strategy for comparing objects
    }
});

In the above example, defining the Comparator inline increases the readability of the code, since there is no need to look in another class to see the comparison strategy.

However, the same refactoring opportunity is often overlooked in the case of methods that vary by multiple similar method calls – especially if there is other logic separating the calls. The example below shows two methods that, although similar in structure, might easily escape refactoring.

public MyClass operationA(MyClass myClass) {
   for(MyItem myItem : myClass.getList() {
      utilA.transform(myItem, 1));
   }
   doStuff(myClass);
   myClass = serviceA.execute(myClass);
   doMoreStuff(myClass);
   return myClass;
}

public MyClass operationB(MyClass myClass) {
   for(MyItem myItem : myClass.getList() {
      utilB.transform(myItem, 2));
   }
   doStuff(myClass);
   myClass = serviceB.execute(myClass);
   doMoreStuff(myClass);
   return myClass;
}

To refactor, define an interface with the signatures of the varying method calls:

interface MyInterface {
   void doMethod(MyItem myItem, int transformInt);
   int getTransformInt();
   MyClass execute(MyClass myClass);
}

Notice that an additional method was added in this case to supply the differing int values used in the transform method.

Now replace the two methods with a single method that takes the interface as one of its arguments:

public MyClass operationC(MyClass myClass, MyInterface myInterface) {
   for(MyItem myItem : myClass.getList() {
      myInterface.doMethod(myItem, myInterface.getTransformInt()));
   }
   doStuff(myClass);
   myClass = myInterface.execute(myClass);
   doMoreStuff(myClass);
   return myClass;
}

The refactored method can then be called with the interface implementation defined anonymously in the method call:

MyClass myClass = operationC(myClass, new MyInterface() {
   public void doMethod(myClass) {
      // call UtilA.transform or UtilB.transform or...
   }
   public int getTransformInt() {
      // return whatever int value is needed
   }
   public MyClass execute(MyClass) {
      // call ServiceA.execute or ServiceB.execute or...
   }
});

One caveat: the extracted interface methods should be cohesive. If the interface definition becomes a hodge-podge of unrelated methods, it should be divided into multiple interfaces so that each interface has a clear focus.

Granted, the above refactoring does not produce an impressive simplification for only two methods. But often there are several similar methods all executing slightly different strategies, in which case this approach eliminates significant duplication and streamlines code considerably. An easy win!

%d bloggers like this: