Source code: com/clra/web/OarsetSet.java
1 /*
2 * Copyright (c) Carnegie Lake Rowing Association 2002. All rights reserved.
3 * Distributed under the GPL license. See doc/COPYING.
4 * $RCSfile: OarsetSet.java,v $
5 * $Date: 2003/02/26 03:38:46 $
6 * $Revision: 1.4 $
7 */
8
9 package com.clra.web;
10
11 import com.clra.rowing.OarsetView;
12 import com.clra.util.DBConfiguration;
13 import com.clra.util.ValidationException;
14 import java.io.InputStream;
15 import java.net.URL;
16 import java.sql.Connection;
17 import java.sql.Driver;
18 import java.sql.DriverManager;
19 import java.sql.PreparedStatement;
20 import java.sql.ResultSet;
21 import java.sql.SQLException;
22 import java.util.Collection;
23 import java.util.Comparator;
24 import java.util.GregorianCalendar;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.Properties;
29 import java.util.SortedSet;
30 import java.util.TreeSet;
31 import org.apache.log4j.Category;
32 import org.apache.log4j.helpers.Loader;
33
34 /**
35 * A collection of "finder" methods that return read-only, sorted sets
36 * of oarsets.<p>
37 * FIXME: when this class changes to a "Session-like" design, make sure
38 *
39 * @version $Id: OarsetSet.java,v 1.4 2003/02/26 03:38:46 rphall Exp $
40 * @author <a href="mailto:rphall@pluto.njcc.com">Rick Hall</a>
41 */
42 public class OarsetSet implements SortedSet {
43
44 private final static String base = OarsetSet.class.getName();
45 private final static Category theLog = Category.getInstance( base );
46
47 /**
48 * The current implementations return data in an in-memory collections.
49 * Since the underlaying Oarset database table may already be
50 * cached in memory, this can lead to duplicate caching. Future
51 * implementations should avoid in-memory duplicates by implementing
52 * SortedSet and Iterator methods directly in SQL.<p>
53 */
54 private final SortedSet data = new TreeSet();
55
56 /**
57 * Finds all active oarsets of the CLRA. Oarsets are sorted by name
58 * (the natural comparator for oarsets).
59 */
60 public static OarsetSet findAllActiveOarsets()
61 throws WebException {
62
63 Connection conn = null;
64 PreparedStatement stmt = null;
65 OarsetSet retVal = new OarsetSet();
66 try {
67 conn = DBConfiguration.getConnection();
68 stmt = conn.prepareStatement(
69 Configuration.SQL_OARSET_01,
70 ResultSet.TYPE_FORWARD_ONLY,
71 ResultSet.CONCUR_READ_ONLY);
72 loadOarsetSet( stmt, retVal.data );
73 }
74 catch(SQLException x) {
75 String msg = "SQLException: " + x.getMessage();
76 theLog.fatal( msg, x );
77 throw new WebException( msg );
78 }
79 finally {
80 DBConfiguration.closeSQLStatement( stmt );
81 DBConfiguration.closeSQLConnection( conn );
82 }
83 conn = null;
84 stmt = null;
85
86 return retVal;
87 } // findAllActiveOarsets()
88
89 /**
90 * Finds the oarset that has the given id. This "finder" returns at most
91 * one oarset.
92 */
93 public static OarsetView findOarsetById( int id )
94 throws WebException {
95
96 Connection conn = null;
97 PreparedStatement stmt = null;
98 OarsetView retVal = null;
99 try {
100 conn = DBConfiguration.getConnection();
101 stmt = conn.prepareStatement(
102 Configuration.SQL_OARSET_02,
103 ResultSet.TYPE_FORWARD_ONLY,
104 ResultSet.CONCUR_READ_ONLY);
105 stmt.setInt( 1, id );
106 retVal = loadOarset( stmt );
107 }
108 catch(SQLException x) {
109 String msg = "SQLException for id == '" + id + "': "
110 + x.getMessage();
111 theLog.fatal( msg, x );
112 throw new WebException( msg );
113 }
114 finally {
115 DBConfiguration.closeSQLStatement( stmt );
116 DBConfiguration.closeSQLConnection( conn );
117 }
118 conn = null;
119 stmt = null;
120
121 return retVal;
122 } // findOarsetById(int)
123
124 /**
125 * Finds the oarset that has the given name. Names
126 * are unique, so this "finder" returns at most one oarset.
127 */
128 public static OarsetView findOarsetByName( String name )
129 throws WebException {
130
131 Connection conn = null;
132 PreparedStatement stmt = null;
133 OarsetView retVal = null;
134 try {
135 conn = DBConfiguration.getConnection();
136 stmt = conn.prepareStatement(
137 Configuration.SQL_OARSET_03,
138 ResultSet.TYPE_FORWARD_ONLY,
139 ResultSet.CONCUR_READ_ONLY);
140 stmt.setString( 1, name );
141 retVal = loadOarset( stmt );
142 }
143 catch(SQLException x) {
144 String msg = "SQLException for name == '" + name + "': "
145 + x.getMessage();
146 theLog.fatal( msg, x );
147 throw new WebException( msg );
148 }
149 finally {
150 DBConfiguration.closeSQLStatement( stmt );
151 DBConfiguration.closeSQLConnection( conn );
152 }
153 conn = null;
154 stmt = null;
155
156 return retVal;
157 } // findOarsetByName(String)
158
159 /** OarsetSet instances are created by static "finder" methods */
160 private OarsetSet() {}
161
162 /**
163 * Returns the comparator associated with this sorted set, or
164 * <tt>null</tt> if it uses its elements' natural ordering.
165 *
166 * @return the comparator associated with this sorted set, or
167 * <tt>null</tt> if it uses its elements' natural ordering.
168 */
169 public Comparator comparator() {
170 return this.data.comparator();
171 }
172
173 /**
174 * Returns a view of the portion of this sorted set whose elements range
175 * from <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>, exclusive.
176 *
177 * @param fromElement low endpoint (inclusive) of the subSet.
178 * @param toElement high endpoint (exclusive) of the subSet.
179 * @return a view of the specified range within this sorted set.
180 *
181 * @throws ClassCastException if <tt>fromElement</tt> and
182 * <tt>toElement</tt> are not <tt>Oarset</tt> objects.
183 * @throws IllegalArgumentException if <tt>fromElement</tt> is greater than
184 * <tt>toElement</tt>; or if this set is itself a subSet, headSet,
185 * or tailSet, and <tt>fromElement</tt> or <tt>toElement</tt> are
186 * not within the specified range of the subSet, headSet, or
187 * tailSet.
188 * @throws NullPointerException if <tt>fromElement</tt> or
189 * <tt>toElement</tt> is <tt>null</tt>
190 */
191 public SortedSet subSet(Object fromElement, Object toElement) {
192 return this.data.subSet(fromElement,toElement);
193 }
194
195 /**
196 * Returns a view of the portion of this sorted set whose elements are
197 * strictly less than <tt>toElement</tt>.
198 *
199 * @param toElement high endpoint (exclusive) of the headSet.
200 * @return a view of the specified initial range of this sorted set.
201 * @throws ClassCastException if <tt>toElement</tt> is not compatible
202 * with this set's comparator (or, if the set has no comparator,
203 * if <tt>toElement</tt> does not implement <tt>Comparable</tt>).
204 * @throws NullPointerException if <tt>toElement</tt> is <tt>null</tt>
205 * @throws IllegalArgumentException if this set is itself a subSet,
206 * headSet, or tailSet, and <tt>toElement</tt> is not within the
207 * specified range of the subSet, headSet, or tailSet.
208 */
209 public SortedSet headSet(Object toElement) {
210 return this.data.headSet(toElement);
211 }
212
213 /**
214 * Returns a view of the portion of this sorted set whose elements are
215 * greater than or equal to <tt>fromElement</tt>.
216 *
217 * @param fromElement low endpoint (inclusive) of the tailSet.
218 * @return a view of the specified final range of this sorted set.
219 * @throws ClassCastException if <tt>fromElement</tt> is not compatible
220 * with this set's comparator (or, if the set has no comparator,
221 * if <tt>fromElement</tt> does not implement <tt>Comparable</tt>).
222 * @throws NullPointerException if <tt>fromElement</tt> is <tt>null</tt>
223 * @throws IllegalArgumentException if this set is itself a subSet,
224 * headSet, or tailSet, and <tt>fromElement</tt> is not within the
225 * specified range of the subSet, headSet, or tailSet.
226 */
227 public SortedSet tailSet(Object fromElement) {
228 return this.data.tailSet(fromElement);
229 }
230
231 /**
232 * Returns the first (lowest) element currently in this sorted set.
233 *
234 * @return the first (lowest) element currently in this sorted set.
235 * @throws NoSuchElementException sorted set is empty.
236 */
237 public Object first() {
238 return this.data.first();
239 }
240
241 /**
242 * Returns the last (highest) element currently in this sorted set.
243 *
244 * @return the last (highest) element currently in this sorted set.
245 * @throws NoSuchElementException sorted set is empty.
246 */
247 public Object last() {
248 return this.data.last();
249 }
250
251 /**
252 * Returns the number of elements in this set (its cardinality). If this
253 * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
254 * <tt>Integer.MAX_VALUE</tt>.
255 *
256 * @return the number of elements in this set (its cardinality).
257 */
258 public int size() {
259 return this.data.size();
260 }
261
262 /**
263 * Returns <tt>true</tt> if this set contains no elements.
264 *
265 * @return <tt>true</tt> if this set contains no elements.
266 */
267 public boolean isEmpty() {
268 return this.data.isEmpty();
269 }
270
271 /**
272 * Returns <tt>true</tt> if this set contains the specified element.
273 *
274 * @param o element whose presence in this set is to be tested.
275 * @return <tt>true</tt> if this set contains the specified element.
276 */
277 public boolean contains(Object o) {
278 /*
279 * formally, returns <tt>true</tt> if and only if this set contains an
280 * element <code>e</code> such that <code>(o==null ? e==null :
281 * o.equals(e))</code>.
282 */
283 return this.data.contains(o);
284 }
285
286 /**
287 * Returns an iterator over the (sorted) elements in this set.
288 *
289 * @return an iterator over the elements in this set.
290 */
291 public Iterator iterator() {
292 return this.data.iterator();
293 }
294
295 /**
296 * Returns an array containing all of the elements in this set.
297 *
298 * @return an array containing all of the elements in this set.
299 */
300 public Object[] toArray() {
301 return this.data.toArray();
302 }
303
304 /**
305 * Returns an array containing all of the elements in this set whose
306 * runtime type is that of the specified array.
307 *
308 * @param a the array into which the elements of this set are to
309 * be stored, if it is big enough; otherwise, a new array of the
310 * same runtime type is allocated for this purpose.
311 * @return an array containing the elements of this set.
312 * @throws ArrayStoreException the runtime type of a is not a supertype
313 * of the runtime type of Oarset.
314 */
315 public Object[] toArray(Object a[]) {
316 return this.data.toArray(a);
317 }
318
319 // Bulk Operations
320
321 /**
322 * Returns <tt>true</tt> if this set contains all of the elements of the
323 * specified collection.
324 *
325 * @param c collection to be checked for containment in this set.
326 * @return <tt>true</tt> if this set contains all of the elements of the
327 * specified collection.
328 */
329 public boolean containsAll(Collection c) {
330 return this.data.containsAll(c);
331 }
332
333 // Comparison and hashing
334
335 /**
336 * Compares the specified object with this set for equality.
337 *
338 * @param o Object to be compared for equality with this set.
339 * @return <tt>true</tt> if the specified Object is equal to this set.
340 */
341 public boolean equals(Object o) {
342 return this.data.equals(o);
343 }
344
345 /**
346 * Returns the hash code value for this set. The hash code of a set is
347 * defined to be the sum of the hash codes of the elements in the set.
348 *
349 * @return the hash code value for this set.
350 */
351 public int hashCode() {
352 return this.data.hashCode();
353 }
354
355 // Modification Operations are not supported
356
357 /**
358 * @throws UnsupportedOperationException since the <tt>add</tt> method is
359 * not supported by this set.
360 */
361 public boolean add(Object o) {
362 throw new UnsupportedOperationException( "not supported" );
363 }
364
365 /**
366 * @throws UnsupportedOperationException since the <tt>remove</tt> method is
367 * not supported by this set.
368 */
369 public boolean remove(Object o) {
370 throw new UnsupportedOperationException( "not supported" );
371 }
372
373 /**
374 * @throws UnsupportedOperationException since the <tt>addAll</tt> method is
375 * not supported by this set.
376 */
377 public boolean addAll(Collection c) {
378 throw new UnsupportedOperationException( "not supported" );
379 }
380
381 /**
382 * @throws UnsupportedOperationException since the <tt>retainAll</tt> method
383 * is not supported by this Collection.
384 */
385 public boolean retainAll(Collection c) {
386 throw new UnsupportedOperationException( "not supported" );
387 }
388
389 /**
390 * @throws UnsupportedOperationException since the <tt>removeAll</tt>
391 * method is not supported by this Collection.
392 */
393 public boolean removeAll(Collection c) {
394 throw new UnsupportedOperationException( "not supported" );
395 }
396
397 /**
398 * @throws UnsupportedOperationException since the <tt>clear</tt> method
399 * is not supported by this set.
400 */
401 public void clear() {
402 throw new UnsupportedOperationException( "not supported" );
403 }
404
405 // UTILITIES
406
407 /** Loads an in-memory object from a database using the specified SQL */
408 private static OarsetView loadOarset( PreparedStatement stmt )
409 throws SQLException, WebException {
410
411 // Initialize result set and return value to facilitate error recovery
412 ResultSet rs = null;
413 OarsetView retVal = null;
414
415 try {
416 rs = stmt.executeQuery();
417 if ( rs.next() ) {
418 retVal = mapRowToOarset(rs);
419 } // if
420 }
421 finally {
422 if (rs != null) {
423 try {
424 rs.close();
425 rs = null;
426 }
427 catch(Exception x) {
428 theLog.error(x.getMessage(),x);
429 }
430 }
431 } // finally
432
433 return retVal;
434 } // loadOarset(PreparedStatement)
435
436 /** Loads an in-memory set from a database using the specified SQL */
437 private static void loadOarsetSet( PreparedStatement stmt, SortedSet set )
438 throws SQLException, WebException {
439
440 // Initialize result set to facilitate error recovery
441 ResultSet rs = null;
442 int rowIdx = -1;
443
444 try {
445 rs = stmt.executeQuery();
446 while ( rs.next() ) {
447 ++rowIdx;
448 OarsetView oarset = mapRowToOarset(rs);
449 set.add( oarset );
450 } // while
451 }
452 finally {
453 if (rs != null) {
454 try {
455 rs.close();
456 rs = null;
457 }
458 catch(Exception x) {
459 theLog.error(x.getMessage(),x);
460 }
461 }
462 } // finally
463 } // loadOarsetSet(PreparedStatement,SortedSet)
464
465 /** Maps a row of SQL ResultSet to a OarsetView object */
466 private static OarsetView mapRowToOarset( ResultSet rs )
467 throws SQLException, WebException {
468
469 final int oarset_id = rs.getInt( "oarset_id" );
470 final String oarset_name = rs.getString( "oarset_name" );
471 final int oarset_size = rs.getInt( "oarset_size" );
472 final String oarset_type = rs.getString( "oarset_type" );
473
474 if ( theLog.isDebugEnabled() ) {
475 theLog.debug( oarset_id + ", " + oarset_name );
476 }
477
478 OarsetView retVal = null;
479 try {
480 retVal = new OarsetView( oarset_id, oarset_name, oarset_size, oarset_type );
481 }
482 catch( ValidationException x ) {
483 String msg = "Problem with data for oarset == '" + oarset_id + "', '"
484 + oarset_name + "': " + x.getMessage();
485 theLog.fatal( msg, x );
486 throw new WebException( msg );
487 }
488
489 return retVal;
490 } // mapRowToOarset(ResultSet)
491
492 } // OarsetSet
493
494 /*
495 * $Log: OarsetSet.java,v $
496 * Revision 1.4 2003/02/26 03:38:46 rphall
497 * Added copyright and GPL license
498 *
499 * Revision 1.3 2003/02/19 22:38:40 rphall
500 * Removed gratuitous use of CLRA acronym
501 *
502 * Revision 1.2 2002/02/18 18:06:44 rphall
503 * Ran dos2unix to remove ^M (carriage return) from end of lines
504 */
505