001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jbpm.persistence.db;
023:
024: import java.sql.Connection;
025:
026: import javax.sql.DataSource;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030: import org.hibernate.Session;
031: import org.hibernate.SessionFactory;
032: import org.hibernate.StaleObjectStateException;
033: import org.hibernate.Transaction;
034: import org.jbpm.JbpmContext;
035: import org.jbpm.JbpmException;
036: import org.jbpm.db.ContextSession;
037: import org.jbpm.db.GraphSession;
038: import org.jbpm.db.JobSession;
039: import org.jbpm.db.LoggingSession;
040: import org.jbpm.db.TaskMgmtSession;
041: import org.jbpm.persistence.JbpmPersistenceException;
042: import org.jbpm.persistence.PersistenceService;
043: import org.jbpm.svc.Service;
044: import org.jbpm.svc.Services;
045: import org.jbpm.tx.TxService;
046:
047: public class DbPersistenceService implements Service,
048: PersistenceService {
049:
050: private static final long serialVersionUID = 1L;
051:
052: protected DbPersistenceServiceFactory persistenceServiceFactory = null;
053:
054: protected Connection connection = null;
055: protected boolean mustConnectionBeClosed = false;
056:
057: protected Transaction transaction = null;
058: protected boolean isTransactionEnabled = true;
059: protected boolean isCurrentSessionEnabled = false;
060:
061: // boolean isRollbackOnly = false;
062:
063: protected Session session;
064: protected boolean mustSessionBeFlushed = false;
065: protected boolean mustSessionBeClosed = false;
066:
067: protected Services services = null;
068:
069: protected GraphSession graphSession = null;
070: protected TaskMgmtSession taskMgmtSession = null;
071: protected JobSession jobSession = null;
072: protected ContextSession contextSession = null;
073: protected LoggingSession loggingSession = null;
074:
075: public DbPersistenceService(
076: DbPersistenceServiceFactory persistenceServiceFactory) {
077: this (persistenceServiceFactory, getCurrentServices());
078: }
079:
080: static Services getCurrentServices() {
081: Services services = null;
082: JbpmContext currentJbpmContext = JbpmContext
083: .getCurrentJbpmContext();
084: if (currentJbpmContext != null) {
085: services = currentJbpmContext.getServices();
086: }
087: return services;
088: }
089:
090: DbPersistenceService(
091: DbPersistenceServiceFactory persistenceServiceFactory,
092: Services services) {
093: this .persistenceServiceFactory = persistenceServiceFactory;
094: this .isTransactionEnabled = persistenceServiceFactory
095: .isTransactionEnabled();
096: this .isCurrentSessionEnabled = persistenceServiceFactory
097: .isCurrentSessionEnabled();
098: this .services = services;
099: }
100:
101: public SessionFactory getSessionFactory() {
102: return persistenceServiceFactory.getSessionFactory();
103: }
104:
105: public Session getSession() {
106: if ((session == null) && (getSessionFactory() != null)) {
107: Connection connection = getConnection(false);
108: if (isCurrentSessionEnabled) {
109: session = getSessionFactory().getCurrentSession();
110: log.debug("using current hibernate session " + session);
111: mustSessionBeClosed = false;
112: mustSessionBeFlushed = false;
113: mustConnectionBeClosed = false;
114: } else if (connection != null) {
115: log.debug("creating hibernate session with connection "
116: + connection);
117: session = getSessionFactory().openSession(connection);
118: mustSessionBeClosed = true;
119: mustSessionBeFlushed = true;
120: mustConnectionBeClosed = false;
121: } else {
122: log.debug("creating hibernate session");
123: session = getSessionFactory().openSession();
124: mustSessionBeClosed = true;
125: mustSessionBeFlushed = true;
126: mustConnectionBeClosed = false;
127: }
128:
129: if (isTransactionEnabled) {
130: beginTransaction();
131: }
132: }
133: return session;
134: }
135:
136: public void beginTransaction() {
137: log.debug("beginning hibernate transaction");
138: transaction = session.beginTransaction();
139: log.debug("begun hibernate transaction "
140: + transaction.toString());
141: }
142:
143: public void endTransaction() {
144: if ((isTransactionEnabled) && (transaction != null)) {
145: if (isRollbackOnly()) {
146: try {
147: log.debug("rolling back hibernate transaction "
148: + transaction.toString());
149: mustSessionBeFlushed = false; // flushing updates that will be rolled back is not very clever :-)
150: transaction.rollback();
151: } catch (Exception e) {
152: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
153: throw new JbpmPersistenceException(
154: "couldn't rollback hibernate session", e);
155: }
156: } else {
157: try {
158: log.debug("committing hibernate transaction "
159: + transaction.toString());
160: mustSessionBeFlushed = false; // commit does a flush anyway
161: transaction.commit();
162: } catch (Exception e) {
163: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
164: try {
165: // if the commit fails, we must do a rollback
166: transaction.rollback();
167: } catch (Exception e2) {
168: // if the rollback fails, we did what we could and you're in
169: // deep shit :-(
170: log
171: .error(
172: "problem rolling back after failed commit",
173: e2);
174: }
175: throw new JbpmPersistenceException(
176: "couldn't commit hibernate session", e);
177: }
178: }
179: }
180: }
181:
182: public Connection getConnection() {
183: return getConnection(true);
184: }
185:
186: public Connection getConnection(boolean resolveSession) {
187: if (connection == null) {
188: if (persistenceServiceFactory.getDataSource() != null) {
189: try {
190: log
191: .debug("fetching jdbc connection from datasource");
192: connection = persistenceServiceFactory
193: .getDataSource().getConnection();
194: mustConnectionBeClosed = true;
195: } catch (Exception e) {
196: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
197: throw new JbpmException(
198: "couldn't obtain connection from datasource",
199: e);
200: }
201: } else {
202: if (resolveSession) {
203: // initializes the session member
204: getSession();
205: }
206: if (session != null) {
207: connection = session.connection();
208: log
209: .debug("fetching connection from hibernate session. this transfers responsibility for closing the jdbc connection to the user! "
210: + connection);
211: mustConnectionBeClosed = false;
212: }
213: }
214: }
215: return connection;
216: }
217:
218: public void close() {
219:
220: if ((session != null) && (transaction == null)
221: && (isRollbackOnly())) {
222: throw new JbpmException(
223: "setRollbackOnly was invoked while configuration specifies user managed transactions");
224: }
225:
226: if ((isTransactionEnabled) && (transaction != null)) {
227:
228: if (!isRollbackOnly()) {
229: Exception commitException = commit();
230: if (commitException != null) {
231: rollback();
232: closeSession();
233: closeConnection();
234: throw new JbpmPersistenceException(
235: "hibernate commit failed", commitException);
236: }
237:
238: } else { // isRollbackOnly==true
239: Exception rollbackException = rollback();
240: if (rollbackException != null) {
241: closeSession();
242: closeConnection();
243: throw new JbpmPersistenceException(
244: "hibernate rollback failed",
245: rollbackException);
246: }
247: }
248: }
249:
250: Exception flushException = flushSession();
251: if (flushException != null) {
252: rollback();
253: closeSession();
254: closeConnection();
255: throw new JbpmPersistenceException(
256: "hibernate flush failed", flushException);
257: }
258:
259: Exception closeSessionException = closeSession();
260: if (closeSessionException != null) {
261: closeConnection();
262: throw new JbpmPersistenceException(
263: "hibernate close session failed",
264: closeSessionException);
265: }
266:
267: Exception closeConnectionException = closeConnection();
268: if (closeConnectionException != null) {
269: throw new JbpmPersistenceException(
270: "hibernate close connection failed",
271: closeConnectionException);
272: }
273: }
274:
275: Exception commit() {
276: try {
277: log.debug("committing hibernate transaction "
278: + transaction.toString());
279: mustSessionBeFlushed = false; // commit does a flush anyway
280: transaction.commit();
281: } catch (StaleObjectStateException e) {
282: log.info("optimistic locking failed");
283: StaleObjectLogConfigurer.staleObjectExceptionsLog.error(
284: "optimistic locking failed", e);
285: return e;
286: } catch (Exception e) {
287: log.error("hibernate commit failed", e);
288: return e;
289: }
290: return null;
291: }
292:
293: Exception flushSession() {
294: if (mustSessionBeFlushed) {
295: try {
296: log.debug("flushing hibernate session "
297: + session.toString());
298: session.flush();
299: } catch (Exception e) {
300: log.error("hibernate flush failed", e);
301: return e;
302: }
303: }
304: return null;
305: }
306:
307: Exception closeConnection() {
308: if (mustConnectionBeClosed) {
309: try {
310: if ((connection != null) && (!connection.isClosed())) {
311: log.debug("closing jdbc connection");
312: connection.close();
313: } else {
314: log.warn("jdbc connection was already closed");
315: }
316: } catch (Exception e) {
317: log.error("hibernate session close failed", e);
318: return e;
319: }
320: }
321: return null;
322: }
323:
324: Exception rollback() {
325: try {
326: log.debug("rolling back hibernate transaction");
327: mustSessionBeFlushed = false; // flushing updates that will be rolled back is not very clever :-)
328: transaction.rollback();
329: } catch (Exception e) {
330: log.error("hibernate rollback failed", e);
331: return e;
332: }
333: return null;
334: }
335:
336: Exception closeSession() {
337: if (mustSessionBeClosed) {
338: try {
339: if (session.isOpen()) {
340: log.debug("closing hibernate session");
341: session.close();
342: } else {
343: log.warn("hibernate session was already closed");
344: }
345: } catch (Exception e) {
346: return e;
347: }
348: }
349: return null;
350: }
351:
352: public void assignId(Object object) {
353: try {
354: getSession().save(object);
355: } catch (Exception e) {
356: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
357: throw new JbpmPersistenceException("couldn't assign id to "
358: + object, e);
359: }
360: }
361:
362: // getters and setters //////////////////////////////////////////////////////
363:
364: public GraphSession getGraphSession() {
365: if (graphSession == null) {
366: Session session = getSession();
367: if (session != null) {
368: graphSession = new GraphSession(session);
369: }
370: }
371: return graphSession;
372: }
373:
374: public LoggingSession getLoggingSession() {
375: if (loggingSession == null) {
376: Session session = getSession();
377: if (session != null) {
378: loggingSession = new LoggingSession(session);
379: }
380: }
381: return loggingSession;
382: }
383:
384: public JobSession getJobSession() {
385: if (jobSession == null) {
386: Session session = getSession();
387: if (session != null) {
388: jobSession = new JobSession(session);
389: }
390: }
391: return jobSession;
392: }
393:
394: public ContextSession getContextSession() {
395: if (contextSession == null) {
396: Session session = getSession();
397: if (session != null) {
398: contextSession = new ContextSession(session);
399: }
400: }
401: return contextSession;
402: }
403:
404: public TaskMgmtSession getTaskMgmtSession() {
405: if (taskMgmtSession == null) {
406: Session session = getSession();
407: if (session != null) {
408: taskMgmtSession = new TaskMgmtSession(session);
409: }
410: }
411: return taskMgmtSession;
412: }
413:
414: public DataSource getDataSource() {
415: return persistenceServiceFactory.dataSource;
416: }
417:
418: /**
419: * @deprecated use {@link org.jbpm.tx.TxService} instead.
420: */
421: public boolean isRollbackOnly() {
422: TxService txService = (services != null ? services
423: .getTxService() : null);
424: if (txService == null) {
425: throw new JbpmException("no jbpm tx service configured");
426: }
427: return txService.isRollbackOnly();
428: }
429:
430: /**
431: * @deprecated use {@link org.jbpm.tx.TxService} instead.
432: */
433: public void setRollbackOnly(boolean isRollbackOnly) {
434: throw new UnsupportedOperationException(
435: "method setRollbackOnly has been removed. Use TxService instead.");
436: }
437:
438: /**
439: * @deprecated use {@link org.jbpm.tx.TxService} instead.
440: */
441: public void setRollbackOnly() {
442: TxService txService = (services != null ? services
443: .getTxService() : null);
444: if (txService == null) {
445: throw new JbpmException("no jbpm tx service configured");
446: }
447: txService.setRollbackOnly();
448: }
449:
450: public void setSession(Session session) {
451: this .session = session;
452: log.debug("injecting a session disables transaction");
453: isTransactionEnabled = false;
454: }
455:
456: public void setSessionWithoutDisablingTx(Session session) {
457: this .session = session;
458: }
459:
460: public void setConnection(Connection connection) {
461: this .connection = connection;
462: }
463:
464: public void setContextSession(ContextSession contextSession) {
465: this .contextSession = contextSession;
466: }
467:
468: public void setDataSource(DataSource dataSource) {
469: this .persistenceServiceFactory.dataSource = dataSource;
470: }
471:
472: public void setGraphSession(GraphSession graphSession) {
473: this .graphSession = graphSession;
474: }
475:
476: public void setLoggingSession(LoggingSession loggingSession) {
477: this .loggingSession = loggingSession;
478: }
479:
480: public void setJobSession(JobSession jobSession) {
481: this .jobSession = jobSession;
482: }
483:
484: public void setTaskMgmtSession(TaskMgmtSession taskMgmtSession) {
485: this .taskMgmtSession = taskMgmtSession;
486: }
487:
488: public void setSessionFactory(SessionFactory sessionFactory) {
489: this .persistenceServiceFactory.sessionFactory = sessionFactory;
490: }
491:
492: public Transaction getTransaction() {
493: return transaction;
494: }
495:
496: public void setTransaction(Transaction transaction) {
497: this .transaction = transaction;
498: }
499:
500: public boolean isTransactionEnabled() {
501: return isTransactionEnabled;
502: }
503:
504: public void setTransactionEnabled(boolean isTransactionEnabled) {
505: this .isTransactionEnabled = isTransactionEnabled;
506: }
507:
508: private static Log log = LogFactory
509: .getLog(DbPersistenceService.class);
510: }
|