org.eclipse.sirius.business.internal.session.danalysis.SessionResourcesTracker.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.business.internal.session.danalysis.SessionResourcesTracker.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.sirius.business.internal.session.danalysis;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.sirius.business.api.query.URIQuery;
import org.eclipse.sirius.common.tools.DslCommonPlugin;
import org.eclipse.sirius.ecore.extender.tool.api.ModelUtils;
import org.eclipse.sirius.ext.emf.EReferencePredicate;
import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey;
import org.eclipse.sirius.viewpoint.DAnalysis;
import org.eclipse.sirius.viewpoint.DView;
import org.eclipse.sirius.viewpoint.Messages;
import org.eclipse.sirius.viewpoint.SiriusPlugin;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;

/**
 * This class is responsible for keeping track of which resources in the
 * ResourceSet correspond to what kind of model (semantic,
 * session/analysis/representation, description...).
 * 
 * @author pcdavid
 */
class SessionResourcesTracker {
    /**
     * The session for which we keep track of resources.
     */
    private DAnalysisSessionImpl session;

    /** The semantic resources collection. */
    private Collection<Resource> semanticResources;

    /** The semantic resources collection updater. */
    private SemanticResourcesUpdater semanticResourcesUpdater;

    private ControlledResourcesDetector controlledResourcesDetector;

    private DAnalysisRefresher dAnalysisRefresher;

    /**
     * Creates a new tracker for the specified session.
     * 
     * @param session
     *            the session to track.
     */
    SessionResourcesTracker(DAnalysisSessionImpl session) {
        this.session = Preconditions.checkNotNull(session);
        this.controlledResourcesDetector = new ControlledResourcesDetector(session);
        dAnalysisRefresher = new DAnalysisRefresher(session);
    }

    void initialize(IProgressMonitor monitor) {
        DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.RESOLVE_ALL_KEY);
        Collection<DAnalysis> analyses = session.allAnalyses();
        // First resolve all VSM resources used for Sirius to ignore VSM
        // resources and VSM linked resources (as viewpoint:/environment
        // resource) as new semantic element
        resolveAllVSMResources(analyses);
        // Resolve all semantic resources from {@link DAnalysis.getModels()}
        resolveAllSemanticResourcesFromModels(analyses);
        // Then resolve all resources (to automatically add new semantic
        // resources)
        List<Resource> resourcesBeforeLoadOfSession = Lists
                .newArrayList(session.getTransactionalEditingDomain().getResourceSet().getResources());
        forceLoadingOfEveryLinkedResource();
        monitor.worked(10);

        // Add the unknown resources to the semantic resources of this
        // session.
        manageAutomaticallyLoadedResources(session, resourcesBeforeLoadOfSession);
        monitor.worked(1);

        DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.RESOLVE_ALL_KEY);
        // Look for controlled resources after load of every linked
        // resources.
        // Detect actual controlled resources.
        ControlledResourcesDetector.refreshControlledResources(session);
        if (controlledResourcesDetector != null) {
            controlledResourcesDetector.initialize();
        }
        // Reset semanticResources to have getSemanticResources() ignores
        // controlledResources which are computed only at this step
        if (semanticResourcesUpdater != null) {
            semanticResourcesUpdater.dispose();
            semanticResourcesUpdater = null;
        }
        semanticResources = null;
        monitor.worked(1);
        dAnalysisRefresher.initialize();
    }

    void addAdaptersOnAnalysis(final DAnalysis analysis) {
        if (semanticResourcesUpdater != null && !analysis.eAdapters().contains(semanticResourcesUpdater)) {
            analysis.eAdapters().add(semanticResourcesUpdater);
        }
    }

    void removeAdaptersOnAnalysis(final DAnalysis analysis) {
        if (semanticResourcesUpdater != null && analysis.eAdapters().contains(semanticResourcesUpdater)) {
            analysis.eAdapters().remove(semanticResourcesUpdater);
        }
    }

    Collection<Resource> getSemanticResources() {
        if (semanticResources == null) {
            semanticResources = new CopyOnWriteArrayList<Resource>();
            if (semanticResourcesUpdater == null) {
                semanticResourcesUpdater = new SemanticResourcesUpdater(session);
            }
            semanticResourcesUpdater.setSemanticResources(semanticResources);

            RunnableWithResult<Collection<Resource>> semanticResourcesGetter = new RunnableWithResult.Impl<Collection<Resource>>() {
                @Override
                public void run() {
                    setResult(SemanticResourceGetter.collectTopLevelSemanticResources(session));
                }
            };
            try {
                TransactionUtil.runExclusive(session.getTransactionalEditingDomain(), semanticResourcesGetter);
            } catch (InterruptedException e) {
                SiriusPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, SiriusPlugin.ID,
                        Messages.SessionResourcesTracker_semanticResourcesAccessErrorMsg));
            }
            ((CopyOnWriteArrayList<Resource>) semanticResources).addAllAbsent(semanticResourcesGetter.getResult());
        }
        return Collections.unmodifiableCollection(semanticResources);
    }

    /**
     * Allow semanticResources to be recomputed when calling
     * <code>getSemanticResources()</code>.
     */
    void setSemanticResourcesNotUptodate() {
        semanticResources.clear();
        semanticResources = null;
    }

    /**
     * Resolve all resources of the resource set of this session. Some
     * references are ignored (derived features, containment/container
     * references).
     */
    private void forceLoadingOfEveryLinkedResource() {
        ModelUtils.resolveAll(session.getTransactionalEditingDomain().getResourceSet(), new EReferencePredicate() {
            @Override
            public boolean apply(EReference input) {
                // Do not resolve derived features.
                // Do not resolve containment/container references : they are
                // already resolved by the model structural analysis course.
                return !input.isDerived() && !input.isContainer() && !input.isContainment();
            }
        });
    }

    /**
     * Resolve all VSM resources, and VSM linked resources (as
     * viewpoint:/environment resource), used through Sirius in
     * <code>allAnalysis</code>.
     * 
     * @param allAnalysis
     *            The analysis of this session (owned analysis or referenced
     *            analysis by this session).
     */
    private void resolveAllVSMResources(Collection<DAnalysis> allAnalysis) {
        List<Resource> resolvedResources = Lists.newArrayList();
        for (DAnalysis dAnalysis : allAnalysis) {
            for (DView dView : dAnalysis.getOwnedViews()) {
                if (dView.getViewpoint() != null) {
                    Resource vsmResource = dView.getViewpoint().eResource();
                    if (vsmResource != null && !resolvedResources.contains(vsmResource)) {
                        ModelUtils.resolveAll(vsmResource, true);
                        resolvedResources.add(vsmResource);
                    }
                }
            }
        }
    }

    /**
     * Resolve all semantic resources.
     * 
     * @param allAnalysis
     *            The analysis of this session
     */
    private void resolveAllSemanticResourcesFromModels(Collection<DAnalysis> allAnalysis) {
        for (DAnalysis dAnalysis : allAnalysis) {
            for (EObject model : dAnalysis.getModels()) {
                EcoreUtil.resolve(model, dAnalysis);
            }
        }
    }

    /**
     * Check the resources in the resourceSet. Detect new resources and add them
     * to the session as new semantic resources or referenced session resources.<BR>
     * <BR>
     * New semantic resources are :
     * <UL>
     * <LI>Resources that are not in the <code>knownResources</code> list</LI>
     * <LI>Resources that are not in the semantic resources of this session</LI>
     * <LI>Resources that are not in the referenced representations files
     * resources of this session</LI>
     * <LI>Resources that are not the Sirius environment resource</LI>
     * </UL>
     * <BR>
     * New referenced session resources are :
     * <UL>
     * <LI>Resources that are not in the <code>knownResources</code> list</LI>
     * <LI>Resources that are in the referenced representations files resources
     * of this session (the list is computed from the allAnalyses() result)</LI>
     * </UL>
     * 
     * @param knownResources
     *            List of resources that is already loaded before the resolveAll
     *            of the representations file load.
     */
    static void manageAutomaticallyLoadedResources(final DAnalysisSessionImpl session,
            List<Resource> knownResources) {
        TransactionalEditingDomain domain = session.getTransactionalEditingDomain();
        List<Resource> resourcesAfterLoadOfSession = Lists.newArrayList(domain.getResourceSet().getResources());
        // Remove the known resources
        Iterators.removeAll(resourcesAfterLoadOfSession.iterator(), knownResources);

        if (resourcesAfterLoadOfSession.isEmpty()) {
            return;
        }

        Set<Resource> referencedSessionResources = session.getReferencedSessionResources();
        Collection<Resource> newReferencedSessionResources = Lists.newArrayList(
                Iterables.filter(resourcesAfterLoadOfSession, Predicates.in(referencedSessionResources)));
        if (!newReferencedSessionResources.isEmpty()) {
            for (Resource newReferencedSessionResource : newReferencedSessionResources) {
                session.registerResourceInCrossReferencer(newReferencedSessionResource);
                for (DAnalysis refAnalysis : Iterables.filter(newReferencedSessionResource.getContents(),
                        DAnalysis.class)) {
                    session.addAdaptersOnAnalysis(refAnalysis);
                }
            }
        }

        // Remove the known semantic resources
        Iterators.removeAll(resourcesAfterLoadOfSession.iterator(), session.getSemanticResources());
        // Remove the known referenced representations file resources
        Iterators.removeAll(resourcesAfterLoadOfSession.iterator(), referencedSessionResources);

        final Iterable<Resource> newSemanticResourcesIterator = Iterables.filter(resourcesAfterLoadOfSession,
                new Predicate<Resource>() {
                    public boolean apply(Resource resource) {
                        // Remove empty resource and the Sirius environment
                        return !resource.getContents().isEmpty()
                                && !(new URIQuery(resource.getURI()).isEnvironmentURI());
                    }
                });
        if (!Iterables.isEmpty(newSemanticResourcesIterator)) {
            domain.getCommandStack().execute(new RecordingCommand(domain,
                    Messages.SessionResourcesTracker_addReferencedSemanticResourcesMsg) {
                @Override
                protected void doExecute() {
                    for (Resource resource : newSemanticResourcesIterator) {
                        session.addSemanticResource(resource.getURI(), new NullProgressMonitor());
                    }
                }
            });
        }
    }

    void dispose() {
        session = null;
        if (dAnalysisRefresher != null) {
            dAnalysisRefresher.dispose();
            dAnalysisRefresher = null;
        }
        if (controlledResourcesDetector != null) {
            controlledResourcesDetector.dispose();
            controlledResourcesDetector = null;
        }
        if (semanticResourcesUpdater != null) {
            semanticResourcesUpdater.dispose();
            semanticResourcesUpdater = null;
        }
        if (semanticResources != null) {
            semanticResources.clear();
        }
    }

    void detectControlledResources() {
        ControlledResourcesDetector.refreshControlledResources(session);
    }
}