001: package org.apache.ojb.broker.accesslayer;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.lang.reflect.Constructor;
019: import java.sql.SQLException;
020: import java.util.Enumeration;
021: import java.util.NoSuchElementException;
022:
023: import org.apache.ojb.broker.Identity;
024: import org.apache.ojb.broker.PersistenceBroker;
025: import org.apache.ojb.broker.PersistenceBrokerException;
026: import org.apache.ojb.broker.PersistenceBrokerSQLException;
027: import org.apache.ojb.broker.metadata.ClassDescriptor;
028: import org.apache.ojb.broker.metadata.FieldDescriptor;
029: import org.apache.ojb.broker.query.Query;
030: import org.apache.ojb.broker.util.ConstructorHelper;
031: import org.apache.ojb.broker.util.logging.LoggerFactory;
032:
033: /**
034: * this class can be used to create enumerations of PrimaryKey objects.
035: * This is interesting for EJB finder methods
036: * in BMP entity beans which must return such enumerations.
037: * @author Thomas Mahler
038: * @version $Id: PkEnumeration.java,v 1.17.2.3 2005/12/21 22:22:59 tomdz Exp $
039: */
040: public class PkEnumeration implements Enumeration {
041: static final long serialVersionUID = -834955711995869884L;
042: protected boolean hasCalledCheck = false;
043: protected boolean hasNext = false;
044:
045: protected PersistenceBroker broker;
046:
047: /**
048: * The underlying jdbc resultset produced by select statement
049: */
050: protected ResultSetAndStatement resultSetAndStatment;
051:
052: /**
053: * descriptor for the class of which items are to be found
054: */
055: protected ClassDescriptor classDescriptor;
056:
057: /**
058: * the Constructor that is needed to build the PrimaryKey Objects
059: */
060: protected Constructor constructor;
061:
062: /**
063: * PkEnumeration constructor.
064: * @param query the SELECT statement gerating the underlying resultset
065: * @param cld classDescriptor of the target entity class (say Article)
066: * @param primaryKeyClass the entity classes PrimaryKey class (say ArticleKey).
067: * this key-class MUST have a constructor with one argument of type org.apache.ojb.broker.Identity !
068: */
069: public PkEnumeration(Query query, ClassDescriptor cld,
070: Class primaryKeyClass, PersistenceBroker broker) {
071: this .resultSetAndStatment = broker.serviceJdbcAccess()
072: .executeQuery(query, cld);
073: this .classDescriptor = cld;
074: this .broker = broker;
075: // get a contructor object that can be used to build instances of class primaryKeyClass
076: try {
077: Class[] argArray = { Identity.class };
078: this .constructor = primaryKeyClass.getConstructor(argArray);
079: } catch (NoSuchMethodException e) {
080: LoggerFactory
081: .getDefaultLogger()
082: .error(
083: primaryKeyClass.getName()
084: + " must implement a Constructor with one argument of type org.apache.ojb.broker.Identity");
085: throw new PersistenceBrokerException(e);
086: } catch (SecurityException e) {
087: LoggerFactory.getDefaultLogger().error(e);
088: throw new PersistenceBrokerException(e);
089: }
090: }
091:
092: /**
093: * returns an Identity object representing the current resultset row
094: */
095: private Identity getIdentityFromResultSet() {
096:
097: try {
098: // 1. get an empty instance of the target class
099: Constructor con = classDescriptor
100: .getZeroArgumentConstructor();
101: Object obj = ConstructorHelper.instantiate(con);
102:
103: // 2. fill only primary key values from Resultset
104: Object colValue;
105: FieldDescriptor fld;
106: FieldDescriptor[] pkfields = classDescriptor.getPkFields();
107: for (int i = 0; i < pkfields.length; i++) {
108: fld = pkfields[i];
109: colValue = fld.getJdbcType().getObjectFromColumn(
110: resultSetAndStatment.m_rs, fld.getColumnName());
111: fld.getPersistentField().set(obj, colValue);
112: }
113: // 3. return the representing identity object
114: return broker.serviceIdentity().buildIdentity(
115: classDescriptor, obj);
116: } catch (SQLException e) {
117: throw new PersistenceBrokerSQLException(
118: "Error reading object from column", e);
119: } catch (Exception e) {
120: throw new PersistenceBrokerException(
121: "Error reading Identity from result set", e);
122: }
123: }
124:
125: /**
126: * Tests if this enumeration contains more elements.
127: * @return <code>true</code> if and only if this enumeration object
128: * contains at least one more element to provide;
129: * <code>false</code> otherwise.
130: */
131: public boolean hasMoreElements() {
132: try {
133: if (!hasCalledCheck) {
134: hasCalledCheck = true;
135: hasNext = resultSetAndStatment.m_rs.next();
136: }
137: } catch (SQLException e) {
138: LoggerFactory.getDefaultLogger().error(e);
139: //releaseDbResources();
140: hasNext = false;
141: } finally {
142: if (!hasNext) {
143: releaseDbResources();
144: }
145: }
146: return hasNext;
147: }
148:
149: private void releaseDbResources() {
150: resultSetAndStatment.close();
151: resultSetAndStatment = null;
152: }
153:
154: /**
155: * Returns the next element of this enumeration if this enumeration
156: * object has at least one more element to provide.
157: * @return the next element of this enumeration.
158: * @exception NoSuchElementException if no more elements exist.
159: */
160: public Object nextElement() {
161: try {
162: if (!hasCalledCheck) {
163: hasMoreElements();
164: }
165: hasCalledCheck = false;
166: if (hasNext) {
167: Identity oid = getIdentityFromResultSet();
168: Identity[] args = { oid };
169: return this .constructor.newInstance(args);
170: } else
171: throw new NoSuchElementException();
172: } catch (Exception ex) {
173: LoggerFactory.getDefaultLogger().error(ex);
174: throw new NoSuchElementException();
175: }
176: }
177:
178: /**
179: * protection just in case someone leaks.
180: */
181: protected void finalize() {
182: if (resultSetAndStatment != null) {
183: LoggerFactory
184: .getDefaultLogger()
185: .error(
186: "["
187: + PkEnumeration.class.getName()
188: + "] Found unclosed resources while finalize");
189: releaseDbResources();
190: }
191: }
192: }
|