org.apache.cayenne.modeler.dialog.db.DataSourceWizard Maven / Gradle / Ivy
/*****************************************************************
* 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
*
* https://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;
import javax.sql.DataSource;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import java.awt.Component;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Map;
import java.util.prefs.Preferences;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.modeler.ClassLoadingService;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.dialog.pref.GeneralPreferences;
import org.apache.cayenne.modeler.dialog.pref.PreferenceDialog;
import org.apache.cayenne.modeler.event.DataSourceModificationEvent;
import org.apache.cayenne.modeler.event.DataSourceModificationListener;
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.pref.DataMapDefaults;
import org.apache.cayenne.modeler.util.CayenneController;
import org.apache.cayenne.swing.BindingBuilder;
import org.apache.cayenne.swing.ObjectBinding;
import static org.apache.cayenne.modeler.pref.DBConnectionInfo.*;
/**
* A subclass of ConnectionWizard that tests configured DataSource, but does not
* keep an open connection.
*
*/
public class DataSourceWizard extends CayenneController {
private final ProjectController projectController;
private final DataSourceWizardView view;
private final String[] buttons;
private ObjectBinding dataSourceBinding;
private Map dataSources;
private String dataSourceKey;
// this object is a clone of an object selected from the dropdown, as we need to allow local temporary modifications
private DBConnectionInfo connectionInfo;
private DbAdapter adapter;
private DataSource dataSource;
private boolean canceled;
private DataSourceModificationListener dataSourceListener;
public DataSourceWizard(ProjectController parent, String title) {
this(parent, title, new String[]{"Continue", "Cancel"});
}
public DataSourceWizard(ProjectController parent, String title, String[] buttons) {
super(parent);
this.buttons = buttons;
this.connectionInfo = new DBConnectionInfo();
this.projectController = parent;
this.view = createView();
this.view.setTitle(title);
initBindings();
initDataSourceListener();
}
/**
* Creates swing dialog for this wizard
*/
private DataSourceWizardView createView() {
return new DataSourceWizardView(this, buttons);
}
protected void initBindings() {
final BindingBuilder builder = new BindingBuilder(getApplication().getBindingFactory(), this);
dataSourceBinding = builder.bindToComboSelection(view.getDataSources(), "dataSourceKey");
builder.bindToAction(view.getCancelButton(), "cancelAction()");
builder.bindToAction(view.getOkButton(), "okAction()");
builder.bindToAction(view.getConfigButton(), "dataSourceConfigAction()");
}
private void initDataSourceListener() {
dataSourceListener = new DataSourceModificationListener() {
@Override
public void callbackDataSourceRemoved(DataSourceModificationEvent e) {}
@Override
public void callbackDataSourceAdded(DataSourceModificationEvent e) {
setDataSourceKey(e.getDataSourceName());
refreshDataSources();
}
};
getApplication().getFrameController().getProjectController()
.addDataSourceModificationListener(dataSourceListener);
}
private void initFavouriteDataSource() {
final Preferences pref = getApplication().getPreferencesNode(GeneralPreferences.class, "");
final String favouriteDataSource = pref.get(GeneralPreferences.FAVOURITE_DATA_SOURCE, null);
if (favouriteDataSource != null && dataSources.containsKey(favouriteDataSource)) {
setDataSourceKey(favouriteDataSource);
dataSourceBinding.updateView();
}
}
private void removeDataSourceListener() {
getApplication().getFrameController().getProjectController()
.removeDataSourceModificationListener(dataSourceListener);
}
private DBConnectionInfo getConnectionInfoFromPreferences() {
DBConnectionInfo connectionInfo = new DBConnectionInfo();
DataMapDefaults dataMapDefaults = getProjectController()
.getDataMapPreferences(getProjectController().getCurrentDataMap());
connectionInfo.setDbAdapter(dataMapDefaults.getCurrentPreference().get(DB_ADAPTER_PROPERTY, null));
connectionInfo.setUrl(dataMapDefaults.getCurrentPreference().get(URL_PROPERTY, null));
connectionInfo.setUserName(dataMapDefaults.getCurrentPreference().get(USER_NAME_PROPERTY, null));
connectionInfo.setPassword(dataMapDefaults.getCurrentPreference().get(PASSWORD_PROPERTY, null));
connectionInfo.setJdbcDriver(dataMapDefaults.getCurrentPreference().get(JDBC_DRIVER_PROPERTY, null));
return connectionInfo;
}
private ProjectController getProjectController() {
return projectController;
}
public String getDataSourceKey() {
return dataSourceKey;
}
public void setDataSourceKey(final String dataSourceKey) {
this.dataSourceKey = dataSourceKey;
// update a clone object that will be used to obtain connection...
final DBConnectionInfo currentInfo = dataSources.get(dataSourceKey);
if (currentInfo != null) {
currentInfo.copyTo(connectionInfo);
} else {
connectionInfo = new DBConnectionInfo();
}
view.getConnectionInfo().setConnectionInfo(connectionInfo);
}
/**
* Main action method that pops up a dialog asking for user selection.
* Returns true if the selection was confirmed, false - if canceled.
*/
public boolean startupAction() {
this.canceled = true;
refreshDataSources();
initFavouriteDataSource();
final DataMapDefaults dataMapDefaults = projectController.
getDataMapPreferences(projectController.getCurrentDataMap());
if (dataMapDefaults.getCurrentPreference().get(DB_ADAPTER_PROPERTY, null) != null) {
getConnectionInfoFromPreferences().copyTo(connectionInfo);
}
view.pack();
view.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
view.setModal(true);
view.connectionInfo.setConnectionInfo(connectionInfo);
makeCloseableOnEscape();
centerView();
view.setVisible(true);
return !canceled;
}
public DBConnectionInfo getConnectionInfo() {
return connectionInfo;
}
/**
* Tests that the entered information is valid and can be used to open a
* conneciton. Does not store the open connection.
*/
public void okAction() {
final DBConnectionInfo info = getConnectionInfo();
final ClassLoadingService classLoader = getApplication().getClassLoadingService();
// doing connection testing...
try {
try {
this.adapter = info.makeAdapter(classLoader);
this.dataSource = info.makeDataSource(classLoader);
} catch (SQLException ignore) {
showNoConnectorDialog("Unable to load driver '" + info.getJdbcDriver() + "'");
return;
}
// Test connection
try (Connection connection = dataSource.getConnection()) {
}
} catch (Throwable th) {
reportError("Connection Error", th);
return;
}
onClose(false);
}
public void cancelAction() {
onClose(true);
}
/**
* On close handler. Introduced to remove data source listener.
*/
protected void onClose(final boolean canceled) {
// set success flag, and unblock the caller...
this.canceled = canceled;
view.dispose();
removeDataSourceListener();
if(!canceled) {
Preferences pref = getApplication().getPreferencesNode(GeneralPreferences.class, "");
pref.put(GeneralPreferences.FAVOURITE_DATA_SOURCE, getDataSourceKey());
}
}
/**
* Opens preferences panel to allow configuration of DataSource presets.
*/
public void dataSourceConfigAction() {
final PreferenceDialog prefs = new PreferenceDialog(this);
prefs.showDataSourceEditorAction(dataSourceKey);
refreshDataSources();
}
/**
* Opens preferences panel to allow configuration of classpath.
*/
public void classPathConfigAction() {
final PreferenceDialog prefs = new PreferenceDialog(this);
prefs.showClassPathEditorAction();
refreshDataSources();
}
public Component getView() {
return view;
}
@SuppressWarnings("unchecked")
private void refreshDataSources() {
this.dataSources = (Map) getApplication().getCayenneProjectPreferences().getDetailObject(DBConnectionInfo.class)
.getChildrenPreferences();
// 1.2 migration fix - update data source adapter names
final String _12package = "org.objectstyle.cayenne.";
for(DBConnectionInfo info : dataSources.values()) {
if (info.getDbAdapter() != null && info.getDbAdapter().startsWith(_12package)) {
info.setDbAdapter("org.apache.cayenne." + info.getDbAdapter().substring(_12package.length()));
}
}
final String[] keys = dataSources.keySet().toArray(new String[0]);
Arrays.sort(keys);
view.getDataSources().setModel(new DefaultComboBoxModel<>(keys));
String key = null;
if (getDataSourceKey() == null || !dataSources.containsKey(getDataSourceKey())) {
if (keys.length > 0) {
key = keys[0];
}
}
setDataSourceKey(key != null ? key : getDataSourceKey());
dataSourceBinding.updateView();
}
protected void showNoConnectorDialog(String message) {
final String[] options = {"Setup driver", "Cancel"};
final int selection = JOptionPane.showOptionDialog(getView(), message, "Configuration error",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
if (selection == 0) {
classPathConfigAction();
}
}
public DataSource getDataSource() {
return dataSource;
}
/**
* Returns configured DbAdapter.
*/
public DbAdapter getAdapter() {
return adapter;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy