1 package org.sourceforge.jemm.database.components;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import org.apache.log4j.Logger;
7 import org.sourceforge.jemm.collections.JemmAtomicInteger;
8 import org.sourceforge.jemm.collections.JemmList;
9 import org.sourceforge.jemm.collections.JemmMap;
10 import org.sourceforge.jemm.collections.JemmSet;
11 import org.sourceforge.jemm.database.ClassId;
12 import org.sourceforge.jemm.database.ClassInfo;
13 import org.sourceforge.jemm.database.ClientId;
14 import org.sourceforge.jemm.database.ClientThreadId;
15 import org.sourceforge.jemm.database.Database;
16 import org.sourceforge.jemm.database.DatabaseDebugIF;
17 import org.sourceforge.jemm.database.EnumId;
18 import org.sourceforge.jemm.database.EnumInfo;
19 import org.sourceforge.jemm.database.FieldInfo;
20 import org.sourceforge.jemm.database.GetObjectResp;
21 import org.sourceforge.jemm.database.LockAcquiredListener;
22 import org.sourceforge.jemm.database.ObjectSyncData;
23 import org.sourceforge.jemm.database.ObjectSyncResp;
24 import org.sourceforge.jemm.database.StructureModifiedException;
25 import org.sourceforge.jemm.database.components.interfaces.DBClassHandler;
26 import org.sourceforge.jemm.database.components.interfaces.DBClientRefHandler;
27 import org.sourceforge.jemm.database.components.interfaces.DBEnumHandler;
28 import org.sourceforge.jemm.database.components.interfaces.DBGarbageSweeper;
29 import org.sourceforge.jemm.database.components.interfaces.DBObjectHandler;
30 import org.sourceforge.jemm.database.components.interfaces.DBRootHandler;
31 import org.sourceforge.jemm.database.components.interfaces.DBUserLockHandler;
32 import org.sourceforge.jemm.database.components.types.StoredObject;
33 import org.sourceforge.jemm.lifecycle.TypeRequest;
34 import org.sourceforge.jemm.lifecycle.TypeResponse;
35 import org.sourceforge.jemm.types.ID;
36 import org.sourceforge.jemm.util.JEMMType;
37
38 public abstract class BaseDatabase implements Database {
39
40 private static final Logger LOG = Logger.getLogger(BaseDatabase.class);
41
42 protected final DBClassHandler classHandler;
43 protected final DBEnumHandler enumHandler;
44 protected final DBObjectHandler objectHandler;
45 protected final DBUserLockHandler userLockHandler;
46 protected final DBRootHandler rootHandler;
47 protected final DatabaseDebugIF debugHandler;
48 protected final DBClientRefHandler clientRefHandler;
49 protected final DBGarbageSweeper gcHandler;
50
51 protected DefaultDBListTypeHandler listHandler;
52 protected DefaultDBSetTypeHandler setHandler;
53 protected DefaultDBMapTypeHandler mapHandler;
54 protected DefaultDBAtomicIntTypeHandler atomicIntHandler;
55
56 protected final ObjectStatusListener objectStatusListener;
57
58 protected StorageEngine storageEngine;
59
60 protected Map<ClassId,TypeHandler> typeHandlers = new HashMap<ClassId, TypeHandler>();
61
62 public BaseDatabase(StorageEngine storageEngine,GCMode gcMode) {
63 this.storageEngine = storageEngine;
64 storageEngine.initialise();
65 classHandler = new DefaultDBClassHandler(storageEngine);
66 enumHandler = new DefaultDBEnumHandler(storageEngine);
67 clientRefHandler = new DefaultDBClientRefHandler(storageEngine);
68 objectHandler = new DefaultDBObjectHandler(storageEngine,classHandler,clientRefHandler);
69 userLockHandler = new DefaultDBUserLockHandler(storageEngine,objectHandler);
70 rootHandler = new DefaultDBRootHandler(storageEngine);
71 gcHandler = new DefaultDBGarbageSweeper(storageEngine,objectHandler,gcMode);
72 debugHandler = new DefaultDBDebugHandler(objectHandler,clientRefHandler,gcHandler);
73
74 objectStatusListener = gcHandler.getObjectStatusListener();
75
76 rootHandler.setObjectStatusListener(objectStatusListener);
77 clientRefHandler.setObjectStatusListener(objectStatusListener);
78 objectHandler.setObjectStatusListener(objectStatusListener);
79
80
81 ClassId setClassId = registerTypeClass(JemmSet.class);
82 ClassId mapClassId = registerTypeClass(JemmMap.class);
83 ClassId listClassId = registerTypeClass(JemmList.class);
84 ClassId atomicIntClassId = registerTypeClass(JemmAtomicInteger.class);
85
86 listHandler = new DefaultDBListTypeHandler(listClassId,objectHandler,clientRefHandler);
87 setHandler = new DefaultDBSetTypeHandler(setClassId,objectHandler,clientRefHandler);
88 mapHandler = new DefaultDBMapTypeHandler(mapClassId,objectHandler,clientRefHandler,setClassId,listClassId);
89 atomicIntHandler = new DefaultDBAtomicIntTypeHandler(atomicIntClassId,objectHandler,clientRefHandler);
90
91 registerTypeHandler(setClassId,setHandler);
92 registerTypeHandler(mapClassId,mapHandler);
93 registerTypeHandler(listClassId,listHandler);
94 registerTypeHandler(atomicIntClassId,atomicIntHandler);
95 }
96
97 private ClassId registerTypeClass(Class<? extends JEMMType> typeClass) {
98 ClassId classId;
99 try {
100 classId = this.registerClass(null,
101 new ClassInfo(typeClass));
102 } catch (StructureModifiedException e) {
103 LOG.error("Unable to register type class " + typeClass,e);
104 throw new RuntimeException(e);
105 }
106 return classId;
107 }
108
109 private void registerTypeHandler(ClassId classId,TypeHandler handler) {
110 typeHandlers.put(classId, handler);
111 objectHandler.registerType(classId,handler);
112 }
113
114 @Override
115 public void setClientLockAcquiredListener(ClientId clientId,LockAcquiredListener listener) {
116 userLockHandler.setClientListener(clientId,listener);
117 }
118
119 @Override
120 public void acquireLock(ClientThreadId threadId, ID jemmId) {
121 userLockHandler.acquire(threadId,jemmId);
122 }
123
124 @Override
125 public ClassInfo getClassInfo(ClientId clientId,ClassId classId) {
126 return classHandler.get(classId);
127 }
128
129 @Override
130 public EnumInfo getEnumInfo(ClientId clientId,EnumId enumId) {
131 if(clientId == null)
132 throw new IllegalArgumentException("clientId may not be null");
133
134 return enumHandler.get(enumId);
135 }
136
137 @Override
138 public GetObjectResp getObject(ClientId clientId,ID jemmId) {
139 GetObjectResp resp;
140 StoredObject so = objectHandler.getObject(jemmId);
141 try {
142 resp = so.getObjectData();
143 } finally {
144 objectHandler.release(so);
145 }
146
147 for (Map.Entry<FieldInfo, Object> fieldValue : resp.fieldValues.entrySet()) {
148 switch(fieldValue.getKey().fieldType) {
149 case OBJECT:
150 ID referenceId = (ID) fieldValue.getValue();
151 if(referenceId != null)
152 clientRefHandler.recordReference(clientId, referenceId);
153 break;
154 default:
155
156 break;
157 }
158 }
159
160 return resp;
161 }
162
163 @Override
164 public ID getRoot(ClientId clientId,String rootName) {
165 ID id = rootHandler.getRoot(rootName);
166 if(id != null)
167 clientRefHandler.recordReference(clientId, id);
168 return id;
169 }
170
171 @Override
172 public ID newObject(ClientId clientId,ClassId classId) {
173
174 if(clientId == null)
175 throw new IllegalArgumentException("clientId most not be null");
176 if(classId == null)
177 throw new IllegalArgumentException("classId must not be null");
178
179 ID id = objectHandler.createObject(clientId,classId);
180 return id;
181 }
182
183 @Override
184 public void referenceCleared(ClientId clientId,ID... ids) {
185 for(ID id: ids)
186 clientRefHandler.clearReference(clientId, id);
187 }
188
189 @Override
190 public ClassId registerClass(ClientId clientId,ClassInfo classInfo) throws StructureModifiedException {
191 return classHandler.register(classInfo);
192 }
193
194 @Override
195 public EnumId registerEnum(ClientId clientId,EnumInfo enumInfo) throws StructureModifiedException {
196 return enumHandler.register(enumInfo);
197 }
198
199 @Override
200 public void releaseLock(ClientThreadId threadId, ID jemmId) {
201 userLockHandler.release(threadId,jemmId);
202 }
203
204 @Override
205 public void removeLockAcquiredListener(ClientId clientId) {
206 userLockHandler.removeClientListener(clientId);
207 }
208
209 @Override
210 public void setRoot(ClientId clientId,String rootName, ID newValue) {
211 rootHandler.setRoot(rootName,newValue);
212 }
213
214 @Override
215 public ID setRootIfNull(ClientId clientId,String rootName, ID newValue) {
216 return rootHandler.setRootIfNull(rootName,newValue);
217 }
218
219 @Override
220 public ObjectSyncResp synchroniseObject(ClientId clientId,ID objectId, ObjectSyncData syncData) {
221 return objectHandler.synchroniseObject(objectId,syncData);
222 }
223
224 @Override
225 public DatabaseDebugIF getDebugInterface() {
226 return debugHandler;
227 }
228
229 public void shutdown() {
230 gcHandler.shutdown();
231 userLockHandler.shutdown();
232 storageEngine.shutdown();
233 storageEngine = null;
234 System.gc();
235 }
236
237 @Override
238 public void clientDisconnect(ClientId clientId) {
239 userLockHandler.clientDisconnect(clientId);
240 clientRefHandler.clientDisconnect(clientId);
241 }
242
243 @Override
244 public TypeResponse<?> processTypeRequest(ClientId clientId,
245 ClassId classId, ID objId, TypeRequest<?> request) {
246 TypeHandler handler = typeHandlers.get(classId);
247 if(handler != null)
248 return handler.processRequest(clientId, classId, objId, request);
249 else
250 throw new IllegalArgumentException("No type handler defined for class type");
251 }
252 }