Project

General

Profile

Download (4.46 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

    
10
/**
11
 * @author markus
12
 * Aspect class that adds a firePropertyChange call to all setter methods 
13
 * which names start with "set" and that belong to subclasses form CdmBase
14
 * CdmBase defines the rest of the ProeprtyChangeSupport like listener registration 
15
 */
16
public aspect PropertyChangeAspect {
17
	static Logger logger = Logger.getLogger(PropertyChangeAspect.class);
18
	
19
//	pointcut execAdder(CdmBase cb): target(cb) && execution(void CdmBase+.add*(..) );  //once implemented we may want to remove addToSetWithChangeEvent and remove... from CdmBase
20
	
21
	pointcut execSetter(CdmBase cb): target(cb) && execution(void CdmBase+.set*(..) );
22
//	/** *********** OLD ***********************/
23
//	pointcut callSetter( CdmBase b ) : call( * CdmBase+.set*(..) ) && target( b );
24

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

    
81

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

    
120
		//logger.debug( "PropertyChangeEvent: property [" + property + "], old value [" + oldval + "], new value [" + newval + "]");
121
		// call firePropertyChange in original class. Method defined in CdmBase superclass!
122
		cb.firePropertyChange( property,
123
				( oldval == null ) ? oldval : oldval.toString(),
124
				( newval == null ) ? newval : newval.toString());
125
	}
126
		
127
}
    (1-1/1)