KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > util > sequence > SequenceManagerHelper


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

17
18 import java.sql.ResultSet JavaDoc;
19 import java.sql.Statement JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Properties JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import org.apache.ojb.broker.PersistenceBroker;
26 import org.apache.ojb.broker.PersistenceBrokerException;
27 import org.apache.ojb.broker.accesslayer.StatementManagerIF;
28 import org.apache.ojb.broker.metadata.ClassDescriptor;
29 import org.apache.ojb.broker.metadata.FieldDescriptor;
30 import org.apache.ojb.broker.query.Query;
31 import org.apache.ojb.broker.util.logging.Logger;
32 import org.apache.ojb.broker.util.logging.LoggerFactory;
33
34 /**
35  * Helper class for SequenceManager implementations.
36  *
37  * @author <a HREF="mailto:armin@codeAuLait.de">Armin Waibel</a>
38  * @version $Id: SequenceManagerHelper.java,v 1.17.2.8 2005/12/21 22:28:41 tomdz Exp $
39  */

40 public class SequenceManagerHelper
41 {
42     private static Logger log = LoggerFactory.getLogger(SequenceManagerHelper.class);
43
44     /**
45      * Property name used to configure sequence manager implementations.
46      */

47     public static final String JavaDoc PROP_SEQ_AS = "seq.as";
48     /**
49      * Property name used to configure sequence manager implementations.
50      * @deprecated use {@link #PROP_SEQ_START} instead.
51      */

52     public static final String JavaDoc PROP_SEQ_START_OLD = "sequenceStart";
53     /**
54      * Property name used to configure sequence manager implementations.
55      */

56     public static final String JavaDoc PROP_SEQ_START = "seq.start";
57     /**
58      * Property name used to configure sequence manager implementations.
59      */

60     public static final String JavaDoc PROP_SEQ_INCREMENT_BY = "seq.incrementBy";
61     /**
62      * Property name used to configure sequence manager implementations.
63      */

64     public static final String JavaDoc PROP_SEQ_MAX_VALUE = "seq.maxValue";
65     /**
66      * Property name used to configure sequence manager implementations.
67      */

68     public static final String JavaDoc PROP_SEQ_MIN_VALUE = "seq.minValue";
69     /**
70      * Property name used to configure sequence manager implementations.
71      */

72     public static final String JavaDoc PROP_SEQ_CYCLE = "seq.cycle";
73     /**
74      * Property name used to configure sequence manager implementations.
75      */

76     public static final String JavaDoc PROP_SEQ_CACHE = "seq.cache";
77     /**
78      * Property name used to configure sequence manager implementations.
79      */

80     public static final String JavaDoc PROP_SEQ_ORDER = "seq.order";
81
82     private static final String JavaDoc SEQ_PREFIX = "SEQ_";
83     private static final String JavaDoc SEQ_UNASSIGNED = "UNASSIGNED";
84     private static final String JavaDoc SM_SELECT_MAX = "SELECT MAX(";
85     private static final String JavaDoc SM_FROM = ") FROM ";
86
87     /**
88      * Prefix for global sequence names.
89      */

90
91     /**
92      * Returns a unique sequence name (unique across all extents).
93      * <br/>
94      * If we found a non null value for the 'sequence-name' attribute in
95      * the field descriptor, we use the 'sequence-name' value as sequence name.
96      * <br/>
97      * Else if the top-level class of the target class has extents,
98      * we take the first extent class table name of the extents as
99      * sequence name.
100      * <br/>
101      * Else we take the table name of the target class.
102      * <p>
103      * If the method argument 'autoNaming' is true, the generated
104      * sequence name will be set in the given field descriptor
105      * using {@link org.apache.ojb.broker.metadata.FieldDescriptor#setSequenceName}
106      * to speed up sequence name lookup in future calls.
107      * </p>
108      * @param brokerForClass current used PB instance
109      * @param field target field
110      * @param autoNaming if 'false' no auto sequence name was build and
111      * a exception was throw if none could be found in field.
112      */

113     public static String JavaDoc buildSequenceName(PersistenceBroker brokerForClass,
114                                            FieldDescriptor field, boolean autoNaming)
115             throws SequenceManagerException
116     {
117         String JavaDoc seqName = field.getSequenceName();
118         /*
119         if we found a sequence name bound to the field descriptor
120         via 'sequence-name' attribute we use that name
121         */

122         if (seqName != null && seqName.trim().length() != 0)
123         {
124             return seqName;
125         }
126         else if (!autoNaming)
127         {
128             /*
129             arminw:
130             we don't find a sequence name and we should not automatic build one,
131             thus we throw an exception
132             */

133             throw new SequenceManagerException("Could not find sequence-name for field '" +
134                     field + "' of class '" + field.getClassDescriptor().getClassNameOfObject() +
135                     "', property 'autoNaming' in sequence-manager element in repository was '" +
136                     autoNaming + "'. Set autoNaming true in sequence-descriptor or define a " +
137                     " sequence-name in field-descriptor.");
138         }
139
140         ClassDescriptor cldTargetClass = field.getClassDescriptor();
141         /*
142         check for inheritance on multiple table
143         */

144         cldTargetClass = findInheritanceRoot(cldTargetClass);
145         Class JavaDoc topLevel = brokerForClass.getTopLevelClass(cldTargetClass.getClassOfObject());
146         ClassDescriptor cldTopLevel = brokerForClass.getClassDescriptor(topLevel);
147         /**
148          *
149          * MBAIRD
150          * Should not use classname for the sequenceName as we will end up
151          * re-using sequence numbers for classes mapped to the same table.
152          * Instead, make the FullTableName the discriminator since it will
153          * always be unique for that table, and hence that class.
154          *
155          * arminw:
156          * If the found top-level class has extents, we take the first
157          * found extent class table name as sequence name. Else we take
158          * the table name of the 'targetClass'.
159          *
160          */

161         if (cldTopLevel.isExtent())
162         {
163             /*
164             arminw:
165             this is a little critical, because we do not know if the extent classes
166             will change by and by and the first found extent class may change, thus the
167             returned table name could change!
168             But I don't know a way to resolve this problem. I put a comment to the
169             sequence manager docs
170             TODO: find better solution
171             */

172 // seqName = brokerForClass.getClassDescriptor(((Class) cldTopLevel.getExtentClasses().
173
// get(0))).getFullTableName();
174
seqName = firstFoundTableName(brokerForClass, cldTopLevel);
175         }
176         else
177         {
178             seqName = cldTargetClass.getFullTableName();
179         }
180 // log.info("* targetClass: "+targetClass +", toplevel: "+topLevel+ " seqName: "+seqName);
181
if (seqName == null)
182         {
183             seqName = SEQ_UNASSIGNED;
184             log.warn("Too complex structure, can not assign automatic sequence name for field '" +
185                     field.getAttributeName() + "' in class '" +
186                     field.getClassDescriptor().getClassNameOfObject() +
187                     "'. Use a default sequence name instead: " + (SEQ_PREFIX + seqName));
188         }
189 // System.out.println("* targetClass: " + cldTargetClass.getClassNameOfObject() + ", toplevel: " + topLevel + " seqName: " + seqName);
190
seqName = SEQ_PREFIX + seqName;
191         if (log.isDebugEnabled())
192                 log.debug("Set automatic generated sequence-name for field '" +
193                         field.getAttributeName() + "' in class '" +
194                         field.getClassDescriptor().getClassNameOfObject() +
195                         "'.");
196         field.setSequenceName(seqName);
197         return seqName;
198     }
199
200     /**
201      * Returns the root {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the inheriatance
202      * hierachy of the given descriptor or the descriptor itself if no inheriatance on multiple table is
203      * used.
204      */

205     private static ClassDescriptor findInheritanceRoot(ClassDescriptor cld)
206     {
207         ClassDescriptor result = cld;
208         if(cld.getSuperClassDescriptor() != null)
209         {
210             result = findInheritanceRoot(cld.getSuperClassDescriptor());
211         }
212         return result;
213     }
214
215     /**
216      * try to find the first none null table name for the given class-descriptor.
217      * If cld has extent classes, all of these cld's searched for the first none null
218      * table name.
219      */

220     private static String JavaDoc firstFoundTableName(PersistenceBroker brokerForClass, ClassDescriptor cld)
221     {
222         String JavaDoc name = null;
223         if (!cld.isInterface() && cld.getFullTableName() != null)
224         {
225             return cld.getFullTableName();
226         }
227         if (cld.isExtent())
228         {
229             Collection JavaDoc extentClasses = cld.getExtentClasses();
230             for (Iterator JavaDoc iterator = extentClasses.iterator(); iterator.hasNext();)
231             {
232                 name = firstFoundTableName(brokerForClass, brokerForClass.getClassDescriptor((Class JavaDoc) iterator.next()));
233                 // System.out.println("## " + cld.getClassNameOfObject()+" - name: "+name);
234
if (name != null) break;
235             }
236         }
237         return name;
238     }
239
240     /**
241      * Lookup all tables associated with given class (search all extent classes)
242      * to find the current maximum value for the given field.
243      * <br><b>Note:</b> Only works for <code>long</code> autoincrement fields.
244      * @param brokerForClass persistence broker instance match the database of the
245      * given field/class
246      * @param field the target field
247      */

248     public static long getMaxForExtent(PersistenceBroker brokerForClass, FieldDescriptor field) throws PersistenceBrokerException
249     {
250         if (field == null)
251         {
252             log.error("Given FieldDescriptor was null, could not detect max value across all extents");
253             return 0;
254             // throw new PersistenceBrokerException("Given FieldDescriptor was null");
255
}
256         // first lookup top-level class
257
Class JavaDoc topLevel = brokerForClass.getTopLevelClass(field.getClassDescriptor().getClassOfObject());
258         return getMaxId(brokerForClass, topLevel, field);
259     }
260
261     /**
262      * Search down all extent classes and return max of all found
263      * PK values.
264      */

265     public static long getMaxId(PersistenceBroker brokerForClass, Class JavaDoc topLevel, FieldDescriptor original) throws PersistenceBrokerException
266     {
267         long max = 0;
268         long tmp;
269         ClassDescriptor cld = brokerForClass.getClassDescriptor(topLevel);
270
271         // if class is not an interface / not abstract we have to search its directly mapped table
272
if (!cld.isInterface() && !cld.isAbstract())
273         {
274             tmp = getMaxIdForClass(brokerForClass, cld, original);
275             if (tmp > max)
276             {
277                 max = tmp;
278             }
279         }
280         // if class is an extent we have to search through its subclasses
281
if (cld.isExtent())
282         {
283             Vector JavaDoc extentClasses = cld.getExtentClasses();
284             for (int i = 0; i < extentClasses.size(); i++)
285             {
286                 Class JavaDoc extentClass = (Class JavaDoc) extentClasses.get(i);
287                 if (cld.getClassOfObject().equals(extentClass))
288                 {
289                     throw new PersistenceBrokerException("Circular extent in " + extentClass +
290                             ", please check the repository");
291                 }
292                 else
293                 {
294                     // fix by Mark Rowell
295
// Call recursive
296
tmp = getMaxId(brokerForClass, extentClass, original);
297                 }
298                 if (tmp > max)
299                 {
300                     max = tmp;
301                 }
302             }
303         }
304         return max;
305     }
306
307     /**
308      * lookup current maximum value for a single field in
309      * table the given class descriptor was associated.
310      */

311     public static long getMaxIdForClass(
312             PersistenceBroker brokerForClass, ClassDescriptor cldForOriginalOrExtent, FieldDescriptor original)
313             throws PersistenceBrokerException
314     {
315         FieldDescriptor field = null;
316         if (!original.getClassDescriptor().equals(cldForOriginalOrExtent))
317         {
318             // check if extent match not the same table
319
if (!original.getClassDescriptor().getFullTableName().equals(
320                     cldForOriginalOrExtent.getFullTableName()))
321             {
322                 // we have to look for id's in extent class table
323
field = cldForOriginalOrExtent.getFieldDescriptorByName(original.getAttributeName());
324             }
325         }
326         else
327         {
328             field = original;
329         }
330         if (field == null)
331         {
332             // if null skip this call
333
return 0;
334         }
335
336         String JavaDoc column = field.getColumnName();
337         long result = 0;
338         ResultSet JavaDoc rs = null;
339         Statement JavaDoc stmt = null;
340         StatementManagerIF sm = brokerForClass.serviceStatementManager();
341         String JavaDoc table = cldForOriginalOrExtent.getFullTableName();
342         // String column = cld.getFieldDescriptorByName(fieldName).getColumnName();
343
String JavaDoc sql = SM_SELECT_MAX + column + SM_FROM + table;
344         try
345         {
346             //lookup max id for the current class
347
stmt = sm.getGenericStatement(cldForOriginalOrExtent, Query.NOT_SCROLLABLE);
348             rs = stmt.executeQuery(sql);
349             rs.next();
350             result = rs.getLong(1);
351         }
352         catch (Exception JavaDoc e)
353         {
354             log.warn("Cannot lookup max value from table " + table + " for column " + column +
355                     ", PB was " + brokerForClass + ", using jdbc-descriptor " +
356                     brokerForClass.serviceConnectionManager().getConnectionDescriptor(), e);
357         }
358         finally
359         {
360             try
361             {
362                 sm.closeResources(stmt, rs);
363             }
364             catch (Exception JavaDoc ignore)
365             {
366                 // ignore it
367
}
368         }
369         return result;
370     }
371
372     /**
373      * Database sequence properties helper method.
374      * Return sequence <em>start value</em> or <em>null</em>
375      * if not set.
376      *
377      * @param prop The {@link java.util.Properties} instance to use.
378      * @return The found expression or <em>null</em>.
379      */

380     public static Long JavaDoc getSeqStart(Properties JavaDoc prop)
381     {
382         String JavaDoc result = prop.getProperty(PROP_SEQ_START, null);
383         if(result == null)
384         {
385             result = prop.getProperty(PROP_SEQ_START_OLD, null);
386         }
387         if(result != null)
388         {
389             return new Long JavaDoc(Long.parseLong(result));
390         }
391         else
392         {
393             return null;
394         }
395     }
396
397     /**
398      * Database sequence properties helper method.
399      * Return sequence <em>increment by value</em> or <em>null</em>
400      * if not set.
401      *
402      * @param prop The {@link java.util.Properties} instance to use.
403      * @return The found expression or <em>null</em>.
404      */

405     public static Long JavaDoc getSeqIncrementBy(Properties JavaDoc prop)
406     {
407         String JavaDoc result = prop.getProperty(PROP_SEQ_INCREMENT_BY, null);
408         if(result != null)
409         {
410             return new Long JavaDoc(Long.parseLong(result));
411         }
412         else
413         {
414             return null;
415         }
416     }
417
418     /**
419      * Database sequence properties helper method.
420      * Return sequence <em>max value</em> or <em>null</em>
421      * if not set.
422      *
423      * @param prop The {@link java.util.Properties} instance to use.
424      * @return The found expression or <em>null</em>.
425      */

426     public static Long JavaDoc getSeqMaxValue(Properties JavaDoc prop)
427     {
428         String JavaDoc result = prop.getProperty(PROP_SEQ_MAX_VALUE, null);
429         if(result != null)
430         {
431             return new Long JavaDoc(Long.parseLong(result));
432         }
433         else
434         {
435             return null;
436         }
437     }
438
439     /**
440      * Database sequence properties helper method.
441      * Return sequence <em>min value</em> or <em>null</em>
442      * if not set.
443      *
444      * @param prop The {@link java.util.Properties} instance to use.
445      * @return The found expression or <em>null</em>.
446      */

447     public static Long JavaDoc getSeqMinValue(Properties JavaDoc prop)
448     {
449         String JavaDoc result = prop.getProperty(PROP_SEQ_MIN_VALUE, null);
450         if(result != null)
451         {
452             return new Long JavaDoc(Long.parseLong(result));
453         }
454         else
455         {
456             return null;
457         }
458     }
459
460     /**
461      * Database sequence properties helper method.
462      * Return sequence <em>cache value</em> or <em>null</em>
463      * if not set.
464      *
465      * @param prop The {@link java.util.Properties} instance to use.
466      * @return The found expression or <em>null</em>.
467      */

468     public static Long JavaDoc getSeqCacheValue(Properties JavaDoc prop)
469     {
470         String JavaDoc result = prop.getProperty(PROP_SEQ_CACHE, null);
471         if(result != null)
472         {
473             return new Long JavaDoc(Long.parseLong(result));
474         }
475         else
476         {
477             return null;
478         }
479     }
480
481     /**
482      * Database sequence properties helper method.
483      * Return sequence <em>cycle</em> Booelan or <em>null</em>
484      * if not set.
485      *
486      * @param prop The {@link java.util.Properties} instance to use.
487      * @return The found expression or <em>null</em>.
488      */

489     public static Boolean JavaDoc getSeqCycleValue(Properties JavaDoc prop)
490     {
491         String JavaDoc result = prop.getProperty(PROP_SEQ_CYCLE, null);
492         if(result != null)
493         {
494             return Boolean.valueOf(result);
495         }
496         else
497         {
498             return null;
499         }
500     }
501
502     /**
503      * Database sequence properties helper method.
504      * Return sequence <em>order</em> Booelan or <em>null</em>
505      * if not set.
506      *
507      * @param prop The {@link java.util.Properties} instance to use.
508      * @return The found expression or <em>null</em>.
509      */

510     public static Boolean JavaDoc getSeqOrderValue(Properties JavaDoc prop)
511     {
512         String JavaDoc result = prop.getProperty(PROP_SEQ_ORDER, null);
513         if(result != null)
514         {
515             return Boolean.valueOf(result);
516         }
517         else
518         {
519             return null;
520         }
521     }
522
523     /**
524      * Database sequence properties helper method.
525      * Return the datatype to set for the sequence or <em>null</em>
526      * if not set.
527      *
528      * @param prop The {@link java.util.Properties} instance to use.
529      * @return The found expression or <em>null</em>.
530      */

531     public static String JavaDoc getSeqAsValue(Properties JavaDoc prop)
532     {
533         return prop.getProperty(PROP_SEQ_AS, null);
534     }
535 }
536
Popular Tags