Project

General

Profile

Download (4.81 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
			property.setAccessible(true);
49
			String propertyName = property.getName();
50
			//logger.debug("execSetter: The property is ["+propertyName+"]");
51
			try {
52
				// use property attribute directly, not through get method.
53
				// get method might modify things, like setting a UUID when called for the first time.
54
				// Also get methods for booleans start with "is" or "has"
55
				Object oldValue = property.get(cb);
56
				proceed( cb );
57
				Object newValue = property.get(cb);
58
//				logger.error ("Prop: " + propertyName);
59
//				logger.warn("OLD:" + oldValue);
60
//				logger.warn("New:" + newValue);
61
				if (! isPersistentSet(newValue) && ! isPersistentSet(oldValue)  ){
62
					cb.firePropertyChange( propertyName, oldValue, newValue);
63
				}
64
			} catch (NoSuchMethodException e) {
65
				e.printStackTrace();
66
				proceed( cb );
67
			}catch (IllegalArgumentException e) {
68
				e.printStackTrace();
69
				proceed( cb );
70
			}catch (IllegalAccessException e) {
71
				e.printStackTrace();
72
				proceed( cb );
73
			} catch (InvocationTargetException e) {
74
				e.printStackTrace();
75
				proceed( cb );
76
			}
77
		}
78
	}
79
	
80
	private boolean isPersistentSet(Object value){
81
		if (value == null){
82
			//logger.debug("(null) is not PS");
83
			return false;
84
		}else if (value.getClass().getSimpleName().equals("PersistentSet")){
85
			logger.debug("Don't throw event for setter of Persistent Set");
86
			return true;
87
		}else{
88
			//logger.warn(value.getClass().getSimpleName() + " is is not PS");
89
			return false;
90
		}
91
	}
92

    
93

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

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