View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.jelly.tags.sql;
18  
19  import java.sql.Connection;
20  import java.sql.SQLException;
21  
22  import javax.sql.DataSource;
23  
24  import org.apache.commons.jelly.JellyTagException;
25  import org.apache.commons.jelly.TagSupport;
26  import org.apache.commons.jelly.XMLOutput;
27  import org.apache.commons.jelly.tags.Resources;
28  
29  /***
30   * <p>Tag handler for &lt;Transaction&gt; in JSTL.
31   *
32   * @author Hans Bergsten
33   */
34  
35  public class TransactionTag extends TagSupport {
36  
37      //**********************************************************************
38      // Private constants
39  
40      private static final String TRANSACTION_READ_COMMITTED = "read_committed";
41      private static final String TRANSACTION_READ_UNCOMMITTED = "read_uncommitted";
42      private static final String TRANSACTION_REPEATABLE_READ = "repeatable_read";
43      private static final String TRANSACTION_SERIALIZABLE = "serializable";
44  
45      //*********************************************************************
46      // Protected state
47  
48      protected Object rawDataSource;
49      protected boolean dataSourceSpecified;
50  
51      //*********************************************************************
52      // Private state
53  
54      private Connection conn;
55      private int isolation = Connection.TRANSACTION_NONE;
56      private int origIsolation;
57  
58      //*********************************************************************
59      // Constructor and initialization
60  
61      public TransactionTag() {
62      }
63  
64      /**
65       * Sets the SQL DataSource. DataSource can be
66       * a String or a DataSource object.
67       */
68      public void setDataSource(Object dataSource) {
69          this.rawDataSource = dataSource;
70          this.dataSourceSpecified = true;
71      }
72  
73  
74      //**********************************************************************
75      // Tag logic
76  
77      /**
78       * Prepares for execution by setting the initial state, such as
79       * getting the <code>Connection</code> and preparing it for
80       * the transaction.
81       */
82      public void doTag(XMLOutput output) throws JellyTagException {
83  
84          if ((rawDataSource == null) && dataSourceSpecified) {
85              throw new JellyTagException(Resources.getMessage("SQL_DATASOURCE_NULL"));
86          }
87  
88          DataSource dataSource = DataSourceUtil.getDataSource(rawDataSource, context);
89  
90          try {
91              conn = dataSource.getConnection();
92              origIsolation = conn.getTransactionIsolation();
93              if (origIsolation == Connection.TRANSACTION_NONE) {
94                  throw new JellyTagException(Resources.getMessage("TRANSACTION_NO_SUPPORT"));
95              }
96              if ((isolation != Connection.TRANSACTION_NONE)
97                  && (isolation != origIsolation)) {
98                  conn.setTransactionIsolation(isolation);
99              }
100             conn.setAutoCommit(false);
101         }
102         catch (SQLException e) {
103             throw new JellyTagException(
104                 Resources.getMessage("ERROR_GET_CONNECTION", e.getMessage()));
105         }
106 
107         boolean finished = false;
108         try {
109             invokeBody(output);
110             finished = true;
111         }
112         catch (Exception e) {
113             if (conn != null) {
114                 try {
115                     conn.rollback();
116                 }
117                 catch (SQLException s) {
118                     // Ignore to not hide orignal exception
119                 }
120                 doFinally();
121             }
122             throw new JellyTagException(e);
123         }
124 
125         // lets commit
126         try {
127             conn.commit();
128         }
129         catch (SQLException e) {
130             throw new JellyTagException(
131                 Resources.getMessage("TRANSACTION_COMMIT_ERROR", e.getMessage()));
132         }
133         finally {
134             doFinally();
135         }
136     }
137 
138     //**********************************************************************
139     // Public utility methods
140 
141     /**
142      * Sets the transaction isolation level.
143      */
144     public void setIsolation(String iso) throws JellyTagException {
145 
146         if (TRANSACTION_READ_COMMITTED.equals(iso)) {
147             isolation = Connection.TRANSACTION_READ_COMMITTED;
148         }
149         else if (TRANSACTION_READ_UNCOMMITTED.equals(iso)) {
150             isolation = Connection.TRANSACTION_READ_UNCOMMITTED;
151         }
152         else if (TRANSACTION_REPEATABLE_READ.equals(iso)) {
153             isolation = Connection.TRANSACTION_REPEATABLE_READ;
154         }
155         else if (TRANSACTION_SERIALIZABLE.equals(iso)) {
156             isolation = Connection.TRANSACTION_SERIALIZABLE;
157         }
158         else {
159             throw new JellyTagException(Resources.getMessage("TRANSACTION_INVALID_ISOLATION"));
160         }
161     }
162 
163     /***
164      * Called by nested parameter elements to get a reference to
165      * the Connection.
166      */
167     public Connection getSharedConnection() {
168         return conn;
169     }
170 
171     //**********************************************************************
172     // Implementation methods methods
173 
174     /**
175      * Restores the <code>Connection</code> to its initial state and
176      * closes it.
177      */
178     protected void doFinally() {
179         if (conn != null) {
180             try {
181                 if ((isolation != Connection.TRANSACTION_NONE)
182                     && (isolation != origIsolation)) {
183                     conn.setTransactionIsolation(origIsolation);
184                 }
185                 conn.setAutoCommit(true);
186                 conn.close();
187             }
188             catch (SQLException e) {
189                 // Not much we can do
190             }
191         }
192         conn = null;
193     }
194 
195 }