1 /*
2 * PROJECT : DAR Runtime and Tools
3 * COPYRIGHT : Copyright (C) 1999-2004 tim.stephenson@enableit.org
4 * LICENSE : GNU LESSER GENERAL PUBLIC LICENSE
5 * Version 2.1, February 1999
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 package org.enableit.db.darrt.ext;
23
24 import java.io.InputStreamReader;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import org.apache.log4j.Logger;
30 import org.enableit.db.beans.Column;
31 import org.enableit.db.beans.DarrtDbms;
32 import org.enableit.db.beans.Function;
33 import org.enableit.db.beans.Index;
34 import org.enableit.db.beans.Table;
35 import org.enableit.db.beans.View;
36 import org.enableit.db.darrt.AbstractDDLGenerator;
37 import org.enableit.db.darrt.ConfigurationException;
38 import org.enableit.db.darrt.DDLGenerator;
39 import org.enableit.db.darrt.beans.DiffData;
40 import org.exolab.castor.xml.Unmarshaller;
41
42 /***
43 * RDBMS-specific extensions backed by XML files.
44 */
45 public class DeclarativeDDLGenerator
46 extends AbstractDDLGenerator implements DDLGenerator {
47 /***
48 * The Log4J <code>Logger</code> doing the logging.
49 */
50 private static Logger logger
51 = Logger.getLogger(DeclarativeDDLGenerator.class);
52
53 /***
54 * CVS info about this class and its current version
55 */
56 public static final String ABOUT
57 = "$Revision: 1.7 $";
58
59 /***
60 * The config for this instance.
61 */
62 private DarrtDbms dbms;
63
64 /***
65 * Name of this generator.
66 */
67 private String name;
68
69 /***
70 * Default constructor.
71 */
72 public DeclarativeDDLGenerator() {
73 super();
74 }
75
76 /***
77 * Constructor that also sets the resource to configure with.
78 *
79 * @param resourceName The resource name to read.
80 * @throws ConfigurationException If no meta-data definition available
81 * for the specified resourceName.
82 */
83 public DeclarativeDDLGenerator(String resourceName)
84 throws ConfigurationException {
85 this();
86 setResourceName(resourceName);
87 }
88
89 /***
90 * Sets the resource name to read to instantiate from.
91 *
92 * @param resourceName The resource name to read config'n from.
93 * @throws ConfigurationException If no meta-data definition available
94 * for the specified resourceName.
95 */
96 public void setResourceName(String resourceName)
97 throws ConfigurationException {
98 logger.fatal("METHOD_ENTRY: setResourceName: " + resourceName);
99
100 this.name = resourceName;
101
102 try {
103 InputStreamReader isr = new InputStreamReader(
104 this.getClass().getResourceAsStream(resourceName + ".xml"));
105
106 dbms = (DarrtDbms) Unmarshaller.unmarshal(DarrtDbms.class, isr);
107 logger.debug("DBMS alter table parentheses setting: "
108 + dbms.hasParenthesesWrappedDdlColumns());
109 } catch (NullPointerException e) {
110 logger.error(e.getClass().getName() + ":" + e.getMessage(), e);
111 throw new ConfigurationException(e.getMessage(), e);
112 } catch (org.exolab.castor.xml.CastorException e) {
113 logger.error(e.getClass().getName() + ":" + e.getMessage());
114 throw new ConfigurationException(e.getMessage(), e);
115 }
116
117 logger.info("METHOD_EXIT: setResourceName");
118 }
119
120 /***
121 * @return the name of this DDLGenerator.
122 */
123 public String getName() {
124 return name;
125 }
126
127 /***
128 * Create a database object that does not currently exist.
129 *
130 * @param dataObject Java representation of the data object to create.
131 * @return <code>List</code> of DDL statements (<code>String</code> type).
132 */
133 public List getCreate(Object dataObject) {
134 logger.info("METHOD_ENTRY: getCreate");
135
136 List ddlList = new ArrayList();
137 StringBuffer ddl = new StringBuffer();
138
139 if (dataObject instanceof Table) {
140 Table table = (Table) dataObject;
141 List pkCols = new ArrayList() ;
142 List fkCols = new ArrayList() ;
143
144 ddl.append("CREATE TABLE " + table.getName() + "(" + EOL);
145
146 for (int i = 0; i < table.getColumnCount(); i++) {
147 Column col = (Column) table.getColumn(i);
148
149 ddl.append(col.getColName() + " ");
150 ddl.append(getDataType(col.getColType()) + " ");
151 ddl.append(col.getNull().equalsIgnoreCase("false") ? "NOT NULL"
152 : "NULL");
153 if (col.getDefault() != null) {
154 ddl.append(getDefault(col.getDefault())) ;
155 }
156
157 if ("TRUE".equalsIgnoreCase(col.getPrimaryKey())) {
158 pkCols.add(col) ;
159 }
160 if (col.getForeignKey() != null) {
161 fkCols.add(col) ;
162 }
163
164 if ((i + 1) < table.getColumnCount()) {
165 ddl.append("," + EOL);
166 } else {
167 ddl.append(")" + EOL);
168 }
169 }
170
171 ddlList.add(ddl.toString());
172
173 // Add alter table for PK constraint
174 if (pkCols.size() > 0) {
175 ddlList.add(getPKConstraint(table.getName(), pkCols)) ;
176 }
177
178 // Add alter table for FK constraints
179 if (fkCols.size() > 0) {
180 for (Iterator it = fkCols.iterator() ; it.hasNext() ;) {
181 ddlList.add(getFKConstraint(table.getName(), (Column) it.next())) ;
182 }
183 }
184
185 // Now get DDL for any indexes
186 for (int i = 0; i < table.getIndexCount(); i++) {
187 ddlList.addAll(getCreate(table.getIndex(i)));
188 }
189 } else if (dataObject instanceof Column) {
190 Column col = (Column) dataObject;
191 String table = col.getTableName();
192
193 ddl.append("ALTER TABLE " + table + EOL);
194 ddl.append("ADD ");
195 ddl.append(col.getColName() + " ");
196 ddl.append(getDataType(col.getColType()) + " ");
197 ddl.append(col.getNull().equalsIgnoreCase("false") ? "NOT NULL"
198 : "NULL");
199 ddl.append(EOL);
200 ddlList.add(ddl.toString());
201 } else if (dataObject instanceof Index) {
202 ddlList.add(getCreateIndex((Index) dataObject));
203 } else if (dataObject instanceof View) {
204 View view = (View) dataObject;
205
206 if ((view.getDefinition() == null)
207 || (view.getDefinition().trim().length() < 1)) {
208 ddl.append("/* No definition available */");
209 } else if (!view.getDefinition().toUpperCase().startsWith("CREATE VIEW")) {
210 // Oracle
211 ddl.append("CREATE VIEW " + view.getName() + EOL);
212 ddl.append(" AS ");
213 ddl.append(view.getDefinition());
214 } else {
215 // Sybase
216 ddl.append(view.getDefinition());
217 }
218
219 ddlList.add(ddl.toString());
220 } else {
221 ddl.append("Unsupported database object "
222 + dataObject.getClass().getName());
223 }
224
225 logger.info("METHOD_EXIT: getCreate, ddl=" + ddlList);
226
227 return ddlList;
228 }
229
230 /***
231 * @param def The RDBMS-independent default.
232 * @return The RDBMS-specific default.
233 */
234 private String getDefault(String def) {
235 logger.info("METHOD_ENTRY getDefault, def") ;
236 System.out.println("METHOD_ENTRY getDefault, def") ;
237 StringBuffer sb = new StringBuffer() ;
238 sb.append(" ") ;
239 if ("autoincrement".equals(def)) {
240 sb.append(dbms.getAutoincrement()) ;
241 } else if ("CURRENT TIMESTAMP".equals(def)) {
242 sb.append(dbms.getDefault() + " ") ;
243 sb.append(getCurrentTimestamp()) ;
244 } else {
245 sb.append(dbms.getDefault() + " " + def) ;
246 }
247 System.out.println("METHOD_EXIT getDefault, returning: " + sb) ;
248 logger.info("METHOD_EXIT getDefault, returning: " + sb) ;
249 return sb.toString();
250 }
251
252 /***
253 * @param fkCols List of foreign key <code>Columns</code>.
254 * @return Data definition language String.
255 */
256 private String getFKConstraint(String tableName, Column col) {
257 StringBuffer ddl = new StringBuffer();
258 ddl.append("ALTER TABLE ") ;
259 ddl.append(tableName) ;
260 ddl.append(" ADD FOREIGN KEY (") ;
261 ddl.append(col.getColName()) ;
262 ddl.append(")") ;
263 ddl.append(" REFERENCES ") ;
264 ddl.append(col.getForeignKey().getFkTableName()) ;
265 ddl.append(" (") ;
266 ddl.append(col.getForeignKey().getDataColumn().getColName()) ;
267 ddl.append(")") ;
268 return ddl.toString();
269 }
270
271 /***
272 * @param pkCols List of primary key <code>Columns</code>.
273 * @return Data definition language String.
274 */
275 private String getPKConstraint(String tableName, List pkCols) {
276 StringBuffer ddl = new StringBuffer();
277 ddl.append("ALTER TABLE ") ;
278 ddl.append(tableName) ;
279 ddl.append(" ADD ") ;
280 ddl.append(dbms.getPrimaryKey()) ;
281 ddl.append(" (") ;
282 for (Iterator it = pkCols.iterator() ; it.hasNext() ;) {
283 ddl.append(((Column) it.next()).getColName()) ;
284 if (it.hasNext()) {
285 ddl.append(",") ;
286 }
287 }
288 ddl.append(")") ;
289 return ddl.toString();
290 }
291
292 /***
293 * @param diff
294 * @return <code>List</code> of DDL statements (<code>String</code> type).
295 */
296 public List getModify(DiffData diff) {
297 logger.info("METHOD_ENTRY: getModify");
298
299 List ddlList = new ArrayList();
300 StringBuffer ddl = new StringBuffer();
301 Object refObject = diff.getRefObj();
302
303 if (refObject instanceof Column) {
304 Column rColumn = (Column) refObject;
305 Column tColumn = (Column) diff.getTargetObj();
306 String table = diff.getName().substring(0,
307 diff.getName().indexOf("."));
308
309 // Handle column def'n change in one go (supported by most modern dbms)
310 ddl.append("ALTER TABLE " + table + EOL);
311 ddl.append(getModifyColumn(rColumn));
312
313 ddl.append(EOL);
314 ddlList.add(ddl.toString());
315 } else if (refObject instanceof Index) {
316 Index index = (Index) refObject;
317
318 ddl.append("DROP INDEX ");
319 ddl.append(index.getTableName());
320 ddl.append(".");
321 ddl.append(index.getName());
322 ddlList.add(ddl.toString());
323 ddlList.add(getCreateIndex(index));
324 } else {
325 ddl.append("Unsupported database object "
326 + refObject.getClass().getName());
327 }
328
329 logger.info("METHOD_EXIT: getModify, ddl=" + ddlList);
330
331 return ddlList;
332 }
333
334 private String getModifyColumn(Column rColumn) {
335 StringBuffer ddl = new StringBuffer(dbms.getModifyColumn()) ;
336 ddl.append(" ") ;
337 if (dbms.getParenthesesWrappedDdlColumns()) {
338 ddl.append("(");
339 }
340
341 ddl.append(rColumn.getColName() + " ");
342 ddl.append(getDataType(rColumn.getColType()) + " ");
343 ddl.append(rColumn.getNull().equalsIgnoreCase("false") ? "NOT NULL"
344 : "NULL");
345
346 if (dbms.getParenthesesWrappedDdlColumns()) {
347 ddl.append(")");
348 }
349 return ddl.toString();
350 }
351
352 /***
353 * Returns this RDBMS' implementation for the JDBC type.
354 */
355 public String getDataType(String schemaDataType) {
356 logger.info("METHOD_ENTRY: getDataType, schemaDataType="
357 + schemaDataType);
358
359 String baseType = schemaDataType;
360 if (schemaDataType.indexOf("(") > 0) {
361 baseType = schemaDataType.substring(0, schemaDataType.indexOf("(")) ;
362 logger.debug("BaseType: " + baseType) ;
363 }
364 String returnType = baseType ;
365 for (int i = 0; i < dbms.getJdbcMappingCount(); i++) {
366 if (dbms.getJdbcMapping(i).getJdbc().equals(baseType)) {
367 logger.debug("found rdbms specific type: " + dbms.getJdbcMapping(i).getName()) ;
368 returnType = dbms.getJdbcMapping(i).getName();
369
370 break;
371 }
372 }
373 if (schemaDataType.indexOf("(") > 0) {
374 returnType += schemaDataType.substring(schemaDataType.indexOf("(")) ;
375 }
376
377 logger.info("METHOD_EXIT: getDataType, returnType=" + returnType);
378 return returnType;
379 }
380 /***
381 * @see org.enableit.db.darrt.DDLGenerator#getSubstring(java.lang.String, int, int)
382 */
383 public String getSubstring(String colName, int from, int to) {
384 StringBuffer retVal = new StringBuffer("SUBSTR(");
385
386 retVal.append(colName);
387 retVal.append(",");
388 retVal.append(from);
389
390 if (to > 0) {
391 retVal.append(",");
392 retVal.append(to);
393 }
394
395 retVal.append(")");
396
397 return retVal.toString();
398 }
399
400 /***
401 * @see org.enableit.db.darrt.DDLGenerator#getFormattedDate(java.lang.String, java.lang.String)
402 */
403 public String getFormattedDate(String colName, String format) {
404 StringBuffer formattedCol = new StringBuffer("DATEFORMAT(");
405
406 formattedCol.append(colName);
407 formattedCol.append(", '");
408 formattedCol.append(format);
409 formattedCol.append("')");
410
411 return formattedCol.toString();
412 }
413
414 private String getCurrentTimestamp() {
415 StringBuffer sFunc = new StringBuffer() ;
416
417 for (int i = 0 ; i < dbms.getFunctionCount() ; i++) {
418 Function func = dbms.getFunction(i) ;
419 if (func.getName().equals("CURRENT TIMESTAMP")) {
420 sFunc.append(func.getPattern()) ;
421 break ;
422 }
423 }
424 return sFunc.toString() ;
425 }
426
427 /***
428 * @see org.enableit.db.darrt.DDLGenerator#getGenericDefault(java.lang.String)
429 */
430 public String getGenericDefault(String dbmsDefault) {
431 logger.info("METHOD_ENTRY getGenericDefault") ;
432 StringBuffer sFunc = new StringBuffer() ;
433 boolean found = false ;
434
435 if ("autoincrement".equals(dbmsDefault)) {
436 sFunc.append("autoincrement") ;
437 found = true ;
438 } else {
439 for (int i = 0 ; i < dbms.getFunctionCount() ; i++) {
440 Function func = dbms.getFunction(i) ;
441 logger.fatal("Comparing " + func.getPattern()
442 + " to " + dbmsDefault) ;
443 if (func.getPattern().equals(dbmsDefault)) {
444 logger.fatal("... matched") ;
445 sFunc.append(func.getName()) ;
446 found = true;
447 break ;
448 }
449 }
450 }
451
452 if (!found) {
453 logger.warn("No generic default found for: " + dbmsDefault) ;
454 sFunc.append(dbmsDefault) ;
455 }
456 logger.fatal("METHOD_EXIT getGenericDefault, returning:" + sFunc) ;
457 return sFunc.toString() ;
458 }
459 }
This page was automatically generated by Maven