KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > generator > database > MappingPolicy


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * MappingPolicy.java
26  *
27  * Created on Jan 14, 2003
28  */

29
30 package com.sun.jdo.spi.persistence.generator.database;
31
32 import java.io.BufferedInputStream JavaDoc;
33 import java.io.FileInputStream JavaDoc;
34 import java.io.InputStream JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.util.Map JavaDoc;
41 import java.util.Properties JavaDoc;
42 import java.util.ResourceBundle JavaDoc;
43 import java.util.Set JavaDoc;
44 import java.util.StringTokenizer JavaDoc;
45 import java.util.TreeSet JavaDoc;
46 import java.security.AccessController JavaDoc;
47 import java.security.PrivilegedAction JavaDoc;
48 import java.sql.Types JavaDoc;
49
50 import com.sun.jdo.spi.persistence.utility.I18NHelper;
51 import com.sun.jdo.spi.persistence.utility.StringHelper;
52
53 import com.sun.jdo.spi.persistence.utility.logging.Logger;
54
55 import com.sun.jdo.spi.persistence.utility.database.*;
56
57 // XXX Capitalization of acronyms such as Jdbc vs. JDBC is inconsistent
58
// throught out this package.
59

60 /**
61  * Describes how Java classes and their fields are to be mapped to database
62  * tables and columns
63  */

64 public class MappingPolicy implements Cloneable JavaDoc {
65     //
66
// The names of many properties in our .properties files are composed of
67
// different pieces, here called "bases", followed by "indicators". The
68
// idea is that a base may have multiple indicators. In a way, they are
69
// kind of like instances of structs, with each base naming an instance
70
// and each indicator naming an accessor to a value in the struct.
71
//
72
// The concatenation of bases and indicators is just another String,
73
// which you can look up in a Properties object to get a value.
74
//
75
// Note that some property names have more than one base concatenated.
76
// See SQL92.properties for examples.
77
//
78

79     /** @see DatabaseGenerationConstants#DOT */
80     static final char DOT = DatabaseGenerationConstants.DOT;
81
82     //
83
// Base names of properties which describe how class and field names are
84
// to be represented in a database.
85
//
86

87     /** Base name to denote a class. */
88     private static final String JavaDoc CLASS_BASE = "{class-name}"; //NOI18N
89

90     /** Base name to denote a field. */
91     private static final String JavaDoc FIELD_BASE = "{field-name}"; //NOI18N
92

93     /** Base name to denote a relationship field. */
94     private static final String JavaDoc RELATIONSHIP_BASE =
95             "{relationship-field-name}"; //NOI18N
96

97
98     /** Represents a '.' in a regular expression */
99     private static String JavaDoc REGEXP_DOT = "\\."; // NOI18N
100

101     /** Synonym for DatabaseGenerationConstants.INDICATOR_JDBC_PREFIX. */
102     private static final String JavaDoc INDICATOR_JDBC_PREFIX =
103         DatabaseGenerationConstants.INDICATOR_JDBC_PREFIX;
104
105     /**
106      * Base name to denote maximum length of a name in a database. We
107      * support different maximum lengths for table, column, and constraint
108      * names.
109      */

110     private static final String JavaDoc INDICATOR_MAXIMUM_LENGTH =
111         DatabaseGenerationConstants.INDICATOR_MAXIMUM_LENGTH;
112
113     //
114
// Indicator names for properties which describe how class and field
115
// names are to be represented in a database.
116
//
117

118     /** Indicator that property is for a table name. */
119     private static final String JavaDoc INDICATOR_TABLE_NAME =
120         "table-name"; //NOI18N
121

122     /** Indicator that property is for a column name. */
123     private static final String JavaDoc INDICATOR_COLUMN_NAME =
124         "column-name"; //NOI18N
125

126     /** Indicator that property is for a join table name. */
127     private static final String JavaDoc INDICATOR_JOIN_TABLE_NAME =
128         "join-table-name"; //NOI18N
129

130     /** Indicator that property is for a constraint name. */
131     private static final String JavaDoc INDICATOR_CONSTRAINT_NAME =
132         "constraint-name"; //NOI18N
133

134
135     //
136
// These are complete property names composed of bases and indicators.
137
//
138

139     /** Prefix of properties that denote classes. */
140     private static final String JavaDoc CLASS_PREFIX =
141         CLASS_BASE + DOT;
142
143     /** Prefix of properties that denote classes. */
144     private static final String JavaDoc RELATIONSHIP_PREFIX =
145         CLASS_PREFIX + RELATIONSHIP_BASE + DOT;
146
147     /** Name of property that provides default field-to-column name mapping. */
148     private static final String JavaDoc DEFAULT_COLUMN_KEY =
149         CLASS_PREFIX + FIELD_BASE + DOT + INDICATOR_COLUMN_NAME;
150
151     /** Name of property that provides default jointable name mapping. */
152     private static final String JavaDoc DEFAULT_JOIN_TABLE_KEY =
153         RELATIONSHIP_PREFIX + INDICATOR_JOIN_TABLE_NAME;
154
155     /** Name of property that provides default constraint name mapping. */
156     private static final String JavaDoc DEFAULT_CONSTRAINT_KEY =
157         RELATIONSHIP_PREFIX + INDICATOR_CONSTRAINT_NAME;
158
159     /** Name of property that provides default class-to-table name mapping. */
160     private static final String JavaDoc DEFAULT_TABLE_KEY =
161         CLASS_PREFIX + INDICATOR_TABLE_NAME;
162
163
164     //
165
// Now, here are values of properties which indicate how table and column
166
// names are to be generated. I.e., in our .properties files, these are
167
// potential values for some property names composed of the above bases
168
// and indicators.
169
//
170

171     /** Property value indicating table name must be same as class name. */
172     private static final String JavaDoc TABLE_NAME_AS_CLASSNAME =
173         "{className}"; //NOI18N
174

175     /** Property value indicating table name must be upper case. */
176     private static final String JavaDoc TABLE_NAME_UPPERCASE =
177         TABLE_NAME_AS_CLASSNAME.toUpperCase();
178
179     /** Property value indicating table name must be uppercase and unique. */
180     private static final String JavaDoc TABLE_NAME_HASH_UPPERCASE =
181         "{HASH-CLASSNAME}"; //NOI18N
182

183     /** Property value indicating colum name must be same as field name. */
184     private static final String JavaDoc COLUMN_NAME_AS_FIELDNAME =
185         "{fieldName}"; //NOI18N
186

187     /** Property value indicating column name must be uppercase. */
188     private static final String JavaDoc COLUMN_NAME_UPPERCASE =
189         COLUMN_NAME_AS_FIELDNAME.toUpperCase();
190
191     /** Property value indicating join table name must be uppercase. */
192     private static final String JavaDoc JOIN_TABLE_NAME_UPPERCASE =
193         "{CLASSNAMES}"; //NOI18N
194

195     /** Property value indicating constraint name must be uppercase. */
196     private static final String JavaDoc CONSTRAINT_NAME_UPPERCASE =
197         "{FIELDNAMES}"; //NOI18N
198

199
200     //
201
// Here are indicators for properties that direct how vendor-dependent
202
// SQL is generated.
203
//
204

205     /** Indicator that property is for formatting SQL */
206     private static final String JavaDoc INDICATOR_SQL_FORMAT = "sql-format"; //NOI18N
207

208     /** The indicator for a statement separator. */
209     private static final String JavaDoc STATEMENT_SEPARATOR_INDICATOR =
210         "statementSeparator"; // NOI18N
211

212     /** The indicator for starting a "create table". */
213     private static final String JavaDoc CREATE_TABLE_START_INDICATOR =
214         "createTableStart"; // NOI18N
215

216     /** The indicator for ending a "create table". */
217     private static final String JavaDoc CREATE_TABLE_END_INDICATOR =
218         "createTableEnd"; // NOI18N
219

220     /** The indicator for starting a "drop table". */
221     private static final String JavaDoc DROP_TABLE_INDICATOR =
222         "dropTable"; // NOI18N
223

224     /** The indicator for "add constraint". */
225     private static final String JavaDoc ALTER_TABLE_ADD_CONSTRAINT_START_INDICATOR =
226         "alterTableAddConstraintStart"; // NOI18N
227

228     /** The indicator for "drop constraint". */
229     private static final String JavaDoc ALTER_TABLE_DROP_CONSTRAINT_INDICATOR =
230         "alterTableDropConstraint"; // NOI18N
231

232     /** The indicator for adding a primary key constraint. */
233     private static final String JavaDoc PRIMARY_KEY_CONSTRAINT_INDICATOR =
234         "primaryKeyConstraint"; // NOI18N
235

236     /** The indicator for adding a foreign key constraint. */
237     private static final String JavaDoc FOREIGN_KEY_CONSTRAINT_INDICATOR =
238         "foreignKeyConstraint"; // NOI18N
239

240     /** The indicator for verbose nullability. */
241     private static final String JavaDoc COLUMN_NULLABILITY_INDICATOR =
242         "columnNullability"; // NOI18N
243

244     /** The indicator for information used with LOB columns. */
245     private static final String JavaDoc LOB_LOGGING_INDICATOR =
246         "LOBLogging"; // NOI18N
247

248     //
249
// The remaining constants are neither bases nor indicators.
250
//
251

252     /** Prefix of column names which are primary key columns. */
253     private static final String JavaDoc PK_PREFIX = "PK_"; //NOI18N
254

255     /** Prefix of column names which are foreign key columns. */
256     private static final String JavaDoc FK_PREFIX = "FK_"; //NOI18N
257

258     /** Name of the "global" namespace. */
259     private static final String JavaDoc GLOBAL_NAMING_SPACE = "GLOBAL"; //NOI18N
260

261     /** Property name which indicates unique table names should be generated. */
262     public static final String JavaDoc USE_UNIQUE_TABLE_NAMES = "use-unique-table-names"; // NOI18N
263

264     /** Property name which indicates reserved words. */
265     private static final String JavaDoc RESERVED_WORDS = "reserved-words";// NOI18N
266

267     /** When appended to a reserved word, causes it to be not-reserved. */
268     private static final String JavaDoc RESERVED_WORD_UNRESERVER = "9"; // NOI18N
269

270     /**
271      * Maximum length of the counter used to create unique names with a
272      * numeric id. Note that this length includes a NAME_SEPARATOR, so that
273      * we allow for 3 digits total.
274      */

275     private static final int MAX_LEN_COUNTER = 4;
276
277     /** Number of chars to change a reserved word into * unreserved. */
278     private static final int MAX_LEN_RESERVED = 1;
279
280     /**
281      * Name of subdirectory in which db vendor - specific properties files
282      * are located.
283      */

284     private static final String JavaDoc PROPERTY_FILE_DIR =
285         "com/sun/jdo/spi/persistence/generator/database/"; // NOI18N
286

287     /** Extension used by properties files. */
288     private static final String JavaDoc PROPERTY_FILE_EXT = ".properties"; // NOI18N
289

290     //
291
// The above are all constants; below things get "interesting".
292
//
293

294     
295     /** This is the set of all default properties. */
296     private static final Properties JavaDoc defaultProps = new Properties JavaDoc();
297
298     //
299
// XXX Consider getting these String-Integer and Integer-String maps into
300
// SQLTypeUtil, which is in the dbschema module. Or not: we support only a
301
// subset of java.sql.types, and (presumably) the dbschema module would
302
// provide mappings for all types.
303
//
304
// Note also that is code in MappingGenerator of a "SQLTypeUtil" nature.
305
//
306

307     /**
308      * Map from String names to the Integer-boxed values from
309      * java.sql.Types.
310      */

311     private static final Map JavaDoc jdbcTypes = new HashMap JavaDoc();
312
313     /**
314      * Maps from Integer-boxed values from java.sql.Types to String names.
315      */

316     private static final Map JavaDoc jdbcTypeNames = new HashMap JavaDoc();
317
318
319     /**
320      * Global counter for creating unique names in each of the namespaces.
321      * <em>Note that a single counter is used across all namespaces.</em>
322      */

323     private int counter = 0;
324     
325     /**
326      * Map from namespaces to Set of names defined in each namespace. Used
327      * to ensure uniqueness within namespaces.
328      */

329     private Map JavaDoc namespaces = new HashMap JavaDoc();
330
331     /**
332      * Indicates whether or not generated table names should include a
333      * unique value as part of their names.
334      */

335     private boolean uniqueTableName = false;
336
337     /**
338      * Set of reserved words for a particular policy.
339      */

340     private final Set JavaDoc reservedWords = new TreeSet JavaDoc();
341
342     /**
343      * Set of reserved words for the default database.
344      */

345     private static Set JavaDoc defaultReservedWords;
346     
347     /**
348      * Map from the string names of the java types (e.g. "java.lang.String")
349      * to a JDBCInfo of information about the corresponding java.sql.Types
350      * type. Different for different dbvendor types, but the same instance,
351      * per dbvendor, is shared by all MappingPolicy instances.
352      */

353     private final Map JavaDoc dbJdbcInfoMap = new HashMap JavaDoc();
354
355     /**
356      * Similar to {@link #dbJdbcInfoMap}, but is reinitialized by each
357      * clone(). Contains user-provided overrides of the information in
358      * dbjdbcInfoMap.
359      */

360     private Map JavaDoc userJdbcInfoMap = new HashMap JavaDoc();
361
362     /**
363      * Map from a boxed value based on fields in java.sql.Types to the String
364      * name of a SQL type.
365      */

366     private final Map JavaDoc sqlInfo = new HashMap JavaDoc();
367
368
369     //
370
// Maximum lengths for table, column, and constraint names are
371
// vendor-specific.
372
//
373

374     /** Maximum length of the name of a table. */
375     private int tableNameMaxLength;
376
377     /** Maximum length of the name of a column. */
378     private int columnNameMaxLength;
379
380     /** Maximum length of the name of a constraint. */
381     private int constraintNameMaxLength;
382
383
384     //
385
// Strings to represent vendor-specific SQL that starts a table,
386
// separates statements, etc.
387
//
388

389     /** The SQL for a statement separator. */
390     private String JavaDoc statementSeparator;
391
392     /** The SQL for starting a "create table". */
393     private String JavaDoc createTableStart;
394
395     /** The SQL for ending a "create table". */
396     private String JavaDoc createTableEnd;
397
398     /** The SQL for "drop table". */
399     private String JavaDoc dropTable;
400
401     /** The SQL for "add constraint". */
402     private String JavaDoc alterTableAddConstraintStart;
403
404     /** The SQL for "drop constraint". */
405     private String JavaDoc alterTableDropConstraint;
406
407     /** The SQL for adding a primary key constraint. */
408     private String JavaDoc primaryKeyConstraint;
409
410     /** The SQL for adding a foreign key constraint. */
411     private String JavaDoc foreignKeyConstraint;
412
413     /** The SQL for indicating column nullability */
414     private String JavaDoc columnNullability;
415
416     /** The SQL for indicating LOB column logging */
417     private String JavaDoc lobLogging = "";
418
419     /**
420      * Map from the encoded name of a policy to its value. For example, a
421      * class name's naming policy would be encoded as
422      * "<classname>.table-name".
423      */

424     // XXX Consider renaming this.
425
private final Map JavaDoc namingPolicy = new HashMap JavaDoc();
426
427     /** Map from database vendor names to instances of MappingPolicy. */
428     private static final Map JavaDoc instances = new HashMap JavaDoc();
429
430      /** Logger for warning & error messages */
431     private static final Logger logger =
432             LogHelperDatabaseGenerator.getLogger();
433     
434     /** I18N message handler */
435     private final static ResourceBundle JavaDoc messages =
436             I18NHelper.loadBundle(MappingPolicy.class);
437
438     //
439
// Initialize the JDBC String to Integer map and the default (SQL92)
440
// MappingPolicy.
441
//
442

443     // XXX Why initialize the SQL policy, when there's a good chance it won't
444
// ever be used? Do we really want to support unrecognized databases?
445
// See comment in getMappingPolicy. The default properties, on the other
446
// hand, *do* need to be loaded.
447

448     // XXX We need to decide what happens when an unrecognized dbvendorname
449
// is given: Error? Warning, continue running?
450
static {
451         // Initialize jdbcType map.
452
jdbcTypes.put("BIGINT", new Integer JavaDoc(Types.BIGINT)); // NOI18N
453
jdbcTypes.put("BIT", new Integer JavaDoc(Types.BIT)); // NOI18N
454
jdbcTypes.put("BLOB", new Integer JavaDoc(Types.BLOB)); // NOI18N
455
jdbcTypes.put("CHAR", new Integer JavaDoc(Types.CHAR)); // NOI18N
456
jdbcTypes.put("CLOB", new Integer JavaDoc(Types.CLOB)); // NOI18N
457
jdbcTypes.put("DATE", new Integer JavaDoc(Types.DATE)); // NOI18N
458
jdbcTypes.put("DECIMAL", new Integer JavaDoc(Types.DECIMAL)); // NOI18N
459
jdbcTypes.put("DOUBLE", new Integer JavaDoc(Types.DOUBLE)); // NOI18N
460
jdbcTypes.put("INTEGER", new Integer JavaDoc(Types.INTEGER)); // NOI18N
461
jdbcTypes.put("LONGVARBINARY", new Integer JavaDoc(Types.LONGVARBINARY)); // NOI18N
462
jdbcTypes.put("LONGVARCHAR", new Integer JavaDoc(Types.LONGVARCHAR)); // NOI18N
463
jdbcTypes.put("NULL", new Integer JavaDoc(Types.NULL)); // NOI18N
464
jdbcTypes.put("REAL", new Integer JavaDoc(Types.REAL)); // NOI18N
465
jdbcTypes.put("SMALLINT", new Integer JavaDoc(Types.SMALLINT)); // NOI18N
466
jdbcTypes.put("TIME", new Integer JavaDoc(Types.TIME)); // NOI18N
467
jdbcTypes.put("TIMESTAMP", new Integer JavaDoc(Types.TIMESTAMP)); // NOI18N
468
jdbcTypes.put("TINYINT", new Integer JavaDoc(Types.TINYINT)); // NOI18N
469
jdbcTypes.put("VARCHAR", new Integer JavaDoc(Types.VARCHAR)); // NOI18N
470

471         jdbcTypeNames.put(new Integer JavaDoc(Types.BIGINT), "BIGINT"); // NOI18N
472
jdbcTypeNames.put(new Integer JavaDoc(Types.BIT), "BIT"); // NOI18N
473
jdbcTypeNames.put(new Integer JavaDoc(Types.BLOB), "BLOB"); // NOI18N
474
jdbcTypeNames.put(new Integer JavaDoc(Types.CHAR), "CHAR"); // NOI18N
475
jdbcTypeNames.put(new Integer JavaDoc(Types.CLOB), "CLOB"); // NOI18N
476
jdbcTypeNames.put(new Integer JavaDoc(Types.DATE), "DATE"); // NOI18N
477
jdbcTypeNames.put(new Integer JavaDoc(Types.DECIMAL), "DECIMAL"); // NOI18N
478
jdbcTypeNames.put(new Integer JavaDoc(Types.DOUBLE), "DOUBLE"); // NOI18N
479
jdbcTypeNames.put(new Integer JavaDoc(Types.INTEGER), "INTEGER"); // NOI18N
480
jdbcTypeNames.put(new Integer JavaDoc(Types.LONGVARBINARY), "LONGVARBINARY"); // NOI18N
481
jdbcTypeNames.put(new Integer JavaDoc(Types.LONGVARCHAR), "LONGVARCHAR"); // NOI18N
482
jdbcTypeNames.put(new Integer JavaDoc(Types.NULL), "NULL"); // NOI18N
483
jdbcTypeNames.put(new Integer JavaDoc(Types.REAL), "REAL"); // NOI18N
484
jdbcTypeNames.put(new Integer JavaDoc(Types.SMALLINT), "SMALLINT"); // NOI18N
485
jdbcTypeNames.put(new Integer JavaDoc(Types.TIME), "TIME"); // NOI18N
486
jdbcTypeNames.put(new Integer JavaDoc(Types.TIMESTAMP), "TIMESTAMP"); // NOI18N
487
jdbcTypeNames.put(new Integer JavaDoc(Types.TINYINT), "TINYINT"); // NOI18N
488
jdbcTypeNames.put(new Integer JavaDoc(Types.VARCHAR), "VARCHAR"); // NOI18N
489

490         try {
491
492             // Create and load the default mapping policy.
493
new MappingPolicy();
494
495         } catch (Throwable JavaDoc ex) {
496             logger.log(Logger.SEVERE,
497                        I18NHelper.getMessage(
498                                messages,
499                                "EXC_MappingPolicyNotFound", //NOI18N
500
DBVendorTypeHelper.DEFAULT_DB));
501         }
502     }
503
504     /**
505      * Create the default MappingPolicy instance.
506      */

507     // This should be invoked only once per JVM. See the class static
508
// block of code above.
509
private MappingPolicy() throws IOException JavaDoc {
510         load(getPropertyFileName(DBVendorTypeHelper.DEFAULT_DB),
511              defaultProps, false);
512         init(defaultProps);
513
514         // The DEFAULT_DB has reserved words for the default database type.
515
// Other databases can access those same values through the
516
// defaultReservedWords set.
517
defaultReservedWords = reservedWords;
518
519         instances.put(DBVendorTypeHelper.DEFAULT_DB, this);
520
521         if (logger.isLoggable(Logger.FINEST)) {
522             logger.finest("new MappingPolicy():\n" + toString()); // NOI18N
523
}
524     }
525
526     /**
527      * Create a MappingPolicy for the named database type.
528      * @param databaseType Name of the database for which a MappingPolicy is
529      * created. The name must conform to one of the .properties files in
530      * this package.
531      */

532     // This should be invoked only once per databaseType per JVM. See
533
// {@link #getMappingPolicy}.
534
private MappingPolicy(String JavaDoc databaseType) throws IOException JavaDoc {
535         Properties JavaDoc mergedProp = new Properties JavaDoc(defaultProps);
536         load(getPropertyFileName(databaseType), mergedProp, false);
537         init(mergedProp);
538         instances.put(databaseType, this);
539
540         if (logger.isLoggable(Logger.FINEST)) {
541             logger.finest("new MappingPolicy(" // NOI18N
542
+ databaseType + "):\n" + toString()); // NOI18N
543
}
544     }
545
546     /**
547      * Returns a vendor-specifc MappingPolicy instance. This method always
548      * returns a copy (clone) of the known MappingPolicy to allow for
549      * user-specific overrides.
550      * @param databaseType a database vendor name as a String.
551      * @return MappingPolicy instance corresponding to the provided
552      * database vendor name.
553      * @throws IOException if there are problems reading the vendor-
554      * specific mappinng policy file
555      */

556     public synchronized static MappingPolicy getMappingPolicy(
557            String JavaDoc databaseType) throws IOException JavaDoc {
558                
559         if (logger.isLoggable(Logger.FINE)) {
560             logger.fine("get MappingPolicy"+databaseType); // NOI18N
561
}
562         
563         MappingPolicy mappingPolicy = null;
564         try {
565             if (databaseType == null) {
566                 databaseType = DBVendorTypeHelper.DEFAULT_DB;
567                 // XXX FIXME Need to log a warning and report to user that we
568
// are *not* using databaseType given, that we are using
569
// SQL92 instead, and provide list of recognized names.
570
}
571             mappingPolicy = (MappingPolicy) instances.get(databaseType);
572             if (mappingPolicy == null) {
573                 mappingPolicy = new MappingPolicy(databaseType);
574             }
575             mappingPolicy = (MappingPolicy) mappingPolicy.clone();
576         } catch (CloneNotSupportedException JavaDoc ec) {
577             // ignore it because it will not happen
578
}
579         return mappingPolicy;
580     }
581
582     /**
583      * Clones the vendor-specific policy for generator session. Replace the
584      * namespaces map in the clone, so that each instance has its own.
585      * @return clone of this MappingPolicy
586      * @throws CloneNotSupportedException never thrown
587      */

588     protected Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
589         MappingPolicy mappingPolicyClone = (MappingPolicy) super.clone();
590         mappingPolicyClone.namespaces = new HashMap JavaDoc();
591         mappingPolicyClone.uniqueTableName = false;
592         mappingPolicyClone.userJdbcInfoMap = new HashMap JavaDoc();
593         return mappingPolicyClone;
594     }
595
596     /**
597      * Initializes the given properties from the given resourceName.
598      * @param resourceName Name of the resource to open, expected to contain
599      * properties in text form.
600      * @param properties Properties that are to be loaded.
601      * @param override If <code>true</code>, treat resourceName as a filename
602      * from which to read; if <code>false</code>, treat resourceName as the
603      * name of a resource accessed via the class loader which loaded the
604      * MappingPolicy class.
605      */

606     private synchronized void load(
607             final String JavaDoc resourceName, Properties JavaDoc properties, boolean override)
608             throws IOException JavaDoc {
609  
610         if (logger.isLoggable(Logger.FINE)) {
611             logger.fine("load resource:" + resourceName); // NOI18N
612
}
613
614         InputStream JavaDoc bin = null;
615         InputStream JavaDoc in = null;
616
617         try {
618             if (override) {
619                 in = new FileInputStream JavaDoc(resourceName);
620             } else {
621                 final ClassLoader JavaDoc loader =
622                         MappingPolicy.class.getClassLoader();
623                 in = (InputStream JavaDoc) AccessController.doPrivileged(
624                         new PrivilegedAction JavaDoc() {
625
626                             public Object JavaDoc run() {
627                                 Object JavaDoc rc = null;
628                                 if (loader != null) {
629                                     rc =loader.getResourceAsStream(
630                                             resourceName);
631                                 } else {
632                                     rc =
633                                         ClassLoader.getSystemResourceAsStream(
634                                                 resourceName);
635                                 }
636                                 return rc;
637                             }
638                         });
639                 if (in == null) {
640                     throw new IOException JavaDoc(I18NHelper.getMessage(messages,
641                         "EXC_ResourceNotFound", resourceName));// NOI18N
642
}
643             }
644
645             bin = new BufferedInputStream JavaDoc(in);
646             properties.load(bin);
647             if (logger.isLoggable(Logger.FINE)) {
648                 logger.fine("load "+resourceName + " successfuly"); // NOI18N
649
}
650         } finally {
651             try {
652                 bin.close();
653                 // XXX Need to close both streams in.close();
654
} catch (Exception JavaDoc e) {
655                 // ignore
656
}
657         }
658     }
659  
660     /**
661      * Resets the namespaces and counter.
662      */

663     // XXX Consider renaming to "reset".
664
void resetCounter() {
665         namespaces.clear();
666         userJdbcInfoMap.clear();
667         counter = 0;
668     }
669
670     /**
671      * Sets user-provided policy to that provided in the given properties.
672      * @param userProp Properties which override built in defaults.
673      */

674     public void setUserPolicy(Properties JavaDoc props) {
675         if (null != props) {
676
677             // Look for and set JDBCInfo entries. Use Enumeration instead of
678
// iterator because former gets default values while latter does
679
// not.
680
for (Enumeration JavaDoc e = props.propertyNames(); e.hasMoreElements();) {
681                 String JavaDoc name = (String JavaDoc) e.nextElement();
682                 String JavaDoc value = props.getProperty(name);
683
684                 if (name.equals(USE_UNIQUE_TABLE_NAMES)) {
685                     if (! StringHelper.isEmpty(value)) {
686                         uniqueTableName =
687                             Boolean.valueOf(value).booleanValue();
688                     }
689                     continue;
690                 }
691
692                 StringTokenizer JavaDoc nameParser =
693                     new StringTokenizer JavaDoc(name, String.valueOf(DOT));
694
695                 // Get the last element from key which is separated by DOT.
696
String JavaDoc indicator = null;
697                 while (nameParser.hasMoreTokens()) {
698                     indicator = nameParser.nextToken();
699                 }
700
701                 if (indicator.startsWith(INDICATOR_JDBC_PREFIX)) {
702                     setJDBCInfoEntry(userJdbcInfoMap, name, value, indicator);
703                 } else {
704                     if (logger.isLoggable(Logger.INFO)) {
705                         logger.info(
706                                 I18NHelper.getMessage(
707                                         messages,
708                                         "MSG_UnexpectedUserProp", // NOI18N
709
name, value)); // NOI18N
710
}
711                 }
712             }
713         }
714     }
715
716     /**
717      * Sets whether or not unique table names should be generated.
718      * @param uniqueTableName If <code>true</code>, tables names will be
719      * unique.
720      */

721     public void setUniqueTableName(boolean uniqueTableName) {
722         this.uniqueTableName = uniqueTableName;
723     }
724
725     /**
726      * Returns the String name of the SQL type for a given JDBC type.
727      * @param jdbcType One of the values from java.sql.Types.
728      * @return Name of SQL type corresponding to given jdbcType.
729      */

730     public String JavaDoc getSQLTypeName(int jdbcType) {
731         String JavaDoc rc = null;
732
733         // The name is in sqlInfo if it was loaded from one of our
734
// vendor-specific properties files.
735
Object JavaDoc o = sqlInfo.get(new Integer JavaDoc(jdbcType));
736         if (null != o) {
737             rc = (String JavaDoc) o;
738         } else {
739             // Otherwise, user has overriden, e.g. java.lang.String -> CLOB.
740
rc = getJdbcTypeName(jdbcType);
741         }
742
743         return rc;
744     }
745
746     /**
747      * Returns JDBC type information corresponding to the given field name
748      * and type. If fieldName is <code>null</code> or there is no
749      * fieldName - specific information already existing, the default for the
750      * given fieldType is returned. Otherwise, information specific to the
751      * fieldName is returned. <em>Note:</em> It is possible to have a field
752      * in a class have the same name as another class; this mechanism is not
753      * robust in that case:
754      * <pre>
755      * class Foo { }
756      *
757      * class MyFoo {
758      * Foo Foo = new Foo();
759      * }
760      * </pre>
761      * We think this obfuscation unlikely to occur.
762      * @param fieldName Name of field for which information is needed. May
763      * be null, in which case only fieldType is used to determine returned
764      * information.
765      * @param fieldType Name of a Java type.
766      * @return JDBCInfo representing the field or type.
767      */

768     public JDBCInfo getJDBCInfo(String JavaDoc fieldName, String JavaDoc fieldType) {
769         JDBCInfo rc = null;
770
771         if (logger.isLoggable(Logger.FINEST)) {
772             logger.finest("Entering MappingPolicy.getJDBCInfo: " // NOI18N
773
+ fieldName + ", " + fieldType); // NOI18N
774
}
775
776         if (null != fieldName) {
777
778             // If fieldName is given, try to find a JDBCInfo using that name.
779
// Looking up fieldName only makes sense in userJdbcInfoMap
780
// which contains the user's overrides.
781
rc = (JDBCInfo) userJdbcInfoMap.get(fieldName);
782             if (null != rc && (! rc.isComplete())) {
783
784                 // There is an override for the field named fieldName, but
785
// it is not complete, i.e., not all possible information
786
// about the field was provided in the user override.
787
//
788
// Choose a JDBCInfo to use to complete the information in rc.
789
// If the user override specifies a type and there is
790
// information about that type for the database, use that.
791
// Otherwise, use the given fieldType.
792
JDBCInfo ji = null;
793                 if (rc.hasJdbcType()) {
794                     ji = getdbJDBCInfo(rc.getJdbcType());
795                 }
796                 if (null == ji) {
797                     ji = getdbJDBCInfo(fieldType);
798                 }
799
800                 // Fill in the rest of the fields in rc with values from ji.
801
rc.complete(ji);
802             }
803         }
804
805         if (null == rc) {
806
807             // Either fieldName is null, or there is no JDBCInfo specific to
808
// fieldName, so use fieldType.
809
rc = getdbJDBCInfo(fieldType);
810         }
811
812         // If dbJdbcInfoMap has an entry for rc's jdbc type, replace rc's jdbc
813
// type with the result of the mapping. This allows, for example, a
814
// user to specify that a field should be represented by a CLOB, when
815
// the database and/or driver do not support that but do support
816
// LONGVARCHAR (e.g. Sybase).
817
JDBCInfo ji = getdbJDBCInfo(rc.getJdbcType());
818         rc.override(ji);
819
820         if (logger.isLoggable(Logger.FINEST)) {
821             logger.finest("Leaving MappingPolicy.getJDBCInfo: " // NOI18N
822
+ fieldName + ", " + fieldType // NOI18N
823
+ " => " + rc); // NOI18N
824
}
825
826         return rc;
827     }
828
829     /**
830      * Gets the JDBCInfo corresponding to the type in the given JDBCInfo.
831      * I.e., it maps from one JDBCInfo to another on the basis of their
832      * types.
833      * @param ji JDBCInfo
834      * @return a JDBCInfo
835      * @throws IllegalArgumentException if <code>type</code> is not recognized
836      * as being a valid member of java.sql.Types. Note that only a subset of
837      * the types in java.sql.Types are recognized.
838      */

839     private JDBCInfo getdbJDBCInfo(int jdbcType) {
840         String JavaDoc typename = getJdbcTypeName(jdbcType);
841         return (JDBCInfo) dbJdbcInfoMap.get(typename);
842     }
843
844     /**
845      * Gets the JDBCInfo for the given fieldType
846      * @param fieldType Name of the type of a field
847      * @return a JDBCInfo for the given fieldType
848      */

849     private JDBCInfo getdbJDBCInfo(String JavaDoc fieldType) {
850         JDBCInfo rc = (JDBCInfo) dbJdbcInfoMap.get(fieldType);
851         
852         if (null == rc) {
853             
854             // There is also nothing provided for the field's
855
// type, so use a BLOB.
856
rc = (JDBCInfo) dbJdbcInfoMap.get("BLOB"); // NOI18N
857
}
858         return rc;
859     }
860
861     /**
862      * Returns the boxed form of the java.sql.Types value corresponding to the
863      * given name.
864      * @param jdbcStringType Name of the value to return.
865      * @return Value from java.sql.Types, wrapped into an Integer, or null if
866      * jdbcTypeName is not that of a recognized JDBC type.
867      */

868     static Integer JavaDoc getJdbcType(String JavaDoc jdbcTypeName) {
869         return (Integer JavaDoc) jdbcTypes.get(jdbcTypeName.toUpperCase());
870     }
871
872     /**
873      * Provides a String that can be recognized as a policy to override the
874      * default length of a field.
875      * @param className name of a class
876      * @param fieldName name of a field in that class
877      * @return a String that can be used as the name of a length override
878      * for a field in a class.
879      */

880     public static String JavaDoc getOverrideForLength(
881             String JavaDoc className, String JavaDoc fieldName) {
882         
883         return className
884             + DOT + fieldName
885             + DOT + DatabaseGenerationConstants.INDICATOR_JDBC_LENGTH;
886     }
887
888     /**
889      * Provides a String that can be recognized as a policy to override the
890      * default nullability of a field.
891      * @param className name of a class
892      * @param fieldName name of a field in that class
893      * @return a String that can be used as the name of a nullability override
894      * for a field in a class.
895      */

896     public static String JavaDoc getOverrideForNullability(
897             String JavaDoc className, String JavaDoc fieldName) {
898         
899         return className
900             + DOT + fieldName
901             + DOT + DatabaseGenerationConstants.INDICATOR_JDBC_NULLABLE;
902     }
903
904     /**
905      * Provides a String that can be recognized as a policy to override the
906      * default precision of a field.
907      * @param className name of a class
908      * @param fieldName name of a field in that class
909      * @return a String that can be used as the name of a precision override
910      * for a field in a class.
911      */

912     public static String JavaDoc getOverrideForPrecision(
913             String JavaDoc className, String JavaDoc fieldName) {
914         
915         return className
916             + DOT + fieldName
917             + DOT + DatabaseGenerationConstants.INDICATOR_JDBC_PRECISION;
918     }
919
920     /**
921      * Provides a String that can be recognized as a policy to override the
922      * default scale of a field.
923      * @param className name of a class
924      * @param fieldName name of a field in that class
925      * @return a String that can be used as the name of a scale override
926      * for a field in a class.
927      */

928     public static String JavaDoc getOverrideForScale(
929             String JavaDoc className, String JavaDoc fieldName) {
930         
931         return className
932             + DOT + fieldName
933             + DOT + DatabaseGenerationConstants.INDICATOR_JDBC_SCALE;
934     }
935
936     /**
937      * Provides a String that can be recognized as a policy to override the
938      * default type of a field.
939      * @param className name of a class
940      * @param fieldName name of a field in that class
941      * @return a String that can be used as the name of a type override
942      * for a field in a class.
943      */

944     public static String JavaDoc getOverrideForType(
945             String JavaDoc className, String JavaDoc fieldName) {
946         
947         return className
948             + DOT + fieldName
949             + DOT + DatabaseGenerationConstants.INDICATOR_JDBC_TYPE;
950     }
951
952
953     /**
954      * Provide the String name of a JDBC type, as per java.sql.Types.
955      * @param type A value from java.sql.Types
956      * @return the String name corresponding to <code>type</code>
957      * @throws IllegalArgumentException if <code>type</code> is not recognized
958      * as being a valid member of java.sql.Types. Note that only a subset of
959      * the types in java.sql.Types are recognized.
960      */

961     public static String JavaDoc getJdbcTypeName(int type) throws
962             IllegalArgumentException JavaDoc {
963         String JavaDoc rc = (String JavaDoc) jdbcTypeNames.get(new Integer JavaDoc(type));
964         if (null == rc) {
965             throw new IllegalArgumentException JavaDoc();
966         }
967         return rc;
968     }
969
970     //
971
// In the getZZZName methods below, we lookup a policy and determine a
972
// name based on that policy. Note that the keys used for lookup are
973
// created from the given name(s), so that the result of looking up a
974
// policy might actually be the name that is returned.
975
//
976

977     /**
978      * Returns the name of a table for a given class, as per current policy.
979      * @param name Basis for what the returned table should be named, for
980      * example the unqualified name of a class.
981      * @param uniqueName Used if the current policy is to return a unique
982      * name. Client must provide a name that is unique to them.
983      * @return Name to be used for table. Regardless of the current policy,
984      * the name is different from other names returned during the current run
985      * of {@link DatabaseGenerator.generate}.
986      */

987     // XXX FIXME: If the user needs to provide a unique name, why do we
988
// invoke getUniqueGlobalName on it?
989
public String JavaDoc getTableName(String JavaDoc name, String JavaDoc uniqueName) {
990         StringBuffer JavaDoc key =
991             new StringBuffer JavaDoc(name).append(DOT).append(INDICATOR_TABLE_NAME);
992         String JavaDoc rc = (String JavaDoc)namingPolicy.get(key.toString());
993
994         if (rc == null) {
995             rc = (String JavaDoc)namingPolicy.get(DEFAULT_TABLE_KEY);
996         }
997
998         if (uniqueTableName) {
999             rc = TABLE_NAME_HASH_UPPERCASE;
1000        }
1001
1002        if (rc.equals(TABLE_NAME_UPPERCASE)) {
1003            rc = name.toUpperCase();
1004        } else if (rc.equals(TABLE_NAME_AS_CLASSNAME)) {
1005            rc = name;
1006        } else if (rc.equals(TABLE_NAME_HASH_UPPERCASE)) {
1007            rc = uniqueName.toUpperCase();
1008        }
1009        
1010        return getUniqueGlobalName(rc, tableNameMaxLength);
1011    }
1012
1013    /**
1014     * Returns the name of a column for a given field in a given class. The
1015     * column name will be unique within the table.
1016     * @param className Name of the class containing the field.
1017     * @param fieldName Name of the field for which a column name is returned.
1018     * @param tableName Name of the table in which the column name is created.
1019     * @return Name of a column that is unique within the named table.
1020     */

1021    public String JavaDoc getColumnName(String JavaDoc className, String JavaDoc fieldName,
1022            String JavaDoc tableName) {
1023
1024        // Get column naming policy based on className and fieldName
1025
StringBuffer JavaDoc key = new StringBuffer JavaDoc(className)
1026            .append(DOT).append(fieldName)
1027            .append(DOT).append(INDICATOR_COLUMN_NAME);
1028        String JavaDoc rc = (String JavaDoc)namingPolicy.get(key.toString());
1029
1030        if (rc == null) {
1031            // No fieldName specific policy, so use default for className
1032
key = new StringBuffer JavaDoc(className)
1033                .append(DOT).append(FIELD_BASE)
1034                .append(DOT).append(INDICATOR_COLUMN_NAME);
1035            rc = (String JavaDoc)namingPolicy.get(key.toString());
1036        }
1037
1038        if (rc == null) {
1039            // No overriding policy, so use overall default.
1040
rc = (String JavaDoc)namingPolicy.get(DEFAULT_COLUMN_KEY);
1041        }
1042
1043        if (rc.equals(COLUMN_NAME_UPPERCASE)) {
1044            rc = fieldName.toUpperCase();
1045        } else if (rc.equals(COLUMN_NAME_AS_FIELDNAME)) {
1046            rc = fieldName;
1047        }
1048
1049        return getUniqueLocalName(rc, tableName, columnNameMaxLength);
1050    }
1051
1052    /**
1053     * Returns the name of the column which represents a foreign key in the
1054     * named table.
1055     * @param tableName Name of the table in which the FK column will be
1056     * created.
1057     * @param columnName Name of PK column in referenced table.
1058     * @return Name of the FK column in the named table.
1059     */

1060    // XXX Does this really need to be public?
1061
// XXX Rename to getFKColumnName
1062
public String JavaDoc getConstraintColumnName(String JavaDoc tableName,
1063            String JavaDoc columnName) {
1064
1065       return getUniqueLocalName(
1066               new StringBuffer JavaDoc(tableName)
1067                   .append(DatabaseConstants.NAME_SEPARATOR)
1068                   .append(columnName).toString(),
1069               tableName,
1070               columnNameMaxLength);
1071    }
1072
1073    /**
1074     * Returns the name of a constraint corresponding to the named
1075     * relationship.
1076     * @param relName Name of a relationship.
1077     * @param uniqueId Id that can be appened to relName to distinguish it
1078     * from other relNames in the database. Will be appended only if
1079     * {@link #uniqueTableName} is true.
1080     * @return Name of a constraint.
1081     */

1082    public String JavaDoc getConstraintName(String JavaDoc relName, String JavaDoc uniqueId) {
1083        String JavaDoc rc = (String JavaDoc)namingPolicy.get(DEFAULT_CONSTRAINT_KEY);
1084
1085        if (rc.equals(CONSTRAINT_NAME_UPPERCASE)) {
1086            rc = FK_PREFIX + relName.toUpperCase();
1087        }
1088
1089        if (uniqueTableName) {
1090            rc += uniqueId;
1091        }
1092
1093        rc = getUniqueGlobalName(rc, constraintNameMaxLength);
1094
1095        if (logger.isLoggable(Logger.FINER)) {
1096            logger.finer("MappingPolicy.getConstraintName: " // NOI8N
1097
+ relName + " -> " + rc); // NOI18N
1098
}
1099
1100        return rc;
1101    }
1102
1103    /**
1104     * Returns the name of a PK constraint, unique-ified as required.
1105     * @param tableName Name of a table on which a constraint is to be placed.
1106     * @return Name of a constraint on named table.
1107     */

1108    public String JavaDoc getPrimaryKeyConstraintName(String JavaDoc tableName) {
1109        return getUniqueGlobalName(PK_PREFIX + tableName, constraintNameMaxLength);
1110    }
1111
1112    /**
1113     * Returns the name of a join table which joins the tables that correspond
1114     * to the two named classes.
1115     * @param className1 Name of one class to join.
1116     * @param className2 Name of the other class to join.
1117     * @return Name of a join table.
1118     */

1119    public String JavaDoc getJoinTableName(String JavaDoc className1, String JavaDoc className2) {
1120        String JavaDoc rc = (String JavaDoc)namingPolicy.get(DEFAULT_JOIN_TABLE_KEY);
1121
1122        if (rc.equals(JOIN_TABLE_NAME_UPPERCASE)) {
1123            rc = (className1 + className2).toUpperCase();
1124        }
1125        return getUniqueGlobalName(rc, tableNameMaxLength);
1126    }
1127
1128    /**
1129     * Return a unique name for a column. The column will be unique within
1130     * the named table.
1131     * @param colName Name of the column
1132     * @param tableName Name of the table.
1133     * @return A unique name for colName within tableName.
1134     */

1135    private String JavaDoc getUniqueLocalName(
1136            String JavaDoc colName, String JavaDoc tableName, int maxLen) {
1137
1138        return getUniqueName(colName, tableName, maxLen);
1139    }
1140
1141    /**
1142     * Return a unique name for the given name. It will be "globally" unique
1143     * between invocations of method {@link #resetCounter}; the first use of
1144     * a MappingPolicy instance is "reset".
1145     * @param name Name for which a unique name is returned.
1146     * @return A unique name for given name.
1147     */

1148    private String JavaDoc getUniqueGlobalName(String JavaDoc name, int maxLen) {
1149        return getUniqueName(name, GLOBAL_NAMING_SPACE, maxLen);
1150    }
1151
1152    /**
1153     * Return a unique name for name. It will be unique within the given
1154     * namespace.
1155     * @param name Name for which a unique name is returned.
1156     * @param space Namespace in which the returned name is unique.
1157     * @return A unique name for given name.
1158     */

1159    private String JavaDoc getUniqueName(String JavaDoc name, String JavaDoc namespace, int maxLen) {
1160        String JavaDoc rc = name;
1161
1162        // Reserve MAX_LEN_COUNTER characters for unique-ifying digits.
1163
maxLen -= MAX_LEN_COUNTER;
1164
1165        // Name cannot be more than maxLen chars long.
1166
if (name.length() > maxLen) {
1167            rc = name.substring(0, maxLen);
1168        }
1169
1170        // Convert to upper case for uniqueing comparisons below.
1171
String JavaDoc nameUpper = rc.toUpperCase();
1172
1173        // Ensure the name we create is not a reserved word by comparing
1174
// nameUpper against reserved words.
1175
if (defaultReservedWords.contains(nameUpper)
1176            || reservedWords.contains(nameUpper)) {
1177
1178            // Append a character that is not used as the last char of any
1179
// existing reserved words. Make sure we have space for this plus
1180
// for any uniqueing below. Length-limit both rc and nameUpper, so
1181
// that the value in the namespace and the end result have the same
1182
// length.
1183
maxLen -= MAX_LEN_RESERVED;
1184            if (rc.length() > maxLen) {
1185                // Limit nameUpper as well as rc because we need to do uniqueing
1186
// in a case-insensitve fashion.
1187
nameUpper = nameUpper.substring(0, maxLen);
1188                rc = rc.substring(0, maxLen);
1189            }
1190            nameUpper += RESERVED_WORD_UNRESERVER;
1191            rc += RESERVED_WORD_UNRESERVER;
1192        }
1193        
1194        Set JavaDoc names = (Set JavaDoc) namespaces.get(namespace);
1195
1196        if (names == null) {
1197            // Name is first entry in namespace, therefore already unique, no
1198
// need to append counter.
1199
names = new HashSet JavaDoc();
1200            names.add(nameUpper);
1201            namespaces.put(namespace, names);
1202
1203        } else if (names.contains(nameUpper)) {
1204            // Name is already in namespace, so make a different name by
1205
// appending a count to given name.
1206
counter++;
1207            rc += DatabaseConstants.NAME_SEPARATOR + counter;
1208
1209        } else {
1210            // Add new name to namespace.
1211
names.add(nameUpper);
1212        }
1213
1214        return rc;
1215    }
1216
1217    //
1218
// Accessors for SQL formatting Strings.
1219
//
1220

1221    /**
1222     * @return the SQL for a statement separator.
1223     */

1224    String JavaDoc getStatementSeparator() {
1225        return statementSeparator;
1226    }
1227
1228    /**
1229     * @return the SQL for starting a "create table".
1230     */

1231    String JavaDoc getCreateTableStart() {
1232        return createTableStart;
1233    }
1234
1235    /**
1236     * @return the SQL for ending a "create table".
1237     */

1238    String JavaDoc getCreateTableEnd() {
1239        return createTableEnd;
1240    }
1241
1242    /**
1243     * @return the SQL for a "drop table".
1244     */

1245    String JavaDoc getDropTable() {
1246        return dropTable;
1247    }
1248
1249    /**
1250     * @return the SQL for "add constraint".
1251     */

1252    String JavaDoc getAlterTableAddConstraintStart() {
1253        return alterTableAddConstraintStart;
1254    }
1255
1256    /**
1257     * @return the SQL for "drop constraint".
1258     */

1259    String JavaDoc getAlterTableDropConstraint() {
1260        return alterTableDropConstraint;
1261    }
1262
1263    /**
1264     * @return the SQL for adding a primary key constraint.
1265     */

1266    String JavaDoc getPrimaryKeyConstraint() {
1267        return primaryKeyConstraint;
1268    }
1269
1270    /**
1271     * @return the SQL for adding a foreign key constraint.
1272     */

1273    String JavaDoc getForeignKeyConstraint() {
1274        return foreignKeyConstraint;
1275    }
1276
1277    /**
1278     * @return the SQL for indicating column nullability
1279     */

1280    String JavaDoc getColumnNullability() {
1281        return columnNullability;
1282    }
1283
1284    /**
1285     * @return the SQL for indicating LOB column logging
1286     */

1287    String JavaDoc getLobLogging() {
1288        return lobLogging;
1289    }
1290
1291    //
1292
// This method and the 4 subsequent ones initialize a MappingPolicy
1293
// instance from a give Properties object.
1294
//
1295

1296    /**
1297     * Initialize this MappingPolicy as per the values in the given
1298     * properties.
1299     * @param props Properties for initializing this MappingPolicy
1300     */

1301    private void init(Properties JavaDoc props) {
1302        // Use Enumeration instead of iterator because former gets default
1303
// values while latter does not.
1304
for (Enumeration JavaDoc e = props.propertyNames(); e.hasMoreElements();) {
1305            String JavaDoc name = (String JavaDoc) e.nextElement();
1306            String JavaDoc value = props.getProperty(name);
1307
1308            if (name.equals(RESERVED_WORDS)) {
1309                initReservedWords(value);
1310                continue;
1311            }
1312                
1313            // The indicator is the last DOT-separated substring in name.
1314
String JavaDoc indicator = null;
1315            StringTokenizer JavaDoc nameParser =
1316                new StringTokenizer JavaDoc(name, String.valueOf(DOT));
1317            while (nameParser.hasMoreTokens()) {
1318                indicator = nameParser.nextToken();
1319            }
1320
1321            if (indicator.equals(INDICATOR_SQL_FORMAT)) {
1322                setSqlFormatEntry(name, value);
1323
1324            } else if (indicator.startsWith(INDICATOR_JDBC_PREFIX)) {
1325                setJDBCInfoEntry(dbJdbcInfoMap, name, value, indicator);
1326                
1327            } else if (indicator.equals(INDICATOR_MAXIMUM_LENGTH)) {
1328                setLengthEntry(name, value);
1329                
1330            } else if (indicator.equals(INDICATOR_TABLE_NAME) ||
1331                       indicator.equals(INDICATOR_COLUMN_NAME) ||
1332                       indicator.equals(INDICATOR_JOIN_TABLE_NAME) ||
1333                       indicator.equals(INDICATOR_CONSTRAINT_NAME)) {
1334                setNamingEntry(name, value);
1335
1336            } else {
1337                setSQLInfoEntry(name, value);
1338            }
1339        }
1340    }
1341
1342    /**
1343     * Initializes the <code>reservedWords</code> field.
1344     * @param res Comma-separated list of reserved words.
1345     */

1346    private void initReservedWords(String JavaDoc res) {
1347        StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(res, ",");
1348        while (st.hasMoreTokens()) {
1349            reservedWords.add(st.nextToken().trim());
1350        }
1351    }
1352
1353    //
1354
// These methods each set a value in one of our maps.
1355
//
1356

1357    /**
1358     * Sets a SQL formatting property in this MappingPolicy.
1359     * @param name Name of the policy property, including its indicator.
1360     * @param indicator The indicator, alone, which should start with
1361     * "sql-format".
1362     * @param value Value to be bound to that property.
1363     */

1364    private void setSqlFormatEntry(String JavaDoc name, String JavaDoc value) {
1365        if (value != null) {
1366            if (name.startsWith(STATEMENT_SEPARATOR_INDICATOR)) {
1367                statementSeparator = value;
1368
1369            } else if (name.startsWith(CREATE_TABLE_START_INDICATOR)) {
1370                createTableStart = value;
1371
1372            } else if (name.startsWith(CREATE_TABLE_END_INDICATOR)) {
1373                createTableEnd = value;
1374
1375            } else if (name.startsWith(DROP_TABLE_INDICATOR)) {
1376                dropTable = value;
1377
1378            } else if (name.startsWith(ALTER_TABLE_ADD_CONSTRAINT_START_INDICATOR)) {
1379                alterTableAddConstraintStart = value;
1380
1381            } else if (name.startsWith(ALTER_TABLE_DROP_CONSTRAINT_INDICATOR)) {
1382                alterTableDropConstraint = value;
1383
1384            } else if (name.startsWith(PRIMARY_KEY_CONSTRAINT_INDICATOR)) {
1385                primaryKeyConstraint = value;
1386
1387            } else if (name.startsWith(FOREIGN_KEY_CONSTRAINT_INDICATOR)) {
1388                foreignKeyConstraint = value;
1389                
1390            } else if (name.startsWith(COLUMN_NULLABILITY_INDICATOR)) {
1391                columnNullability = value;
1392                
1393            } else if (name.startsWith(LOB_LOGGING_INDICATOR)) {
1394                lobLogging = value;
1395            }
1396        }
1397    }
1398
1399    /**
1400     * Sets a JDBC property in this MappingPolicy.
1401     * @param Map into which property is set.
1402     * @param name Name of the policy property, including its indicator.
1403     * @param indicator The indicator, alone, which should start with
1404     * "jdbc-".
1405     * @param value Value to be bound to that property.
1406     */

1407    private void setJDBCInfoEntry(
1408            Map JavaDoc jdbcInfoMap, String JavaDoc name, String JavaDoc value, String JavaDoc indicator) {
1409
1410        if (value != null) {
1411
1412            // Get substring that is before the indicator, which is the name
1413
// of a type or of a particular field.
1414
String JavaDoc fieldOrType = name;
1415            int i = name.indexOf(DOT + indicator);
1416            if (i > 0) {
1417                fieldOrType = name.substring(0, i);
1418            }
1419
1420            JDBCInfo ji = (JDBCInfo) jdbcInfoMap.get(fieldOrType);
1421
1422            try {
1423                if (null != ji) {
1424                    ji.setValue(value, indicator);
1425                } else {
1426                    ji = new JDBCInfo();
1427                    ji.setValue(value, indicator);
1428                    jdbcInfoMap.put(fieldOrType, ji);
1429                }
1430            } catch (JDBCInfo.IllegalJDBCTypeException ex) {
1431                String JavaDoc msg = I18NHelper.getMessage(
1432                        messages,
1433                        "EXC_InvalidJDBCTypeName", // NOI18N
1434
value, fieldOrType);
1435                logger.log(Logger.SEVERE, msg);
1436                throw new IllegalArgumentException JavaDoc(msg);
1437            }
1438        }
1439    }
1440
1441    /**
1442     * Sets a name length attribute.
1443     * @param name Name of the attribute to set. Should be
1444     * INDICATOR_TABLE_NAME, INDICATOR_COLUMN_NAME, or
1445     * INDICATOR_CONSTRAINT_NAME.
1446     * @param value Value to which attribute is set.
1447     */

1448    private void setLengthEntry(String JavaDoc name, String JavaDoc value) {
1449        if (value != null) {
1450
1451            int val = Integer.valueOf(value).intValue();
1452
1453            if (name.startsWith(INDICATOR_TABLE_NAME)) {
1454                tableNameMaxLength = val;
1455
1456            } else if (name.startsWith(INDICATOR_COLUMN_NAME)) {
1457                columnNameMaxLength = val;
1458
1459            } else if (name.startsWith(INDICATOR_CONSTRAINT_NAME)) {
1460                constraintNameMaxLength = val;
1461            }
1462        }
1463    }
1464
1465    /**
1466     * Set a naming property in this MappingPolicy.
1467     * @param name Name of the policy property.
1468     * @param value Value to be bound to that property.
1469     */

1470    private void setNamingEntry(String JavaDoc name, String JavaDoc value) {
1471        namingPolicy.put(name, value);
1472    }
1473
1474    /**
1475     * Sets a JDBC-to-SQL mapping property, that is, a mapping from a JDBC
1476     * type to a SQL type.
1477     * @param name Name of a JDBC type (see {@link java.sql.Types}).
1478     * @param value SQL type to be used to represent given JDBC type in
1479     * database.
1480     */

1481    private void setSQLInfoEntry(String JavaDoc name, String JavaDoc value) {
1482        sqlInfo.put(getJdbcType(name), value);
1483    }
1484
1485    /**
1486     * @param databaseType Name of a type of database.
1487     * @return Name of a file containing a description of properties for
1488     * named database type.
1489     */

1490    private static String JavaDoc getPropertyFileName(String JavaDoc databaseType) {
1491        return PROPERTY_FILE_DIR + databaseType + PROPERTY_FILE_EXT;
1492    }
1493
1494    /**
1495     * Debug support.
1496     * @return A description of this MappingPolicy in string form.
1497     * Basically, all it's "interesting" values.
1498     */

1499    public String JavaDoc toString() {
1500        StringBuffer JavaDoc rc = new StringBuffer JavaDoc(
1501            "statementSeparator=" + statementSeparator // NOI18N
1502
+ "\ncreateTableStart=" + createTableStart // NOI18N
1503
+ "\ncreateTableEnd=" + createTableEnd // NOI18N
1504
+ "\ndropTable=" + dropTable // NOI18N
1505
+ "\nalterTableAddConstraintStart=" + alterTableAddConstraintStart // NOI18N
1506
+ "\nalterTableDropConstraint=" + alterTableDropConstraint // NOI18N
1507
+ "\nprimaryKeyConstraint=" + primaryKeyConstraint // NOI18N
1508
+ "\nforeignKeyConstraint=" + foreignKeyConstraint // NOI18N
1509
+ "\ncolumnNullability=" + columnNullability // NOI18N
1510
+ "\nlobLogging=" + lobLogging // NOI18N
1511
+ "\ntableNameMaxLength=" + tableNameMaxLength // NOI18N
1512
+ "\ncolumnNameMaxLength=" + columnNameMaxLength // NOI18N
1513
+ "\nconstraintNameMaxLength=" + constraintNameMaxLength // NOI18N
1514
+ "\nuniqueTableName=" + uniqueTableName // NOI18N
1515
+ "\ncounter=" + counter // NOI18N
1516
+ "\n\n"); // NOI18N
1517
rc.append(" dbJdbcInfoMap:\n").append(stringifyMap(dbJdbcInfoMap)); // NOI18N
1518
rc.append(" userJdbcInfoMap:\n").append(stringifyMap(userJdbcInfoMap)); // NOI18N
1519
rc.append(" sqlInfo:\n").append(stringifyMap(sqlInfo)); // NOI18N
1520
rc.append(" namingPolicy:\n").append(stringifyMap(namingPolicy)); // NOI18N
1521
rc.append(" namespaces:\n").append(stringifyMap(namespaces)); // NOI18N
1522
rc.append(" reservedWords:\n").append(stringifySet(reservedWords)); // NOI18N
1523
return rc.toString();
1524    }
1525
1526    /**
1527     * Debug support.
1528     * @param m Map whose keys & values are to be returned in a string.
1529     * @return The string form of m's keys and values, each pair separated
1530     * from the next by a newline, with keys separated from values by '='.
1531     */

1532    private String JavaDoc stringifyMap(Map JavaDoc m) {
1533        StringBuffer JavaDoc rc = new StringBuffer JavaDoc();
1534        for (Iterator JavaDoc i = m.entrySet().iterator(); i.hasNext();) {
1535            Map.Entry JavaDoc e = (Map.Entry JavaDoc) i.next();
1536            rc.append(e.getKey()).append("=") // NOI18N
1537
.append(e.getValue()).append("\n"); // NOI18N
1538
}
1539        return rc.toString();
1540    }
1541
1542    /**
1543     * Debug support
1544     * @param s Set whose values are to be returned in a string
1545     * @return values from the given set, separated by spaces, up to 6 per
1546     * line.
1547     */

1548    private String JavaDoc stringifySet(Set JavaDoc s) {
1549        StringBuffer JavaDoc rc = new StringBuffer JavaDoc();
1550        int count = 0;
1551        for (Iterator JavaDoc i = s.iterator(); i.hasNext();) {
1552            rc.append(i.next()).append(" "); // NOI18N
1553
if (count++ > 6) {
1554                rc.append("\n"); // NOI18N
1555
count = 0;
1556            }
1557        }
1558        return rc.toString();
1559    }
1560}
1561            
1562
Popular Tags