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 II zip file - 4 MB