1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 <Transaction> 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
119 }
120 doFinally();
121 }
122 throw new JellyTagException(e);
123 }
124
125
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
190 }
191 }
192 conn = null;
193 }
194
195 }