/* * Licensed to Laurent Broudoux (the "Author") under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Author 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 * * http://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 com.github.lbroudoux.dsl.eip.parser.core.ui.actions; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.handlers.HandlerUtil; import com.github.lbroudoux.dsl.eip.EIPModel; import com.github.lbroudoux.dsl.eip.EipPackage; import com.github.lbroudoux.dsl.eip.Route; import com.github.lbroudoux.dsl.eip.ServiceRef; import com.github.lbroudoux.dsl.eip.parser.core.ui.dialogs.PersistTargetSelectionDialog; /** * Base abstract handler for parsing resources to EIP and persisting them as EIP Model route. * It drives generic parsing, merging and persistence process and provides a sole method <code>extractEIPModelFromFile(IFile)</code> * that subclass should implement in order to specify how to parse the selected file. * @author laurent */ public abstract class AbstractPersistToRouteModelActionHandler extends AbstractHandler { /** * The command has been executed, so extract the needed information * from the application context. */ @Override public Object execute(ExecutionEvent event) throws ExecutionException{ ISelection currentSelection = HandlerUtil.getCurrentSelection(event); if (currentSelection != null && currentSelection instanceof IStructuredSelection) { // Retrieve file corresponding to current selection. IStructuredSelection selection = (IStructuredSelection)currentSelection; IFile selectionFile = (IFile)selection.getFirstElement(); // Open persit target selection dialog. PersistTargetSelectionDialog dialog = new PersistTargetSelectionDialog( HandlerUtil.getActiveShellChecked(event), selectionFile.getName()); if (dialog.open() != Window.OK) { return null; } // Ask concrete subclass to parse source file and extract EIPModel for persisting. EIPModel extracted = extractEIPModelFromFile(selectionFile); // Load and find EIPModel definition. IResource eipModelResource = dialog.getSelectedEIPModel(); ResourceSet resourceSet = initializeResourceSet(); final Resource emfResource = resourceSet.getResource(URI.createURI(eipModelResource.getLocationURI().toString()), true); EIPModel target = null; for (EObject object : emfResource.getContents()){ if (object instanceof EIPModel) { target = (EIPModel) object; break; } } // Merge extracted model into target one. for (Route route : extracted.getOwnedRoutes()) { Route existing = findRouteByName(target, route.getName()); if (existing != null) { // New route totally overrides existing one. Simply replace existing pointer ? existing = EcoreUtil.copy(route); } else { // Add a new route to target model. target.getOwnedRoutes().add(EcoreUtil.copy(route)); } } for (ServiceRef serviceRef : extracted.getOwnedServiceRefs()) { ServiceRef existing = findServiceRefByName(target, serviceRef.getName()); if (existing != null) { // New service ref cannot replace existing one, cause route have only a partial // view on reference. Complete existing one. for (String operation : serviceRef.getOperations()) { if (!isOperationPresent(existing, operation)) { existing.getOperations().add(operation); } } } else { // Add a new service reference to target model. target.getOwnedServiceRefs().add(EcoreUtil.copy(serviceRef)); } } // Finally, save modified EMF resource. WorkspaceModifyOperation modifyOp = new WorkspaceModifyOperation() { @Override protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException, InterruptedException { try { emfResource.save(null); } catch (IOException e) { System.err.println("IOException while saving modified EIP model"); e.printStackTrace(); } } }; try { modifyOp.run(new NullProgressMonitor()); } catch (InvocationTargetException ite) { ite.printStackTrace(); } catch (InterruptedException ie) { ie.printStackTrace(); } // Refresh project containing target model. try { eipModelResource.getProject().refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } catch (CoreException e) { System.err.println("Exception while refreshing project containing target model"); e.printStackTrace(); } } return null; } /** * Hook for concrete subclass. Only called once event is valid and valid EIP Model to host target Route * has been found and loaded. Subclass should implement this method in order to specify how to retrieve the EIPModel * model fragment containing Route that need to be persisted into the target EIP Route to create. * @param selectionFile The event current selection. * @return an EIPModel fragment containing extransted Route dans service references */ protected abstract EIPModel extractEIPModelFromFile(IFile selectionFile); /** Factorize here the EMF loading model plumbing stuffs. */ private ResourceSet initializeResourceSet() { // Initialize a ResourceSet to later load model and add Route. ResourceSet resourceSet = new ResourceSetImpl(); // Register the appropriate resource factory to handle all file extensions. resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); // Register the package to ensure it is available during loading. resourceSet.getPackageRegistry().put(EipPackage.eNS_URI, EipPackage.eINSTANCE); return resourceSet; } /** */ private Route findRouteByName(EIPModel model, String routeName) { for (Route route : model.getOwnedRoutes()) { if (route.getName().equals(routeName)) { return route; } } return null; } /** */ private ServiceRef findServiceRefByName(EIPModel model, String refName) { for (ServiceRef ref : model.getOwnedServiceRefs()) { if (ref.getName().equals(refName)) { return ref; } } return null; } /** */ private boolean isOperationPresent(ServiceRef reference, String opName) { for (String operation : reference.getOperations()) { if (operation.equals(opName)) { return true; } } return false; } }