Project

General

Profile

Download (4.77 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
	/**
22
     * @param cb
23
     * Around aspect that will be weaven into the original setter methods of the CdmBase derived classes
24
     */
25
    after() returning(CdmBase cb): call(CdmBase+.new(..)) { 
26
        //logger.warn(" new instance aop " + cb.getClass().getName());
27
        cb.fireOnCreateEvent(cb);
28
    }
29
    
30
	pointcut execSetter(CdmBase cb): target(cb) && execution(void CdmBase+.set*(..) );
31
//	/** *********** OLD ***********************/
32
//	pointcut callSetter( CdmBase b ) : call( * CdmBase+.set*(..) ) && target( b );
33

    
34

    
35

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

    
92

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

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