001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: /*
042: * SchemaGenerator.java
043: *
044: * Created on Oct 8, 2007, 3:39:14 PM
045: *
046: * To change this template, choose Tools | Template Manager
047: * and open the template in the editor.
048: */
049: package org.netbeans.modules.masterindex.plugin;
050:
051: import org.netbeans.modules.masterindex.plugin.datamodel.ObjectDefinitionBuilder;
052: import org.netbeans.modules.masterindex.plugin.datamodel.Field;
053: import org.netbeans.modules.masterindex.plugin.datamodel.Lookup;
054: import org.netbeans.modules.masterindex.plugin.datamodel.ObjectDefinition;
055: import org.netbeans.modules.masterindex.plugin.util.PluginDTConstants;
056: import java.io.File;
057: import java.io.IOException;
058: import java.sql.Connection;
059: import java.sql.DriverManager;
060: import java.sql.SQLException;
061: import java.sql.Statement;
062: import java.util.ArrayList;
063: import java.util.HashMap;
064: import java.util.Iterator;
065: import java.util.logging.Level;
066: import net.java.hulp.i18n.Logger;
067: import org.axiondb.AxionException;
068: import org.axiondb.io.AxionFileSystem;
069: import org.axiondb.io.BufferedDataInputStream;
070: import org.netbeans.modules.etl.logger.Localizer;
071: import org.netbeans.modules.etl.logger.LogUtil;
072:
073: /**
074: *
075: * @author Manish
076: */
077: public class TargetDBSchemaGenerator {
078:
079: private static TargetDBSchemaGenerator targetdbSchemaGenerator = null;
080: private Lookup lookup = null;
081: private static ObjectDefinition objDef = null;
082: private Connection conn = null;
083: //eview data model type vs. db data type
084: private String[][] datatypes = { { "string", "VARCHAR" },
085: { "int", "INTEGER" }, { "char", "CHAR" },
086: { "boolean", "BOOLEAN" }, { "date", "DATE" },
087: { "blob", "BLOB" }, { "float", "FLOAT" } };
088: /**
089: * logger
090: */
091: /**
092: * logger
093: */
094: private static transient final Logger mLogger = LogUtil
095: .getLogger(TargetDBSchemaGenerator.class.getName());
096: private static transient final Localizer mLoc = Localizer.get();
097:
098: private TargetDBSchemaGenerator() {
099: }
100:
101: public static TargetDBSchemaGenerator getTargetDBSchemaGenerator() {
102: if (targetdbSchemaGenerator == null) {
103: targetdbSchemaGenerator = new TargetDBSchemaGenerator();
104: }
105: return targetdbSchemaGenerator;
106: }
107:
108: public void createTargetDB(String dbname) {
109: //
110: }
111:
112: public void createTargetDB(String dbdir, String dbname) {
113: //Check if dbdir is valid
114: if (validateDir(dbdir)) {
115: // Init DB
116: initDB(dbdir, dbname);
117: // Create List of Tables to be created
118: //[Note - As FKs reference keys in Primary Table, Parent needs to be created first, build a ordered list]
119: ArrayList tablelist = buildTableList();
120: for (int i = 0; i < tablelist.size(); i++) {
121: createTable(normalizeTableName(tablelist.get(i)
122: .toString()), tablelist.get(i).toString());
123: }
124: }
125: }
126:
127: private void createTable(String NormtableName, String ModelTableName) {
128: try {
129: mLogger.infoNoloc(mLoc.t("PRSR001: Creating Table [ {0}",
130: NormtableName));
131: Statement stmt = conn.createStatement();
132: stmt.execute(createSQL(NormtableName, ModelTableName));
133: } catch (SQLException ex) {
134: mLogger.errorNoloc(mLoc.t("PRSR002: global"), ex);
135: }
136: }
137:
138: private String createSQL(String normtablename, String modeltablename) {
139: String query = "CREATE EXTERNAL TABLE IF NOT EXISTS "
140: + normtablename + " ( "
141: + createSQLTableColumns(modeltablename) + " ) "
142: + createOrganizationString(normtablename);
143: mLogger.infoNoloc(mLoc.t("PRSR002: SQL Executed :{0}", query));
144: return query;
145: }
146:
147: private String createSQLTableColumns(String modeltablename) {
148: StringBuilder columns = new StringBuilder();
149: HashMap colmap = (HashMap) lookup.getLookupMap().get(
150: modeltablename);
151: Iterator iterator = colmap.keySet().iterator();
152: String nonQualifiedTableName = modeltablename
153: .substring(modeltablename.lastIndexOf(".") + 1);
154: ArrayList<Field> fieldsForTable = lookup
155: .getFields(nonQualifiedTableName);
156:
157: while (iterator.hasNext()) {
158: String columnname = iterator.next().toString();
159: String fdatatype = getFieldDataType(fieldsForTable,
160: columnname);
161: if (fdatatype.equals("VARCHAR")) {
162: columns.append(columnname + " "
163: + getFieldDataType(fieldsForTable, columnname)
164: + "("
165: + getFieldSize(fieldsForTable, columnname)
166: + "), ");
167: } else {
168: columns.append(columnname + " "
169: + getFieldDataType(fieldsForTable, columnname)
170: + ", ");
171: }
172: }
173:
174: // Add QueryManager Default Columns into the database if already not modelled (<TableName + Id>)
175: String defaultCol = modeltablename.substring(modeltablename
176: .lastIndexOf(".") + 1)
177: + "Id";
178: if (!colmap.containsKey(defaultCol)) {
179: columns.append(defaultCol + " "
180: + getDataTypeMapping(PluginDTConstants.datatype)
181: + "(" + PluginDTConstants.datasize + "), ");
182: }
183:
184: //Add Reference column to Child Tables for the Parent Table Id Column
185: if (!lookup.getRootName().equals(nonQualifiedTableName)) {
186: //Table Being added is a child table
187: String fk_col = lookup.getRootName() + "Id";
188: if (!colmap.containsKey(fk_col)) {
189: //Check if see if colum is already generated using object.xml
190: columns
191: .append(fk_col
192: + " "
193: + getDataTypeMapping(PluginDTConstants.datatype)
194: + "(" + PluginDTConstants.datasize
195: + "), ");
196: }
197: }
198:
199: columns.append(createPrimaryKeyConstraint(defaultCol));
200: columns.append(createForeignKeyConstraint(modeltablename));
201:
202: return columns.toString();
203: }
204:
205: private String createPrimaryKeyConstraint(String defaultcol) {
206: String PK_Constraint = "CONSTRAINT pk_"
207: + defaultcol.toLowerCase() + " PRIMARY KEY ("
208: + defaultcol + ")";
209: return PK_Constraint;
210: }
211:
212: private String createForeignKeyConstraint(String modeltablename) {
213: String tablename = modeltablename.substring(modeltablename
214: .lastIndexOf(".") + 1);
215: if (!tablename.equals(lookup.getRootName())) {
216: return ", CONSTRAINT fk_"
217: + lookup.getRootName().toLowerCase() + "id"
218: + tablename.toLowerCase() + " FOREIGN KEY ("
219: + lookup.getRootName() + "Id" + ") REFERENCES "
220: + normalizeTableName(lookup.getRootName()) + "("
221: + lookup.getRootName() + "Id" + ")";
222: }
223: return "";
224: }
225:
226: private String createOrganizationString(String normtablename) {
227: String orgstr = "organization(LOADTYPE='delimited' filename='"
228: + normtablename + ".csv" + "' FIELDDELIMITER='|')";
229: return orgstr;
230: }
231:
232: /**
233: * Sets eViewConfig File Object (objectmap.xml conventionally)
234: * @param configpath
235: * @param configfilename
236: * @return boolean
237: */
238: public boolean setEViewConfigFilePath(String configpath,
239: String configfilename) {
240: if (validateDir(configpath)) {
241: if (validateFile(configpath, configfilename)) {
242: return true;
243: } else {
244: mLogger.infoNoloc(mLoc.t(
245: "PRSR019: Invalid Config File : {0}",
246: configfilename));
247: }
248: } else {
249: mLogger.infoNoloc(mLoc.t("PRSR004: Invalid Directory :{0}",
250: configpath));
251: }
252: return false;
253: }
254:
255: private boolean validateDir(String dirpath) {
256: File dbdir = new File(dirpath);
257: if (dbdir.exists()) {
258: if (dbdir.isDirectory()) {
259: return true;
260: } else {
261: mLogger.infoNoloc(mLoc.t(
262: "PRSR005: Directory is not a valid dir :{0}",
263: dirpath));
264: }
265: } else {
266: mLogger.infoNoloc(mLoc.t(
267: "PRSR025: Directory is not a valid dir :{0}",
268: dirpath));
269: }
270: return false;
271: }
272:
273: private boolean validateFile(String filepath, String filename) {
274: boolean ret = false;
275: File dbfile = new File(filepath + PluginDTConstants.fs
276: + filename);
277: if (dbfile.exists()) {
278: if (dbfile.isFile()) {
279: setEviewConfigFile(new File(filepath
280: + PluginDTConstants.fs + filename));
281: createObjectDefModel();
282: ret = true;
283: } else {
284: mLogger.infoNoloc(mLoc.t(
285: "PRSR007: File does not exist :{0}", filename));
286: }
287: } else {
288: mLogger.infoNoloc(mLoc.t(
289: "PRSR008: File [{0} ] does not exist in dir :{1}",
290: filename, filepath));
291: }
292: return ret;
293: }
294:
295: private void initDB(String dbdir, String dbname) {
296: try {
297: Class.forName(PluginDTConstants.DB_DRIVER);
298: String uri = PluginDTConstants.URI_PRIFIX
299: + PluginDTConstants.PS + dbname
300: + PluginDTConstants.PS + dbdir;
301: conn = DriverManager.getConnection(uri);
302: } catch (SQLException ex) {
303: mLogger.errorNoloc(mLoc.t("PRSR009: Exception"), ex);
304: } catch (ClassNotFoundException ex) {
305: mLogger.infoNoloc(mLoc.t("PRSR010: Exception"), ex);
306: }
307: }
308:
309: private static void setEviewConfigFile(File filename) {
310: PluginDTConstants.EVIEW_CONFIG_FILE = filename;
311: }
312:
313: public File getEviewConfigFile() {
314: return PluginDTConstants.EVIEW_CONFIG_FILE;
315: }
316:
317: /*
318: public Lookup getLookup(){
319: return this.lookup;
320: }
321: */
322: private void createObjectDefModel() {
323: AxionFileSystem afs = new AxionFileSystem();
324: File configfile = PluginDTConstants.EVIEW_CONFIG_FILE;
325: if (configfile != null) {
326: if (configfile.exists()) {
327: BufferedDataInputStream bdis = null;
328: try {
329: bdis = afs.openBufferedDIS(configfile);
330: objDef = new ObjectDefinitionBuilder().parse(bdis);
331: addExtraFieldsToParent(objDef);
332: lookup = Lookup.createLookup(objDef);
333: validateEviewModel();
334: } catch (AxionException ex) {
335: mLogger
336: .infoNoloc(mLoc
337: .t(
338: "PRSR018: Error Reading eview config file :{0}",
339: ex.getMessage()));
340: } finally {
341: try {
342: bdis.close();
343: } catch (IOException ex) {
344: mLogger
345: .infoNoloc(mLoc
346: .t(
347: "PRSR011: Error Closing Axion BufferedDataInputStream :{0}",
348: ex.getMessage()));
349: }
350: }
351: } else {
352: mLogger.infoNoloc(mLoc.t(
353: "PRSR012: Unable to find file : {0}",
354: PluginDTConstants.EVIEW_CONFIG_FILE
355: .getAbsolutePath()));
356: }
357: } else {
358: mLogger
359: .infoNoloc(mLoc
360: .t("PRSR013: EView Config File is not available. Set the file using DataSourceReaderFactory.setEViewConfigFilePath()"));
361:
362: }
363: }
364:
365: private static void addExtraFieldsToParent(ObjectDefinition objDef) {
366: String[] sysfields = DefaultSystemFields
367: .getDefaultSystemFields();
368: for (int i = 0; i < sysfields.length; i++) {
369: objDef.addField(i, createExtraFieldObj(sysfields[i]));
370: }
371: }
372:
373: private static Field createExtraFieldObj(String name) {
374: Field newfield = new Field();
375: newfield.setName(name);
376: newfield.setType("string"); //Change Later
377: newfield.setSize(32); //Change Later
378: return newfield;
379: }
380:
381: private ArrayList buildTableList() {
382: ArrayList tlist = new ArrayList();
383: tlist.add(lookup.getRootName());
384: Iterator iterator = lookup.getLookupMap().keySet().iterator();
385: while (iterator.hasNext()) {
386: String key = (String) iterator.next();
387: if ((key).indexOf(".") != -1) {
388: tlist.add(key);
389: }
390: }
391: return tlist;
392: }
393:
394: private String normalizeTableName(String tableNameModel) {
395: String tablename = tableNameModel.substring(tableNameModel
396: .lastIndexOf(".") + 1);
397: return PluginDTConstants.QueryManagerTablePrefix
398: + tablename.toUpperCase();
399: }
400:
401: private String getFieldDataType(ArrayList fields, String colname) {
402: for (int i = 0; i < fields.size(); i++) {
403: if (((Field) fields.get(i)).getName().equals(colname)) {
404: return getDataTypeMapping(((Field) fields.get(i))
405: .getType());
406: }
407: }
408: return null;
409: }
410:
411: private int getFieldSize(ArrayList fields, String colname) {
412: for (int i = 0; i < fields.size(); i++) {
413: if (((Field) fields.get(i)).getName().equals(colname)) {
414: return ((Field) fields.get(i)).getSize();
415: }
416: }
417: return -1;
418: }
419:
420: /**
421: * This method Maps datatypes defined in eview data model with Relational DB datatypes
422: */
423: private String getDataTypeMapping(String datatypeModel) {
424: for (int i = 0; i < datatypes.length; i++) {
425: if (datatypes[i][0].equals(datatypeModel)) {
426: return datatypes[i][1];
427: }
428: }
429: return "NULL";
430: }
431:
432: /**
433: * EView Model object.xml is validated against all child tables containing FK column.
434: * All chld tables must contain ObjectId column for the parent to achieve join condition.
435: * This is validated at schema generation level. If not found compliant, used is blocked to generate
436: * staging schema till proper object.xml is provided.
437: */
438: private void validateEviewModel() {
439: String fkname = this .lookup.getRootName() + "Id";
440: //Check if this is present as a field in all child tables
441: Iterator QChildTableNames = this .lookup.getChildIndexMap()
442: .keySet().iterator();
443: boolean overallstatus = true;
444: while (QChildTableNames.hasNext()) {
445: boolean fkavailable = false;
446: Object Qchildname = QChildTableNames.next();
447: HashMap childfieldmap = (HashMap) this .lookup
448: .getLookupMap().get(Qchildname);
449: Iterator childfields = childfieldmap.keySet().iterator();
450: while (childfields.hasNext()) {
451: String childfield = (String) childfields.next();
452: if (childfield.equals(fkname)) {
453: mLogger.infoNoloc(mLoc
454: .t("Foreign Key Column is available for [ "
455: + Qchildname + " ] !!"));
456: fkavailable = true;
457: break;
458: }
459: }
460: if (!fkavailable) {
461: mLogger.infoNoloc(mLoc.t("FK not available for [ "
462: + Qchildname + " ]"));
463: overallstatus = false;
464: }
465: }
466: if (!overallstatus) {
467: mLogger
468: .infoNoloc(mLoc
469: .t("Object.xml validation failed!.\nGenerate [ "
470: + fkname
471: + " ] field in all the child objects and re-run schema generator with the valid object.xml"));
472: // Fix for BugNo:6666486
473: //System.exit(0);
474: }
475:
476: }
477: }
|