KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > shark > processlocking > HibernateLockMaster


1 /*
2 * Shark Hibernate Process Locking - Open Wide
3 */

4
5 package org.enhydra.shark.processlocking;
6
7 import java.util.ArrayList JavaDoc;
8 import java.util.HashMap JavaDoc;
9 import java.util.Iterator JavaDoc;
10 import java.util.List JavaDoc;
11 import java.util.Map JavaDoc;
12 import java.util.Set JavaDoc;
13
14 import net.sf.hibernate.HibernateException;
15 import net.sf.hibernate.Query;
16 import net.sf.hibernate.Session;
17 import net.sf.hibernate.Transaction;
18
19 import org.enhydra.shark.api.RootException;
20 import org.enhydra.shark.api.SharkTransaction;
21 import org.enhydra.shark.api.TransactionException;
22 import org.enhydra.shark.api.internal.processlocking.LockMaster;
23 import org.enhydra.shark.api.internal.working.CallbackUtilities;
24
25 /**
26  * HibernateLockMaster is special implementation of Shark's LockMaster, which
27  * uses database as a lock repository, whereas
28  * simple lock master has only Vector in memory.
29  * <p>
30  * HibernateLockMaster completely circumvents Shark's persistence layer, communicating
31  * directly to Hibernate classes, to store and delete lock entries in database.
32  *
33  * @author Vladislav Pernin
34  * @version 0.1
35  */

36 public class HibernateLockMaster implements LockMaster {
37
38    private static final String JavaDoc ENG_PARAM_NAME = "enginename";
39    private static final String JavaDoc TOUT_PARM_NAME = "HibernateLockMaster.Timeout";
40    private static final String JavaDoc LWT_PARAM_NAME = "HibernateLockMaster.LockWaitTime";
41    private static final String JavaDoc DBG_PARAM_NAME = "HibernateLockMaster.debug";
42    private static final String JavaDoc LDB_PARAM_NAME = "HibernateLockMaster.DatabaseName";
43
44    private Long JavaDoc defaultTimeout;
45    private long lockWaitTime;
46    private CallbackUtilities callback;
47    private Map JavaDoc locks;
48    private String JavaDoc lockMasterName;
49    private boolean cleanStarted;
50    private boolean _debug_;
51
52    /**
53     * Default constructor
54     */

55    public HibernateLockMaster() {
56       locks = new HashMap JavaDoc();
57       defaultTimeout = null;
58       cleanStarted = false;
59    }
60
61    /**
62     * Configures instance of LockMaster implementaition, setting its
63     * name and default timeout.
64     *
65     * @param cbImpl a CallbackUtilities
66     *
67     * @exception RootException
68     */

69    public void configure(CallbackUtilities cbImpl) throws RootException {
70       if (null == cbImpl)
71          throw new RootException("Cannot configure without call back impl.");
72       callback = cbImpl;
73     //HibernateUtilities.init(callback.getProperties());
74
// TODO
75
/*if (LockEntryDO
76              .getConfigurationAdministration()
77              .getCacheAdministration(0)
78              .getMaxCacheSize() > 0) {
79          callback.error("cache for lock entries isn't allowed!!!");
80          throw new Error("cache for lock entries isn't allowed!!!");
81       }*/

82       lockMasterName = callback.getProperty(ENG_PARAM_NAME,"hibernateLockMaster");
83       defaultTimeout = new Long JavaDoc(callback.getProperty(TOUT_PARM_NAME, "-1"));
84       lockWaitTime = Long.parseLong(callback.getProperty(LWT_PARAM_NAME,"100"));
85       _debug_ = Boolean
86          .valueOf(callback.getProperty(DBG_PARAM_NAME, "false"))
87          .booleanValue();
88       if (!cleanStarted) {
89          _cleanAllLocks();
90          cleanStarted = true;
91       }
92       callback.debug(new StringBuffer JavaDoc(lockMasterName)
93                         .append(" startup, timeout is ")
94                         .append(defaultTimeout)
95                         .toString());
96    }
97
98    /**
99     * Method lock ensures that nobody else (other threads) has same processId.
100     * This method may wait a while before acquiring lock requested.
101     * Implementation may set a timeout to limit the time spent waiting.
102     *
103     * @param t - SharkTransaction during wich lock is required
104     * @param processId - lock identifier
105     * @param timeout - limits waiting for this specific lock:
106     * value < 0 means wait forever
107     * value >= 0 specifies number of miliseconds
108     * null value means use default
109     * @return true if lock is acquired without waiting, false otherwise
110     * @exception RootException gets thrown if timeout expires
111     */

112    public boolean lock(SharkTransaction t,
113                        String JavaDoc processId,
114                        Long JavaDoc timeout) throws RootException {
115       boolean ret = true;
116       if (null != processId) {
117          if (null == timeout)
118             timeout = defaultTimeout;
119          long limit = timeout.longValue();
120          boolean checkTimeout = 0 < limit;
121          limit += System.currentTimeMillis();
122          try {
123             while (hasLock(processId)) {
124                 ret = false;
125                 try {
126                    Thread.sleep(lockWaitTime);
127                 } catch (Exception JavaDoc e) {}
128                 if (checkTimeout && (System.currentTimeMillis() > limit)) {
129                    RootException tme = new RootException
130                       (new StringBuffer JavaDoc("Timeout expired waiting on ")
131                           .append(processId)
132                           .toString());
133                    callback.error("SimpleLockMaster", tme);
134                    throw tme;
135                 }
136              }
137         } catch (HibernateException e) {
138             e.printStackTrace();
139             throw new TransactionException(e);
140         } catch (RootException e) {
141             e.printStackTrace();
142             throw new RootException(e);
143         }
144       }
145       if (_debug_) System.err.println("LOCK:"+processId+":"+t);
146       return ret;
147    }
148
149    /**
150     * Method lock ensures that nobody else (other threads) has same processId.
151     * This method may wait a while before acquiring lock requested.
152     *
153     * @param processId lock identifier
154     * @return true if lock is acquired without waiting, false otherwise
155     * @exception TransactionMgrException
156     */

157    public boolean lock(SharkTransaction t,
158                        String JavaDoc processId) throws RootException {
159       return lock(t, processId, null);
160    }
161
162    /**
163     * @param processId
164     * @throws TransactionMgrException
165     */

166    public void unlock(SharkTransaction t,
167                       String JavaDoc processId) throws RootException {
168       if (null != processId) {
169          try {
170             removeLock(processId);
171             if (_debug_) System.err.println("UNLOCK:"+processId+":"+t);
172          } catch (Exception JavaDoc e) {
173             e.printStackTrace();
174             throw new RootException(e);
175          }
176       }
177    }
178    
179    private HibernateLockEntry getLockEntry(String JavaDoc processIdParam, String JavaDoc lockMasterNameParam, Session s) throws RootException {
180     try{
181         Query qLockEntry = s.createQuery(
182                     "from HibernateLockEntry lockEntry where lockEntry.id = :keyValueParam_1 and " +
183                     "lockEntry.engineName = :keyValueParam_2");
184         qLockEntry.setString("keyValueParam_1", processIdParam);
185         qLockEntry.setString("keyValueParam_2", lockMasterNameParam);
186         HibernateLockEntry le = (HibernateLockEntry) qLockEntry.uniqueResult();
187         return (le != null)?le:null;
188     }catch (Exception JavaDoc e) {
189         e.printStackTrace();
190         throw new RootException(e);
191     }
192    }
193
194    /**
195     * Method unlock releases all locks SharkTransaction had acquired.
196     *
197     * @param t - SharkTransaction during which locks had been obtained.
198     * @exception RootException
199     */

200    public synchronized void unlock(SharkTransaction t) throws RootException {
201       List JavaDoc processLocks = retrieveLocks();
202       Session session = null;
203     Transaction tr = null;
204       if (null == processLocks) {
205          throw new RootException("Transaction hasn't locked anything");
206       }
207       try {
208         session = ThreadLocalSession.currentSession();
209         tr = session.beginTransaction();
210          for (Iterator JavaDoc it = processLocks.iterator(); it.hasNext();) {
211             String JavaDoc processId = (String JavaDoc)it.next();
212             session.delete(getLockEntry(processId,lockMasterName,session));
213             locks.remove(processId);
214             if (_debug_) System.err.println("gUNLOCK:"+processId+":"+t);
215          }
216          tr.commit();
217         // To avoid that Hibernate cache the objects manipulated
218
session.clear();
219         session.close();
220       } catch (Exception JavaDoc e) {
221          throw new RootException(e);
222       } finally {
223             tr = null;
224       }
225    }
226
227    /**
228     * Gets locks for the SharkTransaction.
229     *
230     * @param t - SharkTransaction during which lock is required
231     * @return a List of processIds SharkTransaction had previously obtained.
232     * @exception RootException
233     */

234    public List JavaDoc getLocks(SharkTransaction t) throws RootException {
235       List JavaDoc transactionLocks = retrieveLocks();
236       if (null == transactionLocks)
237          throw new RootException("Transaction hasn't locked anything");
238       return transactionLocks;
239    }
240
241    /***/
242    private List JavaDoc retrieveLocks() {
243       List JavaDoc ret = new ArrayList JavaDoc();
244       Set JavaDoc entries = locks.entrySet();
245       Thread JavaDoc th = Thread.currentThread();
246       for (Iterator JavaDoc it = entries.iterator(); it.hasNext();) {
247          Map.Entry JavaDoc me = (Map.Entry JavaDoc)it.next();
248          if (th.equals(me.getValue())) {
249             ret.add(me.getKey());
250          }
251       }
252       return ret;
253    }
254
255    private synchronized boolean hasLock(String JavaDoc processId) throws RootException, HibernateException {
256       Thread JavaDoc lockOwner = (Thread JavaDoc)locks.get(processId);
257         Session session = null;
258     Transaction t;
259       if (null == lockOwner) {
260          try {
261             session = ThreadLocalSession.currentSession();
262             t = session.beginTransaction();
263             
264             HibernateLockEntry le = createLockEntry();
265             le.setEngineName(lockMasterName);
266             le.setId(processId);
267
268             session.save(le);
269             t.commit();
270             // To avoid that Hibernate cache the objects manipulated
271
//session.flush();
272
session.clear();
273             session.close();
274          } catch (Exception JavaDoc e) {
275             return true;
276          } finally {
277             t = null;
278          }
279          locks.put(processId, Thread.currentThread());
280          return false;
281       } else if (lockOwner.equals(Thread.currentThread())) {
282          return false;
283       } else {
284          return true;
285       }
286    }
287
288    /***/
289    private synchronized void removeLock(String JavaDoc processId) throws RootException {
290       Thread JavaDoc lockOwner = (Thread JavaDoc)locks.get(processId);
291       Session session = null;
292     Transaction t = null;
293       if (Thread.currentThread().equals(lockOwner)) {
294          try {
295             session = ThreadLocalSession.currentSession();
296             t = session.beginTransaction();
297             HibernateLockEntry lo = getLockEntry(processId,lockMasterName,session);
298             if (lo != null) session.delete(lo);
299         
300            t.commit();
301            // To avoid that Hibernate cache the objects manipulated
302
session.clear();
303            session.close();
304          } catch (Exception JavaDoc e) {
305             throw new RootException(e);
306          } finally {
307                 t = null;
308          }
309          locks.remove(processId);
310       } else {
311          RootException tme = new RootException
312             (new StringBuffer JavaDoc("Trying to unlock ")
313                 .append(processId)
314                 .append(" while it hasn't been locked ?!?")
315                 .toString());
316          callback.error("SimpleLockMaster", tme);
317          throw tme;
318       }
319    }
320
321    /***/
322    private void _cleanAllLocks() throws RootException {
323     Session session = null;
324     Transaction t;
325       try {
326         session = ThreadLocalSession.currentSession();
327         t = session.beginTransaction();
328         
329         List JavaDoc lockEntries = getAllLockEntry(lockMasterName,session);
330         if (lockEntries.size() != 0){
331             for (Iterator JavaDoc it = lockEntries.iterator(); it.hasNext();) {
332                 session.delete((HibernateLockEntry)it.next());
333             }
334         }
335         
336          t.commit();
337         // To avoid that Hibernate cache the objects manipulated
338
session.clear();
339         session.close();
340       } catch (Exception JavaDoc e) {
341         e.printStackTrace();
342          throw new RootException(e);
343       } finally {
344          t =null;
345       }
346    }
347    
348    private List JavaDoc getAllLockEntry(String JavaDoc lockMasterName, Session s) throws RootException {
349     try{
350         Query qLockEntry = s.createQuery(
351                     "from HibernateLockEntry lockEntry where lockEntry.engineName = :keyValueParam");
352         qLockEntry.setString("keyValueParam", lockMasterName);
353         return qLockEntry.list();
354     }catch (Exception JavaDoc e) {
355         e.printStackTrace();
356         throw new RootException(e);
357     }
358    }
359    
360    private HibernateLockEntry createLockEntry(){
361     return new HibernateLockEntry();
362    }
363
364 }
365
Popular Tags