Project

General

Profile

Download (5.01 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.cdm.aspectj;
2

    
3
import java.lang.reflect.Field;
4
import java.lang.reflect.InvocationTargetException;
5

    
6
import org.apache.log4j.Logger;
7
import org.aspectj.lang.Signature;
8
import eu.etaxonomy.cdm.model.common.CdmBase;
9
import eu.etaxonomy.cdm.model.common.ICdmBase;
10

    
11
/**
12
 * @author markus
13
 * Aspect class that adds a firePropertyChange call to all setter methods 
14
 * which names start with "set" and that belong to subclasses form CdmBase
15
 * CdmBase defines the rest of the ProeprtyChangeSupport like listener registration 
16
 */
17
public aspect PropertyChangeAspect {
18
	static Logger logger = Logger.getLogger(PropertyChangeAspect.class);
19
	
20
//	pointcut execAdder(CdmBase cb): target(cb) && execution(void CdmBase+.add*(..) );  //once implemented we may want to remove addToSetWithChangeEvent and remove... from CdmBase
21
	
22
	/**
23
     * @param cb
24
     * Around aspect that will be weaven into the original setter methods of the CdmBase derived classes
25
     */
26
    after() returning(CdmBase cb): call(CdmBase+.new(..)) { 
27
        //logger.warn(" new instance aop " + cb.getClass().getName());
28
        cb.fireOnCreateEvent(cb);
29
    }
30
    
31
	pointcut execSetter(CdmBase cb): target(cb) && execution(void CdmBase+.set*(..) );
32
//	/** *********** OLD ***********************/
33
//	pointcut callSetter( CdmBase b ) : call( * CdmBase+.set*(..) ) && target( b );
34

    
35

    
36

    
37
	/**
38
	 * @param cb
39
	 * Around aspect that will be weaven into the original setter methods of the CdmBase derived classes
40
	 */
41
	void around( CdmBase cb ) : execSetter( cb )  {
42
		//logger.setLevel(Level.DEBUG);
43
		// get property that is set by setter method
44
		Field property = getFieldOfSetter( thisJoinPointStaticPart.getSignature() );
45
		if (property==null){
46
			proceed( cb );
47
		}else{			
48
			String propertyName = property.getName();
49
			if (logger.isDebugEnabled()){ logger.debug("execSetter: The property is ["+propertyName+"]");}
50
			if ("updated".equals(propertyName) || "updatedBy".equals(propertyName) ||
51
			    "created".equals(propertyName) || "createdBy".equals(propertyName) ||
52
			    "cacheStrategy".equals(propertyName)){
53
			    proceed (cb);
54
			}else{
55
    			property.setAccessible(true);
56
    			try {
57
    				// use property attribute directly, not through get method.
58
    				// get method might modify things, like setting a UUID when called for the first time.
59
    				// Also get methods for booleans start with "is" or "has"
60
    				Object oldValue = property.get(cb);
61
    				proceed( cb );
62
    				Object newValue = property.get(cb);
63
                    //logger.debug ("Prop: " + propertyName);
64
                    //logger.debug("OLD:" + oldValue);
65
                    //logger.debug("New:" + newValue);
66
    				if (! isPersistentSet(newValue) && ! isPersistentSet(oldValue)  ){
67
    					cb.firePropertyChange( propertyName, oldValue, newValue);
68
    				}
69
    			} catch (NoSuchMethodException |IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
70
    				e.printStackTrace();
71
    				proceed( cb );
72
    			}
73
    	    }
74
		}
75
	}
76
	
77
	private boolean isPersistentSet(Object value){
78
		if (value == null){
79
			//logger.debug("(null) is not PS");
80
			return false;
81
		}else if (value.getClass().getSimpleName().equals("PersistentSet")){
82
			logger.debug("Don't throw event for setter of Persistent Set");
83
			return true;
84
		}else{
85
			//logger.warn(value.getClass().getSimpleName() + " is is not PS");
86
			return false;
87
		}
88
	}
89

    
90

    
91
	/**
92
	 * @param signature
93
	 * Return the Field object that belongs to the signature of a setter method
94
	 * If no matching attribute can be found return null instead of throwing an NoSuchFieldException
95
	 * Removes first 3 characters of method name to find property name
96
	 */
97
	private Field getFieldOfSetter( Signature signature ){
98
		Field field = null;
99
		String propertyName = "";
100
		//logger.debug( "Getting the field name of setter ["+signature.getName() + "]" );
101
		try{
102
			String methodName = signature.getName();
103
			propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
104
			field = signature.getDeclaringType().getDeclaredField( propertyName );
105
		}catch( NoSuchFieldException e ){
106
			try{
107
				propertyName = "is"+propertyName.substring(0, 1).toUpperCase()+ propertyName.substring(1);
108
				field = signature.getDeclaringType().getDeclaredField( propertyName );
109
			}catch( NoSuchFieldException nsfe ){
110
				// can't find any matching attribute. catch error and return null
111
				return null;
112
			}
113
		}
114
		return field;
115
	}
116
		
117
	/**
118
	 * Fires a propertyChange Event
119
	 * @param cb  CdmBase that fires that Event
120
	 * @param property the property's name
121
	 * @param oldval the old value
122
	 * @param newval the new value
123
	  */
124
	void fireLoggingPropertyChange( CdmBase cb,
125
			String property,
126
			Object oldval,
127
			Object newval) {
128

    
129
		//logger.debug( "PropertyChangeEvent: property [" + property + "], old value [" + oldval + "], new value [" + newval + "]");
130
		// call firePropertyChange in original class. Method defined in CdmBase superclass!
131
		cb.firePropertyChange( property,
132
				( oldval == null ) ? oldval : oldval.toString(),
133
				( newval == null ) ? newval : newval.toString());
134
	}
135
		
136
}
    (1-1/1)