Project

General

Profile

Download (5.32 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.aspectj;
10

    
11
import java.lang.reflect.Field;
12
import java.lang.reflect.InvocationTargetException;
13

    
14
import org.apache.logging.log4j.LogManager;
15
import org.apache.logging.log4j.Logger;
16
import org.aspectj.lang.Signature;
17
import eu.etaxonomy.cdm.model.common.CdmBase;
18
import eu.etaxonomy.cdm.model.common.ICdmBase;
19

    
20
/**
21
 * @author markus
22
 * Aspect class that adds a firePropertyChange call to all setter methods 
23
 * which names start with "set" and that belong to subclasses form CdmBase
24
 * CdmBase defines the rest of the ProeprtyChangeSupport like listener registration 
25
 */
26
public aspect PropertyChangeAspect {
27

    
28
	static Logger logger = LogManager.getLogger(PropertyChangeAspect.class);
29
	
30
//	pointcut execAdder(CdmBase cb): target(cb) && execution(void CdmBase+.add*(..) );  //once implemented we may want to remove addToSetWithChangeEvent and remove... from CdmBase
31
	
32
	/**
33
     * @param cb
34
     * Around aspect that will be weaven into the original setter methods of the CdmBase derived classes
35
     */
36
    after() returning(CdmBase cb): call(CdmBase+.new(..)) { 
37
        //logger.warn(" new instance aop " + cb.getClass().getName());
38
        cb.fireOnCreateEvent(cb);
39
    }
40
    
41
	pointcut execSetter(CdmBase cb): target(cb) && execution(void CdmBase+.set*(..) );
42
//	/** *********** OLD ***********************/
43
//	pointcut callSetter( CdmBase b ) : call( * CdmBase+.set*(..) ) && target( b );
44

    
45

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

    
99

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

    
138
		//logger.debug( "PropertyChangeEvent: property [" + property + "], old value [" + oldval + "], new value [" + newval + "]");
139
		// call firePropertyChange in original class. Method defined in CdmBase superclass!
140
		cb.firePropertyChange( property,
141
				( oldval == null ) ? oldval : oldval.toString(),
142
				( newval == null ) ? newval : newval.toString());
143
	}
144
		
145
}
    (1-1/1)