Additional Code zip file - 7 KB

Additional Code II zip file - 4 MB


Listing 1: OrderService business interface

*/
public interface OrderService {
	public OrderDAO getDao() ;
	public void setDao(OrderDAO dao) ;
	public ArrayList showAllOrders();
	public int countAllOrders();
	public Order showOrder(int orderId) ;
	public void placeOrder(Order order) ;
	public void modifyOrder(Order order);
	public void dropOrder(int orderId);
	public void printReport(boolean internalUser) ;
	public void printLongReport(int longRunning);
}


Listing 2: orderContext.xml file representing the BeanFactory

	<bean id="orderService" class="com.acme.order.manager.OrderServiceImpl" >
		<property name="dao" ref="orderDAO" />
	</bean>

	<bean id="orderDAO" class="com.acme.order.dao.jdbc.JdbcOrderDAO">
		<property name="jdbcTemplate" ref="orderJdbcTemplate" />
	</bean>

	<bean id="orderJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
		<property name="dataSource" ref="myDataSource"/>
	</bean>

.   .   .

	<!-- non XA dataSource (right now the same) 	-->
	<bean id="xaDataSourceFromWLS" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName">
			<value>${jdbc.jndi.pool}</value>
		</property>
		<property name="jndiEnvironment">
		<props>
			<prop key="java.naming.factory.initial">${java.naming.factory.initial}</prop>
			<prop key="java.naming.provider.url">${java.naming.provider.url}</prop>
		</props>
		</property>
	</bean>


Listing 3: Transaction ProxyBean Configuration

<bean id="myProxiedServiceWithSeveralInterceptors" 
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
	   <property name="target" ref="orderService"/>
	   <property name="transactionManager" ref="transactionManager"/>
	   <property name="transactionAttributes">
	     <props>
	       <prop key="place*">PROPAGATION_REQUIRED</prop>
	       <prop key="modify*">PROPAGATION_REQUIRED</prop>
			 			<prop key="drop*">PROPAGATION_REQUIRED</prop>

			 			<prop key="show*">PROPAGATION_SUPPORTS</prop>
						<prop key="count*">PROPAGATION_SUPPORTS</prop>
			 			<prop key="print*">PROPAGATION_SUPPORTS</prop>
	        <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
	     </props>
	   </property>
	   <!-- force use of CGLIB for performance -->
	   <property name="optimize">
		   <value>true</value>
	   </property>
	   <property name="proxyTargetClass">
		   <value>true</value>
	   </property>
	   <property name="frozen">
		   <value>true</value>
	   </property>

	   <property name="preInterceptors" >
		   <list>
			   <ref local="xaConnectionAdvisor"/>
			   <ref local="auditAdvisor"/>
			   <ref local="loggedMethodAdvisor"/>
			   <ref local="profilingAdvice"/>
			   <ref local="throwsAdvice"/>
		   </list>
	   </property>
	</bean>


Listing 4: LoggedMethodAdvice

public class LoggedMethodAdvice implements  MethodInterceptor{
	protected final Logger LOG = Logger.getLogger(getClass().getName());
	public Object invoke(MethodInvocation invocation) throws Throwable{
		Method method = invocation.getMethod();
		String className = invocation.getThis().getClass().getName();
		String methodName = method.getName();
		LOG.info("Going to invoke: " + className + ":" + methodName);
		Object ret = invocation.proceed();
		LOG.info("Done with method: " + className + ":" + methodName);
		return ret;
	}

}


Listing 5: LoggedMethodPointcut configuration

	<bean id="loggedMethodPointcut"
	class="org.springframework.aop.support.NameMatchMethodPointcut" >
		<property name="mappedNames">
			<list>
				<value>placeOrder</value>
				<value>modifyOrder</value>
				<value>dropOrder</value>
			</list>
		</property>
	</bean>


Listing 6: LoggedMethodAdvisor configuration

<bean id="loggedMethodAdvisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor" >
		<constructor-arg index="0">
            <ref local="loggedMethodPointcut"/>
        </constructor-arg>
        <constructor-arg index="1">
            <ref local="loggedMethodAdvice"/>
        </constructor-arg>
	</bean>


Listing 7: AuditDynamicPointcut

public class AuditDynamicPointcut extends DynamicMethodMatcherPointcut {

	ArrayList methodNames;

	public boolean matches(Method method, Class clazz, Object[] object) {
		boolean ret = false;
		if ((object != null) && (object.length > 0)){
			boolean isInternal = ((Boolean)object[0]).booleanValue();
			//Only audit those calls that are not from internal users
			ret = !isInternal;
		}
		return ret;
	}
	public boolean matches(Method method, Class clazz) {
		String methodName = method.getName();
		boolean ret = false;
		if (methodNames.contains(methodName)){
			ret = true;
		}
		return ret;
	}
	public ClassFilter getClassFilter(){
		return new ClassFilter() {
			public boolean matches (Class clazz){
				return (OrderService.class.isAssignableFrom(clazz));
			}
		};
	}
	public ArrayList getMethodNames() {
		return methodNames;


Listing 8: Specifying auditable methods in the BeanFactory declaratively

	<bean id="auditPointcut" class="com.acme.advice.AuditDynamicPointcut" >
		<property name="methodNames">
			<list>
				<value>printReport</value>
			</list>
		</property>
	</bean>

Listing 9: AuditAdvisor configuration

<bean id="auditAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" >
		<constructor-arg index="0">
            <ref local="auditPointcut"/>
        </constructor-arg>
        <constructor-arg index="1">
		<ref local="auditAdvice"/>
        </constructor-arg>
	</bean>


Listing 10: ProfilingAdvice Class

public class ProfilingAdvice implements MethodInterceptor {

	/**
	 * Purposely left logic for checking name string here, to show that ALL methods targeted 
	 * by a proxy can be intercepted and the check can be made inside the advice after
	  interception to see if
	 * the advice needs applied or not.
	 * This is NOT the preferred way to decide where the advice needs applied.
	 * If possible, use a Pointcut implementation to decide what to apply the advice to.

	 * @see LoggedMethodAdvice
	 */
	protected final Logger LOG = Logger.getLogger(getClass().getName());
	public Object invoke(MethodInvocation invocation) throws Throwable {
		StopWatch sw = null;
		String name = invocation.getMethod().getName();

		boolean profileThis = (name.indexOf("Long") != -1);
		if (profileThis){
			sw = new StopWatch();
			sw.start(name);
		}

		Object ret = invocation.proceed();

		if (profileThis){
			sw.stop();
			LOG.info("Proxied Method " + name + " took " + sw.getTotalTimeMillis() + "
			milliseconds.");
		}
		return ret;
	}

}


Listing 11: PreInterceptors in the TransactionProxyFactoryBean

	   <property name="preInterceptors" >
		   <list>
			   <ref local="xaConnectionAdvisor"/>
			   <ref local="auditAdvisor"/>
			   <ref local="loggedMethodAdvisor"/>
			   <ref local="profilingAdvice"/>
			   <ref local="throwsAdvice"/>
		   </list>
	   </property>
	</bean>


Listing 12: Throws Advice to intercept exceptions

public class ApplicationThrowsAdviceAdapter implements ThrowsAdvice {
	protected final Logger LOG = Logger.getLogger(getClass().getName());

	public void afterThrowing(Method method, Object[] args, Object target, NullPointerException
	infamous ){
		String arguments = "";
		arguments =(args == null?"":args.toString());
		LOG.info("Sending out mail to developer: NullPointerException occurred Target: " 
		+ target.getClass().getName() +
		" Method: " + method.getName() + " Arguments: " + arguments);
	}
	public void afterThrowing(Method method, Object[] args, Object target,
	IllegalStateException infamous ){
		String arguments = "";
		arguments =(args == null?"":args.toString());
		LOG.info("Sending out mail to webmaster: IllegalStateException occurred Target: " 
		+ target.getClass().getName() +
		" Method: " + method.getName() + " Arguments: " + arguments);
	}
}

Listing 13: Injecction of data sources in xaConnectionAroundAdvice

<bean id="xaConnectionAroundAdvice" class="com.acme.advice.XADataSourceAroundAdvice" >
		 <property name="xaDataSource" ref="myDataSource"/>
		 <property name="nonXADataSource" ref="myDataSource"/>
	</bean>

Listing 14: XAConnectionAroundAdvice

public class XADataSourceAroundAdvice implements MethodInterceptor {

	protected final Logger LOG = Logger.getLogger(getClass().getName());
	DataSource xaDataSource ;
	DataSource nonXADataSource ;
	public Object invoke(MethodInvocation invocation) throws Throwable {
		JdbcTemplate template = null;
		String name = invocation.getMethod().getName();
		Object target = invocation.getThis();
		boolean switchit = false;

		OrderService mms = (OrderService)target;
		OrderDAO dao = mms.getDao();
		if (dao instanceof JdbcOrderDAO){
			JdbcOrderDAO jdao = (JdbcOrderDAO)dao;
			template = jdao.getJdbcTemplate();
			switchit = true;
		}
		if (switchit){
			LOG.info("Changing datasource to XA for " + name);
			template.setDataSource(xaDataSource);
		}
		Object ret = invocation.proceed();

		if (switchit){
			LOG.info("Changing datasource back to nonXA for " + name);
			template.setDataSource(nonXADataSource);
		}
		return ret;

Listing 15: xaMethodPointCut configuration

	<bean id="xaMethodPointcut"
	class="org.springframework.aop.support.NameMatchMethodPointcut" >
		<property name="mappedNames">
			<list>
				<value>placeOrder</value>
				<value>modifyOrder</value>
			</list>
		</property>
	</bean>

Listing 16: XAConnectionAdvisor configuration

	<bean id="xaConnectionAdvisor"
	class="org.springframework.aop.support.DefaultPointcutAdvisor" >
		<constructor-arg index="0">
            <ref local="xaMethodPointcut"/>
        </constructor-arg>
        <constructor-arg index="1">
            <ref local="xaConnectionAroundAdvice"/>
        </constructor-arg>
	</bean>

Listing 17: Defining an SLSB in the BeanFactory

(See Graphic Called Listing17.gif in Tandon's Article)




Listing 18: Configuring the BeanFactory in web.xml

<listener>
    	<listener-class>
    		org.springframework.web.context.ContextLoaderListener
    	</listener-class>
    </listener>

    <context-param>
    	<param-name>
    		contextConfigLocation
    	</param-name>
    	<param-value>
    		/WEB-INF/classes/orderContext.xml
    	</param-value>
    </context-param>


Listing 19: Accessing the applicationContext from your servlet context

	ApplicationContext ctx =
	WebApplicationContextUtils.getWebApplicationContext
	(getServletConfig().getServletContext());
	OrderService   nonProxiedService = (OrderService)ctx.getBean("orderService");
	OrderService   proxiedService =
	(OrderService)ctx.getBean("myProxiedServiceWithSeveralInterceptors");


Listing 20: Accessing the applicationContext from the classpath

String[] paths = { "classpath:orderContext.xml" };
ApplicationContext ctx = new ClassPathXmlApplicationContext(paths);
nonProxiedService = (OrderService)ctx.getBean("orderService");
proxiedService = (OrderService)ctx.getBean
("myProxiedServiceWithSeveralInterceptors");

Additional Code zip file - 7 KB

Additional Code II zip file - 4 MB