/*
* 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.webservice.ui.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.teiid.core.designer.util.I18nUtil;
import org.teiid.designer.core.transaction.SourcedNotification;
import org.teiid.designer.metamodels.transformation.SqlTransformation;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.metamodels.webservice.Input;
import org.teiid.designer.metamodels.webservice.Interface;
import org.teiid.designer.metamodels.webservice.Operation;
import org.teiid.designer.metamodels.webservice.Output;
import org.teiid.designer.metamodels.webservice.WebServicePackage;
import org.teiid.designer.metamodels.xml.XmlDocument;
import org.teiid.designer.transformation.ui.PluginConstants;
import org.teiid.designer.transformation.ui.UiPlugin;
import org.teiid.designer.transformation.ui.editors.sqleditor.SqlEditorPanel;
import org.teiid.designer.transformation.util.SqlMappingRootCache;
import org.teiid.designer.transformation.util.TransformationHelper;
import org.teiid.designer.ui.common.util.UiUtil;
import org.teiid.designer.ui.undo.ModelerUndoManager;
import org.teiid.designer.ui.util.ModelObjectNotificationHelper;
import org.teiid.designer.ui.viewsupport.ModelIdentifier;
import org.teiid.designer.webservice.ui.IInternalUiConstants;
import org.teiid.designer.webservice.ui.editor.OperationObjectEditorPage;
/**
* @since 8.0
*/
public class WebServiceNotificationListener implements INotifyChangedListener, IInternalUiConstants {
private static final String I18N_PFX = I18nUtil.getPropertyPrefix(WebServiceNotificationListener.class);
private static final String CONFIRM_SQLUPDATE_TITLE = UTIL.getString(I18N_PFX + "confirmSQLUpdateTitle"); //$NON-NLS-1$
private static final String CONFIRM_SQLUPDATE_MSG = UTIL.getString(I18N_PFX + "confirmSQLUpdateMsg"); //$NON-NLS-1$
// Required class variable that can be used in Runnable code to insure dialogs are placed in UI (SWT) thread
boolean uiBooleanResult = false;
/**
* Notifications handler. Gathers all like notifications and handles them together. Only the relevant notifications will be
* processed by this listener.
*
* @param notifications the collection of all notifications
* @param transactionSource
*/
private void handleNotifications( Collection notifications,
Object transactionSource ) {
// Here's where we do some additional work if we detect something that needs to be done as a result of
// the notification
for (Iterator noteIter = notifications.iterator(); noteIter.hasNext();) {
// NOTE: We are listening for ONE particular notification here. You can't use NotificationUtilities.isAdded()
// method
// because it doesn't pass the standard criteria. The "Source" added to the transformation isn't a container-based
// add,
// so we have to trust the notification.getEventType() and check the notifier and newValue objects
Notification note = (Notification)noteIter.next();
Object src = note.getNotifier();
Object newVal = note.getNewValue();
Object oldVal = note.getOldValue();
switch (note.getEventType()) {
case Notification.ADD: {
if (src instanceof Interface && newVal instanceof Operation) {
WebServiceUiUtil.initializeProcedure((Operation)newVal, transactionSource, false);
} else {
processChangedXmlDocumentAsSource(src, newVal, true, transactionSource);
}
break;
}
case Notification.REMOVE: {
processChangedXmlDocumentAsSource(src, oldVal, false, transactionSource);
break;
}
case Notification.SET: {
if (src instanceof Input && note.getFeatureID(Input.class) == WebServicePackage.INPUT__CONTENT_ELEMENT) {
boolean shouldReplace = true;
if (!(transactionSource instanceof OperationObjectEditorPage.MySqlPanelDropTargetListener)
&& !(transactionSource instanceof SqlEditorPanel)) {
uiBooleanResult = false;
// put on SWT thread
UiUtil.runInSwtThread(new Runnable() {
@Override
public void run() {
uiBooleanResult = confirmReplaceProcedure();
}
}, true);
shouldReplace = uiBooleanResult;
}
if (!(transactionSource instanceof SqlEditorPanel)) {
WebServiceUiUtil.initializeProcedure(((Input)src).getOperation(), transactionSource, shouldReplace);
}
} else if (src instanceof Output && note.getFeatureID(Output.class) == WebServicePackage.OUTPUT__XML_DOCUMENT) {
boolean shouldReplace = true;
if (!(transactionSource instanceof OperationObjectEditorPage.MySqlPanelDropTargetListener)
&& !(transactionSource instanceof SqlEditorPanel)) {
uiBooleanResult = false;
// put on SWT thread
UiUtil.runInSwtThread(new Runnable() {
@Override
public void run() {
uiBooleanResult = confirmReplaceProcedure();
}
}, true);
shouldReplace = uiBooleanResult;
}
if (!(transactionSource instanceof SqlEditorPanel)) {
WebServiceUiUtil.initializeProcedure(((Output)src).getOperation(), transactionSource, shouldReplace);
}
} else if (transactionSource instanceof SqlEditorPanel && src instanceof SqlTransformation) {
// If user sets the SQL to NULL, we need to assume they want to clear the source document from the
// Output message property and clear the content via element.
if (newVal == null) {
SqlTransformationMappingRoot mappingRoot = (SqlTransformationMappingRoot)((EObject)src).eContainer();
// Check if root's target is Operation
EObject target = mappingRoot.getTarget();
if (target != null && TransformationHelper.isOperation(target)) {
String sql = SqlMappingRootCache.getSelectSql(mappingRoot);
if (sql == null || sql.trim().length() == 0) {
// Then we have an EMPTY SQL here and we need to clean out the XML Doc AND Content via element
// properties
WebServiceUiUtil.clearXmlDocumentAsSource(mappingRoot, true, transactionSource);
}
}
}
}
break;
}
}
}
}
/*
* Method to confirm that the user wants to overwrite the existing procedure
* @return 'true' if procedure is to be overwritten, 'false' if not.
*/
boolean confirmReplaceProcedure() {
boolean replaceProc = false;
// Check if callbacks are disabled
IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore();
boolean disableCallbacks = prefStore.getBoolean(PluginConstants.Prefs.Callbacks.DISABLE_CALLBACKS);
if (!disableCallbacks) {
// Prompt whether to add the proc symbols to the target
replaceProc = MessageDialog.openQuestion(null, CONFIRM_SQLUPDATE_TITLE, CONFIRM_SQLUPDATE_MSG);
}
return replaceProc;
}
/**
* Handler method for Undo notifications. Basically, the undo/redo notifications are ignored unless the SQL statement has
* changed. In the event that the SQL is being changed, then the only thing that needs to be done is to invalidate the
* SqlMappingRootCache. This insures that the cache will not be stale.
*
* @param notifications the collection of notifications
*/
private void handleUndo( Collection notifications,
Object txnSource ) {
if (!notifications.isEmpty()) {
// NO SPECIFIC WORK YET
}
}
/**
* @see org.eclipse.emf.edit.provider.INotifyChangedListener#notifyChanged(org.eclipse.emf.common.notify.Notification)
*/
@Override
public void notifyChanged( Notification notification ) {
// ----------------------------------------------------------------------------------------------
// NOTE: Transaction boundaries are taken care of by the specific
// handler. Don't start one here
// ----------------------------------------------------------------------------------------------
// Check for SourcedNotification (we should only get
// SourcedNotifications)
if (notification instanceof SourcedNotification) {
SourcedNotification note = (SourcedNotification)notification;
Object src = note.getSource();
if (src == null || !src.equals(this)) {
if (src == null) {
src = notification.getNotifier();
}
// Undos - special handler
if (src instanceof ModelerUndoManager) {
Collection notifications = ((SourcedNotification)notification).getNotifications();
handleUndo(notifications, src);
} else {
// Let's do a check here to see if notifications involve Web Service Models
ModelObjectNotificationHelper helper = new ModelObjectNotificationHelper(notification);
boolean webServiceModelsChanged = false;
for (Iterator iter = helper.getModifiedResources().iterator(); iter.hasNext();) {
if (ModelIdentifier.isWebServicesViewModel((IResource)iter.next())) {
webServiceModelsChanged = true;
break;
}
}
if (webServiceModelsChanged) {
Collection notifications = ((SourcedNotification)notification).getNotifications();
handleNotifications(notifications, src);
}
}
}
} else { // handle single Notification
Collection notifications = new ArrayList(1);
notifications.add(notification);
handleNotifications(notifications, notification.getNotifier());
}
}
/**
* This private method sets additional properties on a Web Services's Operation's Output object In particular, it calls
* setXmlDocument() and setContentViaElement()
*/
private void processChangedXmlDocumentAsSource( Object source,
Object value,
boolean add,
Object transactionSource ) {
// Ensure that targetObject is SqlTransformationMappingRoot
if (!TransformationHelper.isSqlTransformationMappingRoot(source)) {
return;
}
// Ensure root's target is Web Service Operation object
Object target = ((SqlTransformationMappingRoot)source).getTarget();
if (!(target instanceof Operation)) {
return;
}
Operation operation = (add ? (Operation)target : null);
// Ensure that there is only one XmlDocument (i.e. can't add multiple XML documents as sources)
XmlDocument xmlDocument = null;
if (value instanceof List) {
for (Iterator iter = ((List)value).iterator(); iter.hasNext();) {
Object obj = iter.next();
if (obj instanceof XmlDocument) {
if (xmlDocument == null) {
xmlDocument = (XmlDocument)obj;
} else {
xmlDocument = null;
break;
}
}
} // for
} else if (value instanceof XmlDocument) {
xmlDocument = (XmlDocument)value;
}
// Ensure there is only one new value and it's an XML document
if (xmlDocument != null && operation != null && operation.getOutput() != null) {
WebServiceUiUtil.addXmlDocumentAsSource((SqlTransformationMappingRoot)source, xmlDocument, transactionSource);
}
}
}