Monday 18 April 2016

How to handle Exception in Spring MVC application


Below is one way to handling errors in an spring  MVC  architecture

The class that is given provided below is an ExceptionHandler class which takes care of handing the errors that occurs in the controller and redirect to the error page

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class GlobalExceptionHandler {

private @Value("${debugmode.enabled}") Boolean isDebugModeEnabled;

@ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest request, HttpSession session,  Exception e) throws Exception {
     
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) throw e;
     
        // Otherwise setup and send the user to a default error-view.
        ModelAndView mav = new ModelAndView();
        if(isDebugModeEnabled) {
        mav.addObject("exceptionMessage", e);
        } else {
        mav.addObject("exceptionMessage", null);
        }
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("error");
        return mav;
    }

}

How to configure Ehcache at Entity level in Spring+Hibernate+JPA application

Add the below entries in ehcache.xml which is placed in resources folder incase of maven project and otherwise in the classpath



<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="false" monitoring="autodetect"
         dynamicConfig="true">
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="1200" timeToLiveSeconds="1200"     overflowToDisk="true" diskPersistent="false"
     diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"/>
   
     <cache name="org.hibernate.cache.internal.StandardQueryCache"  maxElementsInMemory="10000"   eternal="false"   timeToIdleSeconds="3600"  timeToLiveSeconds="3600"/>
  <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"  maxElementsInMemory="10000"  eternal="true"/>  
     <cache name="com.traveldesk.TravelDetail"  eternal="true"  maxElementsInMemory="10000"/>  
</ehcache>


The annotation @cache  helps in making the entity as a cacheable one

@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@Table(name="TRAVEL_DETAIL" , schema="travel")
@NamedQuery(name="TravelDetail.findAll", query="SELECT d FROM TravelDetail d")
public class TravelDetail implements Serializable { }


The properties that are to be provided in the persistence.xml are as follows


<property name="hibernate.cache.region_prefix" value=""/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
            <property name="hibernate.cache.use_second_level_cache" value="true" />
            <property name="hibernate.cache.use_query_cache" value="true" />
            <property name="hibernate.generate_statistics" value="true" />
            <property name="hibernate.cache.use_structured_entries" value="true" />                
            <property name="net.sf.ehcache.configurationResourceName" value="META-INF/ehcache.xml" />
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory" />



How to configure SLF4j & Logback Logger in Spring+Hibernate applications

Add the below dependencies in the pom.xml

 <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
      </dependency>

 <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>${logback.version}</version>
      </dependency>



if it is a maven project , place the below logback.xml in travel-desk\src\main\resources\. Place the **logback-appenders.xml and **logback-loggers.xml in path specified in {-Dapp.configs=c:\<path>}, try to add {-Dapp.configs=c:\<path>} in vm-arguments of  the application server that  you have configured in Eclipse IDE or whichever IDE you use.

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scanPeriod="60 seconds" scan="true">

<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>

<!-- To enable JMX Management -->
<jmxConfigurator/>
<include file="${app.configs}/travelDesk/travelDesk-logback-appenders.xml"/>
<include file="${app.configs}/travelDesk/travelDesk-logback-loggers.xml"/>
</configuration>


 Try to add {-Dapp.logs=<path>}  in vm-arguments of  the application server that  you have configured in Eclipse IDE or whichever IDE you use. Below is an snippet from **appenders.xml

/travelDesk-logback-appenders.xml

<included>
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%date{ISO8601} %-5p [%t][%c] %m%n</pattern>
    </encoder>
  </appender>
 
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${app.logs}/travelDesk/travelDesk.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>${app.logs}/travelDesk/travelDesk.%d{yyyy-MM-dd}.log</fileNamePattern>
      <!-- keep 50 days' worth of history -->
      <maxHistory>50</maxHistory>
    </rollingPolicy>
    <encoder>
      <pattern>%X{NDC0}%X{NDC1}%X{NDC2}%X{NDC3}%date{ISO8601} %-5p [%t][%c] %m%n</pattern>
    </encoder>
  </appender>
</included>


Below are the lines from  **loggers.xml
travelDesk-logback-loggers.xml

<included>
<!-- Loggers -->
<logger name="com.traveldesk" level="debug"/>
<logger name="org.springframework.integration" level="warn"/>

<root level="warn">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</included>