/** * Copyright (c) 2017 committers of YAKINDU and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * Contributors: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.sct.ui.editor.validation; import java.util.List; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.TreeIterator; 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.Copier; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.transaction.util.TransactionUtil; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.validation.CheckMode; import org.eclipse.xtext.validation.Issue; import org.yakindu.sct.ui.editor.DiagramActivator; import com.google.common.collect.Lists; import com.google.inject.Inject; /** * Copies the resource contents to a shadow model that is validated then. Does * not block UI during validation but consumes more memory since the whole model * is duplicated. * * @author andreas muelder - Initial contribution and API * */ public class ShadowModelValidationJob extends ValidationJob { @Inject private ResourceCopier copier; @Override protected IStatus runInternal(final IProgressMonitor monitor) { ResourceSet set = new ResourceSetImpl(); try { if (!resource.isLoaded()) return Status.CANCEL_STATUS; final Resource shadowResource = set.createResource(resource.getURI()); cloneResource(monitor, shadowResource); if (monitor.isCanceled()) return Status.CANCEL_STATUS; final List<Issue> issues = Lists.newArrayList(); try { issues.addAll(doValidation(monitor, shadowResource)); } catch (Throwable ex) { return Status.CANCEL_STATUS; } validationIssueProcessor.processIssues(issues, monitor); } catch (Exception ex) { ex.printStackTrace(); return new Status(IStatus.ERROR, DiagramActivator.PLUGIN_ID, ex.getMessage()); } return Status.OK_STATUS; } protected List<Issue> doValidation(final IProgressMonitor monitor, final Resource shadowResource) { return validator.validate(shadowResource, CheckMode.FAST_ONLY, new CancelIndicator() { public boolean isCanceled() { return monitor.isCanceled(); } }); } protected void cloneResource(final IProgressMonitor monitor, final Resource shadowResource) throws ExecutionException { AbstractTransactionalCommand cmd = new AbstractTransactionalCommand(TransactionUtil.getEditingDomain(resource), "", null) { @Override protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, IAdaptable info) throws ExecutionException { try { copier.cloneResource(resource, shadowResource); } catch (Throwable t) { return CommandResult.newErrorCommandResult(t.getMessage()); } return CommandResult.newOKCommandResult(); } }; cmd.execute(monitor, null); } public static class ResourceCopier extends Copier { private static final long serialVersionUID = 1L; public void cloneResource(Resource original, Resource clone) { clone.setURI(original.getURI()); clone.getContents().addAll(super.copyAll(original.getContents())); copyReferences(); copyXMIIds(original, clone); } protected void copyXMIIds(Resource original, Resource clone) { if (original instanceof XMLResource) { TreeIterator<EObject> iterator = original.getAllContents(); TreeIterator<EObject> cloneIterator = clone.getAllContents(); while (iterator.hasNext()) { EObject next = iterator.next(); EObject nextClone = cloneIterator.next(); if (next.eClass() != nextClone.eClass()) { throw new IllegalStateException("Models are out of sync!"); } ((XMLResource) clone).setID(nextClone, ((XMLResource) original).getID(next)); } } } } }