/*
* 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.transformation.ui.wizards.rest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IMarkerResolution;
import org.teiid.core.designer.ModelerCoreException;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.extension.ModelExtensionUtils;
import org.teiid.designer.core.util.ModelObjectCollector;
import org.teiid.designer.core.workspace.ModelObjectAnnotationHelper;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.core.workspace.ModelWorkspaceException;
import org.teiid.designer.extension.ExtensionPlugin;
import org.teiid.designer.metamodels.relational.Procedure;
import org.teiid.designer.metamodels.relational.extension.RelationalModelExtensionAssistant;
import org.teiid.designer.metamodels.relational.extension.RelationalModelExtensionConstants;
import org.teiid.designer.metamodels.relational.extension.RestModelExtensionAssistant;
import org.teiid.designer.metamodels.relational.extension.RestModelExtensionConstants;
import org.teiid.designer.transformation.ui.Messages;
import org.teiid.designer.transformation.ui.UiConstants;
import org.teiid.designer.transformation.ui.UiPlugin;
import org.teiid.designer.ui.common.viewsupport.UiBusyIndicator;
import org.teiid.designer.ui.editors.ModelEditor;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
public class RestExtensionPropertiesMarkerResolution implements IMarkerResolution, RestModelExtensionConstants {
private Map<EObject, Properties> existingRestPropertyMap;
@Override
public String getLabel() {
return Messages.restMedQuickFixLabel;
}
@Override
public void run(IMarker marker) {
/*
1) Gather up a cache of all "exten. prop. overrides", their values, ext. prop IDs and their target objects
2) Throw away the old MEDs, inject/apply new MEDs
3) Reset new exten. overrides using the map of old ID's to new IDs
*/
this.existingRestPropertyMap = new HashMap<EObject, Properties>();
IResource resource = marker.getResource();
// Fix the Marked Model Resource
if(ModelUtilities.isModelFile(resource)) {
final IFile theFile = (IFile)resource;
final ModelEditor editor = ModelEditorManager.getModelEditorForFile(theFile, false);
// If editor is open and dirty, ask user whether to save
if ((editor != null) && editor.isDirty()) {
boolean saveEditor = MessageDialog.openQuestion(getShell(), Messages.quickFixModelDirtyTitle, Messages.quickFixModelDirtyMsg);
if(!saveEditor) {
return;
} else {
// Add the selected Med
UiBusyIndicator.showWhile(Display.getDefault(), new Runnable() {
@Override
public void run() {
editor.doSave(new NullProgressMonitor());
fixInTxn(theFile);
}
});
return;
}
}
// Add the selected Med
UiBusyIndicator.showWhile(Display.getDefault(), new Runnable() {
@Override
public void run() {
fixInTxn(theFile);
}
});
// Fix the Marked mxd File
}
this.existingRestPropertyMap.clear();
}
private void fixInTxn(IResource modelFile) {
boolean requiredStart = ModelerCore.startTxn(true, false, "Fix out-dated rest model extensions", modelFile);
boolean succeeded = false;
try {
replaceRestMedAndSetProperties(modelFile);
succeeded = true;
} finally {
// if we started the transaction, commit it.
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
}
}
/*
* Fix Legacy Names in the supplied Model File by replacing the legacy 'com.metamatrix' names with 'org.teiid.designer'
* @param modelResource the supplied model resource
*/
private void replaceRestMedAndSetProperties( IResource modelFile ) {
final ModelResource mr = ModelUtilities.getModelResource(modelFile);
/* ------------------------------
* STEP 1: Find ALL extended REST properties in the model file and cache off properties for object
-------------------------------- */
// Get the list of EObjects in a model and look for Procedure with properties
try {
final ModelObjectCollector moc = new ModelObjectCollector(mr.getEmfResource());
@SuppressWarnings("unchecked")
List<EObject> eObjects = moc.getEObjects();
ModelObjectAnnotationHelper helper = new ModelObjectAnnotationHelper();
for( EObject eObj : eObjects) {
if( eObj instanceof Procedure ) {
// find extension properties for eObj
Properties props = helper.getProperties(eObj, OLD_REST_INFO.OLD_REST_PREFIX);
// If they exist, get the property "key" values and if they are "rest:URI" or "rest:method" then add these to the existingRestPropertyMap
if( ! props.isEmpty() ) {
this.existingRestPropertyMap.put(eObj, props);
}
}
}
} catch (ModelWorkspaceException e) {
UiConstants.Util.log(e);
} catch (ModelerCoreException e) {
UiConstants.Util.log(e);
}
/* ------------------------------
* STEP 2: remove the old "rest" MED from the model
-------------------------------- */
//
try {
ModelExtensionUtils.removeModelExtensionDefinition(mr, OLD_REST_INFO.OLD_REST_NAMESPACE_PREFIX);
} catch (Exception e) {
UiConstants.Util.log(e);
}
/* ------------------------------
* STEP 3: remove old extension properties
-------------------------------- */
ModelObjectAnnotationHelper helper = new ModelObjectAnnotationHelper();
try {
for( EObject eObj : this.existingRestPropertyMap.keySet() ) {
if( eObj instanceof Procedure ) {
helper.removeProperties(eObj, OLD_REST_INFO.OLD_REST_PREFIX);
}
}
} catch (ModelerCoreException e) {
UiConstants.Util.log(e);
}
/* ------------------------------
* STEP 4: add the new REST MED and RELATIONAL MED to the model
-------------------------------- */
final String prefix = RelationalModelExtensionConstants.NAMESPACE_PROVIDER.getNamespacePrefix();
final RelationalModelExtensionAssistant relatinalAssistant = (RelationalModelExtensionAssistant)ExtensionPlugin.getInstance().getRegistry().getModelExtensionAssistant(prefix);
final RestModelExtensionAssistant restAssistant = RestModelExtensionAssistant.getRestAssistant();
try {
relatinalAssistant.applyMedIfNecessary(modelFile);
restAssistant.applyMedIfNecessary(modelFile);
} catch (Exception e) {
UiConstants.Util.log(e);
}
/* ------------------------------
* STEP 5: Re-add the cached rest properties to the model using the new REST: prefix
-------------------------------- */
for( EObject eObj : this.existingRestPropertyMap.keySet() ) {
if( eObj instanceof Procedure ) {
Properties props = this.existingRestPropertyMap.get(eObj);
for( Object key : props.keySet() ) {
String keyStr = (String)key;
String value = props.getProperty(keyStr);
if( keyStr.equals(OLD_REST_INFO.OLD_REST_METHOD_KEY)) {
RestModelExtensionAssistant.setRestProperty(eObj, PropertyIds.REST_METHOD, value.toUpperCase());
} else if( keyStr.equals(OLD_REST_INFO.OLD_REST_URI_KEY)) {
RestModelExtensionAssistant.setRestProperty(eObj, PropertyIds.URI, value);
}
}
}
}
/* ------------------------------
* STEP 5: SAVE ALL CHANGES
-------------------------------- */
try {
ModelResource mdlResc = ModelUtilities.getModelResourceForIFile((IFile)modelFile, false);
if(mdlResc!=null) {
mdlResc.save(new NullProgressMonitor(), true);
}
modelFile.deleteMarkers(MED_PROBLEM_MARKER_ID, true, IResource.DEPTH_INFINITE);
modelFile.getParent().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
} catch (CoreException e) {
UiConstants.Util.log(IStatus.ERROR, e, NLS.bind(Messages.saveModelErrorMsg, modelFile.getName()));
}
}
private static Shell getShell() {
return UiPlugin.getDefault().getCurrentWorkbenchWindow().getShell();
}
}