KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > nava > informa > impl > hibernate > ChannelBuilder


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

26 // $Id: ChannelBuilder.java,v 1.25 2004/07/10 09:11:06 spyromus Exp $
27

28 package de.nava.informa.impl.hibernate;
29
30 import java.net.URL JavaDoc;
31 import java.util.*;
32
33 import net.sf.hibernate.*;
34
35 import org.apache.commons.logging.*;
36 import org.jdom.Element;
37
38 import de.nava.informa.core.*;
39 import de.nava.informa.utils.InformaUtils;
40
41 /**
42  * Factory for the creation of the channel object model with the hibernate
43  * persistent store.
44  *
45  * NOT THREAD SAFE
46  *
47  * Hibernate Multi-threading notes: ChannelBuilder has some subtleties as it
48  * relates to threading. The specifics of the way it is supported
49  * still need to be proven. Certainly the error handling here and in
50  * UpdateChannelTask and in ChannelRegistry is incomplete. It seems to work,
51  * but I would consider it incomplete still.
52  *
53  * The key facts are (1) Sessions are not thread safe and (2) Sessions should
54  * have relatively short lifespans.
55  *
56  * To support this, there is a mode of using ChannelBuilder where it holds on
57  * to a SessionHandler and manages the creation and destruction of Sessions on
58  * behalf of the caller. When you supply a SessionHandler to ChannelBuilder,
59  * you may use the beginTransaction() and endTransaction() calls to take all the
60  * steps needed before and after a transaction. At the end of endTransaction()
61  * the transaction will be closed and the session will be flushed and closed.
62  * To use this mode, you should (1) Create a SessionHandler , (2) Create a
63  * JDBC Connection to the database, (3) sessionHandler.setConnection(connection),
64  * and (4) use new ChannelBuilder(sessionHandler).
65  *
66  * @author Niko Schmuck (niko@nava.de)
67  */

68 public class ChannelBuilder implements ChannelBuilderIF {
69
70   private static Log logger = LogFactory.getLog(ChannelBuilder.class);
71   private Session session;
72   private SessionHandler handler;
73   private Transaction transaction;
74
75   /**
76    * ChannelBuilder constructor. Caller is responsible for managing sessions
77    * and transactions.
78    */

79   public ChannelBuilder(Session session) {
80     logger.info("New Channel Builder for: " + session);
81     this.session = session;
82     this.handler = null;
83   }
84
85   /**
86    * ChannelBuilder constructor. ChannelBuilder will manage sessions and
87    * transactions. Supplied SessionHandler needs to have a live JDBC connection
88    * available.
89    */

90   public ChannelBuilder(SessionHandler handler) {
91     logger.debug("New Channel Builder for: " + handler);
92     this.handler = handler;
93     this.session = null;
94   }
95
96   // --------------------------------------------------------------
97
// Hibernate Specific Methods
98
// --------------------------------------------------------------
99

100   /**
101    * Processing needed at the start of a transaction.
102    * - creating a session
103    * - beginning the transaction
104    */

105   public void beginTransaction() throws ChannelBuilderException {
106     logger.info("beginTransaction");
107     if (session != null || handler == null)
108       throw new IllegalStateException JavaDoc("Session != null || handler == null");
109     try {
110       session = handler.getSession();
111       transaction = session.beginTransaction();
112     } catch (HibernateException e) {
113       e.printStackTrace();
114       transaction = null;
115       throw new ChannelBuilderException(e);
116     }
117   }
118
119   /**
120    * Processing needed at the end of a transaction.
121    * - commit the transaction
122    * - flush the session
123    * - close the session
124    * TODO: catch the exception so this method doesn't have any throws.
125    */

126   public void endTransaction() throws ChannelBuilderException {
127     logger.info("endTransaction");
128     if (handler == null || transaction == null || session == null)
129       throw new IllegalStateException JavaDoc("handler == null || transaction == null || session == null");
130     try {
131       transaction.commit();
132       session.flush();
133       session.close();
134       session = null;
135       transaction = null;
136
137     } catch (HibernateException he) {
138       if (transaction != null)
139         try {
140           he.printStackTrace();
141           transaction.rollback();
142           transaction = null;
143           if (session.isOpen()) {
144             session.close();
145             session = null;
146           }
147         } catch (HibernateException e) {
148           if (session.isOpen()) {
149             session = null;
150           }
151           e.printStackTrace();
152           throw new ChannelBuilderException(e);
153         }
154       throw new ChannelBuilderException(he);
155     }
156   }
157
158   /**
159    * Check if we are already in the middle of a transaction. This is needed because
160    * as of now begin/endTransactions cannot be nested and in fact give assert errors
161    * if you try.
162    *
163    * @return - boolean indicating whether we are currently in a transaction.
164    */

165   public boolean inTransaction()
166   {
167     return session != null && transaction != null;
168   }
169   /**
170    * resetTransaction - Used during error handling. If in a catch block there
171    * is a potentially still open transaction (i.e. beginTransaction() was called)
172    * then call this method to reset the state of the ChannelBuilder and clean up
173    * the transaction.
174    *
175    */

176   public void resetTransaction()
177   {
178     logger.debug("Transaction being reset.");
179     if (transaction != null)
180     {
181       try {
182         transaction.commit();
183         transaction = null;
184       }
185       catch (HibernateException e) {
186         transaction = null;
187         e.printStackTrace();
188       }
189     }
190     if (session != null) {
191       try {
192         session.flush();
193         session.close();
194         session = null;
195      }
196       catch (HibernateException e) {
197         e.printStackTrace();
198         session = null;
199       }
200     }
201   }
202
203   /**
204    * Certain Hibernate calls require the session. Note that this
205    * call should only be made between a beginTransaction and endTransaction call
206    * which is why we throw an IllegalStateException otherwise.
207    */

208   public Session getSession() {
209     if (handler == null || session == null)
210       throw new IllegalStateException JavaDoc("getSession must be bracketed by begin/endTransaction");
211     if (!handler.isSessionOpen())
212         throw new IllegalStateException JavaDoc("Hibernate Handler must be open");
213     return session;
214   }
215
216   /**
217    * update - Hibernate Update some object
218    *
219    * @param o
220    * @throws ChannelBuilderException -
221    */

222   public void update(Object JavaDoc o) throws ChannelBuilderException {
223     try {
224       session.update(o);
225     } catch (HibernateException e) {
226       e.printStackTrace();
227       throw new ChannelBuilderException("update() Failed");
228     }
229   }
230
231   /**
232    * uHibernate Delete some object
233    *
234    * @param o - Object to Delete
235    * @throws ChannelBuilderException - Translation of Hibernate exception
236    */

237   public void delete(Object JavaDoc o) throws ChannelBuilderException {
238     try {
239       session.delete(o);
240     } catch (HibernateException e) {
241       e.printStackTrace();
242       throw new ChannelBuilderException("delete() Failed");
243     }
244   }
245
246
247   // --------------------------------------------------------------
248
// implementation of ChannelBuilderIF interface
249
// --------------------------------------------------------------
250

251   public void init(Properties props) throws ChannelBuilderException {
252     logger.debug("initialising channel builder for hibernate backend");
253   }
254
255   public ChannelGroupIF createChannelGroup(String JavaDoc title) {
256     ChannelGroupIF obj = new ChannelGroup(title);
257     save(obj);
258     return obj;
259   }
260
261   public ChannelIF createChannel(String JavaDoc title) {
262     ChannelIF obj = new Channel(title);
263     save(obj);
264     return obj;
265   }
266
267   public ChannelIF createChannel(Element channelElement, String JavaDoc title) {
268     ChannelIF obj = new Channel(channelElement, title);
269     save(obj);
270     return obj;
271   }
272
273   public ItemIF createItem(ChannelIF channel, String JavaDoc title, String JavaDoc description,
274                            URL JavaDoc link) {
275     return createItem(null, channel, title, description, link);
276   }
277
278   public ItemIF createItem(Element itemElement, ChannelIF channel,
279                            String JavaDoc title, String JavaDoc description, URL JavaDoc link) {
280     ItemIF obj = new Item(itemElement, channel, title, description, link);
281     save(obj);
282     if (channel != null) {
283       channel.addItem(obj);
284     }
285     return obj;
286   }
287
288   /**
289    * Create an item from an existing item.
290    *
291    * @TODO: Add code to copy the complete state of the item rather than just four fields!
292    *
293    * @param chan - Channel in which the new item will be held
294    * @param oldItem - Old item which will provide the state for the new item
295    * @return - the newly created item
296    */

297   public ItemIF createItem(ChannelIF chan, ItemIF oldItem) {
298     ItemIF obj = createItem(null, chan, oldItem.getTitle(), oldItem.getDescription(), oldItem.getLink());
299     InformaUtils.copyItemProperties(oldItem, obj);
300     save(obj);
301     return obj;
302   }
303
304   public ImageIF createImage(String JavaDoc title, URL JavaDoc location, URL JavaDoc link) {
305     ImageIF obj = new Image(title, location, link);
306     save(obj);
307     return obj;
308   }
309
310   public CloudIF createCloud(String JavaDoc domain, int port, String JavaDoc path, String JavaDoc registerProcedure, String JavaDoc protocol) {
311     logger.info("ChannelBuilder is creating a Persistent Cloud");
312     CloudIF obj = new Cloud(domain, port, path, registerProcedure, protocol);
313     save(obj);
314     return obj;
315   }
316
317   public TextInputIF createTextInput(String JavaDoc title, String JavaDoc description,
318                                      String JavaDoc name, URL JavaDoc link) {
319     TextInputIF obj = new TextInput(title, description, name, link);
320     save(obj);
321     return obj;
322   }
323
324   public ItemSourceIF createItemSource(ItemIF item, String JavaDoc name,
325                                        String JavaDoc location, Date timestamp) {
326     return new ItemSource(item, name, location, timestamp);
327   }
328
329   public ItemEnclosureIF createItemEnclosure(ItemIF item, URL JavaDoc location,
330                                              String JavaDoc type, int length) {
331     return new ItemEnclosure(item, location, type, length);
332   }
333
334   public ItemGuidIF createItemGuid(ItemIF item, String JavaDoc location, boolean permaLink) {
335     return new ItemGuid(item, location, permaLink);
336   }
337
338   public CategoryIF createCategory(CategoryIF parent, String JavaDoc title) {
339     CategoryIF cat = new Category(title);
340     save(cat);
341     if (parent != null) {
342       parent.addChild(cat);
343     }
344     return cat;
345   }
346
347   public void close() throws ChannelBuilderException {
348     logger.debug("closing channel builder for hibernate backend");
349   }
350
351   /**
352    * Reloads group for use in new session.
353    *
354    * @param group to reload.
355    *
356    * @return reloaded group for chaning.
357    *
358    * @throws ChannelBuilderException when unable to reload data.
359    */

360   public ChannelGroup reload(ChannelGroup group)
361     throws ChannelBuilderException
362   {
363     try
364     {
365       getSession().load(group, new Integer JavaDoc(group.getIntId()));
366     } catch (HibernateException e)
367     {
368       throw new ChannelBuilderException("Unable to reload group: " + e.getMessage());
369     }
370
371     return group;
372   }
373
374   /**
375    * Reloads channel for use in new session.
376    *
377    * @param channel channel to reload.
378    *
379    * @return reloaded channel for chaining.
380    *
381    * @throws ChannelBuilderException when unable to reload data.
382    */

383   public Channel reload(Channel channel)
384     throws ChannelBuilderException
385   {
386     try
387     {
388       getSession().load(channel, new Integer JavaDoc(channel.getIntId()));
389     } catch (HibernateException e)
390     {
391       throw new ChannelBuilderException("Unable to reload channel: " + e.getMessage());
392     }
393
394     return channel;
395   }
396
397   /**
398    * Reloads item for use in new session.
399    *
400    * @param item item to reload.
401    *
402    * @return reloaded item for chaning.
403    *
404    * @throws ChannelBuilderException when unable to reload data.
405    */

406   public Item reload(Item item)
407     throws ChannelBuilderException
408   {
409     try
410     {
411       getSession().load(item, new Integer JavaDoc(item.getIntId()));
412     } catch (HibernateException e)
413     {
414       throw new ChannelBuilderException("Unable to reload item: " + e.getMessage());
415     }
416
417     return item;
418   }
419
420   // -------------------------------------------------------------
421
// internal helper methods
422
// -------------------------------------------------------------
423

424   protected void save(Object JavaDoc dataObject) {
425     if (session == null)
426       throw new IllegalStateException JavaDoc("Session == null");
427     try {
428       session.save(dataObject);
429     } catch (HibernateException he) {
430       throw new RuntimeException JavaDoc(he.getMessage());
431     }
432   }
433 }
434
Popular Tags