KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20
21 package org.apache.cayenne.dba.oracle;
22
23 import java.sql.Connection JavaDoc;
24 import java.sql.ResultSet JavaDoc;
25 import java.sql.SQLException JavaDoc;
26 import java.sql.Statement JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31
32 import org.apache.cayenne.CayenneRuntimeException;
33 import org.apache.cayenne.access.DataNode;
34 import org.apache.cayenne.access.QueryLogger;
35 import org.apache.cayenne.dba.JdbcPkGenerator;
36 import org.apache.cayenne.map.DbEntity;
37 import org.apache.cayenne.map.DbKeyGenerator;
38
39 /**
40  * Sequence-based primary key generator implementation for Oracle. Uses Oracle sequences
41  * to generate primary key values. This approach is at least 50% faster when tested with
42  * Oracle compared to the lookup table approach.
43  * <p>
44  * When using Cayenne key caching mechanism, make sure that sequences in the database have
45  * "INCREMENT BY" greater or equal to OraclePkGenerator "pkCacheSize" property value. If
46  * this is not the case, you will need to adjust PkGenerator value accordingly. For
47  * example when sequence is incremented by 1 each time, use the following code:
48  * </p>
49  *
50  * <pre>
51  * dataNode.getAdapter().getPkGenerator().setPkCacheSize(1);
52  * </pre>
53  *
54  * @author Andrus Adamchik
55  */

56 public class OraclePkGenerator extends JdbcPkGenerator {
57
58     private static final String JavaDoc _SEQUENCE_PREFIX = "pk_";
59
60     public void createAutoPk(DataNode node, List JavaDoc dbEntities) throws Exception JavaDoc {
61         List JavaDoc sequences = getExistingSequences(node);
62
63         // create needed sequences
64
Iterator JavaDoc it = dbEntities.iterator();
65         while (it.hasNext()) {
66             DbEntity ent = (DbEntity) it.next();
67             if (!sequences.contains(sequenceName(ent))) {
68                 runUpdate(node, createSequenceString(ent));
69             }
70         }
71     }
72
73     public List JavaDoc createAutoPkStatements(List JavaDoc dbEntities) {
74         List JavaDoc list = new ArrayList JavaDoc();
75         Iterator JavaDoc it = dbEntities.iterator();
76         while (it.hasNext()) {
77             DbEntity ent = (DbEntity) it.next();
78             list.add(createSequenceString(ent));
79         }
80
81         return list;
82     }
83
84     public void dropAutoPk(DataNode node, List JavaDoc dbEntities) throws Exception JavaDoc {
85         List JavaDoc sequences = getExistingSequences(node);
86
87         // drop obsolete sequences
88
Iterator JavaDoc it = dbEntities.iterator();
89         while (it.hasNext()) {
90             DbEntity ent = (DbEntity) it.next();
91             if (sequences.contains(stripSchemaName(sequenceName(ent)))) {
92                 runUpdate(node, dropSequenceString(ent));
93             }
94         }
95     }
96
97     public List JavaDoc dropAutoPkStatements(List JavaDoc dbEntities) {
98         List JavaDoc list = new ArrayList JavaDoc();
99         Iterator JavaDoc it = dbEntities.iterator();
100         while (it.hasNext()) {
101             DbEntity ent = (DbEntity) it.next();
102             list.add(dropSequenceString(ent));
103         }
104
105         return list;
106     }
107
108     protected String JavaDoc createSequenceString(DbEntity ent) {
109         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
110         buf
111                 .append("CREATE SEQUENCE ")
112                 .append(sequenceName(ent))
113                 .append(" START WITH 200")
114                 .append(" INCREMENT BY ")
115                 .append(pkCacheSize(ent));
116         return buf.toString();
117     }
118
119     /**
120      * Returns a SQL string needed to drop any database objects associated with automatic
121      * primary key generation process for a specific DbEntity.
122      */

123     protected String JavaDoc dropSequenceString(DbEntity ent) {
124         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
125         buf.append("DROP SEQUENCE ").append(sequenceName(ent));
126         return buf.toString();
127     }
128
129     /**
130      * Generates primary key by calling Oracle sequence corresponding to the
131      * <code>dbEntity</code>. Executed SQL looks like this:
132      *
133      * <pre>
134      * SELECT pk_table_name.nextval FROM DUAL
135      * </pre>
136      */

137     protected int pkFromDatabase(DataNode node, DbEntity ent) throws Exception JavaDoc {
138
139         DbKeyGenerator pkGenerator = ent.getPrimaryKeyGenerator();
140         String JavaDoc pkGeneratingSequenceName;
141         if (pkGenerator != null
142                 && DbKeyGenerator.ORACLE_TYPE.equals(pkGenerator.getGeneratorType())
143                 && pkGenerator.getGeneratorName() != null)
144             pkGeneratingSequenceName = pkGenerator.getGeneratorName();
145         else
146             pkGeneratingSequenceName = sequenceName(ent);
147
148         Connection JavaDoc con = node.getDataSource().getConnection();
149         try {
150             Statement JavaDoc st = con.createStatement();
151             try {
152                 String JavaDoc sql = "SELECT " + pkGeneratingSequenceName + ".nextval FROM DUAL";
153                 QueryLogger.logQuery(sql, Collections.EMPTY_LIST);
154                 ResultSet JavaDoc rs = st.executeQuery(sql);
155                 try {
156                     // Object pk = null;
157
if (!rs.next()) {
158                         throw new CayenneRuntimeException(
159                                 "Error generating pk for DbEntity " + ent.getName());
160                     }
161                     return rs.getInt(1);
162                 }
163                 finally {
164                     rs.close();
165                 }
166             }
167             finally {
168                 st.close();
169             }
170         }
171         finally {
172             con.close();
173         }
174     }
175
176     protected int pkCacheSize(DbEntity entity) {
177         // use custom generator if possible
178
DbKeyGenerator keyGenerator = entity.getPrimaryKeyGenerator();
179         if (keyGenerator != null
180                 && DbKeyGenerator.ORACLE_TYPE.equals(keyGenerator.getGeneratorType())
181                 && keyGenerator.getGeneratorName() != null) {
182
183             Integer JavaDoc size = keyGenerator.getKeyCacheSize();
184             return (size != null && size.intValue() >= 1) ? size.intValue() : super
185                     .getPkCacheSize();
186         }
187         else {
188             return super.getPkCacheSize();
189         }
190     }
191
192     /** Returns expected primary key sequence name for a DbEntity. */
193     protected String JavaDoc sequenceName(DbEntity entity) {
194
195         // use custom generator if possible
196
DbKeyGenerator keyGenerator = entity.getPrimaryKeyGenerator();
197         if (keyGenerator != null
198                 && DbKeyGenerator.ORACLE_TYPE.equals(keyGenerator.getGeneratorType())
199                 && keyGenerator.getGeneratorName() != null) {
200
201             return keyGenerator.getGeneratorName().toLowerCase();
202         }
203         else {
204             String JavaDoc entName = entity.getName();
205             String JavaDoc seqName = _SEQUENCE_PREFIX + entName.toLowerCase();
206
207             if (entity.getSchema() != null && entity.getSchema().length() > 0) {
208                 seqName = entity.getSchema() + "." + seqName;
209             }
210             return seqName;
211         }
212     }
213
214     protected String JavaDoc stripSchemaName(String JavaDoc sequenceName) {
215         int ind = sequenceName.indexOf('.');
216         return (ind >= 0) ? sequenceName.substring(ind + 1) : sequenceName;
217     }
218
219     /**
220      * Fetches a list of existing sequences that might match Cayenne generated ones.
221      */

222     protected List JavaDoc getExistingSequences(DataNode node) throws SQLException JavaDoc {
223
224         // check existing sequences
225
Connection JavaDoc con = node.getDataSource().getConnection();
226
227         try {
228             Statement JavaDoc sel = con.createStatement();
229             try {
230                 String JavaDoc sql = "SELECT LOWER(SEQUENCE_NAME) FROM ALL_SEQUENCES";
231                 QueryLogger.logQuery(sql, Collections.EMPTY_LIST);
232                 ResultSet JavaDoc rs = sel.executeQuery(sql);
233                 try {
234                     List JavaDoc sequenceList = new ArrayList JavaDoc();
235                     while (rs.next()) {
236                         sequenceList.add(rs.getString(1));
237                     }
238                     return sequenceList;
239                 }
240                 finally {
241                     rs.close();
242                 }
243             }
244             finally {
245                 sel.close();
246             }
247         }
248         finally {
249             con.close();
250         }
251     }
252 }
253
Popular Tags