KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > nava > informa > utils > manager > hibernate > NonCachingPersistenceManager


1 //
2
// Informa -- RSS Library for Java
3
// Copyright (c) 2002 by Niko Schmuck
4
//
5
// Niko Schmuck
6
// http://sourceforge.net/projects/informa
7
// mailto:niko_schmuck@users.sourceforge.net
8
//
9
// This library is free software.
10
//
11
// You may redistribute it and/or modify it under the terms of the GNU
12
// Lesser General Public License as published by the Free Software Foundation.
13
//
14
// Version 2.1 of the license should be included with this distribution in
15
// the file LICENSE. If the license is not included with this distribution,
16
// you may find a copy at the FSF web site at 'www.gnu.org' or 'www.fsf.org',
17
// or you may write to the Free Software Foundation, 675 Mass Ave, Cambridge,
18
// MA 02139 USA.
19
//
20
// This library is distributed in the hope that it will be useful,
21
// but WITHOUT ANY WARRANTY; without even the implied waranty of
22
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23
// Lesser General Public License for more details.
24
//
25
// $Id: NonCachingPersistenceManager.java,v 1.2 2004/10/18 08:36:49 spyromus Exp $
26
//
27

28 package de.nava.informa.utils.manager.hibernate;
29
30 import de.nava.informa.core.ChannelGroupIF;
31 import de.nava.informa.core.ChannelIF;
32 import de.nava.informa.core.ItemIF;
33 import de.nava.informa.impl.hibernate.Channel;
34 import de.nava.informa.impl.hibernate.ChannelGroup;
35 import de.nava.informa.impl.hibernate.Item;
36 import de.nava.informa.utils.InformaUtils;
37 import de.nava.informa.utils.manager.PersistenceManagerException;
38 import de.nava.informa.utils.manager.PersistenceManagerIF;
39 import net.sf.hibernate.HibernateException;
40 import net.sf.hibernate.Session;
41 import net.sf.hibernate.Transaction;
42
43 import java.net.URL JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.logging.Level JavaDoc;
47 import java.util.logging.Logger JavaDoc;
48
49 /**
50  * Implementation of persistence manager interface, talking with Hibernate. This implementation
51  * is not 100% usable becase it isn't confirming to the rule of using the same instances. This
52  * means that each time it looks for object (for example, using method <code>getGroups()</code>)
53  * it returns new instances of group objects (<code>group1 != group2</code>, but
54  * <code>group1.getId() == group2.getId()</code>). Persistence Manager implementation should
55  * operate with the same instances all the way and it's carefully checked by acceptance test.
56  * <p>
57  * There's another implementation wrapping this one -- <code>PersistenceManager</code>. It
58  * conforms to the rule.</p>
59  *
60  * @author Aleksey Gureev (spyromus@noizeramp.com)
61  *
62  * @see PersistenceManager
63  */

64 class NonCachingPersistenceManager implements PersistenceManagerIF {
65
66   private static final Logger JavaDoc LOG = Logger.getLogger(NonCachingPersistenceManager.class.getName());
67
68   /**
69    * Creates new group of channels in persistent storage.
70    *
71    * @param title title of the group.
72    * @return initialized and persisted group object.
73    *
74    * @throws PersistenceManagerException in case of any problems.
75    */

76   public ChannelGroupIF createGroup(String JavaDoc title)
77     throws PersistenceManagerException {
78
79     // Create group object
80
final ChannelGroupIF group = new ChannelGroup(title);
81     HibernateUtil.saveObject(group);
82
83     return group;
84   }
85
86   /**
87    * Updates data in storage with data from the group object.
88    *
89    * @param group group object
90    *
91    * @throws PersistenceManagerException in case of any problems.
92    */

93   public void updateGroup(ChannelGroupIF group)
94     throws PersistenceManagerException {
95
96     HibernateUtil.updateObject(group);
97   }
98
99   /**
100    * Deletes group from persistent storage.
101    *
102    * @param group group to delete.
103    *
104    * @throws PersistenceManagerException in case of any problems.
105    */

106   public void deleteGroup(ChannelGroupIF group)
107     throws PersistenceManagerException {
108
109     // Remove all associations and delete object
110
deleteGroup(group, null);
111     group.setId(-1);
112   }
113
114   /**
115    * Takes channels from the <code>second</code> group and put them all in <code>first</code>
116    * group. Then <code>second</code> group is deleted.
117    *
118    * @param first first group of channels.
119    * @param second second group of channels.
120    *
121    * @throws PersistenceManagerException in case of any problems.
122    */

123   public void mergeGroups(ChannelGroupIF first, ChannelGroupIF second)
124     throws PersistenceManagerException {
125
126     Transaction tx = null;
127     try {
128       final Session session = HibernateUtil.openSession();
129       tx = session.beginTransaction();
130
131       HibernateUtil.lock(first, session);
132       HibernateUtil.lock(second, session);
133       mergeGroups(first, second, session);
134
135       tx.commit();
136
137       second.setId(-1);
138     } catch (HibernateException e) {
139       if (tx != null) {
140         try {
141           tx.rollback();
142         } catch (HibernateException e1) {
143           // We can do nothing here.
144
}
145       }
146
147       LOG.log(Level.SEVERE, "Could not merge groups.", e);
148       throw new PersistenceManagerException("Could not merge groups.", e);
149     } finally {
150       HibernateUtil.closeSession();
151     }
152   }
153
154   /**
155    * Returns the list of groups available in database.
156    *
157    * @return list of groups.
158    *
159    * @throws PersistenceManagerException in case of any problems.
160    */

161   public ChannelGroupIF[] getGroups()
162     throws PersistenceManagerException {
163
164     // Read the list of groups from Hibernate session.
165
// Note that list of channels in each of groups is lazy and it will not be
166
// loaded right away. So, please, don't worry about too much taken memory.
167
ChannelGroupIF[] groups = null;
168     try {
169       final Session session = HibernateUtil.openSession();
170       groups = getGroups(session);
171     } catch (HibernateException e) {
172       LOG.log(Level.SEVERE, "Could not read the list of groups.", e);
173       throw new PersistenceManagerException("Could not read the list of groups.", e);
174     } finally {
175       HibernateUtil.closeSession();
176     }
177
178     return groups == null ? new ChannelGroupIF[0] : groups;
179   }
180
181   /**
182    * Creates new channel object and persists it into storage.
183    *
184    * @param title title of the channel.
185    * @param location location of channel data resource.
186    *
187    * @return newly created object.
188    *
189    * @throws PersistenceManagerException in case of any problems.
190    */

191   public ChannelIF createChannel(String JavaDoc title, URL JavaDoc location)
192     throws PersistenceManagerException {
193
194     // Create channel object and perform some initialization and save
195
final ChannelIF channel = new Channel(title);
196     channel.setLocation(location);
197     HibernateUtil.saveObject(channel);
198
199     return channel;
200   }
201
202   /**
203    * Updates data in database with data from channel object.
204    *
205    * @param channel channel object.
206    *
207    * @throws PersistenceManagerException in case of any problems.
208    */

209   public void updateChannel(ChannelIF channel)
210     throws PersistenceManagerException {
211
212     HibernateUtil.updateObject(channel);
213   }
214
215   /**
216    * Adds <code>channel</code> to the <code>group</code>.
217    *
218    * @param channel channel to add.
219    * @param group group to use.
220    *
221    * @throws PersistenceManagerException in case of any problems.
222    */

223   public void addChannelToGroup(ChannelIF channel, ChannelGroupIF group)
224     throws PersistenceManagerException {
225
226     // Trick to avoid locking of session while hashcode of Channel based on location
227
// is calculated. Hashcode is cached and means that will not have problems with locking.
228
channel.hashCode();
229
230     Transaction tx = null;
231     try {
232       final Session session = HibernateUtil.openSession();
233       tx = session.beginTransaction();
234
235       HibernateUtil.lock(channel, session);
236       group.add(channel);
237       HibernateUtil.updateObject(group, session);
238
239       tx.commit();
240     } catch (HibernateException e) {
241       if (tx != null) {
242         try {
243           tx.rollback();
244         } catch (HibernateException e1) {
245           // We can do nothing here.
246
}
247       }
248
249       LOG.log(Level.SEVERE, "Could add channel to group.", e);
250       throw new PersistenceManagerException("Could add channel to group.", e);
251     } finally {
252       HibernateUtil.closeSession();
253     }
254   }
255
256   /**
257    * Deletes <code>channel</code> from the <code>group</code>.
258    * This method doesn't delete channel from persistent storage. It only
259    * breaks the association between channel and group.
260    *
261    * @param channel channel to delete.
262    * @param group group to use.
263    *
264    * @throws PersistenceManagerException in case of any problems.
265    */

266   public void removeChannelFromGroup(ChannelIF channel, ChannelGroupIF group)
267     throws PersistenceManagerException {
268
269     Transaction tx = null;
270     try {
271       final Session session = HibernateUtil.openSession();
272       tx = session.beginTransaction();
273
274       HibernateUtil.lock(channel, session);
275       group.remove(channel);
276       HibernateUtil.updateObject(group, session);
277
278       tx.commit();
279     } catch (HibernateException e) {
280       if (tx != null) {
281         try {
282           tx.rollback();
283         } catch (HibernateException e1) {
284           // We can do nothing here.
285
}
286       }
287
288       LOG.log(Level.SEVERE, "Could add channel to group.", e);
289       throw new PersistenceManagerException("Could add channel to group.", e);
290     } finally {
291       HibernateUtil.closeSession();
292     }
293   }
294
295   /**
296    * Deletes channel from persistent storage.
297    *
298    * @param channel channel to delete.
299    *
300    * @throws PersistenceManagerException in case of any problems.
301    */

302   public void deleteChannel(ChannelIF channel)
303     throws PersistenceManagerException {
304
305     // This call is taken out of transaction intentionally because
306
// we require separate session for that. If we go in the main
307
// transaction channels will be loaded in session by this call,
308
// the Id's of channel being removed and the other channel in
309
// session will match, but they will be different instances and
310
// session will throw exception on update.
311
final ChannelGroupIF[] groups = getGroups();
312     ItemIF[] items = null;
313
314     Transaction tx = null;
315     try {
316       final Session session = HibernateUtil.openSession();
317       tx = session.beginTransaction();
318
319       HibernateUtil.lock(channel, session);
320       items = deleteChannel(channel, groups, session);
321
322       tx.commit();
323
324       // Reset Id's of objects
325
channel.setId(-1);
326       for (int i = 0; i < items.length; i++) {
327         items[i].setId(-1);
328       }
329     } catch (HibernateException e) {
330       if (tx != null) {
331         try {
332           tx.rollback();
333         } catch (HibernateException e1) {
334           // We can do nothing here.
335
}
336       }
337
338       LOG.log(Level.SEVERE, "Could not delete channel.", e);
339       throw new PersistenceManagerException("Could not delete channel.", e);
340     } finally {
341       HibernateUtil.closeSession();
342     }
343   }
344
345   /**
346    * Creates new item in the channel.
347    *
348    * @param channel channel to put new item into.
349    * @param title title of new item.
350    *
351    * @return new item object.
352    *
353    * @throws PersistenceManagerException in case of any problems.
354    */

355   public ItemIF createItem(ChannelIF channel, String JavaDoc title)
356     throws PersistenceManagerException {
357
358     final ItemIF item = new Item(channel, title, null, null);
359
360     saveCreatedItem(channel, item);
361
362     return item;
363   }
364
365   /**
366    * Creates new item using specified object as ethalon.
367    * <b>Note that application <i>could</i> already add object to the channel and
368    * only persistent modifications required.</b>
369    *
370    * @param channel channel to put new item into.
371    * @param ethalon object to copy properties values from.
372    *
373    * @return new item object.
374    *
375    * @throws PersistenceManagerException in case of any problems.
376    */

377   public ItemIF createItem(ChannelIF channel, ItemIF ethalon)
378     throws PersistenceManagerException {
379
380     // Create item by copying another's properties and save
381
final ItemIF item = new Item(channel, null, null, null);
382     InformaUtils.copyItemProperties(ethalon, item);
383
384     saveCreatedItem(channel, item);
385
386     return item;
387   }
388
389   /**
390    * Updates data in database with data from item object.
391    *
392    * @param item item object.
393    *
394    * @throws PersistenceManagerException in case of any errors.
395    */

396   public void updateItem(ItemIF item)
397     throws PersistenceManagerException {
398
399     HibernateUtil.updateObject(item);
400   }
401
402   /**
403    * Deletes the item from the persistent storage.
404    *
405    * @param item item to delete.
406    *
407    * @throws PersistenceManagerException in case of any problems.
408    */

409   public void deleteItem(ItemIF item)
410     throws PersistenceManagerException {
411
412     Transaction tx = null;
413     try {
414       final Session session = HibernateUtil.openSession();
415       tx = session.beginTransaction();
416
417       // Create item object and save to database
418
deleteItem(item, session);
419
420       tx.commit();
421       item.setId(-1);
422     } catch (HibernateException e) {
423       if (tx != null) {
424         try {
425           tx.rollback();
426         } catch (HibernateException e1) {
427           // We can do nothing here.
428
}
429       }
430
431       LOG.log(Level.SEVERE, "Could not delete item.", e);
432       throw new PersistenceManagerException("Could not delete item.", e);
433     } finally {
434       HibernateUtil.closeSession();
435     }
436   }
437
438   // -----------------------------------------------------------------------------------------------
439
// Atomic operations
440
// -----------------------------------------------------------------------------------------------
441

442   /**
443    * Merges two groups by moving channels from second to first.
444    *
445    * @param first first group.
446    * @param second second group.
447    * @param session session to use or NULL.
448    *
449    * @throws PersistenceManagerException in case of any problems with Hibernate.
450    */

451   private static void mergeGroups(ChannelGroupIF first, ChannelGroupIF second,
452                                   final Session session)
453     throws PersistenceManagerException {
454
455     // Move all channels (without duplicates) from second group to the first
456
first.getAll().addAll(second.getAll());
457     HibernateUtil.updateObject(first, session);
458
459     // Delete second group
460
deleteGroup(second, session);
461   }
462
463   /**
464    * Removes all associations with channels and deletes group object.
465    *
466    * @param group object to delete.
467    * @param session session to use or NULL.
468    *
469    * @throws PersistenceManagerException in case of any problems with Hibernate.
470    */

471   private static void deleteGroup(ChannelGroupIF group, Session session)
472     throws PersistenceManagerException {
473
474     if (session != null) {
475       HibernateUtil.lock(group, session);
476     }
477
478     group.getAll().clear();
479     HibernateUtil.deleteObject(group, session);
480   }
481
482   /**
483    * Returns list of groups available in database using given session.
484    *
485    * @param session session to use.
486    *
487    * @return list of groups.
488    *
489    * @throws PersistenceManagerException in case of any problems with Hibernate.
490    */

491   private static ChannelGroupIF[] getGroups(final Session session)
492     throws PersistenceManagerException {
493
494     ChannelGroupIF[] groups;
495
496     try {
497       final List JavaDoc groupsList = session.find("from ChannelGroup");
498       groups = (ChannelGroupIF[]) groupsList.toArray(new ChannelGroupIF[0]);
499
500       // At this step we load all internal collections (channels and items in channels) as
501
// we will be detached from the session in the client application.
502
for (int i = 0; i < groups.length; i++) {
503         ChannelGroupIF group = groups[i];
504         initGroupCollections(group);
505       }
506     } catch (HibernateException e) {
507       LOG.log(Level.SEVERE, "Could not read the list of groups.", e);
508       throw new PersistenceManagerException("Could not read the list of groups.", e);
509     }
510
511     return groups;
512   }
513
514   /**
515    * Lads collections of group.
516    *
517    * @param group group collections.
518    */

519   private static void initGroupCollections(ChannelGroupIF group) {
520
521     // Load the lists of channels and items in all channels
522
ChannelIF[] channels = (ChannelIF[]) group.getAll().toArray(new ChannelIF[0]);
523     for (int i = 0; i < channels.length; i++) {
524       ChannelIF channel = channels[i];
525       channel.getCategories().size();
526       ((Channel)channel).getGroups().size();
527       for (Iterator JavaDoc it = channel.getItems().iterator(); it.hasNext();) {
528         ((ItemIF)it.next()).getCategories().size();
529       }
530     }
531   }
532
533   /**
534    * Deletes channel and all its items. Also removes associations with groups.
535    *
536    * @param channel channel to delete.
537    * @param groups list of all present group. We can't get this list here because we require
538    * to get it from separate session.
539    * @param session session to use or NULL.
540    *
541    * @return list of deleted items.
542    *
543    * @throws PersistenceManagerException in case of any problems with Hibernate.
544    */

545   private ItemIF[] deleteChannel(ChannelIF channel, ChannelGroupIF[] groups, final Session session)
546     throws PersistenceManagerException {
547
548     // Remove channel from all groups
549
for (int i = 0; i < groups.length; i++) {
550       ChannelGroupIF group = groups[i];
551       if (group.getAll().contains(channel)) {
552         group.remove(channel);
553         HibernateUtil.updateObject(group, session);
554       }
555     }
556
557     // Delete all items
558
final ItemIF[] items = (ItemIF[]) channel.getItems().toArray(new ItemIF[0]);
559     for (int i = 0; i < items.length; i++) {
560       ItemIF item = items[i];
561       channel.removeItem(item);
562       HibernateUtil.deleteObject(item, session);
563     }
564
565     // Delete object
566
HibernateUtil.deleteObject(channel, session);
567
568     return items;
569   }
570
571   /**
572    * Saves created item to storage and associates it with channel using give session.
573    *
574    * @param item item to save.
575    * @param channel channel to put item in.
576    * @param session session to use or NULL.
577    *
578    * @throws PersistenceManagerException in case of any problems with Hibernate.
579    */

580   private static void createItem(final ItemIF item, ChannelIF channel, Session session)
581     throws PersistenceManagerException {
582
583     // Saves newly created item
584
HibernateUtil.saveObject(item, session);
585
586     // Put item in the channel
587
channel.addItem(item);
588     HibernateUtil.updateObject(channel, session);
589   }
590
591   /**
592    * Deletes item from persistent storage using sinle session object.
593    *
594    * @param item item to delete.
595    * @param session session to use or NULL.
596    *
597    * @throws PersistenceManagerException in case of any problems with Hibernate.
598    */

599   private static void deleteItem(ItemIF item, Session session)
600     throws PersistenceManagerException {
601
602     // Find the channel and remove item from it
603
final ChannelIF channel = item.getChannel();
604     if (channel != null) {
605       channel.removeItem(item);
606     }
607
608     // Delete item
609
HibernateUtil.deleteObject(item, session);
610   }
611
612   // -----------------------------------------------------------------------------------------------
613
// Hibernate Tools
614
// -----------------------------------------------------------------------------------------------
615

616   /**
617    * Saves created item.
618    *
619    * @param channel channel to assign to.
620    * @param item item to save.
621    *
622    * @throws PersistenceManagerException in case of any problems.
623    */

624   private void saveCreatedItem(ChannelIF channel, final ItemIF item)
625     throws PersistenceManagerException {
626
627     Transaction tx = null;
628     try {
629       final Session session = HibernateUtil.openSession();
630       tx = session.beginTransaction();
631
632       // Save item to database
633
HibernateUtil.lock(channel, session);
634       createItem(item, channel, session);
635
636       tx.commit();
637     } catch (HibernateException e) {
638       if (tx != null) {
639         try {
640           tx.rollback();
641         } catch (HibernateException e1) {
642           // We can do nothing here.
643
}
644       }
645
646       LOG.log(Level.SEVERE, "Could not create item.", e);
647       throw new PersistenceManagerException("Could not create item.", e);
648     } finally {
649       HibernateUtil.closeSession();
650     }
651   }
652 }
653
Popular Tags