001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2004, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.metadata.sql;
018:
019: // J2SE dependencies
020: import java.sql.Array;
021: import java.sql.Connection;
022: import java.sql.PreparedStatement;
023: import java.sql.ResultSet;
024: import java.sql.SQLException;
025: import org.geotools.util.logging.Logging;
026:
027: /**
028: * The result of a query for metadata attributes. This object {@linkplain PreparedStatement
029: * prepares a statement} once for ever for a given table. When a particular record in this
030: * table is fetched, the {@link ResultSet} is automatically constructed. If many attributes
031: * are fetched consecutivly for the same record, then the same {@link ResultSet} is reused.
032: *
033: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/metadata/sql/MetadataResult.java $
034: * @version $Id: MetadataResult.java 27862 2007-11-12 19:51:19Z desruisseaux $
035: * @author Martin Desruisseaux
036: *
037: * @since 2.1
038: *
039: * @todo Automatically close the ResultSet after some delay (e.g. 2 minutes).
040: */
041: final class MetadataResult {
042: /**
043: * The table name, used for formatting error message.
044: */
045: private final String tableName;
046:
047: /**
048: * The statements for a specific table.
049: */
050: private final PreparedStatement statement;
051:
052: /**
053: * The results, or {@code null} if not yet determined.
054: */
055: private ResultSet results;
056:
057: /**
058: * The identifier (usually the primary key) for current results.
059: * If the record to fetch doesn't have the same identifier, then
060: * the {@link #results} will need to be closed and reconstructed.
061: */
062: private String identifier;
063:
064: /**
065: * Constructs a metadata result from the specified connection.
066: *
067: * @param connection The connection to the database.
068: * @param query The SQL query. The first question mark will be replaced
069: * by the table name.
070: * @param tableName The table name.
071: * @throws SQLException if the statement can't be created.
072: */
073: public MetadataResult(final Connection connection,
074: final String query, final String tableName)
075: throws SQLException {
076: this .tableName = tableName;
077: final int index = query.indexOf('?');
078: if (index < 0) {
079: // TODO: localize
080: throw new SQLException("Invalid query");
081: }
082: final StringBuffer buffer = new StringBuffer(query);
083: buffer.replace(index, index + 1, tableName);
084: statement = connection.prepareStatement(buffer.toString());
085: }
086:
087: /**
088: * Returns the result set for the given record.
089: *
090: * @param identifier The object identifier, usually the primary key value.
091: * @return The result set.
092: * @throws SQLException if an SQL operation failed.
093: */
094: private ResultSet getResultSet(final String identifier)
095: throws SQLException {
096: if (results != null) {
097: if (this .identifier.equals(identifier)) {
098: return results;
099: }
100: if (results.next()) {
101: // TODO: Localize
102: Logging.getLogger("org.geotools.metadata.sql").warning(
103: "Duplicate identifier: " + identifier);
104: }
105: results.close();
106: results = null; // In case the 'results = ...' below will fails.
107: }
108: this .identifier = identifier;
109: statement.setString(1, identifier);
110: results = statement.executeQuery();
111: if (!results.next()) {
112: results.close();
113: results = null;
114: throw new SQLException("Metadata not found: \""
115: + identifier + "\" in table \"" + tableName + '"');
116: // TODO: localize
117: }
118: return results;
119: }
120:
121: /**
122: * Returns the attribute value in the given column for the given record.
123: *
124: * @param identifier The object identifier, usually the primary key value.
125: * @param columnName The column name of the attribute to search.
126: * @return The attribute value.
127: * @throws SQLException if an SQL operation failed.
128: */
129: public Object getObject(final String identifier,
130: final String columnName) throws SQLException {
131: return getResultSet(identifier).getObject(columnName);
132: }
133:
134: /**
135: * Returns the attribute value in the given column for the given record.
136: *
137: * @param identifier The object identifier, usually the primary key value.
138: * @param columnName The column name of the attribute to search.
139: * @return The attribute value.
140: * @throws SQLException if an SQL operation failed.
141: */
142: public Object getArray(final String identifier,
143: final String columnName) throws SQLException {
144: final Array array = getResultSet(identifier).getArray(
145: columnName);
146: return (array != null) ? array.getArray() : null;
147: }
148:
149: /**
150: * Returns the attribute value in the given column for the given record.
151: *
152: * @param identifier The object identifier, usually the primary key value.
153: * @param columnName The column name of the attribute to search.
154: * @return The attribute value.
155: * @throws SQLException if an SQL operation failed.
156: */
157: public int getInt(final String identifier, final String columnName)
158: throws SQLException {
159: return getResultSet(identifier).getInt(columnName);
160: }
161:
162: /**
163: * Returns the attribute value in the given column for the given record.
164: *
165: * @param identifier The object identifier, usually the primary key value.
166: * @param columnName The column name of the attribute to search.
167: * @return The attribute value.
168: * @throws SQLException if an SQL operation failed.
169: */
170: public String getString(final String identifier,
171: final String columnName) throws SQLException {
172: return getResultSet(identifier).getString(columnName);
173: }
174:
175: /**
176: * Returns the string value in the first column of the given record.
177: * This is used for fetching the name of a code list element.
178: *
179: * @param code The object identifier, usually the primary key value.
180: * @return The string value found in the first column.
181: * @throws SQLException if an SQL operation failed.
182: */
183: public String getString(final String code) throws SQLException {
184: return getResultSet(code).getString(1);
185: }
186:
187: /**
188: * Returns {@code true} if the last value returned by a {@code getFoo} method was null.
189: */
190: public boolean wasNull() throws SQLException {
191: return results.wasNull();
192: }
193:
194: /**
195: * Close this statement and free all resources.
196: * After this method has been invoked, this object can't be used anymore.
197: *
198: * @throws SQLException if an SQL operation failed.
199: */
200: public void close() throws SQLException {
201: if (results != null) {
202: results.close();
203: results = null;
204: }
205: statement.close();
206: }
207: }
|