Project

General

Profile

Download (4.68 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.debug ("Prop: " + propertyName);
59
                //logger.debug("OLD:" + oldValue);
60
                //logger.debug("New:" + newValue);
61
				if (! isPersistentSet(newValue) && ! isPersistentSet(oldValue)  ){
62
					cb.firePropertyChange( propertyName, oldValue, newValue);
63
				}
64
			} catch (NoSuchMethodException |IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
65
				e.printStackTrace();
66
				proceed( cb );
67
			}
68
		}
69
	}
70
	
71
	private boolean isPersistentSet(Object value){
72
		if (value == null){
73
			//logger.debug("(null) is not PS");
74
			return false;
75
		}else if (value.getClass().getSimpleName().equals("PersistentSet")){
76
			logger.debug("Don't throw event for setter of Persistent Set");
77
			return true;
78
		}else{
79
			//logger.warn(value.getClass().getSimpleName() + " is is not PS");
80
			return false;
81
		}
82
	}
83

    
84

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

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