View Javadoc
1   package com.wakaleo.schemaspy;
2   
3   import org.apache.maven.doxia.siterenderer.Renderer;
4   import org.apache.maven.plugins.annotations.Component;
5   import org.apache.maven.plugins.annotations.LifecyclePhase;
6   import org.apache.maven.plugins.annotations.Mojo;
7   import org.apache.maven.plugins.annotations.Parameter;
8   import org.apache.maven.project.MavenProject;
9   import org.apache.maven.reporting.AbstractMavenReport;
10  import org.apache.maven.reporting.MavenReportException;
11  
12  import java.io.File;
13  import java.util.ArrayList;
14  import java.util.List;
15  import java.util.Locale;
16  
17  /**
18   * The SchemaSpy Maven plugin report.
19   *
20   * @author John Smart
21   *           The SchemaSpy Maven plugin This plugin is designed to generate
22   *           SchemaSpy reports for a Maven web site.
23   *
24   *           SchemaSpy (http://schemaspy.sourceforge.net) does not need to be
25   *           installed and accessible on your machine. However, SchemaSpy also
26   *           needs the Graphviz tool (http://www.graphviz.org/) in order to
27   *           generate graphical representations of the table/view relationships,
28   *           so this needs to be installed on your machine.
29   *
30   *           The schemaspy goal invokes the SchemaSpy command-line tool.
31   *           SchemaSpy generates a graphical and HTML report describing a given
32   *           relational database.
33   *
34   */
35  @Mojo(name = "schemaspy", defaultPhase = LifecyclePhase.SITE)
36  public class SchemaSpyReport extends AbstractMavenReport {
37  
38      /**
39       * The output directory for the intermediate report.
40       *
41       */
42      @Parameter(property = "targetDirectory", defaultValue = "${project.build.directory}")
43      private File targetDirectory;
44  
45      /**
46       * The output directory where the final HTML reports will be generated. Note
47       * that the reports are always generated in a directory called "schemaspy".
48       * The output directory refers to the directory in which the "schemaspy"
49       * will be generated.
50       *
51       */
52      @Parameter(property = "outputDirectory", defaultValue = "${project.build.directory}/site")
53      private String outputDirectory;
54  
55      /**
56       * Site rendering component for generating the HTML report.
57       */
58      @Component
59      private Renderer siteRenderer;
60  
61      /**
62       * The Maven project object.
63       */
64      @Parameter(defaultValue = "${project}", readonly = true, required = true)
65      private MavenProject project;
66  
67  
68      /**
69       * The name of the database being analysed.
70       */
71      @Parameter (property = "database", required = true)
72      private String database;
73  
74      /**
75       * The host address of the database being analysed.
76       */
77      @Parameter(property = "host")
78      private String host;
79  
80      /**
81       * The port, required by some drivers.
82       */
83      @Parameter(property = "port")
84      private String port;
85  
86  //    /**
87  //     * The JDBC URL to be used to connect to the database. Rather than defining
88  //     * the database and host names and letting SchemaSpy build the URL, you can
89  //     * alternatively specify the complete JDBC URL using this parameter. If this
90  //     * parameter is defined, it will override the host address (which, as a
91  //     * result, is not needed). Note that you still need to specify the database
92  //     * type, since SchemaSpy uses its own database properties file for extra
93  //     * information about each database.
94  //     *
95  //     * @todo Would it be possible to guess the database type from the form of
96  //     *       the URL?
97  //     */
98  //    @Parameter
99  //    private String jdbcUrl;
100 
101     /**
102      * The type of database being analysed - defaults to ora.
103      */
104     @Parameter (property = "databaseType")
105     private String databaseType;
106 
107     /**
108      * Connect to the database with this user id.
109      */
110     @Parameter(property = "user")
111     private String user;
112 
113     /**
114      * Database schema to use - defaults to the specified user.
115      */
116     @Parameter(property = "schema")
117     private String schema;
118 
119     /**
120      * Database password to use - defaults to none.
121      */
122     @Parameter(property = "password")
123     private String password;
124 
125     /**
126      * If specified, SchemaSpy will look for JDBC drivers on this path, rather
127      * than using the application classpath. Useful if your database has a
128      * non-O/S driver not bundled with the plugin.
129      */
130     @Parameter(property = "pathToDrivers")
131     private String pathToDrivers;
132 
133     /**
134      * Schema description. Displays the specified textual description on summary
135      * pages. If your description includes an equals sign then escape it with a
136      * backslash. NOTE: This field doesn't seem to be used by SchemaSpy in the
137      * current version.
138      */
139     @Parameter(property = "schemaDescription")
140     private String schemaDescription;
141 
142     /**
143      * Only include matching tables/views. This is a regular expression that's
144      * used to determine which tables/views to include. For example: -i
145      * "(.*book.*)|(library.*)" includes only those tables/views with 'book' in
146      * their names or that start with 'library'. You might want to use
147      * "description" with this option to describe the subset of tables.
148      */
149     @Parameter(property = "includeTableNamesRegex")
150     private String includeTableNamesRegex;
151 
152     /**
153      * Exclude matching columns from relationship analysis to simplify the
154      * generated graphs. This is a regular expression that's used to determine
155      * which columns to exclude. It must match table name, followed by a dot,
156      * followed by column name. For example: -x "(book.isbn)|(borrower.address)"
157      * Note that each column name regular expression must be surround by ()'s
158      * and separated from other column names by a |.
159      */
160     @Parameter(property = "excludeColumnNamesRegex")
161     private String excludeColumnNamesRegex;
162 
163     /**
164      * Allow HTML In Comments. Any HTML embedded in comments normally gets
165      * encoded so that it's rendered as text. This option allows it to be
166      * rendered as HTML.
167      */
168     @Parameter(property = "allowHtmlInComments")
169     private Boolean allowHtmlInComments;
170 
171     /**
172      * Comments Initially Displayed. Column comments are normally hidden by
173      * default. This option displays them by default.
174      *
175      * @deprecated this seems to no longer be a supported option in SchemaSpy
176      */
177     @Deprecated
178     @Parameter(property = "commentsInitiallyDisplayed")
179     private Boolean commentsInitiallyDisplayed;
180 
181     /**
182      * Don't include implied foreign key relationships in the generated table
183      * details.
184      */
185     @Parameter(property = "noImplied")
186     private Boolean noImplied;
187 
188     /**
189      * Only generate files needed for insertion/deletion of data (e.g. for
190      * scripts).
191      */
192     @Parameter(property = "noHtml")
193     private Boolean noHtml;
194 
195     /**
196      * Detail of execution logging.
197      */
198     @Parameter(property = "logLevel")
199     private String logLevel;
200 
201     /**
202      * Some databases, like Derby, will crash if you use the old driver object
203      * to establish a connection (eg "connection = driver.connect(...)"). In
204      * this case, set useDriverManager to true to use the
205      * DriverManager.getConnection() method instead (eg "connection =
206      * java.sql.DriverManager.getConnection(...)"). Other databases (eg MySQL)
207      * seem to only work with the first method, so don't use this parameter
208      * unless you have to.
209      */
210     @Parameter(property = "useDriverManager")
211     private Boolean useDriverManager;
212 
213     /**
214      * The CSS Stylesheet. Allows you to override the default SchemaSpyCSS
215      * stylesheet.
216      */
217     @Parameter(property = "cssStylesheet")
218     private String cssStylesheet;
219 
220     /**
221      * Single Sign-On. Don't require a user to be specified with -user to
222      * simplify configuration when running in a single sign-on environment.
223      */
224     @Parameter(property = "singleSignOn")
225     private Boolean singleSignOn;
226 
227     /**
228      * Generate lower-quality diagrams. Various installations of Graphviz (depending on OS
229      * and/or version) will default to generating either higher or lower quality images.
230      * That is, some might not have the "lower quality" libraries and others might not have
231      * the "higher quality" libraries.
232      */
233     @Parameter(property = "lowQuality")
234     private Boolean lowQuality;
235 
236     /**
237      * Generate higher-quality diagrams. Various installations of Graphviz (depending on OS
238      * and/or version) will default to generating either higher or lower quality images.
239      * That is, some might not have the "lower quality" libraries and others might not have
240      * the "higher quality" libraries.
241      */
242     @Parameter(property = "highQuality")
243     private Boolean highQuality;
244 
245     /**
246      * Evaluate all schemas in a database. Generates a high-level index of the schemas
247      * evaluated and allows for traversal of cross-schema foreign key relationships.
248      * Use with -schemaSpec "schemaRegularExpression" to narrow-down the schemas to include.
249      */
250     @Parameter(property = "showAllSchemas")
251     private Boolean showAllSchemas;
252 
253     /**
254      * Evaluate specified schemas.
255      * Similar to -showAllSchemas, but explicitly specifies which schema to evaluate without
256      * interrogating the database's metadata. Can be used with databases like MySQL where a
257      * database isn't composed of multiple schemas.
258      */
259     @Parameter(property = "schemas")
260     private String schemas;
261 
262     /**
263      * No schema required for this database (e.g. derby).
264      */
265     @Parameter(property = "noSchema")
266     private Boolean noSchema;
267 
268     /**
269      * Don't query or display row counts.
270      */
271     @Parameter(property = "noRows")
272     private Boolean noRows;
273 
274     /**
275      * Don't query or display row counts.
276      */
277     @Parameter(property = "noViews")
278     private Boolean noViews;
279 
280     /**
281      * Specifies additional properties to be used when connecting to the database.
282      * Specify the entries directly, escaping the ='s with \= and separating each key\=value
283      * pair with a ;.
284      * 
285      * May also be a file name, useful for hiding connection properties from public logs. 
286      */
287     @Parameter(property = "connprops")
288     private String connprops;
289 
290     /**
291      * Don't generate ads in reports.
292      *
293      * @deprecated will be removed
294      */
295     @Deprecated
296     @Parameter(property = "noAds", defaultValue = "true")
297     private Boolean noAds;
298 
299     /**
300      * Don't generate sourceforge logos in reports.
301      *
302      * @deprecated will be removed
303      */
304     @Deprecated
305     @Parameter(property = "noLogo", defaultValue = "true")
306     private Boolean noLogo;
307 
308     @Parameter(property = "catalog", defaultValue = "%")
309     private String catalog;
310 
311     @Parameter(property = "vizjs", defaultValue = "true")
312     protected boolean vizjs = false;
313 
314     /**
315      * Whether to create the report only on the execution root of a multi-module project.
316      *
317      * @since 5.0.4
318      */
319     @Parameter(property = "runOnExecutionRoot", defaultValue = "false")
320     protected boolean runOnExecutionRoot = false;
321 
322     /**
323      * The SchemaSpy analyser that generates the actual report.
324      * Can be overridden for testing purposes.
325      */
326     private MavenSchemaAnalyzer analyzer;
327 
328     protected void setSchemaAnalyzer(final MavenSchemaAnalyzer analyzer) {
329         this.analyzer = analyzer;
330     }
331 
332     /**
333     * Convenience method used to build the schemaspy command line parameters.
334     *
335     * @param argList the current list of schemaspy parameter options.
336     * @param parameter a new parameter to add
337     * @param value the value for this parameter
338     */
339     private void addToArguments(
340         final List<String> argList, final String parameter, final Boolean value) {
341         if (value != null && value) {
342             argList.add(parameter);
343             argList.add(String.valueOf(true));
344         }
345     }
346 
347     /**
348     * Convenience method used to build the schemaspy command line parameters.
349     *
350     * @param argList the current list of schemaspy parameter options.
351     * @param parameter a new parameter to add
352     * @param value the value for this parameter
353     */
354     private void addFlagToArguments(
355         final List<String> argList, final String parameter, final Boolean value) {
356         if (value != null && value) {
357             argList.add(parameter);
358         }
359     }
360 
361     /**
362      * Convenience method used to build the schemaspy command line parameters.
363      *
364      * @param argList
365      *            the current list of schemaspy parameter options.
366      * @param parameter
367      *            a new parameter to add
368      * @param value
369      *            the value for this parameter
370      */
371     private void addToArguments(final List<String> argList, final String parameter, final String value) {
372         if (value != null) {
373             argList.add(parameter);
374             argList.add(value);
375         }
376     }
377 
378     /**
379      * Generate the Schemaspy report.
380      *
381      * @throws MavenReportException
382      *             if schemaspy crashes
383      * @param locale
384      *            the language of the report - currently ignored.
385      */
386     @Override
387     protected void executeReport(final Locale locale) throws MavenReportException {
388 
389         //
390         // targetDirectory should be set by the maven framework. This is
391         // jusr for unit testing purposes
392         //
393         if (targetDirectory == null) {
394             targetDirectory = new File("target");
395         }
396 
397         targetDirectory.mkdirs();
398         File siteDir = new File(targetDirectory, "site");
399         siteDir.mkdirs();
400         File outputDir = null;
401         if (outputDirectory == null) {
402             outputDir = new File(siteDir, "schemaspy");
403             outputDir.mkdirs();
404             outputDirectory = outputDir.getAbsolutePath();
405         } else {
406             outputDir = new File(new File(outputDirectory), "schemaspy");
407             outputDir.mkdirs();
408         }
409         String schemaSpyDirectory = outputDir.getAbsolutePath();
410 
411         List<String> argList = new ArrayList<>();
412 
413 //        if ((jdbcUrl != null) && (databaseType == null)) {
414 //            databaseType = JDBCHelper.extractDatabaseType(jdbcUrl);
415 //        }
416         addToArguments(argList, "-dp", pathToDrivers);
417         addToArguments(argList, "-db", database);
418         addToArguments(argList, "-host", host);
419         addToArguments(argList, "-port", port);
420         addToArguments(argList, "-t", databaseType);
421         addToArguments(argList, "-u", user);
422         addToArguments(argList, "-p", password);
423         addToArguments(argList, "-s", schema);
424         addToArguments(argList, "-o", schemaSpyDirectory);
425         addToArguments(argList, "-desc", schemaDescription);
426         addToArguments(argList, "-i", includeTableNamesRegex);
427         addToArguments(argList, "-x", excludeColumnNamesRegex);
428         addFlagToArguments(argList, "-ahic", allowHtmlInComments);
429         addFlagToArguments(argList, "-noimplied", noImplied);
430         addFlagToArguments(argList, "-nohtml", noHtml);
431         addToArguments(argList, "-loglevel", logLevel);
432         addFlagToArguments(argList, "-norows", noRows);
433         addFlagToArguments(argList, "-noviews", noViews);
434         addFlagToArguments(argList, "-noschema", noSchema);
435         addFlagToArguments(argList, "-all", showAllSchemas);
436         addToArguments(argList, "-schemas", schemas);
437 
438         addToArguments(argList, "-useDriverManager", useDriverManager);
439         addToArguments(argList, "-css", cssStylesheet);
440         addFlagToArguments(argList, "-sso", singleSignOn);
441         addFlagToArguments(argList, "-lq", lowQuality);
442         addFlagToArguments(argList, "-hq", highQuality);
443         addToArguments(argList, "-connprops", connprops);
444         addFlagToArguments(argList, "-cid", commentsInitiallyDisplayed);
445         addFlagToArguments(argList, "-noads", noAds);
446         addFlagToArguments(argList, "-nologo", noLogo);
447         addToArguments(argList, "-cat", catalog);
448         addFlagToArguments(argList, "-vizjs", vizjs);
449 //        addToArguments(argList, "-jdbcUrl", jdbcUrl);
450 
451         try {
452             if (analyzer == null) {
453                 analyzer = new MavenSchemaAnalyzer();
454                 analyzer.applyConfiguration(argList);
455             }
456             analyzer.analyze();
457         } catch (Exception e) {
458             throw new MavenReportException(e.getMessage(), e);
459         }
460     }
461 
462     @Override
463     public boolean canGenerateReport() {
464         return !runOnExecutionRoot || project.isExecutionRoot();
465     }
466 
467     @Override
468     protected String getOutputDirectory() {
469         return outputDirectory;
470     }
471 
472     @Override
473     protected MavenProject getProject() {
474         return project;
475     }
476 
477     @Override
478     protected Renderer getSiteRenderer() {
479         return siteRenderer;
480     }
481 
482     @Override
483     public String getDescription(final Locale locale) {
484         return "SchemaSpy database documentation";
485     }
486 
487     @Override
488     public String getName(final Locale locale) {
489         return "SchemaSpy";
490     }
491 
492     @Override
493     public String getOutputName() {
494         return "schemaspy/index";
495     }
496 
497     /**
498      * Always return {@code true} as we're using the report generated by SchemaSpy
499      * rather than creating our own report.
500      *
501      * @return {@code true}
502      */
503     @Override
504     public boolean isExternalReport() {
505         return true;
506     }
507 }