KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > objectserver > managedobject > PhysicalManagedObjectStateFactory


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.objectserver.managedobject;
5
6 import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
7
8 import com.tc.exception.TCRuntimeException;
9 import com.tc.io.serializer.TCObjectInputStream;
10 import com.tc.io.serializer.TCObjectOutputStream;
11 import com.tc.object.ObjectID;
12 import com.tc.object.dna.api.DNACursor;
13 import com.tc.object.dna.api.PhysicalAction;
14 import com.tc.objectserver.managedobject.bytecode.ClassSpec;
15 import com.tc.objectserver.managedobject.bytecode.FieldType;
16 import com.tc.objectserver.managedobject.bytecode.PhysicalStateClassLoader;
17 import com.tc.objectserver.persistence.api.ClassPersistor;
18 import com.tc.util.Assert;
19
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import java.lang.reflect.Constructor JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.SortedMap JavaDoc;
29 import java.util.TreeMap JavaDoc;
30 import java.util.Map.Entry;
31
32 public class PhysicalManagedObjectStateFactory {
33
34   private static final Class JavaDoc[] CONSTRUCTOR_PARAMS_CLASS = new Class JavaDoc[0];
35   private static final Object JavaDoc[] CONSTRUCTOR_PARAMS = new Object JavaDoc[0];
36   private final PhysicalStateClassLoader loader;
37   private final Map knownClasses;
38   private final ClassPersistor persistor;
39   private int sequenceId = 0;
40
41   public PhysicalManagedObjectStateFactory(ClassPersistor persistor) {
42     this.loader = new PhysicalStateClassLoader();
43     this.knownClasses = new ConcurrentHashMap();
44     this.persistor = persistor;
45     loadAllClassesFromDB();
46   }
47
48   private synchronized void loadAllClassesFromDB() {
49     SortedMap JavaDoc map = new TreeMap JavaDoc(persistor.retrieveAllClasses());
50     for (Iterator JavaDoc i = map.entrySet().iterator(); i.hasNext();) {
51       Map.Entry e = (Entry) i.next();
52       Integer JavaDoc clazzId = (Integer JavaDoc) e.getKey();
53       byte clazzBytes[] = (byte[]) e.getValue();
54       int cid = clazzId.intValue();
55       if (sequenceId < cid) {
56         sequenceId = cid;
57       }
58       loadFromBytes(cid, clazzBytes);
59     }
60   }
61
62   private void addKnownClasses(String JavaDoc classIdentifier, String JavaDoc genClassName, int cid) {
63     knownClasses.put(classIdentifier, genClassName);
64     knownClasses.put(new Integer JavaDoc(cid), genClassName);
65   }
66
67   private void addKnownClasses(ClassSpec cs) {
68     addKnownClasses(cs.getClassIdentifier(), cs.getGeneratedClassName(), cs.getClassID());
69   }
70
71   private void loadFromBytes(int classId, byte[] clazzBytes) {
72     try {
73       ByteArrayInputStream JavaDoc bai = new ByteArrayInputStream JavaDoc(clazzBytes);
74       TCObjectInputStream tci = new TCObjectInputStream(bai);
75
76       String JavaDoc classIdentifier = tci.readString();
77       String JavaDoc genClassName = tci.readString();
78
79       loader.defineClassFromBytes(genClassName, classId, clazzBytes, clazzBytes.length - bai.available(), bai
80           .available());
81       addKnownClasses(classIdentifier, genClassName, classId);
82     } catch (Exception JavaDoc ex) {
83       throw new TCRuntimeException(ex);
84     }
85   }
86
87   private void writeToDB(ClassSpec cs, byte[] data) {
88     try {
89       String JavaDoc classIdentifier = cs.getClassIdentifier();
90       String JavaDoc genClassName = cs.getGeneratedClassName();
91
92       ByteArrayOutputStream JavaDoc bao = new ByteArrayOutputStream JavaDoc(data.length + 1024);
93       TCObjectOutputStream tco = new TCObjectOutputStream(bao);
94       tco.writeString(classIdentifier);
95       tco.writeString(genClassName);
96       tco.write(data);
97       tco.flush();
98
99       persistor.storeClass(cs.getClassID(), bao.toByteArray());
100     } catch (Exception JavaDoc ex) {
101       throw new TCRuntimeException(ex);
102     }
103   }
104
105   public PhysicalManagedObjectState create(long strIdx, ObjectID parentID, String JavaDoc className, String JavaDoc loaderDesc,
106                                            DNACursor cursor) {
107     ClassSpec cs = new ClassSpec(className, loaderDesc, strIdx);
108     String JavaDoc classIdentifier = cs.getClassIdentifier();
109     String JavaDoc generatedClassName = (String JavaDoc) knownClasses.get(classIdentifier);
110     if (generatedClassName == null) {
111       Object JavaDoc lock = cs.getLock();
112       synchronized (lock) {
113         // Check again ! Double check locking is OK here as loader.load() is synchronized internally anyway
114
generatedClassName = (String JavaDoc) knownClasses.get(classIdentifier);
115         if (generatedClassName == null) {
116           PhysicalManagedObjectState po = createNewClassAndInitializeObject(parentID, cs, cursor);
117           return po;
118         }
119       }
120     }
121     return createNewObject(generatedClassName, parentID);
122   }
123
124   public PhysicalManagedObjectState create(ObjectID parentID, int classId) throws ClassNotFoundException JavaDoc {
125     Integer JavaDoc cid = new Integer JavaDoc(classId);
126     String JavaDoc className = (String JavaDoc) knownClasses.get(cid);
127     if (className == null) { throw new ClassNotFoundException JavaDoc("Unknown Class Id :" + classId + " Details : parent = "
128                                                               + parentID); }
129     return createNewObject(className, parentID);
130   }
131
132   public PhysicalManagedObjectState recreate(long classID, ObjectID pid, String JavaDoc className, String JavaDoc loaderDesc,
133                                              DNACursor cursor, PhysicalManagedObjectState oldState) {
134     ClassSpec cs = new ClassSpec(className, loaderDesc, classID);
135     String JavaDoc classIdentifier = cs.getClassIdentifier();
136     String JavaDoc generatedClassName = (String JavaDoc) knownClasses.get(classIdentifier);
137     Assert.assertNotNull(generatedClassName);
138     Object JavaDoc lock = cs.getLock();
139     synchronized (lock) {
140       PhysicalManagedObjectState newState = oldState;
141       if (!oldState.getClass().getName().equals(generatedClassName)) {
142         // There is already a new version generated for this class, first try using that.
143
newState = createNewObject(generatedClassName, pid);
144         initNewStateFromOld(newState, oldState);
145       }
146       List JavaDoc deltaFields = findDeltaFields(newState, cursor);
147       if (deltaFields.isEmpty()) {
148         // This class is sufficient
149
return newState;
150       } else {
151         // This newly generated class subclasses the newState
152
cs.setSuperClassName(newState.getClass().getName());
153         PhysicalManagedObjectState latestState = createNewClassAndInitializeObject(pid, cs, deltaFields);
154         return initNewStateFromOld(latestState, oldState);
155       }
156     }
157   }
158
159   private PhysicalManagedObjectState initNewStateFromOld(PhysicalManagedObjectState newState,
160                                                          PhysicalManagedObjectState oldState) {
161     if (newState == oldState) { return newState; }
162     Map fields2Vals = oldState.addValues(new HashMap());
163     for (Iterator JavaDoc i = fields2Vals.entrySet().iterator(); i.hasNext();) {
164       Map.Entry e = (Entry) i.next();
165       newState.set((String JavaDoc) e.getKey(), e.getValue());
166     }
167     return newState;
168   }
169
170   private List JavaDoc findDeltaFields(PhysicalManagedObjectState state, DNACursor cursor) {
171     try {
172       List JavaDoc deltaFields = new ArrayList JavaDoc();
173       Map fields2Values = new HashMap();
174       state.addValues(fields2Values);
175       cursor.reset();
176       while (cursor.next()) {
177         PhysicalAction action = cursor.getPhysicalAction();
178         if (!fields2Values.containsKey(action.getFieldName())) {
179           deltaFields.add(createFieldType(action, deltaFields.size()));
180         }
181       }
182       return deltaFields;
183     } catch (Exception JavaDoc ex) {
184       throw new TCRuntimeException(ex);
185     } finally {
186       cursor.reset();
187     }
188   }
189
190   /**
191    * This method creates an instance of already loaded class. The fields are not initialized.
192    */

193   private PhysicalManagedObjectState createNewObject(String JavaDoc stateClassName, ObjectID parentID) {
194     try {
195       Class JavaDoc c = loader.loadClass(stateClassName);
196       Constructor JavaDoc constructor = c.getConstructor(CONSTRUCTOR_PARAMS_CLASS);
197       PhysicalManagedObjectState po = (PhysicalManagedObjectState) constructor.newInstance(CONSTRUCTOR_PARAMS);
198       initializeManagedObjectState(po, parentID);
199       return po;
200     } catch (Exception JavaDoc e) {
201       throw new TCRuntimeException(e);
202     }
203   }
204
205   /**
206    * The object returned by this method has the parent Id set
207    */

208   private PhysicalManagedObjectState createNewClassAndInitializeObject(ObjectID parentID, ClassSpec cs, DNACursor cursor) {
209     try {
210       List JavaDoc fields = new ArrayList JavaDoc(cursor.getActionCount());
211       cursor.reset();
212       while (cursor.next()) {
213         PhysicalAction action = cursor.getPhysicalAction();
214         fields.add(createFieldType(action, fields.size()));
215       }
216       return createNewClassAndInitializeObject(parentID, cs, fields);
217     } catch (Exception JavaDoc ex) {
218       throw new TCRuntimeException(ex);
219     } finally {
220       cursor.reset();
221     }
222   }
223
224   private PhysicalManagedObjectState createNewClassAndInitializeObject(ObjectID parentID, ClassSpec cs, List JavaDoc fields) {
225     try {
226       int clazzId = getNextSequenceID();
227       cs.setGeneratedClassID(clazzId);
228       byte data[] = loader.createClassBytes(cs, parentID, fields);
229
230       String JavaDoc generatedClassName = cs.getGeneratedClassName();
231       Class JavaDoc c = loader.defineClassFromBytes(generatedClassName, clazzId, data, 0, data.length);
232       addKnownClasses(cs);
233       writeToDB(cs, data);
234       Constructor JavaDoc constructor = c.getConstructor(CONSTRUCTOR_PARAMS_CLASS);
235       PhysicalManagedObjectState mo = (PhysicalManagedObjectState) constructor.newInstance(CONSTRUCTOR_PARAMS);
236       initializeManagedObjectState(mo, parentID);
237       return mo;
238     } catch (Exception JavaDoc e) {
239       throw new TCRuntimeException(e);
240     }
241   }
242
243   private void initializeManagedObjectState(PhysicalManagedObjectState po, ObjectID parentID) {
244     po.setParentID(parentID);
245   }
246
247   private synchronized int getNextSequenceID() {
248     return ++sequenceId;
249   }
250
251   private FieldType createFieldType(PhysicalAction action, int id) {
252     String JavaDoc fieldName = action.getFieldName();
253     Object JavaDoc value = action.getObject();
254     return FieldType.create(fieldName, value, action.isReference(), id);
255   }
256
257 }
258
Popular Tags