/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
****************************************************************/
package org.apache.cayenne.modeler.dialog.db.gen;
import org.apache.cayenne.access.DbGenerator;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.log.NoopJdbcEventLogger;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.dialog.ValidationResultBrowser;
import org.apache.cayenne.modeler.dialog.db.DataSourceWizard;
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.pref.DBGeneratorDefaults;
import org.apache.cayenne.modeler.util.CayenneController;
import org.apache.cayenne.modeler.util.DbAdapterInfo;
import org.apache.cayenne.swing.BindingBuilder;
import org.apache.cayenne.swing.ObjectBinding;
import org.apache.cayenne.validation.ValidationResult;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.Component;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
*/
public class DBGeneratorOptions extends CayenneController {
protected DBGeneratorOptionsView view;
protected ObjectBinding[] optionBindings;
protected ObjectBinding sqlBinding;
protected ObjectBinding adapterBinding;
protected DBConnectionInfo connectionInfo;
protected Collection<DataMap> dataMaps;
protected DBGeneratorDefaults generatorDefaults;
protected Collection<DbGenerator> generators;
protected String textForSQL;
protected TableSelectorController tables;
public DBGeneratorOptions(ProjectController parent, String title, Collection<DataMap> dataMaps) {
super(parent);
this.dataMaps = dataMaps;
this.tables = new TableSelectorController(parent);
this.view = new DBGeneratorOptionsView(tables.getView());
this.connectionInfo = new DBConnectionInfo();
this.generatorDefaults = new DBGeneratorDefaults(parent
.getPreferenceForProject()
.node("DbGenerator"));
this.view.setTitle(title);
initController();
connectionInfo.setDbAdapter((String) view.getAdapters().getSelectedItem());
tables.updateTables(dataMaps);
prepareGenerator();
generatorDefaults.configureGenerator(generators);
createSQL();
refreshView();
}
public Component getView() {
return view;
}
public DBGeneratorDefaults getGeneratorDefaults() {
return generatorDefaults;
}
public String getTextForSQL() {
return textForSQL;
}
protected void initController() {
DefaultComboBoxModel<String> adapterModel = new DefaultComboBoxModel<>(
DbAdapterInfo.getStandardAdapters());
view.getAdapters().setModel(adapterModel);
view.getAdapters().setSelectedIndex(0);
BindingBuilder builder = new BindingBuilder(
getApplication().getBindingFactory(),
this);
sqlBinding = builder.bindToTextArea(view.getSql(), "textForSQL");
adapterBinding = builder.bindToComboSelection(
view.getAdapters(),
"connectionInfo.dbAdapter",
"refreshSQLAction()",
"org.apache.cayenne.dba.JdbcAdapter");
optionBindings = new ObjectBinding[5];
optionBindings[0] = builder.bindToStateChangeAndAction(
view.getCreateFK(),
"generatorDefaults.createFK",
"refreshSQLAction()");
optionBindings[1] = builder.bindToStateChangeAndAction(
view.getCreatePK(),
"generatorDefaults.createPK",
"refreshSQLAction()");
optionBindings[2] = builder.bindToStateChangeAndAction(
view.getCreateTables(),
"generatorDefaults.createTables",
"refreshSQLAction()");
optionBindings[3] = builder.bindToStateChangeAndAction(
view.getDropPK(),
"generatorDefaults.dropPK",
"refreshSQLAction()");
optionBindings[4] = builder.bindToStateChangeAndAction(
view.getDropTables(),
"generatorDefaults.dropTables",
"refreshSQLAction()");
builder.bindToAction(view.getGenerateButton(), "generateSchemaAction()");
builder.bindToAction(view.getSaveSqlButton(), "storeSQLAction()");
builder.bindToAction(view.getCancelButton(), "closeAction()");
// refresh SQL if different tables were selected
view.getTabs().addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (view.getTabs().getSelectedIndex() == 0) {
// this assumes that some tables where checked/unchecked... not very
// efficient
refreshGeneratorAction();
}
}
});
}
/**
* Creates new internal DbGenerator instance.
*/
protected void prepareGenerator() {
try {
DbAdapter adapter = connectionInfo.makeAdapter(getApplication()
.getClassLoadingService());
generators = new ArrayList<>();
for (DataMap dataMap : dataMaps) {
this.generators.add(new DbGenerator(
adapter,
dataMap,
tables.getExcludedTables(),
null,
NoopJdbcEventLogger.getInstance()));
}
} catch (Exception ex) {
reportError("Error loading adapter", ex);
}
}
/**
* Returns SQL statements generated for selected schema generation options.
*/
protected void createSQL() {
// convert them to string representation for display
StringBuilder buf = new StringBuilder();
for (DbGenerator generator : generators) {
Iterator<String> it = generator.configuredStatements().iterator();
String batchTerminator = generator.getAdapter().getBatchTerminator();
String lineEnd = (batchTerminator != null)
? "\n" + batchTerminator + "\n\n"
: "\n\n";
while (it.hasNext()) {
buf.append(it.next()).append(lineEnd);
}
}
textForSQL = buf.toString();
}
protected void refreshView() {
getView().setEnabled(connectionInfo != null);
for (ObjectBinding optionBinding : optionBindings) {
optionBinding.updateView();
}
sqlBinding.updateView();
}
// ===============
// Actions
// ===============
/**
* Starts options dialog.
*/
public void startupAction() {
view.pack();
view.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
view.setModal(true);
makeCloseableOnEscape();
centerView();
view.setVisible(true);
}
public void refreshGeneratorAction() {
prepareGenerator();
refreshSQLAction();
}
/**
* Updates a text area showing generated SQL.
*/
public void refreshSQLAction() {
// sync generator with defaults, make SQL, then sync the view...
adapterBinding.updateView();
connectionInfo.setDbAdapter((String) view.getAdapters().getSelectedItem());
prepareGenerator();
generatorDefaults.configureGenerator(generators);
createSQL();
sqlBinding.updateView();
}
/**
* Performs configured schema operations via DbGenerator.
*/
public void generateSchemaAction() {
DataSourceWizard connectWizard = new DataSourceWizard(
this.getParent(),
"Generate DB Schema: Connect to Database");
if (!connectWizard.startupAction()) {
return;
}
this.connectionInfo = connectWizard.getConnectionInfo();
refreshGeneratorAction();
Collection<ValidationResult> failures = new ArrayList<ValidationResult>();
// sanity check...
for (DbGenerator generator : generators) {
if (generator.isEmpty(true)) {
JOptionPane.showMessageDialog(getView(), "Nothing to generate.");
return;
}
try {
generator.runGenerator(connectWizard.getDataSource());
failures.add(generator.getFailures());
} catch (Throwable th) {
reportError("Schema Generation Error", th);
}
}
if (failures.size() == 0) {
JOptionPane.showMessageDialog(getView(), "Schema Generation Complete.");
} else {
new ValidationResultBrowser(this)
.startupAction(
"Schema Generation Complete",
"Schema generation finished. The following problem(s) were ignored.",
failures);
}
}
/**
* Allows user to save generated SQL in a file.
*/
public void storeSQLAction() {
JFileChooser fc = new JFileChooser();
fc.setDialogType(JFileChooser.SAVE_DIALOG);
fc.setDialogTitle("Save SQL Script");
File projectDir = new File(getApplication()
.getProject()
.getConfigurationResource()
.getURL()
.getPath());
fc.setCurrentDirectory(projectDir);
if (fc.showSaveDialog(getView()) == JFileChooser.APPROVE_OPTION) {
refreshGeneratorAction();
try {
File file = fc.getSelectedFile();
FileWriter fw = new FileWriter(file);
PrintWriter pw = new PrintWriter(fw);
pw.print(textForSQL);
pw.flush();
pw.close();
} catch (IOException ex) {
reportError("Error Saving SQL", ex);
}
}
}
public void closeAction() {
view.dispose();
}
public DBConnectionInfo getConnectionInfo() {
return this.connectionInfo;
}
public void setConnectionInfo(DBConnectionInfo connectionInfo) {
this.connectionInfo = connectionInfo;
refreshView();
}
}