KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > dba > oracle > OraclePkGenerator


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

56
57 package org.objectstyle.cayenne.dba.oracle;
58
59 import java.sql.Connection JavaDoc;
60 import java.sql.ResultSet JavaDoc;
61 import java.sql.SQLException JavaDoc;
62 import java.sql.Statement JavaDoc;
63 import java.util.ArrayList JavaDoc;
64 import java.util.Collections JavaDoc;
65 import java.util.Iterator JavaDoc;
66 import java.util.List JavaDoc;
67
68 import org.objectstyle.cayenne.CayenneRuntimeException;
69 import org.objectstyle.cayenne.access.DataNode;
70 import org.objectstyle.cayenne.access.QueryLogger;
71 import org.objectstyle.cayenne.dba.JdbcPkGenerator;
72 import org.objectstyle.cayenne.map.DbEntity;
73 import org.objectstyle.cayenne.map.DbKeyGenerator;
74
75 /**
76  * Sequence-based primary key generator implementation for Oracle.
77  * Uses Oracle sequences to generate primary key values. This approach is
78  * at least 50% faster when tested with Oracle compared to the lookup table
79  * approach.
80  *
81  * <p>When using Cayenne key caching mechanism, make sure that sequences in
82  * the database have "INCREMENT BY" greater or equal to OraclePkGenerator
83  * "pkCacheSize" property value. If this is not the case, you will need to
84  * adjust PkGenerator value accordingly. For example when sequence is
85  * incremented by 1 each time, use the following code:</p>
86  *
87  * <pre>
88  * dataNode.getAdapter().getPkGenerator().setPkCacheSize(1);
89  * </pre>
90  *
91  * @author Andrei Adamchik
92  */

93 public class OraclePkGenerator extends JdbcPkGenerator {
94     private static final String JavaDoc _SEQUENCE_PREFIX = "pk_";
95
96     public void createAutoPk(DataNode node, List JavaDoc dbEntities) throws Exception JavaDoc {
97         List JavaDoc sequences = getExistingSequences(node);
98
99         // create needed sequences
100
Iterator JavaDoc it = dbEntities.iterator();
101         while (it.hasNext()) {
102             DbEntity ent = (DbEntity) it.next();
103             if (!sequences.contains(sequenceName(ent))) {
104                 runUpdate(node, createSequenceString(ent));
105             }
106         }
107     }
108
109     public List JavaDoc createAutoPkStatements(List JavaDoc dbEntities) {
110         List JavaDoc list = new ArrayList JavaDoc();
111         Iterator JavaDoc it = dbEntities.iterator();
112         while (it.hasNext()) {
113             DbEntity ent = (DbEntity) it.next();
114             list.add(createSequenceString(ent));
115         }
116
117         return list;
118     }
119
120     public void dropAutoPk(DataNode node, List JavaDoc dbEntities) throws Exception JavaDoc {
121         List JavaDoc sequences = getExistingSequences(node);
122
123         // drop obsolete sequences
124
Iterator JavaDoc it = dbEntities.iterator();
125         while (it.hasNext()) {
126             DbEntity ent = (DbEntity) it.next();
127             if (sequences.contains(stripSchemaName(sequenceName(ent)))) {
128                 runUpdate(node, dropSequenceString(ent));
129             }
130         }
131     }
132
133     public List JavaDoc dropAutoPkStatements(List JavaDoc dbEntities) {
134         List JavaDoc list = new ArrayList JavaDoc();
135         Iterator JavaDoc it = dbEntities.iterator();
136         while (it.hasNext()) {
137             DbEntity ent = (DbEntity) it.next();
138             list.add(dropSequenceString(ent));
139         }
140
141         return list;
142     }
143
144     protected String JavaDoc createSequenceString(DbEntity ent) {
145         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
146         buf
147             .append("CREATE SEQUENCE ")
148             .append(sequenceName(ent))
149             .append(" START WITH 200")
150             .append(" INCREMENT BY ")
151             .append(pkCacheSize(ent));
152         return buf.toString();
153     }
154
155     /**
156      * Returns a SQL string needed to drop any database objects associated
157      * with automatic primary key generation process for a specific DbEntity.
158      */

159     protected String JavaDoc dropSequenceString(DbEntity ent) {
160         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
161         buf.append("DROP SEQUENCE ").append(sequenceName(ent));
162         return buf.toString();
163     }
164
165     /**
166      * Generates primary key by calling Oracle sequence corresponding to the
167      * <code>dbEntity</code>. Executed SQL looks like this:
168      *
169      * <pre>
170      * SELECT pk_table_name.nextval FROM DUAL
171      * </pre>
172      */

173     protected int pkFromDatabase(DataNode node, DbEntity ent) throws Exception JavaDoc {
174
175         DbKeyGenerator pkGenerator = ent.getPrimaryKeyGenerator();
176         String JavaDoc pkGeneratingSequenceName;
177         if (pkGenerator != null
178             && DbKeyGenerator.ORACLE_TYPE.equals(pkGenerator.getGeneratorType())
179             && pkGenerator.getGeneratorName() != null)
180             pkGeneratingSequenceName = pkGenerator.getGeneratorName();
181         else
182             pkGeneratingSequenceName = sequenceName(ent);
183
184         Connection JavaDoc con = node.getDataSource().getConnection();
185         try {
186             Statement JavaDoc st = con.createStatement();
187             try {
188                 String JavaDoc sql = "SELECT " + pkGeneratingSequenceName + ".nextval FROM DUAL";
189                 QueryLogger.logQuery(
190                     QueryLogger.DEFAULT_LOG_LEVEL,
191                     sql,
192                     Collections.EMPTY_LIST);
193                 ResultSet JavaDoc rs = st.executeQuery(sql);
194                 try {
195                     //Object pk = null;
196
if (!rs.next()) {
197                         throw new CayenneRuntimeException(
198                             "Error generating pk for DbEntity " + ent.getName());
199                     }
200                     return rs.getInt(1);
201                 }
202                 finally {
203                     rs.close();
204                 }
205             }
206             finally {
207                 st.close();
208             }
209         }
210         finally {
211             con.close();
212         }
213     }
214
215     protected int pkCacheSize(DbEntity entity) {
216         // use custom generator if possible
217
DbKeyGenerator keyGenerator = entity.getPrimaryKeyGenerator();
218         if (keyGenerator != null
219             && DbKeyGenerator.ORACLE_TYPE.equals(keyGenerator.getGeneratorType())
220             && keyGenerator.getGeneratorName() != null) {
221
222             Integer JavaDoc size = keyGenerator.getKeyCacheSize();
223             return (size != null && size.intValue() >= 1)
224                 ? size.intValue()
225                 : super.getPkCacheSize();
226         }
227         else {
228             return super.getPkCacheSize();
229         }
230     }
231
232     /** Returns expected primary key sequence name for a DbEntity. */
233     protected String JavaDoc sequenceName(DbEntity entity) {
234
235         // use custom generator if possible
236
DbKeyGenerator keyGenerator = entity.getPrimaryKeyGenerator();
237         if (keyGenerator != null
238             && DbKeyGenerator.ORACLE_TYPE.equals(keyGenerator.getGeneratorType())
239             && keyGenerator.getGeneratorName() != null) {
240
241             return keyGenerator.getGeneratorName().toLowerCase();
242         }
243         else {
244             String JavaDoc entName = entity.getName();
245             String JavaDoc seqName = _SEQUENCE_PREFIX + entName.toLowerCase();
246
247             if (entity.getSchema() != null && entity.getSchema().length() > 0) {
248                 seqName = entity.getSchema() + "." + seqName;
249             }
250             return seqName;
251         }
252     }
253
254     protected String JavaDoc stripSchemaName(String JavaDoc sequenceName) {
255         int ind = sequenceName.indexOf('.');
256         return (ind >= 0) ? sequenceName.substring(ind + 1) : sequenceName;
257     }
258
259     /**
260      * Fetches a list of existing sequences that might match Cayenne
261      * generated ones.
262      */

263     protected List JavaDoc getExistingSequences(DataNode node) throws SQLException JavaDoc {
264
265         // check existing sequences
266
Connection JavaDoc con = node.getDataSource().getConnection();
267
268         try {
269             Statement JavaDoc sel = con.createStatement();
270             try {
271                 String JavaDoc sql = "SELECT LOWER(SEQUENCE_NAME) FROM ALL_SEQUENCES";
272                 QueryLogger.logQuery(
273                     QueryLogger.DEFAULT_LOG_LEVEL,
274                     sql,
275                     Collections.EMPTY_LIST);
276                 ResultSet JavaDoc rs = sel.executeQuery(sql);
277                 try {
278                     List JavaDoc sequenceList = new ArrayList JavaDoc();
279                     while (rs.next()) {
280                         sequenceList.add(rs.getString(1));
281                     }
282                     return sequenceList;
283                 }
284                 finally {
285                     rs.close();
286                 }
287             }
288             finally {
289                 sel.close();
290             }
291         }
292         finally {
293             con.close();
294         }
295     }
296 }
297
Popular Tags