View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.benerator.main;
28  
29  import com.rapiddweller.benerator.Consumer;
30  import com.rapiddweller.benerator.wrapper.ProductWrapper;
31  import com.rapiddweller.common.IOUtil;
32  import com.rapiddweller.common.NumberUtil;
33  import com.rapiddweller.common.RoundedNumberFormat;
34  import com.rapiddweller.common.StringUtil;
35  import com.rapiddweller.common.SystemInfo;
36  import com.rapiddweller.common.ui.ProgressMonitor;
37  import com.rapiddweller.format.DataContainer;
38  import com.rapiddweller.format.DataIterator;
39  import com.rapiddweller.model.data.DataModel;
40  import com.rapiddweller.model.data.Entity;
41  import com.rapiddweller.model.data.TypeDescriptor;
42  import com.rapiddweller.platform.db.DefaultDBSystem;
43  import com.rapiddweller.platform.db.SQLEntityExporter;
44  import com.rapiddweller.platform.dbunit.DbUnitEntityExporter;
45  import com.rapiddweller.platform.xls.XLSEntityExporter;
46  import org.apache.logging.log4j.LogManager;
47  import org.apache.logging.log4j.Logger;
48  
49  /**
50   * Creates a snapshot of a database schema and exports it in DbUnit XML file format.
51   *
52   * @author Volker Bergmann
53   * @since 0.3.04
54   */
55  public class DBSnapshotTool {
56  
57    /**
58     * The constant DBUNIT_FORMAT.
59     */
60    public static final String DBUNIT_FORMAT = "dbunit";
61    /**
62     * The constant XLS_FORMAT.
63     */
64    public static final String XLS_FORMAT = "xls";
65    /**
66     * The constant SQL_FORMAT.
67     */
68    public static final String SQL_FORMAT = "sql";
69  
70    /**
71     * The constant DEFAULT_FORMAT.
72     */
73    public static final String DEFAULT_FORMAT = DBUNIT_FORMAT;
74  
75    /**
76     * The constant DB_PASSWORD.
77     */
78    public static final String DB_PASSWORD = "dbPassword";
79    /**
80     * The constant DB_URL.
81     */
82    public static final String DB_URL = "dbUrl";
83    /**
84     * The constant DB_DRIVER.
85     */
86    public static final String DB_DRIVER = "dbDriver";
87    /**
88     * The constant DB_SCHEMA.
89     */
90    public static final String DB_SCHEMA = "dbSchema";
91    /**
92     * The constant DB_USER.
93     */
94    public static final String DB_USER = "dbUser";
95    /**
96     * The constant FORMAT.
97     */
98    public static final String FORMAT = "format";
99    /**
100    * The constant DIALECT.
101    */
102   public static final String DIALECT = "dialect";
103 
104   // TODO v0.8 test with each database
105   private static final Logger logger = LogManager.getLogger(DBSnapshotTool.class);
106 
107   /**
108    * Supported formats string [ ].
109    *
110    * @return the string [ ]
111    */
112   public static String[] supportedFormats() {
113     return new String[] {
114         DBUNIT_FORMAT, XLS_FORMAT, SQL_FORMAT
115     };
116   }
117 
118   /**
119    * The entry point of application.
120    *
121    * @param args the input arguments
122    */
123   public static void main(String[] args) {
124     logger.info("Starting " + DBSnapshotTool.class.getSimpleName());
125     String format = System.getProperty(FORMAT);
126     if (format == null) {
127       format = DEFAULT_FORMAT;
128     }
129     String filename = (args.length > 0 ? args[0] : defaultFilename(format));
130 
131     String dbUrl = System.getProperty(DB_URL);
132     if (StringUtil.isEmpty(dbUrl)) {
133       throw new IllegalArgumentException("No database URL specified. " +
134           "Please provide the JDBC URL as an environment property like '-DdbUrl=jdbc:...'");
135     }
136     String dbDriver = System.getProperty(DB_DRIVER);
137     if (StringUtil.isEmpty(dbDriver)) {
138       throw new IllegalArgumentException("No database driver specified. " +
139           "Please provide the JDBC driver class name as an environment property like '-DdbDriver=...'");
140     }
141     String dbUser = System.getProperty(DB_USER);
142     String dbPassword = System.getProperty(DB_PASSWORD);
143     String dbSchema = System.getProperty(DB_SCHEMA);
144     String dialect = System.getProperty(DIALECT);
145 
146     logger.info("Exporting data of database '" + dbUrl + "' with driver '" + dbDriver + "' as user '" + dbUser
147         + "'" + (dbSchema != null ? " using schema '" + dbSchema + "'" : "")
148         + " in " + format + " format to file " + filename);
149 
150     export(dbUrl, dbDriver, dbSchema, dbUser, dbPassword, filename, format, dialect);
151   }
152 
153   private static String defaultFilename(String format) {
154     if (XLS_FORMAT.equals(format)) {
155       return "snapshot.xls";
156     } else if (SQL_FORMAT.equals(format)) {
157       return "snapshot.sql";
158     } else {
159       return "snapshot.dbunit.xml";
160     }
161   }
162 
163   /**
164    * Export.
165    *
166    * @param dbUrl      the db url
167    * @param dbDriver   the db driver
168    * @param dbSchema   the db schema
169    * @param dbUser     the db user
170    * @param dbPassword the db password
171    * @param filename   the filename
172    * @param format     the format
173    * @param dialect    the dialect
174    */
175   public static void export(String dbUrl, String dbDriver, String dbSchema,
176                             String dbUser, String dbPassword, String filename, String format, String dialect) {
177     export(dbUrl, dbDriver, dbSchema, dbUser, dbPassword, filename, SystemInfo.getFileEncoding(),
178         format, dialect, null);
179   }
180 
181   /**
182    * Export.
183    *
184    * @param dbUrl      the db url
185    * @param dbDriver   the db driver
186    * @param dbSchema   the db schema
187    * @param dbUser     the db user
188    * @param dbPassword the db password
189    * @param filename   the filename
190    * @param encoding   the encoding
191    * @param format     the format
192    * @param dialect    the dialect
193    * @param monitor    the monitor
194    */
195   public static void export(String dbUrl, String dbDriver, String dbSchema,
196                             String dbUser, String dbPassword, String filename, String encoding, String format, String dialect,
197                             ProgressMonitor monitor) {
198     if (dbUser == null) {
199       logger.warn("No JDBC user specified");
200     }
201     String lineSeparator = SystemInfo.getLineSeparator();
202     long startTime = System.currentTimeMillis();
203 
204     Consumer exporter = null;
205     int count = 0;
206     try (DefaultDBSystemultDBSystem.html#DefaultDBSystem">DefaultDBSystem db = new DefaultDBSystem("db", dbUrl, dbDriver, dbUser, dbPassword, new DataModel())) {
207       // connect DB
208       if (dbSchema != null) {
209         db.setSchema(dbSchema);
210       }
211       db.setDynamicQuerySupported(false);
212 
213       // create exporter
214       if (DBUNIT_FORMAT.equalsIgnoreCase(format)) {
215         exporter = new DbUnitEntityExporter(filename, encoding);
216       } else if (XLS_FORMAT.equals(format)) {
217         exporter = new XLSEntityExporter(filename);
218       } else if (SQL_FORMAT.equals(format)) {
219         if (dialect == null) {
220           dialect = db.getDialect().getSystem();
221         }
222         exporter = new SQLEntityExporter(filename, encoding, lineSeparator, dialect);
223       } else {
224         throw new IllegalArgumentException("Unknown format: " + format);
225       }
226 
227       // export data
228       TypeDescriptor[] descriptors = db.getTypeDescriptors();
229       logger.info("Starting export");
230       for (TypeDescriptor descriptor : descriptors) {
231         String note = "Exporting table " + descriptor.getName();
232         if (monitor != null) {
233           monitor.setNote(note);
234           if (monitor.isCanceled()) {
235             throw new RuntimeException("Export cancelled");
236           }
237         }
238         logger.info(note);
239         Thread.yield();
240         DataIterator<Entity> source = db.queryEntities(descriptor.getName(), null, null).iterator();
241         DataContainer<Entity> container = new DataContainer<>();
242         ProductWrapper<Entity> wrapper = new ProductWrapper<>();
243         while ((container = source.next(container)) != null) {
244           Entity entity = container.getData();
245           wrapper.wrap(entity);
246           exporter.startConsuming(wrapper);
247           wrapper.wrap(entity);
248           exporter.finishConsuming(wrapper);
249           count++;
250         }
251         if (monitor != null) {
252           monitor.advance();
253         }
254       }
255       long duration = System.currentTimeMillis() - startTime;
256       if (count == 0) {
257         logger.warn("No entities found for snapshot.");
258       } else {
259         logger.info("Exported " + NumberUtil.format(count, 0) + " entities in " +
260             RoundedNumberFormat.format(duration, 0) + " ms " +
261             "(" + RoundedNumberFormat.format(count * 3600000L / duration, 0) + " p.h.)");
262       }
263     } finally {
264       IOUtil.close(exporter);
265     }
266   }
267 
268 }