/* 
Pro Spring 
By Rob Harrop 
Jan Machacek 
ISBN: 1-59059-461-4 
Publisher: Apress 
*/ 
 
/////////////////////////////////////////////////////////////////////////////////////// 
//File: introductions.xml 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
<beans> 
    <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
        <property name="target"> 
            <bean id="beanTarget" class="TargetBean"> 
                <property name="name"> 
                    <value>Rob Harrop</value> 
                </property> 
            </bean> 
        </property> 
        <property name="interceptorNames"> 
            <list> 
                <value>advisor</value> 
            </list> 
        </property> 
        <property name="proxyTargetClass"> 
            <value>true</value> 
        </property> 
    </bean> 
     
    <bean id="advisor" class="IsModifiedAdvisor"/> 
</beans> 
 
 
/////////////////////////////////////////////////////////////////////////////////////// 
public interface IsModified { 
 
    public boolean isModified(); 
} 
 
 
/////////////////////////////////////////////////////////////////////////////////////// 
 
public class TargetBean { 
 
    private String name; 
     
    public void setName(String name) { 
        this.name = name; 
    } 
     
    public String getName() { 
        return name; 
    } 
} 
 
 
/////////////////////////////////////////////////////////////////////////////////////// 
import org.springframework.aop.support.DefaultIntroductionAdvisor; 
 
public class IsModifiedAdvisor extends DefaultIntroductionAdvisor { 
 
    public IsModifiedAdvisor() { 
        super(new IsModifiedMixin()); 
    } 
} 
 
 
 
/////////////////////////////////////////////////////////////////////////////////////// 
 
import java.lang.reflect.Method; 
import java.util.HashMap; 
import java.util.Map; 
 
import org.aopalliance.intercept.MethodInvocation; 
import org.springframework.aop.support.DelegatingIntroductionInterceptor; 
 
public class IsModifiedMixin extends DelegatingIntroductionInterceptor 
        implements IsModified { 
 
    private boolean isModified = false; 
 
    private Map methodCache = new HashMap(); 
 
    public boolean isModified() { 
        return isModified; 
    } 
 
    public Object invoke(MethodInvocation invocation) throws Throwable { 
 
        if (!isModified) { 
            if ((invocation.getMethod().getName().startsWith("set")) 
                    && (invocation.getArguments().length == 1)) { 
 
                // invoke the corresponding get method to see 
                // if the value has actually changed 
                Method getter = getGetter(invocation.getMethod()); 
 
                if (getter != null) { 
                    // modification check is unimportant 
                    // for write only methods 
                    Object newVal = invocation.getArguments()[0]; 
                    Object oldVal = getter.invoke(invocation.getThis(), null); 
                     
                    if((newVal == null) && (oldVal == null)) { 
                        isModified = false; 
                    } else if((newVal == null) && (oldVal != null)) { 
                        isModified = true; 
                    } else if((newVal != null) && (oldVal == null)) { 
                        isModified = true; 
                    } else { 
                        isModified = (!newVal.equals(oldVal)); 
                    } 
                } 
 
            } 
        } 
 
        return super.invoke(invocation); 
    } 
 
    private Method getGetter(Method setter) { 
        Method getter = null; 
 
        // attempt cache retrieval. 
        getter = (Method) methodCache.get(setter); 
 
        if (getter != null) { 
            return getter; 
        } 
 
        String getterName = setter.getName().replaceFirst("set", "get"); 
        try { 
            getter = setter.getDeclaringClass().getMethod(getterName, null); 
 
            // cache getter 
            synchronized (methodCache) { 
                methodCache.put(setter, getter); 
            } 
 
            return getter; 
        } catch (NoSuchMethodException ex) { 
            // must be write only 
            return null; 
        } 
    } 
} 
 
/////////////////////////////////////////////////////////////////////////////////////// 
 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.FileSystemXmlApplicationContext; 
 
public class IntroductionConfigExample { 
 
    public static void main(String[] args) { 
        ApplicationContext ctx = new FileSystemXmlApplicationContext( 
                "build/introductions.xml"); 
 
        TargetBean bean = (TargetBean) ctx.getBean("bean"); 
        IsModified mod = (IsModified) bean; 
 
        // test interfaces 
        System.out.println("Is TargetBean?: " + (bean instanceof TargetBean)); 
        System.out.println("Is IsModified?: " + (bean instanceof IsModified)); 
 
        // test is modified implementation 
        System.out.println("Has been modified?: " + mod.isModified()); 
        bean.setName("Rob Harrop"); 
        System.out.println("Has been modified?: " + mod.isModified()); 
        bean.setName("Joe Schmoe"); 
        System.out.println("Has been modified?: " + mod.isModified()); 
    } 
}            
       
  |