All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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