View Javadoc

1   package org.sourceforge.jemm.client;
2   
3   import java.lang.reflect.Field;
4   import java.util.HashMap;
5   import java.util.Map;
6   
7   import org.sourceforge.jemm.JEMMInternalException;
8   import org.sourceforge.jemm.client.types.FieldAccessor;
9   import org.sourceforge.jemm.client.types.FieldAccessorChooser;
10  import org.sourceforge.jemm.client.types.FieldTypeAccessorChooser;
11  import org.sourceforge.jemm.database.FieldInfo;
12  import org.sourceforge.jemm.database.FieldType;
13  import org.sourceforge.jemm.lifecycle.AttributeUse;
14  import org.sourceforge.jemm.lifecycle.MethodListener;
15  import org.sourceforge.jemm.lifecycle.ShadowUserObject;
16  import org.sourceforge.jemm.lifecycle.ShadowUserObjectImpl;
17  import org.sourceforge.jemm.types.ID;
18  import org.sourceforge.jemm.util.JEMMObject;
19  
20  /**
21   * Accesses a JEMMObject enhanced class and provides access to the special
22   * fields for common client functionality.
23   * 
24   * @author Paul Keeble
25   * 
26   */
27  public class ObjectAccessor {
28  	public static final int DEFAULT_VERSION = 0;
29  	
30  	JEMMObject obj;
31  	FieldAccessorChooser accessorFactory;
32  	
33  	/**
34  	 * Creates an Accessor to an enhanced object
35  	 * 
36  	 * @param obj The enhanced Object
37  	 */
38  	public ObjectAccessor(JEMMObject obj,ObjectSource database) {
39  		this.obj = obj;
40  		this.accessorFactory = new FieldTypeAccessorChooser(database,new Entity(obj));
41  	}
42  	
43  	
44  	
45  	
46  	/**
47  	 * When an object is first created an ID and ShadowUserObject need to be assigned.
48  	 * This method does the creation steps to get the obejct ready for JEMM tracking.
49  	 * 
50  	 */
51  	public void create(ID id, MethodListener ml) {
52  		
53  		ShadowUserObject so = new ShadowUserObjectImpl(obj, ml, id,
54  				DEFAULT_VERSION);
55  		
56  		Entity e = new Entity(obj);
57  		e.setShadowObject(so);
58  		initialiseObjectFields();
59  	}
60  	
61  	public boolean isCreated() {
62  		Entity e = new Entity(obj);
63  		return e.getShadowObject()!=null;
64  	}
65  	
66  	private void initialiseObjectFields() {
67  		FieldIterator it = new FieldIterator(obj.getClass(),new JEMMObjectFilter());
68  		for(Field field : it) {
69  			setField(field.getDeclaringClass(),field.getName(),null);
70  			initialiseField(field.getDeclaringClass(), field.getName());
71  		}
72  	}
73  
74  	/**
75  	 * Sets the field to a value.
76  	 * 
77  	 * If the field is a primitive then the value is set on the object,
78  	 * otherwise if its an JEMMObject then it is mapped in the ShadowData as the ID
79  	 * of the object.
80  	 * 
81  	 * @param name
82  	 *            The fields name
83  	 * @param value
84  	 *            The value to set the field to.
85  	 */
86  	public void setField(Class<?> declaringClass, String name, Object value) {
87  		FieldKey fKey = new FieldKey(declaringClass,name);
88  		
89  		FieldAccessor fAccessor = accessorFactory.create(fKey);
90  		fAccessor.setField(fKey, value);
91  
92  	}
93  
94  	/**
95  	 * Gets the field value for the object.
96  	 * 
97  	 * If the field is a primitive then the value is retrieved from the JEMMObject.
98  	 * Otherwise if it is a JEMMObject then the ID is returned.
99  	 * 
100 	 * @param declaringClass The class on which the field is found
101 	 * @param name
102 	 *            The field name
103 	 * @param database The ObjectDatabase to retrieve the field from
104 	 * 
105 	 * @return A primitive object wrapper or ID
106 	 */
107 	public Object getField(Class<?> declaringClass,String name) {
108 
109 		FieldKey fKey = new FieldKey(declaringClass,name);
110 		
111 		FieldAccessor fAccessor = accessorFactory.create(fKey);
112 		return fAccessor.getField(fKey);
113 
114 	}
115 
116 	/**
117 	 * Initialises a JEMMObjects field to a real value.
118 	 * 
119 	 * If the field is an object then the ID is collected from the ShadowData, the object
120 	 * is retrieved from the Object database and then set onto the object. If the field is
121 	 * an array or primitive the field will be untouched.
122 	 * 
123 	 * @param declaringClass The class which delcared the field
124 	 * @param fieldName
125 	 *            The name of the field to set
126 	 * @param database
127 	 *            The place to retrieve the Object from
128 	 */
129 	public void initialiseField(String declaringClass, String fieldName) {
130 		try {
131 			initialiseField(Class.forName(declaringClass),fieldName);
132 		} catch (ClassNotFoundException e) {
133 			throw new JEMMInternalException("Programming error, class not found:" + declaringClass,e);
134 		}
135 	}
136 	
137 	public void initialiseField(Class<?> declaringClass,String fieldName) {
138 		FieldKey fKey = new FieldKey(declaringClass,fieldName);
139 
140 		FieldAccessor fAccessor = accessorFactory.create(fKey);
141 		fAccessor.initialise(fKey);
142 	}
143 	
144 	public boolean isInitialised(Class<?> declaringClass,String fieldName) {
145 		return new Entity(obj).getShadowData().
146 			isFieldInitialised(declaringClass, FieldType.OBJECT, fieldName);
147 	}
148 	
149 	public void initialiseAllFields(Descriptor methodDescriptor) {
150 		try {
151 			Entity e = new Entity(obj);
152 			AttributeUse[] attribs = e.methodUses(methodDescriptor);
153 			for(AttributeUse at : attribs) {
154 				initialiseField(at.clazz(),at.name());
155 			}
156  		} catch (Exception e) {
157 			throw new RuntimeException(e);
158 		}
159 	}
160 
161 	/**
162 	 * Clears an Objects field by setting it to null.
163 	 * 
164 	 * Only works on fields which are Objects, any primtives/array
165 	 * will simply be left alone.
166 	 * 
167 	 * @param name
168 	 *            The field name
169 	 */
170 	public void finaliseField(Class<?> declaringClass,String fieldName) {
171 		try {
172 			Field f = declaringClass.getDeclaredField(fieldName);
173 			finaliseField(f);
174 		} catch (Exception e) {
175 			throw new RuntimeException(e);
176 		}
177 		
178 	}
179 	
180 	public void finaliseField(Field f) {
181 		if(f.getType().isPrimitive())
182 			return;
183 		FieldKey fKey = new FieldKey(f.getDeclaringClass(),f.getName());
184 		FieldAccessor fAccessor = accessorFactory.create(fKey);
185 		fAccessor.finalize(fKey);
186 
187 	}
188 	
189 	public void finaliseAllFields() {
190 		FieldIterator it = new FieldIterator(obj.getClass(),new JEMMObjectFilter());
191 		while(it.hasNext()) {
192 			Field f = it.next();
193 			finaliseField(f);
194 		}
195 		new Entity(obj).getShadowUserObject().getData().clearInitialisations();
196 	}
197 	
198 	/**
199 	 * Generates a Map of all the keys and values for all fields associated with this
200 	 * object. The values are either the actual primitive values or the ID of the object
201 	 * referenced, the Object is never retrieved.
202 	 * 
203 	 * @return
204 	 */
205 	public Map<FieldInfo,Object> getAllFieldsMap() {
206 		Map<FieldInfo,Object> results = new HashMap<FieldInfo,Object>();
207 		
208 		FieldFilter allButShadowUserObject = new AllStoredFieldsFilter();
209 		FieldIterator it = new FieldIterator(obj.getClass(),allButShadowUserObject);
210 
211 		for(Field f : it) {
212 			FieldInfo key = new FieldInfo(f.getName(),f.getDeclaringClass(),FieldType.convert(f.getType()));
213 			FieldKey fKey = new FieldKey(f.getDeclaringClass(),f.getName());
214 			
215 			FieldAccessor accessor = accessorFactory.create(fKey);
216 			
217 			Object value = accessor.getFieldRaw(fKey);
218 			results.put(key, value);
219 		}
220 		return results;
221 	}
222 	
223 	/**
224 	 * Returns all JEMMObject fields that are uninitialised and their current value.
225 	 * 
226 	 * The value is either a valid ID or null if the field contains no mapping.
227 	 * 
228 	 * @return Mapping of Field information to ID or null if no mapping exists
229 	 */
230 	public Map<FieldKey,ID> getUninitialisedObjectFields() {
231 		Map<FieldKey,ID> result = new HashMap<FieldKey,ID>();
232 		
233 		FieldFilter filter = new JEMMObjectFilter();
234 		FieldIterator it = new FieldIterator(obj.getClass(),filter);
235 		
236 		for(Field f : it) {
237 			Entity e = new Entity(obj);
238 			if(!e.getShadowData().isFieldInitialised(f.getDeclaringClass(), FieldType.OBJECT, f.getName())) {
239 				FieldKey fKey = new FieldKey(f.getDeclaringClass(),f.getName());
240 				FieldAccessor accessor = accessorFactory.create(fKey);
241 				result.put(fKey,(ID)accessor.getFieldRaw(fKey));
242 			}
243 		}
244 		
245 		return result;
246 	}
247 	
248 	/**
249 	 * Returns the objects referred to by JEMMObject fields that
250 	 * are currently initialised.
251 	 * 
252 	 * @return Mapping of Field to JEMMObject or null if no mapping exists
253 	 */
254 	public Map<FieldKey,JEMMObject> getInitialisedObjectFields() {
255 		Map<FieldKey,JEMMObject> result = new HashMap<FieldKey,JEMMObject>();
256 		
257 		FieldFilter filter = new JEMMObjectFilter();
258 		FieldIterator it = new FieldIterator(obj.getClass(),filter);
259 		
260 		for(Field f : it) {
261 			Entity e = new Entity(obj);
262 			if(e.getShadowData().isFieldInitialised(f.getDeclaringClass(), FieldType.OBJECT, f.getName())) {
263 				FieldKey fKey = new FieldKey(f.getDeclaringClass(),f.getName());
264 				FieldAccessor accessor = accessorFactory.create(fKey);
265 				result.put(fKey,(JEMMObject)accessor.getField(fKey));
266 			}
267 		}
268 		
269 		return result;
270 	}
271 }