Fixing issue with Classloader leaks.

We had an issue with a classloader leak. There were three things we had to do before it worked.

  1. Made the mysql connector provided and add mysql-connector jar to the tomcat/libexe/lib directory
    1. Maven block:
      <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.34</version>
      <scope>provided test</scope>
      </dependency>
      
  2. Added the following jvm option to use G1 garbage collection, and enable class unloading and perm gen sweep.
    NOTE: You need all three for this to work. Ignore the warning from java: “Please use CMSClassUnloadingEnabled in place of CMSPermGenSweepingEnabled in the future.” I’ve tried just G1, G1 with class unload, and G1 with perm gen. They are all needed for heap to stay low and for classes to be unloaded.

    -XX:+UseG1GC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  3. Added the following library for classloader leak prevention.
    1. Add the following block in your pom.xml of the web module:
      <!--
      https://github.com/mjiderhamn/classloader-leak-prevention
      -->
      <dependency>
      <groupId>se.jiderhamn</groupId>
      <artifactId>classloader-leak-prevention</artifactId>
      <version>1.15.2</version>
      </dependency>
      
    2. Add the following listener to your web.xml:
      <listener>
      <description>https://github.com/mjiderhamn/classloader-leak-prevention</description>
      <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor</listener-class>
      </listener>
      

Once that is all setup, do a clean package on maven, redeploy and restart tomcat

Jpa 2.0 performing a count on a query with joins

It’s been too long since I’ve blogged. Here is an interesting one. I recently had to modify old code. They were using jpa 2.0 in more of a 1.0 syntax. There was a very complex query with joins used for searching. There was pagination, sort of. They were not returning the total record count. So I decided to do a count on the same query as a happy medium until we can upgrade to a newer way of doing things.

I tried using the same query and predicates to do the count. I tried following several examples from stack overflows and forums. But, all the examples were with simple queries that did not do joins.

The biggest thing here is that I had to use different query objects and different predicate objects, while using the same root when creating the count predicates and the count query. It appears that query.from() creates a different root each time it’s called. So, I set this to a variable and reused it.

I’ve left out the complex code that generates the predicates to save space. I can add it if needed. It is in the method getPredicates(searchCustomerRequest, criteriaBuilder, customerRoot); which is also used by searchCustomer(searchCustomerRequest); to build the same predicate list.


Map results = new HashMap();
CriteriaBuilder criteriaBuilder = getRoEntityManager().getCriteriaBuilder();
Logger.debug(ToStringBuilder.reflectionToString(searchCustomerRequest));
CriteriaQuery countQuery = criteriaBuilder.createQuery(Long.class);

Root customerRoot = countQuery.from(Customer.class);
List lstCriteria = getPredicates(searchCustomerRequest, criteriaBuilder, customerRoot);
Predicate[] predicates = lstCriteria.toArray(new Predicate[lstCriteria.size()]);

/*Start count*/
Logger.debug("Getting Count");
countQuery.select(criteriaBuilder.countDistinct(customerRoot));
countQuery.where(criteriaBuilder.and(predicates));
Long totalRecordCount = getRoEntityManager().createQuery(countQuery).getSingleResult();

List lstCustomer = searchCustomer(searchCustomerRequest);

results.put("customerList", lstCustomer);
results.put("totalRecordCount", totalRecordCount);
return results;

Exclude URL from EhCache Web Cache

You would think that this would be built-in, to easily exclude a URL. Maybe there is a good reason they left it out. Anyway, I recently needed to cache results from webservice hits, so that we could minimize the load on the database. I liked the idea of caching the response to really minimize the execution of code. EhCache Web Cache seemed perfect, until I had to exclude one specific service from the cache. The specs were already given to the customer and the URL could not change. So, I chose to use filters to prevent caching.

First, I created a filter and overrode the doFilter method as seen below.

public class NoCacheFilter implements javax.servlet.Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        /** do nothing **/
    }

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {

        if (request instanceof HttpServletRequest
            && response instanceof HttpServletResponse) {

            HttpServletRequest httpRequest = (HttpServletRequest) request;
            String requestUri = httpRequest.getRequestURI();
            if(requestUri.contains("/registration/save")) {
                requestUri = requestUri.replace("/vine/", "/vine-nocache/");
                request.getRequestDispatcher(requestUri)
                       .forward(request, response);
            } else {
                chain.doFilter(request, response);
            }
        }
    }

    @Override
    public void destroy() {
        /** do nothing **/
    }
}

Second, I created another controller for URLs that should not be cached.

@Controller
@RequestMapping("vine-nocache")
public class VineNoCacheController {

    @Autowired
    @Qualifier("vineRegisterWsTemplate")
    private WebServiceTemplate vineRegisterWsTemplate;

    @RequestMapping(value = "/site/{siteId}/agency/{agencyId}/offender/{subjectId}
                             /registration/save",
                    produces = "application/json")
    public void registerVictim(@PathVariable Integer siteId,
                               @PathVariable Integer agencyId,
                               @PathVariable String subjectId,
                               @RequestParam(required = false) Boolean enableTTY,
                               @RequestParam(required = false) String pin,
                               @RequestParam EnumLanguage language,
                               @RequestParam String uniqueDeviceId,
                               HttpServletResponse response) throws IOException {

// code omitted to save space
}

Third, I configured the filter in the web.xml. The filters execute in order. So, by putting the no cache filter first, it will execute that doFilter method and if the URI contains the “registration/save”, then forward the request to vine-nocache. If it does not contain that String, then continue down the filter chain(which the next filter is the web cache filter). By using a forward, the end user never knows that it is a different URL.

    <filter>
        <filter-name>VineNoCacheFilter</filter-name>
        <filter-class>com.appriss.patrol.vine.NoCacheFilter</filter-class>
    </filter>
    <filter>
        <filter-name>WebServiceCachingFilter</filter-name>
        <filter-class>com.appriss.patrol.ehcache.WebServiceCachingFilter</filter-class>
        <init-param>
            <param-name>cacheName</param-name>
            <param-value>WebServiceCachingFilter</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>VineNoCacheFilter</filter-name>
        <url-pattern>/vine/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>WebServiceCachingFilter</filter-name>
        <url-pattern>/vine/*</url-pattern>
    </filter-mapping>

If there is a better way, please share. But, this is the best way I found in a short period of time.