Java tutorial
/******************************************************************************* * Copyright (c) 2015 Obeo * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.ecoretools.design.service; import java.util.Collection; import java.util.Set; import org.eclipse.emf.common.command.Command; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.transaction.NotificationFilter; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.sirius.business.api.session.ModelChangeTrigger; import org.eclipse.sirius.ext.base.Option; import org.eclipse.sirius.ext.base.Options; import com.google.common.collect.Sets; public class LiveValidationTrigger implements ModelChangeTrigger { public static final NotificationFilter IS_ECORE_CHANGE = new NotificationFilter.Custom() { public boolean matches(Notification notification) { return (!notification.isTouch() && notification.getFeature() instanceof EStructuralFeature && ((EStructuralFeature) notification.getFeature()).getEContainingClass() .getEPackage() == EcorePackage.eINSTANCE); } }; private TransactionalEditingDomain domain; /** * We need to be triggered before the refresh mechanism takes place so that * the diagnostic attachements are up-to date when computing colors. */ public static final int PRIORITY = 0; public LiveValidationTrigger(TransactionalEditingDomain domain) { this.domain = domain; } public Option<Command> localChangesAboutToCommit(Collection<Notification> notifications) { final Set<EObject> changedEcoreObjects = Sets.newLinkedHashSet(); for (Notification notif : notifications) { Object obj = notif.getNotifier(); if (obj instanceof EObject && ((EObject) obj).eClass() != null && ((EObject) obj).eClass().getEPackage() == EcorePackage.eINSTANCE) { changedEcoreObjects.add((EObject) obj); } } if (changedEcoreObjects.size() > 0) { Command revalidateEObjects = new RecordingCommand(domain) { @Override protected void doExecute() { Set<EObject> containers = Sets.newLinkedHashSet(); for (EObject eObj : changedEcoreObjects) { revalidate(eObj); EObject container = eObj.eContainer(); if (container != null) { containers.add(container); } } /* * When an Ecore object changes it is likely the container * might have a new validation error (or an error might be * gone) even if it has suffered no change itself. Example : * two EStructural features having the same name and * contained in the same EClass will trigger an error on * such EClass. This state should be updated when one of the * EStructuralFeature got renamed. */ for (EObject container : containers) { revalidate(container); } } protected void revalidate(EObject eObj) { DiagnosticAttachment diag = DiagnosticAttachment.getAttachment(eObj); /* * If the EObject had a validation marker, then we need to * update its state, otherwise nobody cared about its * validation status, no need to pre-compute it. */ if (diag != null) { try { /* * anything could happen within the validate. We * make sure we won't fail the whole post-process in * this case. */ Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eObj); /* * We attach the result of the validation on the * EObject through the eAdapters list. It might be * consumed by some modelers to change colors or * update tooltips. */ diag.setDiagnostic(diagnostic); } catch (Throwable e) { /* * Anything which happens here might not be a * concern. */ } } } }; return Options.newSome(revalidateEObjects); } return Options.newNone(); } public int priority() { return PRIORITY; } }