View Javadoc

1   package org.sourceforge.jemm.client;
2   
3   import java.lang.reflect.Field;
4   import java.lang.reflect.Method;
5   
6   import org.sourceforge.jemm.database.FieldType;
7   import org.sourceforge.jemm.lifecycle.AttributeUse;
8   import org.sourceforge.jemm.lifecycle.ShadowData;
9   import org.sourceforge.jemm.lifecycle.ShadowObject;
10  import org.sourceforge.jemm.lifecycle.ShadowUserObject;
11  import org.sourceforge.jemm.lifecycle.Uses;
12  import org.sourceforge.jemm.types.ID;
13  import org.sourceforge.jemm.util.JEMMObject;
14  
15  /**
16   * An Entity is a JEMMObject representation that allows low level access to the
17   * fields, methods and constructors.
18   * 
19   * This interfaces implementations allows manipulation of a JEMMObject and have
20   * intricate knowledge of what the compiler has added to the JEMMObject
21   * entities.
22   * 
23   * @See EntityAccessor Accesses the JEMMObject using reflection
24   * @See ShadowDataEntity Stores Object data as IDs in a Shadow Map
25   * 
26   * @author Paul Keeble
27   * 
28   */
29  public class Entity {
30  	JEMMObject obj;
31  	
32  	public Entity(JEMMObject obj) {
33  		this.obj = obj;
34  	}
35  	
36  	/**
37  	 * Returns the referenced ShadowObject on the Enhanced Object referenced.
38  	 * 
39  	 * @return The ShadowObject the object currently uses.
40  	 */
41  	public ShadowUserObject getShadowUserObject() {
42  		ShadowObject so = getShadowObject();
43  		return (ShadowUserObject) so;
44  	}
45  
46  	/**
47  	 * Returns the referenced ShadowObject on the Enhanced Object referenced.
48  	 * 
49  	 * @return The ShadowObject the object currently uses.
50  	 */
51  	public ShadowObject getShadowObject() {
52  		try {
53  			ClassHierarchyIterator iterator = new ClassHierarchyIterator(obj.getClass());
54  			Class<?> parent=null;
55  			while(iterator.hasNext())
56  				parent = iterator.next();
57  			
58  			Field f = parent.getDeclaredField("jemmOIF");
59  			f.setAccessible(true);
60  			return (ShadowObject)f.get(obj);
61  		} catch (Exception e) {
62  			throw new RuntimeException(e);
63  		}
64  	}
65  
66  	
67  	public ShadowData getShadowData() {
68  		return getShadowUserObject().getData();
69  	}
70  	
71  	public int getVersion() {
72  		return getShadowData().getVersion();
73  	}
74  	
75  	public void setVersion(int newVersion) {
76  		getShadowData().setVersion(newVersion);
77  	}
78  	
79  	/**
80  	 * Sets the ShadowObject that is defined on underlying object
81  	 * 
82  	 * @param so
83  	 *            The new ShadowObject
84  	 */
85  	public void setShadowObject(ShadowUserObject so) {
86  		try {
87  			ClassHierarchyIterator iterator = new ClassHierarchyIterator(obj.getClass());
88  			for(Class<?> clazz : iterator) {
89  				try {
90  					Field f = clazz.getDeclaredField("jemmOIF");
91  					f.setAccessible(true);
92  					f.set(obj, so);
93  				}catch (NoSuchFieldException e) {
94  					//ignore
95  				}
96  			}
97  		} catch (Exception e) {
98  			throw new RuntimeException(e);
99  		}
100 	}
101 	
102 	/**
103 	 * Returns the ID of the JEMMObject as held by the ShadowObject
104 	 * 
105 	 * @return The ID of the object
106 	 */
107 	public ID getID() {
108 		return getShadowObject().getID();
109 	}
110 	
111 	/**
112 	 * Sets the field on the JEMMObject, without changing the ShadowMap.
113 	 * 
114 	 * In a hierarchy of classes the sae field can be declared multiple times. A
115 	 * private field for instance is not overriden in the sub classes
116 	 * 
117 	 * @param className
118 	 *            The name of the class that declares the field
119 	 * @param fieldName
120 	 *            The name of the field to access
121 	 * @param value
122 	 *            The value to set the field to
123 	 */
124 	public void setField(FieldKey fkey, Object value) {
125 		try {
126 			Class<?> c = fkey.getClazz();
127 			Field f = c.getDeclaredField(fkey.getName());
128 			f.setAccessible(true);
129 			f.set(obj, value);
130 		} catch (Exception e) {
131 			throw new RuntimeException(e);
132 		}
133 	}
134 
135 	/**
136 	 * Gets the field as it is on the JEMMObject, without consulting the
137 	 * ShadowMap
138 	 * 
139 	 * @param className
140 	 * @param fieldName
141 	 */
142 	public Object getField(FieldKey fkey) {
143 		try {
144 			Class<?> c = fkey.getClazz();
145 			Field f = c.getDeclaredField(fkey.getName());
146 			f.setAccessible(true);
147 			Object value = f.get(obj);
148 			return value;
149 		} catch (Exception e) {
150 			throw new RuntimeException(e);
151 		} 
152 	}
153 	
154 	/**
155 	 * Determines the Type of a field.
156 	 * 
157 	 * @param fKey The unique identifying key for a field
158 	 * @return The Type of the field
159 	 */
160 	public FieldType getFieldType(FieldKey fKey) {
161 		try {
162 			Field f = fKey.getField();
163 			return FieldType.convert(f.getType());
164 		} catch(Exception e) {
165 			throw new RuntimeException(e);
166 		}
167 		
168 	}
169 
170 	/**
171 	 * Reads any Uses annotations on a method which define which fields should
172 	 * be initialised.
173 	 * 
174 	 * @param methodSignature
175 	 *            The method to read the annotations from./
176 	 * @return The names of the methods
177 	 */
178 	public AttributeUse[] methodUses(Descriptor methodSignature) {
179 		try {
180 			Method m = 
181 				methodSignature.getMethod();
182 			Uses uses = m.getAnnotation(Uses.class);
183 			if(uses==null)
184 				return new AttributeUse[0];
185 			return uses.value();
186 		} catch (Exception e) {
187 			throw new RuntimeException(e);
188 		}
189 	}
190 }