001: package org.apache.ojb.broker.util.sequence;
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.sql.ResultSet;
019: import java.sql.Statement;
020: import java.sql.PreparedStatement;
021:
022: import org.apache.commons.lang.SystemUtils;
023: import org.apache.ojb.broker.PersistenceBroker;
024: import org.apache.ojb.broker.accesslayer.StatementManagerIF;
025: import org.apache.ojb.broker.metadata.ClassDescriptor;
026: import org.apache.ojb.broker.metadata.FieldDescriptor;
027: import org.apache.ojb.broker.query.Query;
028: import org.apache.ojb.broker.util.logging.Logger;
029: import org.apache.ojb.broker.util.logging.LoggerFactory;
030:
031: /**
032: * This SequenceManager implementation uses database
033: * sequence key generation (e.g supported by
034: * Oracle, SAP DB, PostgreSQL, ...).
035: * This class is responsible for creating new unique ID's.
036: * <br/>
037: * It is possible to define a <code>sequence-name</code>
038: * field-descriptor attribute in the repository file. If
039: * such an attribute was not found, the implementation build
040: * an extent aware sequence name by its own.
041: * <br/>
042: * Keep in mind when define a sequence name, that you are responsible
043: * to be aware of extents, that is: if you ask for an uid for an
044: * interface with several
045: * implementor classes, or a baseclass with several subclasses the returned
046: * uid have to be unique accross all tables representing objects of the
047: * extent in question. Thus you have to use the same <code>sequence-name</code>
048: * for all extents.
049: *
050: * <p>
051: * Implementation configuration properties:
052: * </p>
053: *
054: * <table cellspacing="2" cellpadding="2" border="3" frame="box">
055: * <tr>
056: * <td><strong>Property Key</strong></td>
057: * <td><strong>Property Values</strong></td>
058: * </tr>
059: * <tr>
060: * <td>autoNaming</td>
061: * <td>
062: * Default was 'true'. If set 'true' OJB try to build a
063: * sequence name automatic if none found in field-descriptor
064: * and set this generated name as <code>sequence-name</code>
065: * in field-descriptor.
066: * <br/>
067: * If set 'false' OJB throws an exception
068: * if none sequence name was found in field-descriptor, ditto
069: * OJB does NOT try to create a database sequence entry when
070: * for given sequence name no database sequence could be found.
071: * </td>
072: * </tr>
073: * </table>
074: *
075: *
076: * <br/>
077: * <p>
078: * <b>Limitations:</b>
079: * <ul>
080: * <li>none</li>
081: * </ul>
082: * </p>
083: * <br/>
084: * <br/>
085: *
086: * @author Edson Carlos Ericksson Richter
087: * @author Rajeev Kaul
088: * @author Thomas Mahler
089: * @author Armin Waibel
090: * @version $Id: SequenceManagerNextValImpl.java,v 1.17.2.4 2005/12/21 22:28:41 tomdz Exp $
091: */
092: public class SequenceManagerNextValImpl extends AbstractSequenceManager {
093: private Logger log = LoggerFactory
094: .getLogger(SequenceManagerNextValImpl.class);
095:
096: /**
097: *
098: */
099: public SequenceManagerNextValImpl(PersistenceBroker broker) {
100: super (broker);
101: }
102:
103: /**
104: * returns a unique int value for class clazz and field fieldName.
105: * the returned number is unique accross all tables in the extent of clazz.
106: */
107: protected int getUniqueId(FieldDescriptor field)
108: throws SequenceManagerException {
109: return (int) getUniqueLong(field);
110: }
111:
112: /**
113: * returns a unique long value for class clazz and field fieldName.
114: * the returned number is unique accross all tables in the extent of clazz.
115: */
116: protected long getUniqueLong(FieldDescriptor field)
117: throws SequenceManagerException {
118: long result;
119: // lookup sequence name
120: String sequenceName = calculateSequenceName(field);
121: try {
122: result = buildNextSequence(field.getClassDescriptor(),
123: sequenceName);
124: } catch (Throwable e) {
125: // maybe the sequence was not created
126: try {
127: log.info("Create DB sequence key '" + sequenceName
128: + "'");
129: createSequence(field.getClassDescriptor(), sequenceName);
130: } catch (Exception e1) {
131: throw new SequenceManagerException(
132: SystemUtils.LINE_SEPARATOR
133: + "Could not grab next id, failed with "
134: + SystemUtils.LINE_SEPARATOR
135: + e.getMessage()
136: + SystemUtils.LINE_SEPARATOR
137: + "Creation of new sequence failed with "
138: + SystemUtils.LINE_SEPARATOR
139: + e1.getMessage()
140: + SystemUtils.LINE_SEPARATOR, e1);
141: }
142: try {
143: result = buildNextSequence(field.getClassDescriptor(),
144: sequenceName);
145: } catch (Throwable e1) {
146: throw new SequenceManagerException(
147: "Could not grab next id, sequence seems to exist",
148: e);
149: }
150: }
151: return result;
152: }
153:
154: protected long buildNextSequence(ClassDescriptor cld,
155: String sequenceName) throws Exception {
156: ResultSet rs = null;
157: PreparedStatement stmt = null;
158: long result = -1;
159: StatementManagerIF stmtMan = getBrokerForClass()
160: .serviceStatementManager();
161: try {
162: stmt = stmtMan.getPreparedStatement(cld, getPlatform()
163: .nextSequenceQuery(sequenceName),
164: Query.NOT_SCROLLABLE, 1, false);
165: rs = stmt.executeQuery();
166: rs.next();
167: result = rs.getLong(1);
168: } finally {
169: stmtMan.closeResources(stmt, rs);
170: }
171: return result;
172: }
173:
174: protected void createSequence(ClassDescriptor cld,
175: String sequenceName) throws Exception {
176: Statement stmt = null;
177: StatementManagerIF stmtMan = getBrokerForClass()
178: .serviceStatementManager();
179: // arminw: never try to remove existing sequences, because this may lead in unexpected behaviour
180: // if the reason for the create call isn't a missing sequence (e.g. network problems)
181: // try
182: // {
183: // stmt = stmtMan.getGenericStatement(cld, Query.NOT_SCROLLABLE);
184: // stmt.execute(getPlatform().dropSequenceQuery(sequenceName));
185: // }
186: // catch (Exception ignore)
187: // {
188: // // ignore it
189: // }
190: // finally
191: // {
192: // try
193: // {
194: // stmtMan.closeResources(stmt, null);
195: // }
196: // catch (Exception ignore)
197: // {
198: // // ignore it
199: // }
200: // }
201:
202: try {
203: stmt = stmtMan.getGenericStatement(cld,
204: Query.NOT_SCROLLABLE);
205: stmt.execute(getPlatform().createSequenceQuery(
206: sequenceName, getConfigurationProperties()));
207: } finally {
208: try {
209: stmtMan.closeResources(stmt, null);
210: } catch (Exception e) {
211: e.printStackTrace();
212: }
213: }
214: }
215: }
|