001: /*
002: * This file is part of the GeOxygene project source files.
003: *
004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
005: * the development and deployment of geographic (GIS) applications. It is a open source
006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
007: * National Mapping Agency).
008: *
009: * See: http://oxygene-project.sourceforge.net
010: *
011: * Copyright (C) 2005 Institut Géographique National
012: *
013: * This library is free software; you can redistribute it and/or modify it under the terms
014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
015: * either version 2.1 of the License, or any later version.
016: *
017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser General Public License along with
022: * this library (see file LICENSE if present); if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: *
025: */
026:
027: package fr.ign.cogit.geoxygene.util.loader;
028:
029: import java.io.BufferedReader;
030: import java.math.BigDecimal;
031: import java.sql.Connection;
032: import java.sql.ResultSet;
033: import java.sql.SQLException;
034: import java.sql.Statement;
035: import java.util.List;
036:
037: import fr.ign.cogit.geoxygene.datatools.Geodatabase;
038:
039: /**
040: * Usage interne. Appele par EasyLoader ou par la Console.
041: * En faisant une boucle sur la liste allTables, genere le fichier de mapping,
042: * remplit le dico et genere les classes java.
043: * On peut eventuellement choisir le nom des tables (si on a acces a une ligne de commande :
044: * passer un BufferedReader (parametre "in" non null au constructeur).
045: *
046: * <br> AB 18 juillet 2005 : gestion des clés primaires (possiblité d'utiliser une clé primaire existante).
047: *
048: * @author Thierry Badard & Arnaud Braun
049: * @version 1.1
050: *
051: */
052:
053: public class XMLJavaDicoGenerator {
054:
055: private BufferedReader in;
056: private Geodatabase data;
057: private OjbXMLGenerator theXMLGenerator;
058: private DicoGenerator theDicoGenerator;
059: private String geOxygeneData; // path
060: private String geOxygeneMapping; // path
061: private List allTables;
062: private String extentClassName;
063: private String extentMappingFileName;
064: private boolean flagInterroTable;
065: private String packageName;
066: private String userName;
067:
068: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
069: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
070: public XMLJavaDicoGenerator(BufferedReader In, Geodatabase Data,
071: boolean FlagInterroTable, List AllTables,
072: String GeOxygeneData, String GeOxygeneMapping,
073: String PackageName, String ExtentClassName,
074: String mappingFileName, String extentMappingFileName) {
075: if (In != null)
076: in = In;
077: data = Data;
078: try {
079: userName = data.getConnection().getMetaData().getUserName();
080: } catch (SQLException e) {
081: e.printStackTrace();
082: }
083: theDicoGenerator = new DicoGenerator(data);
084: extentClassName = ExtentClassName;
085: geOxygeneData = GeOxygeneData;
086: geOxygeneMapping = GeOxygeneMapping;
087: theXMLGenerator = new OjbXMLGenerator(data, geOxygeneMapping,
088: mappingFileName, extentClassName, extentMappingFileName);
089: flagInterroTable = FlagInterroTable;
090: allTables = AllTables;
091: packageName = PackageName;
092:
093: }
094:
095: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
096: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
097: public void writeAll() {
098:
099: theXMLGenerator.writeFileHeader();
100:
101: try {
102: Connection conn = data.getConnection();
103: Statement stm = conn.createStatement();
104:
105: // boucle sur les tables geographiques a traiter
106: for (int i = 0; i < allTables.size(); i++) {
107:
108: boolean flagInterroFields = false; // examen individuel des champs ?
109: System.out.println();
110:
111: String sqlTableName = (String) allTables.get(i);
112: String javaClassName = packageName + "."
113: + sqlTableName.substring(0, 1).toUpperCase()
114: + sqlTableName.substring(1).toLowerCase();
115:
116: if (flagInterroTable) {
117: Message m = new Message(in, "table : "
118: + sqlTableName
119: + "\nnom propose pour la classe Java : "
120: + javaClassName + "\nOK ?", "o", "n");
121: String r = m.getAnswer();
122: if (r.compareToIgnoreCase("n") == 0) {
123: m = new Message(
124: in,
125: "entre le nom de la classe Java (ATTENTION sans oublier le package en prefixe):");
126: javaClassName = m.getAnswer();
127: }
128: }
129:
130: System.out.println("table : " + sqlTableName
131: + "\nnom de la classe java : " + javaClassName);
132: JavaGenerator aJavaGenerator = new JavaGenerator(
133: geOxygeneData, javaClassName, extentClassName,
134: packageName);
135: aJavaGenerator.writeHeader();
136: theXMLGenerator.writeClassHeader(javaClassName,
137: sqlTableName);
138: theDicoGenerator.writeFeature(javaClassName);
139:
140: if (flagInterroTable) {
141: Message m = new Message(
142: in,
143: "examen individuel des attributs (sinon on les charge tous) ?",
144: "o", "n");
145: String r = m.getAnswer();
146: if (r.compareToIgnoreCase("o") == 0)
147: flagInterroFields = true;
148: }
149:
150: theDicoGenerator.writeAttribute(javaClassName, "id",
151: "int");
152:
153: // Boucle sur les colonnes
154: String query = getQueryColumnName(sqlTableName,
155: userName);
156: conn.commit();
157: ResultSet rs = (ResultSet) stm.executeQuery(query);
158: while (rs.next()) {
159:
160: // La colonne SQL
161: String sqlColumnName = rs.getString(1);
162:
163: // Le type SQL
164: String sqlDbmsType = rs.getString(2);
165:
166: // Si c'est le champ COGITID : on passe
167: if (sqlColumnName.compareToIgnoreCase("COGITID") == 0)
168: continue;
169:
170: // bidouille speciale Oracle pour traiter le cas des entiers ...
171: if (data.getDBMS() == Geodatabase.ORACLE)
172: if (rs.getObject(3) != null) {
173: int dataScale = ((BigDecimal) rs
174: .getObject(3)).intValue();
175: if ((sqlDbmsType
176: .compareToIgnoreCase("NUMBER") == 0)
177: && (dataScale == 0))
178: sqlDbmsType = "INTEGER";
179: }
180: // fin de la bidouille
181:
182: // bidouille speciale Oracle pour traiter le cas des booleans ...
183: // Les booleans ne sont pas reconnus par Oracle JDBC.
184: // On suppose que CHAR(1) est un boolean
185: if (data.getDBMS() == Geodatabase.ORACLE)
186: if (rs.getObject(3) != null) {
187: int dataScale = ((BigDecimal) rs
188: .getObject(3)).intValue();
189: if ((sqlDbmsType
190: .compareToIgnoreCase("CHAR") == 0)
191: && (dataScale == 1))
192: sqlDbmsType = "BOOLEAN";
193: }
194: // fin de la bidouille
195:
196: // Le type Java
197: String javaType = getJavaType(sqlDbmsType);
198:
199: // Gestion exception
200: if (javaType.compareTo("") == 0)
201: continue;
202:
203: // Le nom Java
204: String javaFieldName = sqlColumnName.toLowerCase();
205:
206: // attention : le champ portant la geometrie doit s'appeler geom (heritage de FT_Feature")
207: if ((javaType.compareToIgnoreCase("GM_Object") == 0)) {
208: javaFieldName = "geom";
209: }
210: // attention : population est un nom de champ de FT_Feature
211: if (javaFieldName.equals("population"))
212: javaFieldName = "population_";
213:
214: if (flagInterroFields) {
215: if ((javaFieldName.compareToIgnoreCase("id") != 0)
216: && (javaFieldName
217: .compareToIgnoreCase("geom") != 0)) {
218: Message m = new Message(in, "colonne "
219: + sqlColumnName
220: + " : on la charge ?", "o", "n");
221: String r = m.getAnswer();
222: if (r.compareToIgnoreCase("o") == 0) {
223: m = new Message(
224: in,
225: "colonne : "
226: + sqlColumnName
227: + "\nnom propose pour l'attribut Java : "
228: + javaFieldName
229: + "\nOK ?", "o", "n");
230: r = m.getAnswer();
231: if (r.compareToIgnoreCase("n") == 0) {
232: m = new Message(in,
233: "entre le nom de l'attribut Java :");
234: javaFieldName = m.getAnswer();
235: }
236: theXMLGenerator.writeField(
237: javaFieldName, sqlColumnName,
238: sqlDbmsType);
239: if ((javaFieldName
240: .compareToIgnoreCase("id") != 0)
241: && (javaFieldName
242: .compareToIgnoreCase("geom") != 0))
243: aJavaGenerator.writeField(javaType,
244: javaFieldName);
245: theDicoGenerator.writeAttribute(
246: javaClassName, javaFieldName,
247: javaType);
248: }
249: } else {
250: theXMLGenerator.writeField(javaFieldName,
251: sqlColumnName, sqlDbmsType);
252: theDicoGenerator.writeAttribute(
253: javaClassName, javaFieldName,
254: javaType);
255: }
256:
257: } else {
258: theXMLGenerator.writeField(javaFieldName,
259: sqlColumnName, sqlDbmsType);
260:
261: // Ecriture du champ dans la classe java
262: // Ces champs ne sont pas écrits dans la classe java car ils héritent de FT_Feature
263: if ((javaFieldName.compareToIgnoreCase("id") != 0)
264: && (javaFieldName
265: .compareToIgnoreCase("geom") != 0))
266: aJavaGenerator.writeField(javaType,
267: javaFieldName);
268:
269: // Ecriture dans le dictionnaire des données
270: theDicoGenerator.writeAttribute(javaClassName,
271: javaFieldName, javaType);
272: }
273: System.out.println(" nom sql : " + sqlColumnName
274: + "\n nom java : " + javaFieldName);
275:
276: }
277:
278: rs.close();
279: theXMLGenerator.writeClassBottom();
280: aJavaGenerator.writeBottom();
281: }
282:
283: stm.close();
284:
285: } catch (Exception e) {
286: e.printStackTrace();
287: }
288:
289: theXMLGenerator.writeFileBottom();
290: theXMLGenerator.writeInFile();
291: }
292:
293: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
294: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
295: private String getQueryColumnName(String tableName, String user) {
296: if (data.getDBMS() == Geodatabase.ORACLE)
297: return getQueryColumnNameOracle(tableName);
298: else if (data.getDBMS() == Geodatabase.POSTGIS)
299: return getQueryColumnNamePostgis(tableName, user);
300: return null;
301: }
302:
303: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
304: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
305: private String getQueryColumnNameOracle(String tableName) {
306: return "SELECT COLUMN_NAME, DATA_TYPE, DATA_SCALE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '"
307: + tableName + "'";
308: }
309:
310: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
311: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
312: private String getQueryColumnNamePostgis(String tableName,
313: String user) {
314: return "select pg_attribute.attname, pg_type.typname "
315: + "from pg_attribute, pg_type, pg_class, pg_user "
316: + "where pg_class.oid = pg_attribute.attrelid "
317: + "and pg_attribute.attnum>0 "
318: + "and pg_attribute.atttypid = pg_type.oid "
319: + "and pg_class.relowner = pg_user.usesysid "
320: + "and pg_user.usename = '" + user.toLowerCase() + "' "
321: + "and pg_class.relname='" + tableName.toLowerCase()
322: + "'";
323: }
324:
325: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
326: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
327: private String getJavaType(String sqlType) {
328: try {
329: if (data.getDBMS() == Geodatabase.ORACLE)
330: return oracleType2javaType(sqlType);
331: else if (data.getDBMS() == Geodatabase.POSTGIS)
332: return postgisType2javaType(sqlType);
333: return "";
334: } catch (Exception e) {
335: e.printStackTrace();
336: return "";
337: }
338: }
339:
340: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
341: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
342: private String oracleType2javaType(String oracle) throws Exception {
343: if (oracle.compareToIgnoreCase("VARCHAR2") == 0)
344: return "String";
345: else if (oracle.compareToIgnoreCase("VARCHAR") == 0)
346: return "String";
347: else if (oracle.compareToIgnoreCase("CHAR") == 0)
348: return "String";
349: else if (oracle.compareToIgnoreCase("NUMBER") == 0)
350: return "double";
351: else if (oracle.compareToIgnoreCase("FLOAT") == 0)
352: return "double";
353: else if (oracle.compareToIgnoreCase("INTEGER") == 0)
354: return "int";
355: else if (oracle.compareToIgnoreCase("BOOLEAN") == 0)
356: return "boolean";
357: else if (oracle.compareToIgnoreCase("SDO_GEOMETRY") == 0)
358: return "GM_Object";
359: else
360: throw new Exception("type non reconnu : " + oracle);
361: }
362:
363: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
364: ///////////////////////////////////////////////////////////////////////////////////////////////////////////
365: private String postgisType2javaType(String postgis)
366: throws Exception {
367: if (postgis.compareToIgnoreCase("varchar") == 0)
368: return "String";
369: else if (postgis.compareToIgnoreCase("bpchar") == 0)
370: return "String";
371: else if (postgis.compareToIgnoreCase("float8") == 0)
372: return "double";
373: else if (postgis.compareToIgnoreCase("float4") == 0)
374: return "float";
375: else if (postgis.compareToIgnoreCase("int4") == 0)
376: return "int";
377: else if (postgis.compareToIgnoreCase("int8") == 0)
378: return "long";
379: else if (postgis.compareToIgnoreCase("bool") == 0)
380: return "boolean";
381: else if (postgis.compareToIgnoreCase("geometry") == 0)
382: return "GM_Object";
383: else
384: throw new Exception("type non reconnu : " + postgis);
385: }
386:
387: }
|