1 /* $HeadURL:: $
2 * $Id$
3 *
4 * Copyright (c) 2009-2010 DuraSpace
5 * http://duraspace.org
6 *
7 * In collaboration with Topaz Inc.
8 * http://www.topazproject.org
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 package org.akubraproject.txn;
24
25 import java.io.IOException;
26 import java.net.URI;
27 import java.sql.Connection;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
30 import java.util.Map;
31
32 import javax.sql.XAConnection;
33 import javax.transaction.Transaction;
34
35 import com.google.common.collect.AbstractIterator;
36 import com.google.common.collect.PeekingIterator;
37
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import org.akubraproject.BlobStore;
42 import org.akubraproject.BlobStoreConnection;
43
44 /**
45 * A basic superclass for sql-based transactional store connections. This just closes the sql
46 * connection at the end and provides an Iterator implementation for implementing
47 * {@link BlobStoreConnection#listBlobIds listBlobIds}.
48 *
49 * @author Ronald Tschalär
50 */
51 public abstract class SQLTransactionalConnection extends AbstractTransactionalConnection {
52 private static final Logger logger = LoggerFactory.getLogger(SQLTransactionalConnection.class);
53
54 /** The xa connection being used */
55 protected final XAConnection xaCon;
56 /** The db connection being used */
57 protected final Connection con;
58
59 /**
60 * Create a new sql-based transactional connection.
61 *
62 * @param owner the blob-store we belong to
63 * @param bStore the underlying blob-store to use
64 * @param xaCon the xa connection to use
65 * @param con the db connection to use
66 * @param tx the transaction we belong to
67 * @param hints the hints to pass to <code>openConnection<code> on <var>bStore</var>
68 * @throws IOException if an error occurs initializing this connection
69 */
70 protected SQLTransactionalConnection(BlobStore owner, BlobStore bStore, XAConnection xaCon,
71 Connection con, Transaction tx, Map<String, String> hints)
72 throws IOException {
73 super(owner, bStore, tx, hints);
74 this.con = con;
75 this.xaCon = xaCon;
76 }
77
78 @Override
79 public void afterCompletion(int status) {
80 if (isCompleted)
81 return;
82
83 try {
84 xaCon.close();
85 } catch (SQLException sqle) {
86 logger.error("Error closing db connection", sqle);
87 } finally {
88 super.afterCompletion(status);
89 }
90 }
91
92 /**
93 * A ResultSet based Iterator of blob-id's. Useful for {@link BlobStoreConnection#listBlobIds
94 * listBlobIds}.
95 *
96 * @author Ronald Tschalär
97 */
98 protected static class RSBlobIdIterator extends AbstractIterator<URI>
99 implements PeekingIterator<URI> {
100 protected final ResultSet rs;
101 private final boolean closeStmt;
102
103 /**
104 * Create a new iterator.
105 *
106 * @param rs the underlying result-set to use; the result-set must either have at least
107 * one column such that <code>rs.getString(1)</code> returns a URI, or you
108 * must override {@link #getNextId}.
109 * @param closeStmt whether to close the associated statement when closing the result-set at
110 * the end of the iteration.
111 * @throws SQLException if thrown while attempting to advance to the first row
112 */
113 public RSBlobIdIterator(ResultSet rs, boolean closeStmt) throws SQLException {
114 this.rs = rs;
115 this.closeStmt = closeStmt;
116 }
117
118 @Override
119 protected URI computeNext() {
120 try {
121 URI id = getNextId();
122 if (id != null)
123 return id;
124
125 close();
126 return endOfData();
127 } catch (SQLException sqle) {
128 throw new RuntimeException("error reading db results", sqle);
129 }
130 }
131
132 /**
133 * Get the next id.
134 *
135 * @return the next id, or null if there are none left
136 */
137 protected URI getNextId() throws SQLException {
138 if (!rs.next())
139 return null;
140
141 return URI.create(rs.getString(1));
142 }
143
144 /**
145 * Close the underlying result-set and statement (if <var>closeStmt</var> is true).
146 */
147 protected void close() {
148 try {
149 if (closeStmt)
150 rs.getStatement().close();
151 else
152 rs.close();
153 } catch (SQLException sqle) {
154 logger.error("Error closing statement or result-set", sqle);
155 }
156 }
157 }
158 }