Source code: nl/aidministrator/rdf/ral/ordbms/RecursiveSqlResourceIterator.java
1 /* Sesame - Storage and Querying architecture for RDF and RDF Schema
2 * Copyright (C) 2002 Aidministrator Nederland b.v.
3 *
4 * Contact:
5 * Aidministrator Nederland b.v.
6 * Julianaplein 14b
7 * 3817 CS Amersfoort
8 * The Netherlands
9 * tel. +31(0)33 4659987
10 * fax. +31(0)33 4659987
11 * sesame@aidministrator.nl
12 *
13 * http://www.aidministrator.nl/
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 */
29
30 package nl.aidministrator.rdf.ral.ordbms;
31
32 import nl.aidministrator.rdf.ral.*;
33 import nl.aidministrator.rdf.sail.model.*;
34 import java.util.*;
35 import java.sql.*;
36
37 /**
38 * A ResourceIterator that executes SQL queries recursively by re-inserting
39 * part of the query's results into the query. The query should contain EXACTLY
40 * ONE in-parameter (i.e. there is one '?' in the query) and the ResultSet
41 * should contain the following columns: id (int), isResource (boolean),
42 * namespace (string) and localname (string). The first value (the id) will be
43 * re-inserted into the query.
44 **/
45 public class RecursiveSqlResourceIterator implements ResourceIterator {
46
47 /*-----------------------------------------------+
48 | Variables |
49 +-----------------------------------------------*/
50
51 /**
52 * Connection to the database.
53 **/
54 protected Connection _dbConn;
55
56 /**
57 * The query in the form of a PreparedStatement.
58 **/
59 protected PreparedStatement _st;
60
61 /**
62 * Queue containing the results.
63 **/
64 protected List _resultsQueue;
65
66 /*-----------------------------------------------+
67 | Constructors |
68 +-----------------------------------------------*/
69
70 /**
71 * Calls the supplied query recursively by re-inserting obtained
72 * values as arguments into the query. See class comments for
73 * more information.
74 *
75 * @param query The query to call recursively
76 * @param initialValue The initial value to bootstrap the process.
77 **/
78 public RecursiveSqlResourceIterator(
79 Connection dbConn, String query, IdValue initialValue)
80 throws SQLException
81 {
82 _dbConn = dbConn;
83 _st = _dbConn.prepareStatement(query);
84
85 _resultsQueue = new LinkedList();
86 _resultsQueue.add(initialValue);
87
88 // Maybe there are no results at all, and getNext() will never
89 // be called. Therefore, check if the connection should already
90 // be closed again.
91 if (_resultsQueue.isEmpty()) {
92 close();
93 }
94 }
95
96 /*-----------------------------------------------+
97 | Methods |
98 +-----------------------------------------------*/
99
100 private void _fillQueue(int value) {
101 try {
102 _st.setInt(1, value);
103
104 // Execute query
105 ResultSet rs = _st.executeQuery();
106
107 while (rs.next()) {
108 int id = rs.getInt(1);
109 boolean isResource = rs.getBoolean(2);
110
111 IdValue idValue;
112
113 if (isResource) {
114 String ns = rs.getString(3);
115 String lname = rs.getString(4);
116 idValue = new IdResource(id, ns, lname);
117 }
118 else {
119 String label = rs.getString(4);
120 String lang = rs.getString(5);
121 if ("".equals(lang)) {
122 idValue = new IdLiteral(id, label);
123 }
124 else {
125 idValue = new IdLiteral(id, label, lang);
126 }
127 }
128
129 _resultsQueue.add(idValue);
130 }
131 rs.close();
132 }
133 catch (SQLException e) {
134 System.err.println("SqlException: " + e.getMessage());
135 e.printStackTrace();
136 }
137 }
138
139 /**
140 * Checks whether there are any more results available.
141 **/
142 public boolean hasNext() {
143 return !_resultsQueue.isEmpty();
144 }
145
146 /**
147 * Gets the next result.
148 *
149 * @exception NoSuchElementException If there are no more results
150 * available.
151 **/
152 public Value next() {
153 if (!_resultsQueue.isEmpty()) {
154 IdValue result = (IdValue)_resultsQueue.remove(0);
155
156 _fillQueue( result.getId() );
157
158 if (_resultsQueue.isEmpty()) {
159 close();
160 }
161
162 return result;
163 }
164 else {
165 throw new NoSuchElementException("No more resources");
166 }
167 }
168
169 public void close() {
170 // Make sure to do this only once
171 if (_dbConn != null) {
172 _resultsQueue.clear();
173
174 try {
175 if (_st != null) {
176 _st.close();
177 }
178 _dbConn.close();
179 }
180 catch (SQLException e) {
181 System.err.println("SqlException: " + e.getMessage());
182 e.printStackTrace();
183 }
184
185 _dbConn = null;
186 }
187 }
188
189 protected void finalize() {
190 close();
191 }
192 }