/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.runtime.ui.connection; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.datatools.connectivity.IConnectionProfile; import org.eclipse.datatools.connectivity.ProfileManager; import org.eclipse.datatools.connectivity.drivers.DriverInstance; import org.eclipse.datatools.connectivity.drivers.DriverManager; import org.eclipse.datatools.connectivity.drivers.jdbc.IJDBCDriverDefinitionConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.StringUtilities; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.datatools.connection.ConnectionInfoProviderFactory; import org.teiid.designer.datatools.connection.IConnectionInfoHelper; import org.teiid.designer.datatools.connection.IConnectionInfoProvider; import org.teiid.designer.datatools.ui.DatatoolsUiConstants; import org.teiid.designer.datatools.ui.DatatoolsUiPlugin; import org.teiid.designer.datatools.ui.dialogs.SelectConnectionProfileDialog; import org.teiid.designer.jdbc.JdbcFactory; import org.teiid.designer.jdbc.JdbcSource; import org.teiid.designer.jdbc.impl.JdbcFactoryImpl; import org.teiid.designer.ui.actions.IConnectionAction; import org.teiid.designer.ui.actions.SortableSelectionAction; import org.teiid.designer.ui.common.eventsupport.SelectionUtilities; import org.teiid.designer.ui.editors.ModelEditor; import org.teiid.designer.ui.editors.ModelEditorManager; import org.teiid.designer.ui.viewsupport.DesignerPropertiesUtil; import org.teiid.designer.ui.viewsupport.ModelIdentifier; /** * @since 8.0 */ public class SetConnectionProfileAction extends SortableSelectionAction implements IConnectionAction { private static final String label = DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.title"); //$NON-NLS-1$ private static final String NO_PROFILE_PROVIDER_FOUND_KEY = "NoProfileProviderFound"; //$NON-NLS-1$ private Properties designerProperties; private IConnectionProfile connectionProfile; private static JndiNameInModelHelper jndiHelper = new JndiNameInModelHelper(); /** * @since 5.0 */ public SetConnectionProfileAction() { super(label, SWT.DEFAULT); setImageDescriptor(DatatoolsUiPlugin.getDefault().getImageDescriptor(DatatoolsUiConstants.Images.SET_CONNECTION_ICON)); } /** * @see org.teiid.designer.ui.actions.SortableSelectionAction#isValidSelection(org.eclipse.jface.viewers.ISelection) * @since 5.0 */ @Override public boolean isValidSelection( ISelection selection ) { // Enable for single/multiple Virtual Tables return sourceModelSelected(selection); } /** * @see org.eclipse.jface.action.IAction#run() * @since 5.0 */ @Override public void run() { // A) get the selected model and extract a "ConnectionProfileInfo" from it using the ConnectionProfileInfoHandler // B) Use ConnectionProfileHandler.getConnectionProfile(connectionProfileInfo) to query the user to // select a ConnectionProfile (or create new one) // C) Get the resulting ConnectionProfileInfo from the dialog and re-set the model's connection info // via the ConnectionProfileInfoHandler IFile modelFile = (IFile)SelectionUtilities.getSelectedObjects(getSelection()).get(0); boolean requiredStart = ModelerCore.startTxn(true, true, "Set Connection Profile", this); //$NON-NLS-1$ boolean succeeded = false; try { ModelEditor editor = ModelEditorManager.getModelEditorForFile(modelFile, true); if (editor != null) { boolean isDirty = editor.isDirty(); setConnectionProfile(modelFile); if (!isDirty && editor.isDirty()) { editor.doSave(new NullProgressMonitor()); } succeeded = true; } } catch (Exception e) { logException(e); return; } finally { // if we started the txn, commit it. if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } private void logException(Exception e) { String msg = e.getMessage(); if( msg != null && msg.equalsIgnoreCase(NO_PROFILE_PROVIDER_FOUND_KEY) ) { MessageDialog.openWarning(getShell(), DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.noProvileProviderTitle"), //$NON-NLS-1$ DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.noProvileProviderMessage")); //$NON-NLS-1$ } else { MessageDialog.openError(getShell(), DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.exceptionMessage"), e.getMessage()); //$NON-NLS-1$ IStatus status = new Status(IStatus.ERROR, DatatoolsUiConstants.PLUGIN_ID, DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.exceptionMessage"), e); //$NON-NLS-1$ DatatoolsUiConstants.UTIL.log(status); } } /** * Set the Model's connection profile * @param modelFile the model file * @return 'true' if the ConnectionFile was successfully reset, 'false' if not. * @throws Exception indicates problem */ public static boolean setConnectionProfile( IFile modelFile ) throws Exception { SelectConnectionProfileDialog dialog = new SelectConnectionProfileDialog(Display.getCurrent().getActiveShell()); dialog.open(); if (dialog.getReturnCode() == Window.OK) { Object[] result = dialog.getResult(); if (result != null && result.length == 1 && result[0] instanceof IConnectionProfile) { IConnectionProfile profile = (IConnectionProfile)result[0]; // Cache existing jndi Name ModelResource modelResc = ModelUtil.getModelResource(modelFile, true); String existingJndiName = jndiHelper.getExistingJndiName(modelResc); // Update the JdbcSource properties (if exist) with the new profile. User is prompted if the driver class will be changed. updateJdbcSourceAndConnectionInfo(modelFile,profile); // Check for JNDI name in model if( StringUtilities.isEmpty(existingJndiName)) { jndiHelper.ensureJndiNameExists(modelResc, true); } else { // Note that a connection profile may have a JNDI name in it.. so check if it's different // If it is.. ignore the re-set of the existing jndi name String newJndiName = jndiHelper.getExistingJndiName(modelResc); if( !StringUtilities.areDifferent(newJndiName, existingJndiName)) { jndiHelper.setJNDINameInTxn(modelResc, existingJndiName); } } return true; } } return false; } public boolean setConnectionProfile() { ISelection selection = getSelection(); if( selection == null || selection.isEmpty() ) { // Tell user they have not yet import to create their Source model yet. MessageDialog.openInformation(Display.getCurrent().getActiveShell(), DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.sourceModelUndefined.title"), //$NON-NLS-1$ DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.sourceModelUndefined.title")); //$NON-NLS-1$ return false; } IFile modelFile = (IFile)SelectionUtilities.getSelectedObjects(selection).get(0); if( this.connectionProfile == null ) { SelectConnectionProfileDialog dialog = new SelectConnectionProfileDialog(Display.getCurrent().getActiveShell()); dialog.open(); if (dialog.getReturnCode() == Window.OK) { Object[] result = dialog.getResult(); if (result != null && result.length == 1) { this.connectionProfile = (IConnectionProfile)result[0]; } } } if( this.connectionProfile != null ) { try { updateJdbcSourceAndConnectionInfo(modelFile, this.connectionProfile); } catch (Exception e) { logException(e); return false; } return true; } return false; } /** * @see org.teiid.designer.ui.actions.ISelectionAction#isApplicable(org.eclipse.jface.viewers.ISelection) * @since 5.0 */ @Override public boolean isApplicable( ISelection selection ) { return sourceModelSelected(selection); } private boolean sourceModelSelected( ISelection theSelection ) { boolean result = false; List<?> allObjs = SelectionUtilities.getSelectedObjects(theSelection); if (!allObjs.isEmpty() && allObjs.size() == 1) { Iterator<?> iter = allObjs.iterator(); result = true; Object nextObj = null; while (iter.hasNext() && result) { nextObj = iter.next(); if (nextObj instanceof IFile) { result = ModelIdentifier.isRelationalSourceModel((IFile)nextObj); } else { result = false; } } } return result; } /** * @param model the model file * @param connectionProfile the connection profile * @param driverClassChanged 'true' if driver class was changed, 'false' if not. * @throws Exception indicates a problem */ public static void setConnectionInfo( IFile model, IConnectionProfile connectionProfile, boolean driverClassChanged) throws Exception { ModelResource mr = ModelUtil.getModelResource(model, true); ConnectionInfoProviderFactory manager = new ConnectionInfoProviderFactory(); IConnectionInfoProvider provider = manager.getProvider(connectionProfile); if (null == provider) { throw new Exception(NO_PROFILE_PROVIDER_FOUND_KEY); } provider.setConnectionInfo(mr, connectionProfile); } private Shell getShell() { return Display.getCurrent().getActiveShell(); } /** * Update the JdbcSource within the specified Model, using the supplied connection profile. If the driver class in the provided * profile is different than the JdbcSource, the user is prompted to confirm. * @param model the model file * @param profile the connection profile */ private static void updateJdbcSourceAndConnectionInfo( IFile model, IConnectionProfile profile ) throws Exception { boolean driverClassChanged = false; ModelResource modelResc = ModelUtil.getModelResource(model, true); JdbcSource jdbcSource = null; if(modelResc!=null) { jdbcSource = getJdbcSource(modelResc); // JdbcSource was found - update it if(jdbcSource!=null) { Properties profileProps = profile.getBaseProperties(); // Driver Class from ConnectionProfile String driverClassCP = profileProps.getProperty(IJDBCDriverDefinitionConstants.DRIVER_CLASS_PROP_ID); String driverClassJdbcSrc = jdbcSource.getDriverClass(); // Check driver classes. If different, warn user that import settings will be blown away if(driverClassCP!=null && !driverClassCP.equalsIgnoreCase(driverClassJdbcSrc)) { String title = DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.confirmDriverclassChangeDialogTitle"); //$NON-NLS-1$ String msg = DatatoolsUiConstants.UTIL.getString("SetConnectionProfileAction.confirmDriverclassChangeDialogMsg"); //$NON-NLS-1$ if(!MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), title, msg)) { return; } driverClassChanged = true; } String profileName = profile.getName(); if(!CoreStringUtil.isEmpty(profileName)) { jdbcSource.setName(profileName); } String driverID = profileProps.getProperty("org.eclipse.datatools.connectivity.driverDefinitionID"); //$NON-NLS-1$ DriverInstance driver = DriverManager.getInstance().getDriverInstanceByID(driverID); if(driver!=null) { String driverName = driver.getName(); if(!CoreStringUtil.isEmpty(driverName)) { jdbcSource.setDriverName(driverName); } } String url = profileProps.getProperty(IJDBCDriverDefinitionConstants.URL_PROP_ID); if(!CoreStringUtil.isEmpty(url)) { jdbcSource.setUrl(url); } String driverClass = profileProps.getProperty(IJDBCDriverDefinitionConstants.DRIVER_CLASS_PROP_ID); if(!CoreStringUtil.isEmpty(driverClass)) { jdbcSource.setDriverClass(driverClass); } String userName = profileProps.getProperty(IJDBCDriverDefinitionConstants.USERNAME_PROP_ID); if(!CoreStringUtil.isEmpty(userName)) { jdbcSource.setUsername(userName); } // If driver classes was changed, reset the import settings if(driverClassChanged) { JdbcFactory jdbcFactory = new JdbcFactoryImpl(); jdbcSource.setImportSettings(jdbcFactory.createJdbcImportSettings()); } } // Set Connection Profile on the model SetConnectionProfileAction.setConnectionInfo(model, profile, driverClassChanged); // Set flags on model to prevent AutoUpdate and CostUpdate - if driverClass changed if(driverClassChanged) { ModelUtil.setModelAnnotationPropertyValue(modelResc, IConnectionInfoHelper.JDBCCONNECTION_NAMESPACE+IConnectionInfoHelper.JDBCCONNECTION_ALLOW_AUTOUPDATE_KEY, "false"); //$NON-NLS-1$ ModelUtil.setModelAnnotationPropertyValue(modelResc, IConnectionInfoHelper.JDBCCONNECTION_NAMESPACE+IConnectionInfoHelper.JDBCCONNECTION_ALLOW_COSTUPDATE_KEY, "false"); //$NON-NLS-1$ } } modelResc.save(null, true); } /* * Get the JdbcSource object from the supplied ModelResource. If none is found, null is returned * @param modelResc the Model Resource * @return the JdbcSource, null if not found */ private static JdbcSource getJdbcSource(ModelResource modelResc) { JdbcSource jdbcSource = null; // Non-null model supplied. Transfer the import settings if (modelResc != null) { List<?> rootObjs = null; try { rootObjs = modelResc.getAllRootEObjects(); } catch (Exception ex) { DatatoolsUiConstants.UTIL.log(ex); return null; } if(rootObjs!=null) { for (final Iterator<?> modelIter = rootObjs.iterator(); modelIter.hasNext();) { final Object obj = modelIter.next(); if (obj instanceof JdbcSource) { jdbcSource=(JdbcSource)obj; } } } } return jdbcSource; } public boolean setProperties(Properties properties) { this.designerProperties = properties; if( properties != null ) { String profileName = DesignerPropertiesUtil.getConnectionProfileName(designerProperties); if( profileName != null ) { this.connectionProfile = ProfileManager.getInstance().getProfileByName(profileName); } IFile model = DesignerPropertiesUtil.getSourceModel(this.designerProperties); if( model != null ) { this.setSelection(new StructuredSelection(model)); return true; } } return false; } }