org.eclipse.emf.ecoretools.design.service.LiveValidationTrigger.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.ecoretools.design.service.LiveValidationTrigger.java

Source

/*******************************************************************************
 * 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;
    }

}