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.gui;
28  
29  import com.rapiddweller.benerator.BeneratorConstants;
30  import com.rapiddweller.benerator.archetype.Archetype;
31  import com.rapiddweller.benerator.archetype.ArchetypeManager;
32  import com.rapiddweller.benerator.archetype.MavenFolderLayout;
33  import com.rapiddweller.benerator.main.DBSnapshotTool;
34  import com.rapiddweller.common.ArrayUtil;
35  import com.rapiddweller.common.FileUtil;
36  import com.rapiddweller.common.IOUtil;
37  import com.rapiddweller.common.converter.ToStringConverter;
38  import com.rapiddweller.common.ui.FileOperation;
39  import com.rapiddweller.common.ui.FileTypeSupport;
40  import com.rapiddweller.common.ui.I18NError;
41  import com.rapiddweller.common.ui.I18NSupport;
42  import com.rapiddweller.common.ui.swing.AlignedPane;
43  import com.rapiddweller.common.ui.swing.ProgressMonitor;
44  import com.rapiddweller.common.ui.swing.SwingUtil;
45  import com.rapiddweller.common.ui.swing.delegate.PropertyCheckBox;
46  import com.rapiddweller.common.ui.swing.delegate.PropertyComboBox;
47  import com.rapiddweller.common.ui.swing.delegate.PropertyFileField;
48  import com.rapiddweller.common.ui.swing.delegate.PropertyPasswordField;
49  import com.rapiddweller.common.ui.swing.delegate.PropertyTextField;
50  import com.rapiddweller.jdbacl.JDBCDriverInfo;
51  import org.apache.logging.log4j.LogManager;
52  import org.apache.logging.log4j.Logger;
53  
54  import javax.swing.BorderFactory;
55  import javax.swing.Box;
56  import javax.swing.DefaultListCellRenderer;
57  import javax.swing.Icon;
58  import javax.swing.ImageIcon;
59  import javax.swing.JButton;
60  import javax.swing.JComboBox;
61  import javax.swing.JComponent;
62  import javax.swing.JFrame;
63  import javax.swing.JLabel;
64  import javax.swing.JList;
65  import javax.swing.JOptionPane;
66  import javax.swing.JPanel;
67  import javax.swing.JTextField;
68  import javax.swing.KeyStroke;
69  import javax.swing.SwingUtilities;
70  import java.awt.BorderLayout;
71  import java.awt.Component;
72  import java.awt.Container;
73  import java.awt.event.ActionEvent;
74  import java.awt.event.ActionListener;
75  import java.awt.event.KeyEvent;
76  import java.io.BufferedInputStream;
77  import java.io.File;
78  import java.io.FileInputStream;
79  import java.io.FileOutputStream;
80  import java.io.ObjectInputStream;
81  import java.io.ObjectOutputStream;
82  import java.sql.DriverManager;
83  import java.util.HashMap;
84  import java.util.Map;
85  import java.util.zip.ZipException;
86  
87  /**
88   * Lets the user enter benerator project data and
89   * calls the ArchetypeBuilder for creating a new benerator project.<br/>
90   * <br/>
91   * Created at 17.07.2008 08:00:00
92   *
93   * @author Volker Bergmann
94   * @since 0.5.6
95   */
96  @SuppressWarnings("rawtypes")
97  public class CreateProjectPanel extends JPanel {
98  
99    /**
100    * The Logger.
101    */
102   static final Logger logger = LogManager.getLogger(CreateProjectPanel.class);
103 
104   private static final String SETUP_FILE = "setup.ser";
105 
106   private static final long serialVersionUID = 167461075459757736L;
107 
108   private static final int WIDE = 30;
109 
110   /**
111    * The Setup.
112    */
113   final Setup setup;
114   /**
115    * The 18 n.
116    */
117   final I18NSupport i18n;
118   /**
119    * The Folder field.
120    */
121   PropertyFileField folderField;
122   /**
123    * The Create button.
124    */
125   JButton createButton;
126   /**
127    * The Archetype field.
128    */
129   JComboBox archetypeField;
130   /**
131    * The Db driver type field.
132    */
133   JComboBox dbDriverTypeField;
134   /**
135    * The Db url field.
136    */
137   JTextField dbUrlField;
138   /**
139    * The Db driver field.
140    */
141   JTextField dbDriverField;
142   /**
143    * The Db user field.
144    */
145   JTextField dbUserField;
146   /**
147    * The Db schema field.
148    */
149   JTextField dbSchemaField;
150   /**
151    * The Db password field.
152    */
153   JTextField dbPasswordField;
154   /**
155    * The Db snapshot field.
156    */
157   JComboBox dbSnapshotField;
158   /**
159    * The Test button.
160    */
161   JButton testButton;
162   /**
163    * The Create tables field.
164    */
165   PropertyFileField createTablesField;
166   /**
167    * The Drop tables field.
168    */
169   PropertyFileField dropTablesField;
170 
171   /**
172    * Instantiates a new Create project panel.
173    *
174    * @param i18n the 18 n
175    */
176   public CreateProjectPanel(I18NSupport i18n) {
177     super(new BorderLayout());
178     this.setup = loadOrCreateSetup();
179     this.i18n = i18n;
180 
181     setBorder(BorderFactory.createEmptyBorder(16, 16, 16, 16));
182     add(createPropertiesPane(), BorderLayout.CENTER);
183     add(createButtonPane(), BorderLayout.SOUTH);
184 
185     // Exit the application if 'Escape' is pressed
186     KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
187     registerKeyboardAction(e -> exit(), stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
188   }
189 
190   private Component createButtonPane() {
191     JPanel pane = new JPanel();
192 
193     createButton = createButton("create", arg0 -> new Thread(new Creator()).start());
194     pane.add(createButton);
195 
196     pane.add(createButton("cancel", e -> exit()));
197 
198     return pane;
199   }
200 
201   private Component createPropertiesPane() { // TODO v0.8 simplify using AlignedPropertyPane
202     AlignedPane pane = AlignedPane.createVerticalPane(4);
203 
204     // project name
205     createTextField("projectName", pane);
206     folderField = new PropertyFileField(setup, "projectFolder", WIDE,
207         FileTypeSupport.directoriesOnly, FileOperation.SAVE);
208     folderField.addActionListener(e -> {
209       File folder = CreateProjectPanel.this.folderField.getFile();
210       if (!setup.isOverwrite() && folder.exists() && !FileUtil.isEmptyFolder(folder)) {
211         showErrors(i18n.getString("error.projectFolderNotEmpty"));
212       }
213     });
214 
215     // archetype
216     archetypeField = createComboBox("archetype", null, pane, (Object[]) ArchetypeManager.getInstance().getArchetypes());
217     archetypeField.setRenderer(new ArchetypeRenderer());
218     ArchetypeListener archetypeListener = new ArchetypeListener();
219     archetypeField.addActionListener(archetypeListener);
220     pane.endRow();
221 
222     // project folder
223     pane.addRow(i18n.getString("projectFolder"), folderField);
224     pane.addSeparator();
225 
226     // maven group id, version & options
227     createTextField("groupId", pane);
228     createTextField("version", pane);
229     pane.endRow();
230 
231     pane.addSeparator();
232 
233     Box optionsPane = Box.createHorizontalBox();
234     createCheckBox("eclipseProject", optionsPane);
235     createCheckBox("overwrite", optionsPane);
236     createCheckBox("offline", optionsPane);
237     pane.addRow(i18n.getString("projectOptions"), optionsPane);
238 
239     pane.endRow();
240     pane.addSeparator();
241 
242 
243     // db properties
244     dbDriverTypeField = createComboBox("jdbcDriverType", null, pane, JDBCDriverInfo.getInstances().toArray());
245     dbDriverField = createTextField("dbDriver", pane);
246     pane.endRow();
247 
248     dbUrlField = createTextField("dbUrl", pane);
249     dbSchemaField = createTextField("dbSchema", pane);
250     pane.endRow();
251 
252     dbUserField = createTextField("dbUser", pane);
253     dbPasswordField = createPasswordField(pane);
254     pane.endRow();
255 
256     pane.addElement(new JLabel(""));
257     testButton = createButton("testConnection", new TestConnectionListener());
258     pane.addElement(testButton);
259 
260     String[] supportedFormats = ArrayUtil.append("none", DBSnapshotTool.supportedFormats());
261     dbSnapshotField = createComboBoxRow(i18n, pane, (Object[]) supportedFormats);
262     pane.endRow();
263 
264     // 'create/drop table' scripts
265     createTablesField = new PropertyFileField(setup, "createScriptFile", 20, FileTypeSupport.filesOnly, FileOperation.OPEN);
266     pane.addElement(i18n.getString("createScriptFile"), createTablesField);
267     dropTablesField = new PropertyFileField(setup, "dropScriptFile", 20, FileTypeSupport.filesOnly, FileOperation.OPEN);
268     pane.addElement(i18n.getString("dropScriptFile"), dropTablesField);
269     pane.addSeparator();
270 
271     createTextField("encoding", pane);
272     createTextField("lineSeparator", pane);
273     pane.endRow();
274 
275     createTextField("locale", pane);
276     createTextField("dataset", pane);
277     pane.endRow();
278     pane.addSeparator();
279 
280     archetypeListener.actionPerformed(null);
281     return pane;
282   }
283 
284   private void createCheckBox(String propertyName, Container pane) {
285     PropertyCheckBox checkBox = new PropertyCheckBox(setup, propertyName, i18n.getString(propertyName));
286     pane.add(checkBox);
287   }
288 
289   private JComboBox createComboBoxRow(I18NSupport itemI18n, AlignedPane pane, Object... options) {
290     JComboBox comboBox = createComboBox("dbSnapshot", itemI18n, pane, options);
291     pane.endRow();
292     return comboBox;
293   }
294 
295   private JComboBox createComboBox(String propertyName, I18NSupport itemI18n, AlignedPane pane, Object... options) {
296     JComboBox comboBox = new PropertyComboBox(setup, propertyName, itemI18n, propertyName + ".", options);
297     String label = this.i18n.getString(propertyName);
298     pane.addElement(label, comboBox);
299     return comboBox;
300   }
301 
302   @SuppressWarnings("unused")
303   private JTextField createTextFieldRow(String propertyName, AlignedPane pane) {
304     JTextField textfield = new PropertyTextField(setup, propertyName, WIDE);
305     String label = i18n.getString(propertyName);
306     pane.addRow(label, textfield);
307     return textfield;
308   }
309 
310   private JTextField createTextField(String propertyName, AlignedPane pane) {
311     JTextField textfield = new PropertyTextField(setup, propertyName, WIDE / 2);
312     String label = i18n.getString(propertyName);
313     pane.addElement(label, textfield);
314     return textfield;
315   }
316 
317   private JTextField createPasswordField(AlignedPane pane) {
318     PropertyPasswordField pwfield = new PropertyPasswordField(setup, "dbPassword", WIDE / 2);
319     String label = i18n.getString("dbPassword");
320     pane.addElement(label, pwfield);
321     return pwfield;
322   }
323 
324   private JButton createButton(String label, ActionListener listener) {
325     JButton button = new JButton(i18n.getString(label));
326     button.addActionListener(listener);
327     return button;
328   }
329 
330   /**
331    * Exit.
332    */
333   public void exit() {
334     saveSetup();
335     JFrame frame = (JFrame) SwingUtilities.getRoot(this);
336     frame.dispose();
337     System.exit(BeneratorConstants.EXIT_CODE_NORMAL);
338   }
339 
340   /**
341    * Show errors.
342    *
343    * @param errors the errors
344    */
345   void showErrors(Object... errors) {
346     String[] messages = new String[errors.length];
347     for (int i = 0; i < errors.length; i++) {
348       Object error = errors[i];
349       if (error instanceof ZipException) {
350         messages[i] = I18NError.renderMessage("ZipException", i18n);
351       } else if (error instanceof I18NError) {
352         messages[i] = ((I18NError) error).renderMessage(i18n);
353       } else {
354         messages[i] = ToStringConverter.convert(error, "null");
355       }
356     }
357     JOptionPane.showMessageDialog(CreateProjectPanel.this, messages, "Error", JOptionPane.ERROR_MESSAGE);
358   }
359 
360 
361   /**
362    * The type Archetype listener.
363    */
364   class ArchetypeListener implements ActionListener {
365     @Override
366     public void actionPerformed(ActionEvent e) {
367       boolean useDB = setup.isDatabaseProject();
368       dbDriverTypeField.setEnabled(useDB);
369       dbUrlField.setEnabled(useDB);
370       dbDriverField.setEnabled(useDB);
371       dbUserField.setEnabled(useDB);
372       dbSchemaField.setEnabled(useDB);
373       dbPasswordField.setEnabled(useDB);
374       testButton.setEnabled(useDB);
375       dbSnapshotField.setEnabled(useDB);
376       createTablesField.setEnabled(useDB);
377       dropTablesField.setEnabled(useDB);
378 
379       boolean shop = setup.isShopProject();
380       if (shop) {
381         dbSnapshotField.setEnabled(false);
382         createTablesField.setEnabled(false);
383         dropTablesField.setEnabled(false);
384       }
385     }
386   }
387 
388   /**
389    * The type Creator.
390    */
391   class Creator implements Runnable {
392 
393     @Override
394     public void run() {
395       try {
396         logger.info("Creating project " + setup.getProjectName() + " " +
397             "of type " + setup.getArchetype().getId() + " " +
398             "in " + setup.getProjectFolder());
399         createButton.setEnabled(false);
400         String taskName = i18n.format("message.project.create", setup.getProjectName());
401         String message = i18n.getString("message.project.initializing");
402         ProgressMonitor monitor = new ProgressMonitor(null, taskName, message, 0, 100);
403         monitor.setMillisToDecideToPopup(10);
404         monitor.setMillisToPopup(10);
405         ProjectBuildertBuilder.html#ProjectBuilder">ProjectBuilder builder = new ProjectBuilder(setup, new MavenFolderLayout(), monitor);
406         builder.run();
407         Exception[] errors = builder.getErrors();
408         if (errors.length > 0) {
409           showErrors((Object[]) errors);
410         } else {
411           JOptionPane.showMessageDialog(CreateProjectPanel.this, i18n.getString("message.done"));
412           exit();
413         }
414       } catch (Exception e) {
415         e.printStackTrace();
416         showErrors(e);
417       } finally {
418         createButton.setEnabled(true);
419         SwingUtil.repaintLater(CreateProjectPanel.this);
420       }
421     }
422 
423   }
424 
425   /**
426    * The type Test connection listener.
427    */
428   class TestConnectionListener implements ActionListener {
429 
430     @Override
431     public void actionPerformed(ActionEvent actionevent) {
432       try {
433         Class.forName(setup.getDbDriver());
434         DriverManager.getConnection(setup.getDbUrl(), setup.getDbUser(), setup.getDbPassword());
435         JOptionPane.showMessageDialog(CreateProjectPanel.this, i18n.getString("message.connect.successful"));
436       } catch (Exception e) {
437         showErrors(e.toString());
438       }
439     }
440   }
441 
442   private static Setup loadOrCreateSetup() {
443     ObjectInputStream in = null;
444     try {
445       in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(SETUP_FILE)));
446       return (Setup) in.readObject();
447     } catch (Exception e) {
448       // if no serialized setup exists or loading fails, simply create a new one
449       return new Setup();
450     } finally {
451       IOUtil.close(in);
452     }
453   }
454 
455   private void saveSetup() {
456     ObjectOutputStream out = null;
457     try {
458       out = new ObjectOutputStream(new FileOutputStream(SETUP_FILE));
459       out.writeObject(setup);
460     } catch (Exception e) {
461       e.printStackTrace();
462     } finally {
463       IOUtil.close(out);
464     }
465   }
466 
467   /**
468    * Gets create button.
469    *
470    * @return the create button
471    */
472   public JButton getCreateButton() {
473     return createButton;
474   }
475 
476   /**
477    * The type Archetype renderer.
478    */
479 
480   static class ArchetypeRenderer extends DefaultListCellRenderer {
481 
482     private final Map<Archetype, Icon> icons = new HashMap<>(20);
483 
484     @Override
485     public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
486                                                   boolean cellHasFocus) {
487       super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
488       Archetype../../com/rapiddweller/benerator/archetype/Archetype.html#Archetype">Archetype archetype = (Archetype) value;
489       archetype.getIconURL();
490       Icon icon = getIcon(archetype);
491       setIcon(icon);
492       setText(archetype.getDescription());
493       return this;
494     }
495 
496     private Icon getIcon(Archetype archetype) {
497       Icon icon = icons.get(archetype);
498       if (icon == null) {
499         icon = new ImageIcon(archetype.getIconURL());
500         icons.put(archetype, icon);
501       }
502       return icon;
503     }
504   }
505 
506 }