View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.util.concurrent;
20  
21  import java.util.Objects;
22  
23  import org.apache.logging.log4j.LogManager;
24  import org.apache.logging.log4j.Logger;
25  import org.mycore.common.MCRSession;
26  import org.mycore.common.MCRSessionMgr;
27  import org.mycore.common.MCRTransactionHelper;
28  
29  /**
30   * Encapsulates a {@link Runnable} with a mycore session and a database transaction.
31   * 
32   * @author Matthias Eichner
33   */
34  public class MCRTransactionableRunnable implements Runnable, MCRDecorator<Runnable> {
35  
36      private static final Logger LOGGER = LogManager.getLogger();
37  
38      protected Runnable runnable;
39  
40      private MCRSession session;
41  
42      /**
43       * Creates a new {@link Runnable} encapsulating the {@link #run()} method with a new
44       * {@link MCRSession} and a database transaction. Afterwards the transaction will
45       * be committed and the session will be released and closed.
46       * 
47       * <p>If you want to execute your runnable in the context of an already existing
48       * session use the {@link MCRTransactionableRunnable#MCRTransactionableRunnable(Runnable, MCRSession)}
49       * constructor instead.
50       * 
51       * @param runnable the runnable to execute within a session and transaction
52       */
53      public MCRTransactionableRunnable(Runnable runnable) {
54          this.runnable = Objects.requireNonNull(runnable, "runnable must not be null");
55      }
56  
57      /**
58       * Creates a new {@link Runnable} encapsulating the {@link #run()} method with a new
59       * a database transaction. The transaction will be created in the context of the
60       * given session. Afterwards the transaction will be committed and the session
61       * will be released (but not closed!).
62       * 
63       * @param runnable the runnable to execute within a session and transaction
64       * @param session the session to use
65       */
66      public MCRTransactionableRunnable(Runnable runnable, MCRSession session) {
67          this.runnable = Objects.requireNonNull(runnable, "runnable must not be null");
68          this.session = Objects.requireNonNull(session, "session must not be null");
69      }
70  
71      @Override
72      public void run() {
73          boolean newSession = this.session == null;
74          MCRSessionMgr.unlock();
75          boolean closeSession = newSession && !MCRSessionMgr.hasCurrentSession();
76          if (newSession) {
77              this.session = MCRSessionMgr.getCurrentSession();
78          }
79          MCRSessionMgr.setCurrentSession(this.session);
80          MCRTransactionHelper.beginTransaction();
81          try {
82              this.runnable.run();
83          } finally {
84              try {
85                  MCRTransactionHelper.commitTransaction();
86              } catch (Exception commitExc) {
87                  LOGGER.error("Error while commiting transaction.", commitExc);
88                  try {
89                      MCRTransactionHelper.rollbackTransaction();
90                  } catch (Exception rollbackExc) {
91                      LOGGER.error("Error while rollbacking transaction.", commitExc);
92                  }
93              } finally {
94                  MCRSessionMgr.releaseCurrentSession();
95                  if (closeSession && session != null) {
96                      session.close();
97                  }
98              }
99          }
100     }
101 
102     @Override
103     public Runnable get() {
104         return this.runnable;
105     }
106 
107 }