1 package org.devaki.nextobjects.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import java.awt.Cursor;
17 import java.io.File;
18 import java.io.FileOutputStream;
19 import java.io.FileInputStream;
20 import java.io.IOException;
21 import java.util.Map;
22 import java.io.PrintStream;
23 import java.io.PrintWriter;
24 import java.net.URL;
25 import java.util.Iterator;
26 import java.util.Properties;
27 import javax.xml.transform.Result;
28 import javax.xml.transform.Templates;
29 import javax.xml.transform.TransformerConfigurationException;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.transform.TransformerFactory;
32 import javax.xml.transform.sax.SAXResult;
33 import javax.xml.transform.sax.SAXSource;
34 import javax.xml.transform.sax.SAXTransformerFactory;
35 import javax.xml.transform.sax.TemplatesHandler;
36 import javax.xml.transform.sax.TransformerHandler;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.tools.ant.BuildException;
40 import org.apache.tools.ant.Project;
41 import org.apache.tools.ant.ProjectHelper;
42 import org.apache.xml.serializer.OutputPropertiesFactory;
43 import org.apache.xml.serializer.Serializer;
44 import org.apache.xml.serializer.SerializerFactory;
45 import org.devaki.nextobjects.NextObjects;
46 import org.devaki.nextobjects.ui.editor.SqlEditor;
47 import org.devaki.nextobjects.ui.main.NOLog;
48 import org.devaki.nextobjects.workspace.models.Database;
49 import org.devaki.nextobjects.workspace.models.PhysicalModel;
50 import org.devaki.nextobjects.workspace.models.columns.Column;
51 import org.devaki.nextobjects.workspace.models.columns.ColumnType;
52 import org.devaki.nextobjects.workspace.models.graphics.LineView;
53 import org.devaki.nextobjects.workspace.models.objects.BaseClass;
54 import org.devaki.nextobjects.workspace.models.objects.Constraint;
55 import org.devaki.nextobjects.workspace.models.objects.InheritanceLink;
56 import org.devaki.nextobjects.workspace.models.objects.Table;
57 import org.xml.sax.ErrorHandler;
58 import org.xml.sax.InputSource;
59 import org.xml.sax.SAXException;
60 import org.xml.sax.XMLReader;
61 import org.xml.sax.helpers.XMLReaderFactory;
62 /***
63 * This class is responsible for starting torque-generator It also write
64 * '${project}-schema.xml' it also write torque's project.properties additional
65 * build.properties might be passed to torque-gen throught
66 * APP_HOME/defaultbuild.properties
67 *
68 * @author <a href="mailto:eflorent@devaki.org">Emmanuel Florent</a>
69 */
70 public class TorqueWrapper
71 {
72 /*** Description of the Field */
73 private static boolean pursue = true;
74 /*** Torque's projects-schema file */
75 private static File buildFile =
76 new File(
77 NOPreferences.getProperty("nextobjects.io.torque.home")
78 + File.separator
79 + "build-torque.xml");
80 /*** log4j logging system */
81 private static Log logger = LogFactory.getLog(ModelMan.class.getName());
82 /*** Constructor do nothing except avoid instanciation */
83 public TorqueWrapper()
84 {
85 }
86 /***
87 * Description of the Method
88 *
89 * @param pDatabase Description of the Parameter
90 */
91 private void prepareBuild(final PhysicalModel pDatabase)
92 {
93 this.clean();
94 this.inheritColumns(pDatabase);
95 this.makeBuildProperties(pDatabase);
96 this.writeIdTableSchema(pDatabase);
97 try
98 {
99 this.writeXML(pDatabase);
100 }
101 catch (TransformerConfigurationException e)
102 {
103 logger.error(e.getMessage());
104 e.printStackTrace();
105 }
106 catch (TransformerException e)
107 {
108 logger.error(e.getMessage());
109 e.printStackTrace();
110 }
111 catch (SAXException e)
112 {
113 logger.error(e.getMessage());
114 }
115 catch (IOException e)
116 {
117 logger.error(e.getMessage());
118 e.printStackTrace();
119 }
120 }
121 /***
122 * Generate Object-Model
123 *
124 * @param db the database
125 */
126 public void genObjectModel(final PhysicalModel db)
127 {
128 prepareBuild(db);
129 runTask(db, "om");
130 }
131 /***
132 * Generate DTD
133 *
134 * @param db the database
135 */
136 public void genDTD(final PhysicalModel db)
137 {
138 prepareBuild(db);
139 runTask(db, "datadtd");
140 }
141 /***
142 * Generate XML from JDBC
143 *
144 * @param db the database
145 */
146 public void jdbc2xml(final PhysicalModel db)
147 {
148 makeBuildProperties(db);
149 NextObjects.getReference().setCursor(new Cursor(Cursor.WAIT_CURSOR));
150 ClassLoader coreLoader = TorqueWrapper.class.getClassLoader();
151 try
152 {
153 runBuild(coreLoader, "jdbc");
154 }
155 catch (BuildException be)
156 {
157 logger.error(be.getMessage());
158 }
159
160 NextObjects.getReference().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
161
162 }
163 /***
164 * Run create-db task
165 *
166 * @param db the database
167 */
168 public void createDB(final PhysicalModel db)
169 {
170 makeBuildProperties(db);
171 runTask(db, "create-db");
172 }
173 /***
174 * Run insert-sql task
175 *
176 * @param db the database
177 */
178 public void insertSQL(final PhysicalModel db)
179 {
180 makeBuildProperties(db);
181 runTask(db, "insert-sql");
182 }
183 /***
184 * Inherits all columns move all the columns of a table to it's immediate
185 * parent
186 *
187 * @param model Description of the Parameter
188 * @see http://db.apache.org/torque/inheritance-guide.html
189 */
190 public void inheritColumns(final PhysicalModel model)
191 {
192 Iterator itInhrLnk = model.getInheritanceLinks().iterator();
193 while (itInhrLnk.hasNext())
194 {
195 inheritColumn(model, (InheritanceLink) itInhrLnk.next());
196 }
197 model.getPanel().repaint();
198 }
199 /***
200 * Inherits all columns move all the columns of a table to it's immediate
201 * parent
202 *
203 * @param tmpLink the inheritance link
204 * @param pModel Description of the Parameter
205 * @see http://db.apache.org/torque/inheritance-guide.html
206 */
207 private void inheritColumn(
208 final PhysicalModel pModel,
209 final InheritanceLink tmpLink)
210 {
211 if (!((Table) tmpLink.getChildClass()).getSkipSql())
212 {
213 Column tmpColumn = null;
214
215 for (int i = 0; i < tmpLink.getChildClass().getData().size(); i++)
216 {
217
218 tmpColumn =
219 new Column(
220 (Column) tmpLink.getChildClass().getData().elementAt(
221 i));
222 tmpLink.getParentClass().getData().addElement(tmpColumn);
223 }
224 tmpColumn = null;
225 if (((BaseClass) tmpLink.getParentClass()).getColumnForId("class")
226 == null)
227 {
228 tmpColumn = new Column("class",
229 "class",
230 new ColumnType("INTEGER", null, ""),
231 "",
232 "",
233 false,
234 true,
235 false,
236 false,
237 false,
238 "",
239 "",
240 "single",
241 "",
242 "",
243 "",
244 (BaseClass) tmpLink.getParentClass()
245 );
246 tmpLink.getParentClass().getData().addElement(tmpColumn);
247 }
248 ((Table) tmpLink.getChildClass()).setSkipSql(true);
249 tmpColumn =
250 ((Table) tmpLink.getParentClass()).getColumnForId("class");
251 tmpColumn.getInheritanceLinks().addElement(tmpLink);
252 Iterator itCst = pModel.getConstraints().iterator();
253 while (itCst.hasNext())
254 {
255 Constraint cst = (Constraint) itCst.next();
256 if (cst.getParentClass() == tmpLink.getChildClass())
257 {
258 cst.setParentClass(tmpLink.getParentClass());
259 ((LineView) cst.getObjectView()).computeBestPoints();
260 }
261 if (cst.getChildClass() == tmpLink.getChildClass())
262 {
263 cst.setChildClass(tmpLink.getParentClass());
264 ((LineView) cst.getObjectView()).computeBestPoints();
265 }
266 }
267 }
268 }
269 /***
270 * Generate Documentation
271 *
272 * @param pDatabase the database
273 */
274 public void genDoc(final PhysicalModel pDatabase)
275 {
276 prepareBuild(pDatabase);
277 runTask(pDatabase, "doc");
278 runTask(pDatabase, "java-doc");
279 }
280 /***
281 * Generate OJB
282 *
283 * @param pDatabase the database
284 */
285 public void genOjb(final PhysicalModel pDatabase)
286 {
287 prepareBuild(pDatabase);
288 runTask(pDatabase, "ojb-repository");
289 runTask(pDatabase, "ojb-model");
290 }
291 /***
292 * Generate SQL for the current model
293 *
294 * @param pDatabase the database
295 */
296 public void genSQL(final PhysicalModel pDatabase)
297 {
298 prepareBuild(pDatabase);
299 runTask(pDatabase, "sql");
300 }
301 /***
302 * Write the torque's id-table-schema
303 *
304 * @param pDatabase Description of the Parameter
305 */
306 public void writeIdTableSchema(final PhysicalModel pDatabase)
307 {
308 String xml =
309 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" "
310 + "standalone=\"no\" ?>";
311 xml += "<!DOCTYPE database "
312 + "SYSTEM \"http://db.apache.org/torque/dtd/database_3_1.dtd\">";
313 xml += "<database name=\"" + pDatabase.getId() + "\">";
314 xml += " <table name=\"ID_TABLE\" idMethod=\"idbroker\">";
315 xml += " <column name=\"ID_TABLE_ID\" required=\"true\" "
316 + " primaryKey=\"true\" type=\"INTEGER\"/>";
317 xml += " <column name=\"TABLE_NAME\" required=\"true\" "
318 + " size=\"255\" type=\"VARCHAR\"/>";
319 xml += " <column name=\"NEXT_ID\" type=\"INTEGER\"/>";
320 xml += " <column name=\"QUANTITY\" type=\"INTEGER\"/>";
321 xml += " <unique><unique-column name=\"TABLE_NAME\"/></unique>";
322 xml += " </table></database>";
323 String filePath =
324 NOPreferences.getProperty("nextobjects.io.torque.home")
325 + File.separator
326 + "schema"
327 + File.separator
328 + "id-table-schema.xml";
329
330 try
331 {
332
333 PrintWriter out = new PrintWriter(new FileOutputStream(filePath));
334 out.write(xml);
335 out.flush();
336 out.close();
337 logger.info("Generated " + filePath);
338 pursue = true;
339 }
340 catch (IOException e)
341 {
342 pursue = false;
343 logger.error("error writing " + filePath);
344 logger.error(e.getMessage());
345 }
346 }
347 /***
348 * Call to ant for the torque project
349 *
350 * @param pDatabase the database
351 * @param pTarget the torque target
352 */
353 public void runTask(
354 final PhysicalModel pDatabase,
355 final String pTarget)
356 {
357
358
359 if (pursue)
360 {
361 SwingWorker worker = new SwingWorker()
362 {
363 /***
364 * Swingworker thread init.
365 *
366 * @return Description of the Return Value
367 */
368 public final Object construct()
369 {
370 NextObjects.getReference().setCursor(
371 new Cursor(Cursor.WAIT_CURSOR));
372 ClassLoader coreLoader =
373 TorqueWrapper.class.getClassLoader();
374 try
375 {
376 runBuild(coreLoader, pTarget);
377 logger.info("Done with " + pTarget);
378 if (pTarget.equals("sql"))
379 {
380 String filePath =
381 new StringBuffer()
382 .append(
383 NOPreferences.getProperty(
384 "nextobjects.io.torque.home"))
385 .append(File.separator)
386 .append("src")
387 .append(File.separator)
388 .append("sql")
389 .append(File.separator)
390 .append(ModelMan.getCurrentModel().getId())
391 .append("-schema.sql")
392 .toString();
393 NOLog.showPane(1);
394
395 SqlEditor.setFile(new File(filePath));
396 }
397 }
398 catch (BuildException be)
399 {
400 logger.error(be.getMessage());
401 }
402
403 NextObjects.getReference().setCursor(
404 new Cursor(Cursor.DEFAULT_CURSOR));
405
406 return null;
407 }
408 };
409
410 worker.start();
411 worker=null;
412 }
413 else
414 {
415 logger.error("An error have occured, I give up.");
416 }
417 }
418 /***
419 * Call to ant for the torque project
420 *
421 * @param coreLoader the class loader
422 * @param pTarget the torque target
423 */
424 public void runBuild(
425 final ClassLoader coreLoader,
426 final String pTarget)
427 {
428 NOLog.showPane(0);
429
430 final Project project = new Project();
431 project.setCoreLoader(coreLoader);
432 NOBuildLogger bl = new NOBuildLogger();
433 bl.setOutputPrintStream(new PrintStream(NOLog.getJTextOutStream()));
434 bl.setErrorPrintStream(new PrintStream(NOLog.getJTextOutStream()));
435 project.addBuildListener(bl);
436 project.fireBuildStarted();
437 project.init();
438 project.setUserProperty(
439 "ant.version",
440 org.apache.tools.ant.Main.getAntVersion());
441 project.setUserProperty("ant.file", buildFile.getAbsolutePath());
442 ProjectHelper.configureProject(project, buildFile);
443 project.executeTarget(pTarget);
444 }
445 /*** Make clean. */
446 public void clean()
447 {
448 String filePath =
449 new StringBuffer()
450 .append(NOPreferences.getProperty("nextobjects.io.torque.home"))
451 .append(File.separator)
452 .append("src")
453 .append(File.separator)
454 .toString();
455 logger.info("Cleaning Torque input :" + filePath);
456 File temp = new File(filePath);
457 NOFileUtil.deleteFile(temp);
458 temp.mkdir();
459 filePath =
460 new StringBuffer()
461 .append(NOPreferences.getProperty("nextobjects.io.torque.home"))
462 .append(File.separator)
463 .append("schema")
464 .append(File.separator)
465 .toString();
466 temp = new File(filePath);
467 NOFileUtil.deleteFile(temp);
468 temp.mkdir();
469 }
470 /***
471 * create the file build.properties that is neccessary to run Torque
472 *
473 * @param pDatabase Description of the Parameter
474 */
475 public void makeBuildProperties(final PhysicalModel pDatabase)
476 {
477 Properties build = new Properties();
478
479 build.put("torque.home", NOPreferences.getProperty("nextobjects.io.torque.home"));
480 build.put("project", pDatabase.getId());
481 build.put(
482 "database",
483 ((Database) NOPreferences
484 .TORQUE_DB
485 .elementAt(pDatabase.getDbType()))
486 .getCode());
487 build.put("targetPackage", pDatabase.getPackageName());
488 build.put("createDatabaseUrl", pDatabase.getCreateDatabaseUrl());
489 build.put("buildDatabaseUrl", pDatabase.getBuildDatabaseUrl());
490 build.put("databaseUrl", pDatabase.getBuildDatabaseUrl());
491 build.put("torque.database.schema", pDatabase.getSchema());
492 build.put(
493 "databaseDriver",
494 ((Database) NOPreferences
495 .TORQUE_DB
496 .elementAt(pDatabase.getDbType()))
497 .getDriver());
498 build.put("databaseUser", pDatabase.getDatabaseUser());
499 build.put("databasePassword", pDatabase.getDatabasePassword());
500 build.put("databaseHost", pDatabase.getDatabaseHost());
501 build.put("schemaDirectory", "schema");
502
503 Properties overwrite = new Properties();
504 File fp =
505 new File(
506 NOPreferences.APP_HOME
507 + File.separator
508 + "defaultbuild.properties");
509 try
510 {
511 FileInputStream inStream = new FileInputStream(fp);
512 overwrite.load(inStream);
513 }
514 catch (IOException e)
515 {
516 logger.error(e.getMessage());
517 }
518 build.putAll((Map) overwrite.clone());
519
520 try
521 {
522 String s =
523 NOPreferences.getProperty("nextobjects.io.torque.home")
524 + File.separator
525 + "build.properties";
526 FileOutputStream fops = new FileOutputStream(s);
527 build.store(fops, "--- properties for Torque build ---");
528 fops.flush();
529 fops.close();
530 logger.info("Generated " + s);
531 pursue = true;
532 }
533 catch (IOException e)
534 {
535 logger.error("Error writing Torque's build.properties");
536 logger.error(e.getMessage());
537 pursue = false;
538 }
539 }
540 /***
541 * Transform the model to XML
542 *
543 * @param pDatabase the database
544 * @throws SAXException SAXException
545 * @throws IOException IOException
546 * @throws TransformerException TransformerException
547 */
548 public void writeXML(final PhysicalModel pDatabase)
549 throws TransformerException, SAXException, IOException
550 {
551 File tmpModel = File.createTempFile("gen", "pdm");
552 NOFileManager.save(pDatabase, tmpModel);
553
554 String path = "xsl/pdm2torque.xsl";
555 ClassLoader cl = NextObjects.getReference().getClass().getClassLoader();
556 URL url = cl.getResource(path);
557 InputSource xslSource = new InputSource(url.toExternalForm());
558 InputSource xmlSource = new InputSource(tmpModel.getAbsolutePath());
559 FileOutputStream out =
560 new FileOutputStream(
561 NOPreferences.getProperty("nextobjects.io.torque.home")
562 + File.separator
563 + "schema"
564 + File.separator
565 + pDatabase.getName()
566 + "-schema.xml");
567
568 TransformerFactory tFactory = TransformerFactory.newInstance();
569
570
571 if (tFactory.getFeature(SAXSource.FEATURE)
572 && tFactory.getFeature(SAXResult.FEATURE))
573 {
574
575 SAXTransformerFactory saxTFactory =
576 ((SAXTransformerFactory) tFactory);
577
578 TemplatesHandler templatesHandler =
579 saxTFactory.newTemplatesHandler();
580
581 XMLReader reader = XMLReaderFactory.createXMLReader();
582 reader.setContentHandler(templatesHandler);
583 NOErrorHandler erh = new NOErrorHandler();
584 reader.setErrorHandler((ErrorHandler) erh);
585 reader.setEntityResolver(new NODTDResolver());
586
587 reader.parse(xslSource);
588
589 Templates templates = templatesHandler.getTemplates();
590
591 TransformerHandler handler =
592 saxTFactory.newTransformerHandler(templates);
593
594 reader.setContentHandler(handler);
595
596
597 reader.setProperty(
598 "http://xml.org/sax/properties/lexical-handler",
599 handler);
600 Serializer serializer =
601 SerializerFactory.getSerializer(
602 OutputPropertiesFactory.getDefaultMethodProperties("xml"));
603 serializer.setOutputStream(out);
604
605
606 Result result = new SAXResult(serializer.asContentHandler());
607 handler.setResult(result);
608
609 reader.parse(xmlSource);
610 }
611 else
612 {
613 logger.error("The TransformerFactory does not support SAX I/O");
614 }
615 }
616 }