KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > bsf > listOfValues > LovBean


1 /**
2  * Copyright (c) 2002 Bright Side Factory. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * 3. The end-user documentation included with the redistribution,
17  * if any, must include the following acknowledgment:
18  * "This product includes software developed by the
19  * Bright Side Factory (http://www.bs-factory.org/)."
20  * Alternately, this acknowledgment may appear in the software itself,
21  * if and wherever such third-party acknowledgments normally appear.
22  *
23  * 4. The names "Bright Side", "BS Factory" and "Bright Side Factory" must
24  * not be used to endorse or promote products derived from this
25  * software without prior written permission. For written
26  * permission, please contact info@bs-factory.org.
27  *
28  * 5. Products derived from this software may not be called "Bright Side",
29  * nor may "Bright Side" appear in their name, without prior written
30  * permission of the Apache Software Foundation.
31  *
32  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
33  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
36  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
39  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
41  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
42  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  * ====================================================================
45  *
46  * This software consists of voluntary contributions made by many
47  * individuals on behalf of the Bright Side Factory. For more
48  * information on the Bright Side Factory, please see
49  * <http://www.bs-factory.org/>.
50  */

51
52 package org.bsf.listOfValues;
53
54 import org.bsf.commons.ejb.EntityAdapterBean;
55 import org.bsf.listOfValues.exceptions.NoSuchLovValueException;
56 import org.bsf.listOfValues.lovValue.DefaultLovValue;
57 import org.bsf.listOfValues.lovValue.LovValue;
58 import org.bsf.listOfValues.util.LovDefinitionCache;
59 import org.bsf.listOfValues.util.LovTypeManager;
60
61 import javax.ejb.EJBException JavaDoc;
62 import javax.ejb.FinderException JavaDoc;
63 import javax.ejb.ObjectNotFoundException JavaDoc;
64 import java.sql.Connection JavaDoc;
65 import java.sql.PreparedStatement JavaDoc;
66 import java.sql.ResultSet JavaDoc;
67 import java.sql.SQLException JavaDoc;
68 import java.sql.Statement JavaDoc;
69 import java.util.Collection JavaDoc;
70 import java.util.HashMap JavaDoc;
71 import java.util.List JavaDoc;
72 import java.util.Vector JavaDoc;
73
74 /**
75  * The LovBean is a BMP EJB that enables the retrieval of a List of Values (LOV).
76  * It uses two tables to retrieve the informations needed to build the LOV.<p>
77  *
78  * Description of the two tables used by this BMP:
79  *
80  * 1) BSF_LOV : The definition of the LOV itself (what to retrieve)
81  *
82  * => OID : The oid of the LOV (ex: 1)
83  * => LOV_NAME : The name of the LOV, only for information (ex: LOV_COUNTRIES)
84  * => LOV_REQUEST : The request to execute to retrieve the list of values.
85  * : The first returned column will define the PK of the
86  * : LovValue(cf. S_LOV_DEFINITON below).
87  * : (ex: select oid, short_name, long_name from countries)
88  * => TABLE_NAME : The name of the Table used in this LOV (could be usefull
89  * : when we need to notify that the LOV has to be retrieved
90  * : again since the underlying table has changed). If a LOV
91  * : is based on more than one table set the "most important"
92  * : one (or the one that changes the most... it is up to you).
93  *
94  * 2) BSF_LOV_DEFINITION : The definition of the fields contained in the LovValues
95  * : returned from the execution of the SQL statement cor-
96  * : responding to the selected LOV (cf. BSF_LOV).
97  * : Enables to use the expected data type and to label the
98  * : fields.
99  *
100  * => LOV_OID : The OID of the LOV (cf. BSF_LOV) for which we define
101  * : a field.
102  * => FIELD_NAME : The String used to place and access the column matching
103  * : the given field_position of the the LOV_REQUEST in the
104  * : returned LovValue. Keep the name simple...
105  * => FIELD_TYPE : The type of the field (ie. java.lang.Long, java.lang.String,
106  * : java.lang.Double, ...).
107  * => FIELD_POSITION : The position of this field in the SQL statement defined
108  * : in the LOV_REQUEST column of the BSF_LOV table. The first
109  * : column defined will be used as the PK for the LovValues.
110  *
111  * @see LovServiceBean
112  * @see LovBusinessInterface
113  * @see org.bsf.listOfValues.lovValue.LovValue
114  *
115  * @ejb.bean type="BMP"
116  * name="LOV"
117  * local-jndi-name="ejb/LOVLocal"
118  * view-type="local"
119  *
120  * @ejb.home local-extends="javax.ejb.EJBLocalHome"
121  *
122  * @ejb.interface local-extends="javax.ejb.EJBLocalObject, org.bsf.listOfValues.LovBusinessInterface"
123  *
124  * @ejb.pk class="java.lang.Long"
125  * generate="false"
126  *
127  * @ejb.transaction type="Supports"
128  *
129  * @ejb.resource-ref res-name="jdbc/DBPool"
130  * res-type="javax.sql.DataSource"
131  * res-auth="Container"
132  *
133  * @jboss.read-only read-only="true"
134  *
135  * @jboss.resource-ref res-ref-name="jdbc/DBPool"
136  * resource-name="FwkDataSourceManager"
137  *
138  * @jonas.bean ejb-name="LOV"
139  *
140  * @jonas.resource res-ref-name="jdbc/DBPool"
141  * jndi-name="jdbc_1"
142  */

143 public class LovBean extends EntityAdapterBean implements LovBusinessInterface {
144     // SQL Statements used in this BMP
145
private static final String JavaDoc NAME_AND_REQUEST_FOR_OID_STATEMENT
146             = "SELECT LOV_NAME, LOV_REQUEST FROM BSF_LOV WHERE OID = ?";
147
148     private static final String JavaDoc METADATA_FOR_OID_STATEMENT
149             = "SELECT FIELD_NAME, FIELD_TYPE FROM BSF_LOV_DEFINITION " +
150               "WHERE LOV_OID = ? ORDER BY FIELD_POSITION";
151
152     public static final String JavaDoc LOV_OID_FOR_TABLE_NAME_STATEMENT
153             = "SELECT OID FROM BSF_LOV WHERE TABLE_NAME = ?";
154
155     /**
156      * The JNDI name used to retrieve a connection to the database.
157      */

158     private final String JavaDoc JNDI_DATABASE_NAME = "DBPool";
159
160     /**
161      * Used as a cache to store the results of the executed SQL to prevent the
162      * reexecution of the SQL statement each time the same LOV is requested).
163      */

164     private Vector JavaDoc _sortedLov;
165
166     /**
167      * Stores the lovValues in their "mapped" (OID, LovValue) form (a HashMap)
168      * to prevent remapping each time the map is requested.
169      */

170     private HashMap JavaDoc _lov;
171
172     /**
173      * Stores the metadata (field name, position...) for this list of values.
174      */

175     private List JavaDoc _metaData;
176
177     /**
178      * Loads all the values from the DB using the request defined in the
179      * LOV_REQUESTS table. For each row of the resultSet uses the
180      * LOV_DEFINITION_NAME and LOV_DEFINITION_TYPE from table LOV_DEFINITION
181      * to create the lovValue. This method should be called once per LOV
182      */

183     public void ejbLoad() {
184         String JavaDoc lovRequest = null;
185         String JavaDoc lovTableName = null;
186         ResultSet JavaDoc resultSet = null;
187         Statement JavaDoc statement = null;
188         Connection JavaDoc connection = null;
189         ResultSet JavaDoc resultSetCache = null;
190         ResultSet JavaDoc resultSetMetaData = null;
191         PreparedStatement JavaDoc preparedStatement = null;
192
193         // We retrieve the OID of the list of values that we want to retrieve
194
Long JavaDoc lovRequestID = (Long JavaDoc) ejbContext.getPrimaryKey();
195
196         logGraphBegin( "ejbLoad() with OID " + lovRequestID.toString() );
197
198         try {
199             // We retrieve the connextion to the database pool
200
connection = getConnection( JNDI_DATABASE_NAME );
201
202             // We don't want to get the SQL Statement from the DB if we have
203
// already retrieved it (cf. LovDefinitionCache)... First things first, we
204
// check in the LovDefinitionCache (result will be null if no match is found)
205
lovRequest = LovDefinitionCache.getInstance().getRequestForLovOID( lovRequestID );
206
207             // Do we need to retrieve the SQL preparedStatement from the DB ?
208
// (ie. not in cache, see above)
209
if ( lovRequest == null ) {
210                 // We create a sql preparedStatement using the selected connection
211
preparedStatement = connection.prepareStatement( NAME_AND_REQUEST_FOR_OID_STATEMENT );
212                 preparedStatement.setString( 1, lovRequestID.toString() );
213                 resultSetCache = preparedStatement.executeQuery();
214
215                 if ( resultSetCache.next() == false ) {
216                     String JavaDoc msg = "No existing LOV for OID " + lovRequestID;
217
218                     // We log the error (should not happen but in dev or mishandling of the DB...)
219
logError( msg );
220
221                     throw new EJBException JavaDoc( msg );
222                 }
223
224                 // cf. the NAME_AND_REQUEST_FOR_OID_STATEMENT for the parameters order
225
lovTableName = resultSetCache.getString( 1 );
226                 lovRequest = resultSetCache.getString( 2 );
227
228                 preparedStatement.close();
229             }
230
231             _metaData = LovDefinitionCache.getInstance().getTypesForLovOID( lovRequestID );
232
233             // Next we check for the meta data
234
if ( _metaData == null ) {
235                 preparedStatement = connection.prepareStatement( METADATA_FOR_OID_STATEMENT );
236                 preparedStatement.setString( 1, lovRequestID.toString() );
237                 resultSetMetaData = preparedStatement.executeQuery();
238
239                 _metaData = new Vector JavaDoc();
240
241                 // For each field we retrieve the name and the type
242
while ( resultSetMetaData.next() ) {
243                     String JavaDoc fieldName = resultSetMetaData.getString( 1 );
244                     String JavaDoc fieldType = resultSetMetaData.getString( 2 );
245                     LovMetaDataItem metaDataItem = new LovMetaDataItem( fieldName, fieldType );
246
247                     // The infos are ordered by the ORDER BY of the SQL preparedStatement
248
_metaData.add( metaDataItem );
249                 }
250             }
251
252             if ( !LovDefinitionCache.getInstance().isOIDInCache( lovRequestID ) ) {
253                 // We place the newly acquired informations in the LovDefinitionCache
254
LovDefinitionCache.getInstance().addToCache( lovRequestID, lovTableName, lovRequest, _metaData );
255             }
256
257             // Then we retrieve the values for the list of values
258
logDebug( "Executing : " + lovRequest );
259
260             // We execute the query
261
statement = connection.createStatement();
262             resultSet = statement.executeQuery( lovRequest );
263
264             // We ensure that the number of columns in the resultset equals the number
265
// of fields defined in the metadata (cf. above)
266
int numberOfColumns = resultSet.getMetaData().getColumnCount();
267
268             if ( numberOfColumns != _metaData.size() ) {
269                 // We should have this equallity since the OID field is present
270
// even though it is not defined in the S_LOV_DEFINITION table
271
String JavaDoc msg = "The lov " + lovRequestID + " is badly parametered (check fields definition... PK must be defined in first position...)";
272
273                 logFatal( msg );
274
275                 throw new EJBException JavaDoc( msg );
276             }
277
278             _lov = new HashMap JavaDoc();
279             _sortedLov = new Vector JavaDoc();
280
281             while ( resultSet.next() ) {
282                 // Remember that the PK of the LovValue MUST be in the first column
283
DefaultLovValue lovValue = null;
284
285                 // Now we get each field of the lovValue
286
for ( int index = 0; index < _metaData.size(); index++ ) {
287                     LovMetaDataItem metaDataItem = (LovMetaDataItem) _metaData.get( index );
288                     String JavaDoc lovValueFieldType = metaDataItem.getFieldType();
289                     String JavaDoc lovValueFieldName = metaDataItem.getFieldName();
290
291                     Object JavaDoc lovValueFieldObject = null;
292
293                     try {
294                         // We retrieve the value from the resultset with the corret type
295
lovValueFieldObject = LovTypeManager.getObjectOfType( lovValueFieldType, resultSet, (int) index + 1 );
296
297                         if ( index == 0 ) {
298                             // Different handling the PK... We create the LovValue with it
299
lovValue = new DefaultLovValue( lovValueFieldObject );
300                         } else {
301                             // We add the value to the LovValue
302
lovValue.addField( lovValueFieldName, lovValueFieldObject );
303                         }
304                     } catch ( IllegalArgumentException JavaDoc e ) {
305                         String JavaDoc msg = "Unknown type " + lovValueFieldType + " for Lov " + lovRequestID;
306
307                         logFatal( msg );
308
309                         throw new EJBException JavaDoc( msg );
310                     }
311                 }
312
313                 _lov.put( lovValue.getPK(), lovValue );
314                 _sortedLov.add( lovValue );
315             }
316         } catch ( SQLException JavaDoc Se ) {
317             logError( "SQL Exception... ", Se );
318
319             handleSQLException( Se );
320         } catch ( NullPointerException JavaDoc NPe ) {
321             String JavaDoc msg = "The first LOV_DEFINITION_ORDER in table LOV_DEFINITION must be 2... Check lov "
322                          + lovRequestID;
323
324             logFatal( msg );
325
326             throw new EJBException JavaDoc( msg, NPe );
327         } finally {
328             // We close the various opened connections
329
try {
330                 if ( resultSetCache != null ) {
331                     resultSetCache.close();
332                 }
333
334                 if ( resultSetMetaData != null ) {
335                     resultSetMetaData.close();
336                 }
337
338                 if ( resultSet != null ) {
339                     resultSet.close();
340                 }
341             } catch ( Exception JavaDoc Se ) {
342                 // Nothing else to do....
343
}
344
345             try {
346                 if ( preparedStatement != null ) {
347                     preparedStatement.close();
348                 }
349             } catch ( Exception JavaDoc Se ) {
350                 // Nothing else to do....
351
}
352
353             try {
354                 if ( statement != null ) {
355                     statement.close();
356                 }
357             } catch ( Exception JavaDoc Se ) {
358                 // Nothing else to do....
359
}
360
361             try {
362                 if ( connection != null ) {
363                     connection.close();
364                 }
365             } catch ( Exception JavaDoc Se ) {
366                 // Nothing else to do....
367
}
368         }
369
370         logGraphEnd( "ejbLoad " + lovRequestID.toString() );
371     }
372
373     /**
374      * Checks if the the Lov exist in the S_LOV_REQUESTS table. Used to
375      * test for the LOV existence.
376      *
377      * @return The list of values having the given OID.
378      *
379      * @throws ObjectNotFoundException if the corresponding LOV doesn't exist.
380      * @throws IllegalArgumentException if the given OID is null.
381      */

382     public Long JavaDoc ejbFindByPrimaryKey( Long JavaDoc p_OID ) throws ObjectNotFoundException JavaDoc {
383         if ( p_OID == null ) {
384             throw new IllegalArgumentException JavaDoc();
385         }
386
387         PreparedStatement JavaDoc preparedStatement = null;
388         ResultSet JavaDoc resultSet = null;
389         Connection JavaDoc connection = null;
390
391         logGraphBegin( "ejbFindByPrimaryKey " + p_OID );
392
393         // We only have to do something if the LOV isn't already in cache
394
if ( !LovDefinitionCache.getInstance().isOIDInCache( p_OID ) ) {
395             try {
396                 connection = getConnection( JNDI_DATABASE_NAME );
397                 preparedStatement = connection.prepareStatement( NAME_AND_REQUEST_FOR_OID_STATEMENT );
398                 preparedStatement.setString( 1, p_OID.toString() );
399                 resultSet = preparedStatement.executeQuery();
400
401                 // We should have somethig otherwise the LOV doesn't exist...
402
if ( resultSet.next() == false ) {
403                     String JavaDoc msg = "The LOV " + p_OID + " does not exist...";
404
405                     logError( msg );
406
407                     throw new ObjectNotFoundException JavaDoc( msg );
408                 }
409             } catch ( SQLException JavaDoc Se ) {
410                 handleSQLException( Se );
411             } finally {
412                 try {
413                     // We close the various connection, resultset...
414
if ( resultSet != null ) {
415                         resultSet.close();
416                     }
417
418                     if ( preparedStatement != null ) {
419                         preparedStatement.close();
420                     }
421
422                     if ( connection != null ) {
423                         connection.close();
424                     }
425                 } catch ( SQLException JavaDoc Se ) {
426                     handleSQLException( Se );
427                 }
428             }
429         }
430
431         logGraphEnd( "ejbFindByPrimaryKey " + p_OID.toString() );
432
433         // If we reach this place that means we found the expected LOV, returning its OID
434
return p_OID;
435     }
436
437     /**
438      * Finds the LOVs that are working on a given physical table. In other words
439      * it enables us to get a Collection of LOVs that are related to a given DB
440      * Table.<p>
441      *
442      * Is useful, for example, if the data in the DB are modified (a country is
443      * added or removed) and we want to update the LOVs working on those data
444      * (on the COUNTRIES table) for them to reflect the changes. First we need
445      * to know what LOVs are working on those data and that's what this finder
446      * retrieve for us.<p>
447      *
448      * You can check the Class description to have more informations about the
449      * DB structure.
450      *
451      * @param p_tableName The name of the DB table that we want to match.
452      *
453      * @return The OIDs of the LOVs that refer to the given table name in their
454      * TABLE_NAME field (cf. TABLE description).
455      *
456      * @throws IllegalArgumentException if the given table name is null.
457      * @throws ObjectNotFoundException if none is found matching the given
458      * table name.
459      */

460     public Collection JavaDoc ejbFindByPhysicalTable( String JavaDoc p_tableName ) throws FinderException JavaDoc {
461         if ( p_tableName == null ) {
462             throw new IllegalArgumentException JavaDoc();
463         }
464
465         Vector JavaDoc lovs = new Vector JavaDoc();
466         PreparedStatement JavaDoc preparedStatement = null;
467         ResultSet JavaDoc resultSet = null;
468         Connection JavaDoc connection = null;
469
470         logGraphBegin( "ejbFindByPhysicalTable " + p_tableName );
471
472         try {
473             connection = getConnection( JNDI_DATABASE_NAME );
474
475             preparedStatement = connection.prepareStatement( LOV_OID_FOR_TABLE_NAME_STATEMENT );
476             preparedStatement.setString( 1, p_tableName );
477             resultSet = preparedStatement.executeQuery();
478
479             while ( resultSet.next() ) {
480                 // We add each found OID to the collection to be returned
481
Long JavaDoc lovOID = new Long JavaDoc( resultSet.getLong( 1 ) );
482                 lovs.add( lovOID );
483             }
484
485             if ( lovs.size() == 0 ) {
486                 String JavaDoc message = "No LOVs refering to the table name " + p_tableName;
487
488                 throw new ObjectNotFoundException JavaDoc( message );
489             }
490         } catch ( SQLException JavaDoc Se ) {
491             handleSQLException( Se );
492         } finally {
493             try {
494                 // We close the various connection, resultset...
495
if ( resultSet != null ) {
496                     resultSet.close();
497                 }
498
499                 if ( preparedStatement != null ) {
500                     preparedStatement.close();
501                 }
502
503                 if ( connection != null ) {
504                     connection.close();
505                 }
506             } catch ( SQLException JavaDoc Se ) {
507                 handleSQLException( Se );
508             }
509         }
510
511         return lovs;
512     }
513
514     // *************************************************************************
515
// ******************** LovBusinessInterface methods ***********************
516
// *************************************************************************
517

518     /**
519      * Returns the LovValue corresponding to the given OID in the List Of Values
520      * held in the implementing Object.
521      *
522      * @param p_lovValueOID The OID, in the List Of Values held in the implementing
523      * Object, of the LovValue desired.
524      *
525      * @return the LovValue corresponding to the given oid or null if the
526      * LovValue isn't present.
527      *
528      * @throws NoSuchLovValueException if the requested LovValue isn't found in
529      * the LOV.
530      *
531      * @ejb.interface-method
532      */

533     public LovValue getLovValue( Long JavaDoc p_lovValueOID ) throws NoSuchLovValueException {
534         Long JavaDoc lovOID = (Long JavaDoc) ejbContext.getPrimaryKey();
535
536         logDebug( "getLovValue " + p_lovValueOID.toString() + " in LOV " + lovOID );
537
538         if ( !_lov.containsKey( p_lovValueOID ) ) {
539             throw new NoSuchLovValueException( lovOID, p_lovValueOID );
540         }
541
542         return (LovValue) _lov.get( p_lovValueOID );
543     }
544
545     /**
546      * Gets the LOV mapped by OID.
547      *
548      * @return a HashMap of (key=OID, object=LovValue).
549      *
550      * @ejb.interface-method
551      */

552     public HashMap JavaDoc getLovValuesPerOID() {
553         logDebug( "getLovValues " + ejbContext.getPrimaryKey().toString() );
554
555         return _lov;
556     }
557
558     /**
559      * Gets the LovValues in the order of their retrieval (for example if we
560      * retrieve them by using a EJB BMP and the LOV_REQUESTS table we will get
561      * them in the order of the result of the executed SQL).
562      *
563      * @return A list containing the LovValues.
564      *
565      * @ejb.interface-method
566      */

567     public List JavaDoc getListOfValues() {
568         logDebug( "getSortedLovValues for the LOV " + ejbContext.getPrimaryKey().toString() );
569
570         return _sortedLov;
571     }
572
573     // *************************************************************************
574
// ***************************** Accessors *********************************
575
// *************************************************************************
576

577     /**
578      * @return The LovMetaDataItems in a List.
579      *
580      * @ejb.interface-method
581      */

582     public List JavaDoc getMetaData() {
583         logDebug( "getMetaData for the LOV " + ejbContext.getPrimaryKey().toString() );
584
585         return _metaData;
586     }
587 }
588
Popular Tags