package pyUML.actions; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import org.eclipse.ui.PlatformUI; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.ProfileApplication; import org.eclipse.uml2.uml.internal.impl.UMLFactoryImpl; import org.eclipse.uml2.uml.resource.UMLResource; import pyUML.backend.EclipseHelperMethods; import pyUML.backend.GlobalConstants; import pyUML.backend.PyUMLProfile; import pyUML.backend.UMLToolsHelperMethods; import pyUML.exceptions.PyUMLCancelledException; import pyUML.exceptions.PyUMLParseException; import pyUML.listeners.ModelChangeListener; import pyUML.pythonTree.PythonTreeRoot; public class SyncModelAction implements IWorkbenchWindowActionDelegate, IRunnableWithProgress{ IProject project = null; public void dispose() { // Auto-generated method stub } public void init(IWorkbenchWindow window) { // Auto-generated method stub } /** * Static method to manually run a Model synchronization * @param project The model to use */ public static void runModelSync(IProject project) { SyncModelAction delegate = new SyncModelAction(); delegate.project = project; delegate.run((IAction) null); } public void run(IAction action) { ProgressMonitorDialog monitor = new ProgressMonitorDialog(null); try { monitor.run(false, true, this); } catch (Exception e) { e.printStackTrace(); } } /** * The central method - synchronizes the model by the python code * @param monitor a ProgressMonitor */ public void doSync(IProgressMonitor monitor) { // Ensure a project was given if (this.project == null) { return; } if (monitor != null) { monitor.beginTask("Look for existing Model", IProgressMonitor.UNKNOWN); } // save all open editors EclipseHelperMethods.saveAllOpenEditors(); // initialize XMI dictionaries as empty -> they are filled, if a // model already exists Map modelXmiDict = new HashMap(); Map xmiModelDict = new HashMap(); // read project IPath projectPath = project.getLocation(); // define uml file name String umlFileName=projectPath. append(GlobalConstants.getPyUmlDir()). append(project.getName()+".uml").toOSString(); // look for model file Model model; Resource resource; File modelFile = new File(umlFileName); if (modelFile.exists()) { // read Model EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(umlFileName); model = (Model) diagramRoot; resource = model.eResource(); // get model -> xmi-id dictionary UMLResource r = (UMLResource) resource; modelXmiDict = r.getEObjectToIDMap(); // create reverse dict, so that xmi_id can be the key for (EObject modelObject : modelXmiDict.keySet()) { String xmi_id = modelXmiDict.get(modelObject); xmiModelDict.put(xmi_id, modelObject); } } else { // Model file does *not* exist -> // A model has to be created resource = new ResourceSetImpl().createResource( URI.createFileURI(umlFileName)); model = UMLFactoryImpl.eINSTANCE.createModel(); model.setName(project.getName()); resource.getContents().add(model); try { resource.save(null); } catch (IOException e) { e.printStackTrace(); } // update model in eclipse EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project); } // define profile file name String profileFileName=projectPath. append(GlobalConstants.getPyUmlDir()). append("PyUMLProfile.uml").toOSString(); // look for UML profile file Profile profile; Resource profileResource; File profileFile = new File(profileFileName); if (! profileFile.exists()) { IFile profileIFile = EclipseHelperMethods.createFile(profileFile.getPath(), project); try { profileIFile.create(null, true, null); }catch (CoreException e) { e.printStackTrace(); } EclipseHelperMethods.StringToIFile(profileIFile, PyUMLProfile.getProfileString()); } // read and add Profile EObject profileRoot = UMLToolsHelperMethods.loadUMLDiagram(profileFileName); profile = (Profile) profileRoot; if (model.getProfileApplication(profile) == null) { ProfileApplication profApplication = model.createProfileApplication(); profApplication.setAppliedProfile(profile); EAnnotation eannot = profApplication.createEAnnotation("http://www.eclipse.org/uml2/2.0.0/UML"); } // generate PythonTree out of PythonCode PythonTreeRoot pythonRoot = null; try { pythonRoot = new PythonTreeRoot(this.project, true, monitor); } catch (PyUMLParseException e) { MessageDialog.openError(null, "Error parsing project code", "There was an error parsing the python code of the current\n" + "project.\n" + "PyUML can not work as long as there are errors in the project code!\n" + "Please resolve the error and try again!\n\n" + "Error message was:\n\n"+ e.getMessage()); return; } catch (PyUMLCancelledException e) { MessageDialog.openWarning(null, "Operation cancelled", "The Operation was cancelled by the user"); return; } catch (Exception e) { e.printStackTrace(); MessageDialog.openError(null, "Error parsing project code", "There was an error parsing the python code of the current\n" + "project.\n" +"Error message was:\n\n"+ e.getMessage()); return; } if (monitor != null) monitor.beginTask("Synchronize the Model with the given Code", IProgressMonitor.UNKNOWN); // ### Synchronize model with code ### boolean syncSuccess = false; String errMsg = null; boolean normalRun = false; try { syncSuccess = pythonRoot.synchronizeModel(model, xmiModelDict); normalRun=true; }catch(Exception e) { e.printStackTrace(); errMsg = e.getClass().getName() + "\n" +e.getMessage(); } if (!syncSuccess) { if (! normalRun) { // if no error happened, but model was not synchronized, // we assume there already was an adequate message and leave. // otherwise, we print a generic message and leave afterwards String message = "There was an error synchronizing the Model.\n"; if (errMsg != null) message += "The error message was:\n"+errMsg; MessageDialog.openError(null, "Synchronizing Model Failed", message); } return; } // save new or changed model to .uml file, // if synchronization was successful if (syncSuccess) try { resource.save(null); // update model in eclipse EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project); System.out.println(("Saving model file done.")); } catch (IOException ioe) { MessageDialog.openError(null,"IOException", "Error saving uml file: \n" + ioe.getMessage()); } // Synchronize Code if (syncSuccess) { try{ // after creating the model, synchronize the code // so that all model xmi_ids will be part of the code // re-use existing pythonRoot, so that code will not have // to be read-in again. SyncCodeAction.run(project, pythonRoot, monitor); }catch (Throwable t) { MessageDialog.openError(null,"Error synchronizing Code!", t.getClass().getName() + " while synchronizing Code!: \n\n" + t.getMessage()); t.printStackTrace(); } } monitor.beginTask("Update UML diagram", IProgressMonitor.UNKNOWN); // if model diagram does not exist, create it! // create graphical diagram, if it does not already exist // after creation, open it; if it is opened, refresh view. IFile diagramFile = this.project.getWorkspace() .getRoot().getFile(this.project.getFullPath() .append(GlobalConstants.getPyUmlDir()) .append(project.getName()+GlobalConstants .getDiagramExtension())); if (! diagramFile.exists()) { UMLToolsHelperMethods.createModelDiagram(model, diagramFile); }else { } monitor.beginTask("Open UML diagram", IProgressMonitor.UNKNOWN); // after creating model, be sure the diagram view is reloaded boolean diagramOpened = null != EclipseHelperMethods .firstOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension()); if (diagramOpened) { // set focus to updated diagram only if no diagram is currently active boolean keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage().getActiveEditor().getTitle() .matches(".*"+GlobalConstants.getDiagramExtension()); // close all sub-package pyUML.views of global model diagram for ( IEditorReference editor : EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) { PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage().closeEditor(editor.getEditor(true), true); } IEditorPart modelEditor = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, keepFocus); modelEditor.addPropertyListener(new ModelChangeListener(project)); } else { IEditorPart modelEditor = UMLToolsHelperMethods.openDiagram(project, diagramFile, project.getName()+".uml", true); modelEditor.addPropertyListener(new ModelChangeListener(project)); } UMLToolsHelperMethods.updateModelAndViewPages(this.project); monitor.done(); } public void selectionChanged(IAction action, ISelection selection) { if (selection instanceof TreeSelection) { TreeSelection ts = (TreeSelection) selection; Object selectedElement = ts.getFirstElement(); this.project = (IProject) selectedElement; } } public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.setTaskName("Starting Model Synchronization"); this.doSync(monitor); } }