View Javadoc

1   /**
2    * 
3    */
4   package org.sourceforge.jemm.database.components;
5   
6   import java.util.HashMap;
7   import java.util.Iterator;
8   import java.util.Map;
9   import java.util.Set;
10  
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.ObjectAccessor;
15  import org.sourceforge.jemm.database.ObjectSyncData;
16  import org.sourceforge.jemm.database.ObjectSyncResp;
17  import org.sourceforge.jemm.database.components.interfaces.DBClassHandler;
18  import org.sourceforge.jemm.database.components.interfaces.DBClientRefHandler;
19  import org.sourceforge.jemm.database.components.interfaces.DBObjectHandler;
20  import org.sourceforge.jemm.database.components.se.StorageEngineObjectIF;
21  import org.sourceforge.jemm.database.components.types.StoredListObject;
22  import org.sourceforge.jemm.database.components.types.StoredMapObject;
23  import org.sourceforge.jemm.database.components.types.StoredObject;
24  import org.sourceforge.jemm.database.components.types.StoredSetObject;
25  import org.sourceforge.jemm.database.components.types.StoredUserObject;
26  import org.sourceforge.jemm.types.ID;
27  import org.sourceforge.jemm.util.LockManager;
28  
29  /**
30   * Default implementation of DBObjectHandler used by BaseDatabase based implementations.
31   * @author Rory Graves
32   */
33  public class DefaultDBObjectHandler implements DBObjectHandler,ObjectAccessor {
34  	private final StorageEngineObjectIF seObjectIF;
35  	private final LockManager<ID> lockManager;
36  	private final DBClassHandler classHandler;
37  	private final DBClientRefHandler clientRefHandler;
38  
39  	private ObjectStatusListener objectStatusListener;
40  	private Map<ClassId,TypeHandler> typeHandlers = new HashMap<ClassId, TypeHandler>();
41  	
42  	/** Creates a DefaultDBObjectHandler instance with the given parameters.
43  	 * @param storageEngine The underlying storage engine.
44  	 * @param classHandler The class handler to use.
45  	 * @param clientRefHandler The client reference handler to use.
46  	 */
47      public DefaultDBObjectHandler(StorageEngine storageEngine,DBClassHandler classHandler,
48      		DBClientRefHandler clientRefHandler) {
49      	this.seObjectIF = storageEngine.getObjectIF();
50      	this.lockManager = new LockManager<ID>();
51      	this.classHandler = classHandler;
52      	this.clientRefHandler = clientRefHandler;
53      }
54      
55      public void setObjectStatusListener(ObjectStatusListener objectStatusListener) {
56      	this.objectStatusListener = objectStatusListener;
57      }
58      
59      public StoredObject getObject(ID objectId) {
60      	lockManager.acquire(objectId);
61  		
62  		StoredObject object =  seObjectIF.getObject(objectId);
63          if(object == null)
64              throw new IllegalStateException("Object " + objectId + " missing");
65  
66  		if(object.getModified())
67  			System.out.println("WARNING: ObjectStore.get on unsaved object " + objectId);
68  		
69  		return object;		
70      }
71  	
72  	public void update(StoredObject object) {
73  		object.clearModified();
74  	}
75      
76      /**
77       * Returns the stored user object referred to by 'id'
78       * @param objectId The id of the object to retrieve.
79       * @throws IllegalArgumentException If 'id' is null or is not UOBJECT type id.
80       * @throws IllegalStateException If the object is not in the database (an internal error), or the type
81       *         of the retrieved object is not a user object.
82       */
83      public StoredUserObject getUserObject(ID objectId) {
84      	StoredObject so = getObject(objectId);
85      	if(!(so instanceof StoredUserObject))
86      		throw new IllegalArgumentException("Requested id " + objectId 
87      				+ " not a user type object");
88      	   
89          return (StoredUserObject) so;
90      }
91  
92      @Override
93      public StoredListObject getListObject(ID objectId) {
94      	StoredObject so = getObject(objectId);
95      	if(!(so instanceof StoredListObject))
96      		throw new IllegalArgumentException("Requested id " + objectId 
97      				+ " not a jemm list type object");
98      	   	
99          return (StoredListObject) so;
100     }
101 
102     @Override
103     public StoredSetObject getSetObject(ID objectId) {
104     	StoredObject so = getObject(objectId);
105     	if(!(so instanceof StoredSetObject))
106     		throw new IllegalArgumentException("Requested id " + objectId + " not a jemm set type object");
107     	   	
108         return (StoredSetObject) so;
109     }
110 
111     @Override
112     public StoredMapObject getMapObject(ID objectId) {
113     	StoredObject so = getObject(objectId);
114     	if(!(so instanceof StoredMapObject))
115     		throw new IllegalArgumentException("Requested id " + objectId + " not a jemm map type object");
116     	   	
117         return (StoredMapObject) so;
118     }
119 
120     /**
121      * Creates a new user object with the given class type. <P>
122      * <B>N.b.</B> Once initialisation is complete - caller should call objectAccessor.initialisationFinished on the 
123      * returned id.
124      * @param classId The classId of the new object.
125      * @return The id of the newly created object.
126      */
127     public ID createObject(ClientId clientId,ClassId classId) {
128         ID id = seObjectIF.generateId();
129         StoredObject so;
130         if(typeHandlers.containsKey(classId)) { 
131         	// its a managed type
132         	TypeHandler th = typeHandlers.get(classId);
133         	so = th.createStorageObject(id);
134         	
135         } else { 
136         	// its a user object
137         	ClassInfo classInfo = classHandler.get(classId);
138             so = new StoredUserObject(id,classId,classInfo);
139         }
140         	
141         seObjectIF.save(so);
142         objectStatusListener.objectCreated(id);
143         clientRefHandler.recordReference(clientId, id);
144         objectStatusListener.initialisationComplete(id);
145 
146         return id;
147     }
148 
149     /**
150      * @param objectId The id of the object being synchronized
151      * @param syncData The synchronisation data, containing updated fields and current client version. 
152      * @return The synchronized object response data.
153      */
154     public ObjectSyncResp synchroniseObject(ID objectId, ObjectSyncData syncData) {
155 		StoredUserObject so = getUserObject(objectId);
156     	try {    	
157     		return so.synchronizeObject(syncData);
158     	} finally {
159     		release(so);
160     	}
161     }
162 
163     public void removeObject(ID id) {
164     	seObjectIF.removeObject(id);
165     }
166 
167     /**
168      * @return The number of objects held in this database.
169      */
170     public int getObjectCount() {
171     	return seObjectIF.count();
172     }
173 
174 	@Override
175 	public boolean checkExists(ID objectId) {
176 		return seObjectIF.checkObjectExists(objectId);
177 	}
178 
179 	@Override
180 	public void release(StoredObject object) {
181 		Thread currentThread = Thread.currentThread();
182 		if(currentThread != lockManager.getLockHolder(object.getObjectId()))
183 			throw new IllegalStateException("Current thread does not hold lock on " + object.getObjectId());
184 		
185 		if(object.getModified())
186 			saveObject(object);
187 		
188 		lockManager.release(object.getObjectId());
189 	}
190 	
191 	protected void saveObject(StoredObject object) {
192 		seObjectIF.updateObject(object);
193 	}
194 
195 	public int getNoLocksHeld() {
196 		return lockManager.noLocksHeld();
197 	}
198 
199 	@Override
200 	public Iterator<ID> idIterator() {
201 		return seObjectIF.idIterator();
202 	}
203 
204 	@Override
205 	public Set<ID> getObjectChildren(ID id) {
206     	StoredObject so = getObject(id);
207     	Set<ID> children = so.getReferencedObjects();
208     	release(so);
209     	return children;
210 	}
211 
212 	@Override 
213 	public void registerType(ClassId classId, TypeHandler handler) {
214 		typeHandlers.put(classId, handler);
215 	}
216 }