Project

General

Profile

Download (4.36 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.Level;
7
import org.apache.log4j.Logger;
8
import org.aspectj.lang.Signature;
9
import eu.etaxonomy.cdm.model.common.CdmBase;
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 execSetter(CdmBase cb): target(cb) && execution(void CdmBase+.set*(..) );
21
//	/** *********** OLD ***********************/
22
//	pointcut callSetter( CdmBase b ) : call( * CdmBase+.set*(..) ) && target( b );
23

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

    
80

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

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