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

Java tutorial

Introduction

Here is the source code for org.eclipse.sirius.business.internal.session.danalysis.DAnalysisSessionImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2013, 2016 THALES GLOBAL SERVICES 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:
 *    Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.sirius.business.internal.session.danalysis;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.transaction.util.ValidateEditSupport;
import org.eclipse.emf.workspace.IWorkspaceCommandStack;
import org.eclipse.emf.workspace.ResourceUndoContext;
import org.eclipse.sirius.business.api.componentization.ViewpointRegistry;
import org.eclipse.sirius.business.api.query.DAnalysisQuery;
import org.eclipse.sirius.business.api.query.FileQuery;
import org.eclipse.sirius.business.api.query.RepresentationDescriptionQuery;
import org.eclipse.sirius.business.api.query.ResourceQuery;
import org.eclipse.sirius.business.api.resource.ResourceDescriptor;
import org.eclipse.sirius.business.api.session.CustomDataConstants;
import org.eclipse.sirius.business.api.session.ReloadingPolicy;
import org.eclipse.sirius.business.api.session.SavingPolicy;
import org.eclipse.sirius.business.api.session.Session;
import org.eclipse.sirius.business.api.session.SessionEventBroker;
import org.eclipse.sirius.business.api.session.SessionListener;
import org.eclipse.sirius.business.api.session.SessionManager;
import org.eclipse.sirius.business.api.session.SessionService;
import org.eclipse.sirius.business.api.session.SessionStatus;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSelector;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSelectorService;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSession;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSessionHelper;
import org.eclipse.sirius.business.api.session.danalysis.DAnalysisSessionService;
import org.eclipse.sirius.business.internal.resource.ResourceModifiedFieldUpdater;
import org.eclipse.sirius.business.internal.resource.strategy.ResourceStrategyRegistry;
import org.eclipse.sirius.business.internal.session.IsModifiedSavingPolicy;
import org.eclipse.sirius.business.internal.session.ReloadingPolicyImpl;
import org.eclipse.sirius.business.internal.session.RepresentationNameListener;
import org.eclipse.sirius.business.internal.session.SessionEventBrokerImpl;
import org.eclipse.sirius.common.tools.DslCommonPlugin;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
import org.eclipse.sirius.common.tools.api.resource.ResourceSetSync;
import org.eclipse.sirius.common.tools.api.resource.ResourceSetSync.ResourceStatus;
import org.eclipse.sirius.common.tools.api.resource.ResourceSyncClient;
import org.eclipse.sirius.common.tools.api.util.ECrossReferenceAdapterWithUnproxyCapability;
import org.eclipse.sirius.common.tools.api.util.EqualityHelper;
import org.eclipse.sirius.common.tools.api.util.SiriusCrossReferenceAdapter;
import org.eclipse.sirius.ecore.extender.business.api.accessor.EcoreMetamodelDescriptor;
import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority;
import org.eclipse.sirius.ecore.extender.business.api.permission.PermissionAuthorityRegistry;
import org.eclipse.sirius.ecore.extender.business.api.permission.exception.LockedInstanceException;
import org.eclipse.sirius.tools.api.command.ui.NoUICallback;
import org.eclipse.sirius.tools.api.interpreter.InterpreterRegistry;
import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey;
import org.eclipse.sirius.tools.api.ui.RefreshEditorsPrecommitListener;
import org.eclipse.sirius.tools.internal.interpreter.ODesignGenericInterpreter;
import org.eclipse.sirius.tools.internal.resource.ResourceSetUtil;
import org.eclipse.sirius.viewpoint.DAnalysis;
import org.eclipse.sirius.viewpoint.DRepresentation;
import org.eclipse.sirius.viewpoint.DSemanticDecorator;
import org.eclipse.sirius.viewpoint.DView;
import org.eclipse.sirius.viewpoint.Messages;
import org.eclipse.sirius.viewpoint.SiriusPlugin;
import org.eclipse.sirius.viewpoint.description.RepresentationDescription;
import org.eclipse.sirius.viewpoint.description.Viewpoint;
import org.eclipse.sirius.viewpoint.impl.DAnalysisSessionEObjectImpl;

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

/**
 * A session which store data in {@link DAnalysis} references.
 * 
 * @author cbrun
 */
public class DAnalysisSessionImpl extends DAnalysisSessionEObjectImpl
        implements Session, DAnalysisSession, ResourceSyncClient {
    /** The custom saving policy the session should use. */
    private SavingPolicy savingPolicy;

    /** The {@link TransactionalEditingDomain} associated to this Session. */
    private TransactionalEditingDomain transactionalEditingDomain;

    /** The main Session Resource. */
    private Resource sessionResource;

    /** The {@link DAnalysis} of the main session resource (*.aird). */
    private DAnalysis mainDAnalysis;

    private SessionResourcesTracker tracker = new SessionResourcesTracker(this);

    // Session's configuration

    private final Saver saver;

    private ReloadingPolicy reloadingPolicy;

    private IResourceCollector currentResourceCollector;

    private SessionVSMUpdater vsmUpdater = new SessionVSMUpdater(this);

    private final SessionResourcesSynchronizer resourcesSynchronizer = new SessionResourcesSynchronizer(this);

    // Generic services offered by the session

    /**
     * The event broker suitable for identifying local or remote atomic changes.
     */
    private SessionEventBroker broker;

    private SessionService services;

    private ECrossReferenceAdapterWithUnproxyCapability crossReferencer;

    private IInterpreter interpreter;

    private final ListenerList listeners = new ListenerList();

    private int lastNotification = -1;

    // Default listeners

    /** The listener suitable for refresh the opened viewpoint editors. */
    private RefreshEditorsPrecommitListener refreshEditorsListeners;

    private RepresentationsChangeAdapter representationsChangeAdapter;

    private RepresentationNameListener representationNameListener;

    /**
     * Create a new session.
     * 
     * @param mainDAnalysis
     *            the analysis keeping the session data.
     */
    public DAnalysisSessionImpl(DAnalysis mainDAnalysis) {
        Preconditions.checkNotNull(mainDAnalysis);
        this.sessionResource = mainDAnalysis.eResource();
        Preconditions.checkNotNull(this.sessionResource, Messages.DAnalysisSessionImpl_noRessourceErrorMsg);
        this.transactionalEditingDomain = Preconditions.checkNotNull(
                TransactionUtil.getEditingDomain(mainDAnalysis),
                Messages.DAnalysisSessionImpl_noEditingDomainErrorMsg);
        this.mainDAnalysis = mainDAnalysis;
        this.saver = new Saver(this);
        this.interpreter = new ODesignGenericInterpreter();
        this.representationsChangeAdapter = new RepresentationsChangeAdapter(this);
        super.getAnalyses().add(mainDAnalysis);
        super.getResources().add(sessionResource);
        setAnalysisSelector(DAnalysisSelectorService.getSelector(this));
        setResourceCollector(new LocalResourceCollector(getTransactionalEditingDomain().getResourceSet()));
        setDeferSaveToPostCommit(true);
        setSaveInExclusiveTransaction(true);

    }

    // *******************
    // Session interpreter
    // *******************

    @Override
    public IInterpreter getInterpreter() {
        if (this.crossReferencer == null) {
            this.interpreter.setCrossReferencer(getSemanticCrossReferencer());
        }
        return this.interpreter;
    }

    /**
     * Configure the interpreter attached to this session.
     */
    void configureInterpreter() {
        // Calculate paths of the activated representation description files.
        List<String> filePaths = new ArrayList<String>();
        for (Viewpoint vp : getSelectedViewpointsSpecificToGeneric()) {
            Resource vpResource = vp.eResource();
            if (vpResource != null) {
                filePaths.add(vpResource.getURI().toPlatformString(true));
            }
        }
        // Setting the FILES property is actually interpreted as adding new
        // files for historical reasons, so reset it to null first before
        // setting the new value.
        this.interpreter.setProperty(IInterpreter.FILES, null);
        this.interpreter.setProperty(IInterpreter.FILES, filePaths);
        InterpreterRegistry.prepareImportsFromSession(this.interpreter, this);
        this.interpreter.setCrossReferencer(getSemanticCrossReferencer());
    }

    // *******************
    // Cross-referencer
    // *******************

    @Override
    public ECrossReferenceAdapterWithUnproxyCapability getSemanticCrossReferencer() {
        if (crossReferencer == null) {
            crossReferencer = createSemanticCrossReferencer();
            if (interpreter != null) {
                interpreter.setCrossReferencer(crossReferencer);
            }
        }
        return crossReferencer;
    }

    /**
     * Create the semantic cross referencer.
     * 
     * @return a new cross referencer adapter
     */
    protected ECrossReferenceAdapterWithUnproxyCapability createSemanticCrossReferencer() {
        return new SessionLazyCrossReferencer(this);
    }

    /**
     * Add the cross referencer (if exists and is not present) to the eAdapters
     * list of the given resource.
     * 
     * @param newResource
     *            the resource on which the semantic cross reference should be
     *            added.
     */
    protected void registerResourceInCrossReferencer(final Resource newResource) {
        if (crossReferencer != null) {
            if (!newResource.eAdapters().contains(crossReferencer)) {
                newResource.eAdapters().add(crossReferencer);
            }
        }
    }

    /**
     * Remove the cross referencer (if exists and is present) from the eAdapters
     * list of the given resource.
     * 
     * @param resource
     *            the resource from which the semantic cross reference should be
     *            removed.
     */
    protected void unregisterResourceInCrossReferencer(final Resource resource) {
        if (crossReferencer != null) {
            if (resource.eAdapters().contains(crossReferencer)) {
                resource.eAdapters().remove(crossReferencer);
            }
        }
    }

    /**
     * Disable & Remove all ECrossReferencerAdapter adapters.
     */
    protected void disableAndRemoveECrossReferenceAdapters() {
        ResourceSet resourceSet = getTransactionalEditingDomain().getResourceSet();

        // Disable resolution of proxy for SiriusCrossReferenceAdapter of
        // resourceSet
        List<Adapter> adaptersToRemove = new ArrayList<Adapter>();
        for (Adapter next : resourceSet.eAdapters()) {
            if (next instanceof SiriusCrossReferenceAdapter) {
                ((SiriusCrossReferenceAdapter) next).disableResolveProxy();
                adaptersToRemove.add(next);
            }
        }
        resourceSet.eAdapters().removeAll(adaptersToRemove);

        // disable resolveProxy capability before clearing adapters on resources
        for (Resource resource : resourceSet.getResources()) {
            disableCrossReferencerResolve(resource);
            resource.eAdapters().clear();
        }
        // Also disable resolveProxy capability and remove semantic cross
        // referencer from all resources where it was installed
        // (SessionLazyCrossReferencer.initialize()).
        Collection<Resource> semanticResources = getSemanticResources();
        Collection<Resource> controlledResources = getControlledResources();
        Set<Resource> allSessionResources = getAllSessionResources();
        Object semanticCrossReferencer = getSemanticCrossReferencer();
        Iterable<Resource> resources = Iterables.concat(semanticResources, controlledResources,
                allSessionResources);
        for (Resource resource : resources) {
            if (!(resourceSet.getResources().contains(resource))) {
                disableCrossReferencerResolve(resource);
                resource.eAdapters().remove(semanticCrossReferencer);
            }
        }

        for (final DAnalysis analysis : Iterables.filter(allAnalyses(), Predicates.notNull())) {
            removeAdaptersOnAnalysis(analysis);
        }
    }

    // *******************
    // Analyses
    // *******************

    @Override
    public void addAnalysis(Resource analysisResource) {
        Preconditions.checkArgument(analysisResource.getContents().get(0) instanceof DAnalysis);
        DAnalysis analysis = (DAnalysis) analysisResource.getContents().get(0);
        super.getResources().add(analysisResource);
        super.getAnalyses().add(analysis);
        registerResourceInCrossReferencer(analysisResource);
        addAdaptersOnAnalysis(analysis);
        notifyListeners(SessionListener.REPRESENTATION_CHANGE);
        DViewOperations.on(this).updateSelectedViewpointsData(new NullProgressMonitor());
        configureInterpreter();
    }

    @Override
    public void removeAnalysis(Resource analysisResource) {
        Preconditions.checkArgument(analysisResource.getContents().get(0) instanceof DAnalysis);
        DAnalysis analysis = (DAnalysis) analysisResource.getContents().get(0);
        super.getResources().remove(analysisResource);
        super.getAnalyses().remove(analysis);
        for (DAnalysis potentialRef : allAnalyses()) {
            if (potentialRef.getReferencedAnalysis().contains(analysis)) {
                potentialRef.getReferencedAnalysis().remove(analysis);
            }
        }
        unregisterResourceInCrossReferencer(analysisResource);
        transactionalEditingDomain.getResourceSet().getResources().remove(analysisResource);
        removeAdaptersOnAnalysis(analysis);
        notifyListeners(SessionListener.REPRESENTATION_CHANGE);
    }

    @Override
    public void addReferencedAnalysis(final DAnalysis newAnalysis) {
        assert newAnalysis.eResource() != null;
        List<DAnalysis> sources = Lists.newArrayList();
        if (!super.getAnalyses().isEmpty()) {
            DAnalysis referencer = super.getAnalyses().iterator().next();
            if (referencer != null) {
                sources.add(referencer);
            }
        }
        addReferencedAnalysis(newAnalysis, sources);
    }

    @Override
    public void addReferencedAnalysis(final DAnalysis newAnalysis, final Collection<DAnalysis> referencers) {
        if (referencers != null && !referencers.isEmpty()) {
            // Install the cross referencer as soon as possible
            registerResourceInCrossReferencer(newAnalysis.eResource());

            for (DAnalysis referencer : referencers) {
                referencer.getReferencedAnalysis().add(newAnalysis);
            }

            addAdaptersOnAnalysis(newAnalysis);
            for (DAnalysis dAnalysis : new DAnalysisQuery(newAnalysis).getAllReferencedAnalyses()) {
                registerResourceInCrossReferencer(dAnalysis.eResource());
                addAdaptersOnAnalysis(dAnalysis);
            }

            notifyListeners(SessionListener.REPRESENTATION_CHANGE);
        } else {
            throw new IllegalStateException(Messages.DAnalysisSessionImpl_addNoParentAnalysisErrorMsg);
        }
    }

    @Override
    public void removeReferencedAnalysis(final DAnalysis analysis) {
        assert analysis.eResource() != null;
        Collection<DAnalysis> referencers = Lists.newArrayList();
        for (DAnalysis potentialRef : allAnalyses()) {
            if (potentialRef.getReferencedAnalysis().contains(analysis)) {
                referencers.add(potentialRef);
            }
        }
        if (!referencers.isEmpty()) {
            for (DAnalysis referencer : referencers) {
                referencer.getReferencedAnalysis().remove(analysis);
            }
            removeAdaptersOnAnalysis(analysis);
            notifyListeners(SessionListener.REPRESENTATION_CHANGE);
        } else {
            throw new IllegalStateException(Messages.DAnalysisSessionImpl_removeNoParentAnalysisErrorMsg);
        }
    }

    /**
     * Return all valid(i.e. not null) owned and referenced analyses.
     * 
     * @return all valid(i.e. not null) owned and referenced analyses.
     */
    public Collection<DAnalysis> allAnalyses() {
        Collection<DAnalysis> analysisAndReferenced = Sets.newLinkedHashSet();
        for (DAnalysis analysis : Lists.newArrayList(super.getAnalyses())) {
            /* analysis could be null */
            if (analysis != null) {
                analysisAndReferenced.add(analysis);
                addAllReferencedAnalyses(analysisAndReferenced, analysis);
            }
        }
        return analysisAndReferenced;
    }

    Collection<Resource> getAllSemanticResources() {
        Collection<Resource> semanticResources = new LinkedHashSet<Resource>(this.getSemanticResources());
        semanticResources.addAll(this.getControlledResources());
        return semanticResources;
    }

    private void addAllReferencedAnalyses(final Collection<DAnalysis> analysisAndReferenced,
            final DAnalysis analysis) {
        for (DAnalysis referenced : Sets.newLinkedHashSet(analysis.getReferencedAnalysis())) {
            if (!analysisAndReferenced.contains(referenced) && referenced.eResource() != null) {
                analysisAndReferenced.add(referenced);
                addAllReferencedAnalyses(analysisAndReferenced, referenced);
            }
        }
    }

    DAnalysis getMainAnalysis() {
        return this.mainDAnalysis;
    }

    @Override
    public void addAdaptersOnAnalysis(final DAnalysis analysis) {
        if (this.representationsChangeAdapter != null) {
            this.representationsChangeAdapter.registerAnalysis(analysis);
        }
        if (tracker != null) {
            tracker.addAdaptersOnAnalysis(analysis);
        }
    }

    @Override
    public void removeAdaptersOnAnalysis(final DAnalysis analysis) {
        if (this.representationsChangeAdapter != null) {
            this.representationsChangeAdapter.unregisterAnalysis(analysis);
        }
        if (tracker != null) {
            tracker.removeAdaptersOnAnalysis(analysis);
        }
    }

    @Override
    public void moveRepresentation(final DAnalysis newContainer, final DRepresentation representation) {
        final IPermissionAuthority authority = PermissionAuthorityRegistry.getDefault()
                .getPermissionAuthority(representation.eContainer());
        IProgressMonitor pm = new NullProgressMonitor();
        if (!authority.canDeleteInstance(representation)) {
            throw new LockedInstanceException(representation);
        }
        final EObject semantic;
        if (representation.eContainer() instanceof DView
                && !((DView) representation.eContainer()).getModels().isEmpty()) {
            semantic = ((DView) representation.eContainer()).getModels().iterator().next();
        } else {
            semantic = null;
        }
        Viewpoint viewpoint = ((DView) representation.eContainer()).getViewpoint();
        DView receiver = findViewForRepresentation(viewpoint, newContainer);
        if (receiver == null) {
            final IPermissionAuthority analysisAuthority = PermissionAuthorityRegistry.getDefault()
                    .getPermissionAuthority(newContainer);
            if (analysisAuthority.canCreateIn(newContainer)) {
                createView(viewpoint, Lists.newArrayList(semantic), false, pm);
                receiver = findViewForRepresentation(viewpoint, newContainer);
            } else {
                throw new LockedInstanceException(newContainer);
            }
        }
        final IPermissionAuthority receiverAuthority = PermissionAuthorityRegistry.getDefault()
                .getPermissionAuthority(receiver);
        if (receiverAuthority.canCreateIn(receiver)) {
            receiver.getOwnedRepresentations().add(representation);
            // Add all semantic root elements pointed by the target of all
            // DSemanticDecorator of this representation (except of this root is
            // a root of a referencedAnalysis)
            if (receiver.eContainer() instanceof DAnalysis) {
                DAnalysisSessionHelper.updateModelsReferences((DAnalysis) receiver.eContainer(),
                        Iterators.filter(representation.eAllContents(), DSemanticDecorator.class));
            }
        } else {
            throw new LockedInstanceException(receiver);
        }
        for (EObject object : getServices().getCustomData(CustomDataConstants.GMF_DIAGRAMS, representation)) {
            getServices().putCustomData(CustomDataConstants.GMF_DIAGRAMS, representation, object);
        }
    }

    private static DView findViewForRepresentation(Viewpoint vp, DAnalysis analysis) {
        for (final DView view : analysis.getOwnedViews()) {
            if (view.getViewpoint() != null && EqualityHelper.areEquals(view.getViewpoint(), vp)) {
                return view;
            }
        }
        return null;
    }

    // *******************
    // Semantic Resources
    // *******************

    /**
     * Find all the resources referenced by any object from the specified
     * resource. Ignore "http" resources.
     * 
     * @param res
     *            the resource to start from.
     * @return all the resources referenced by elements from res, except "http"
     *         resources.
     */
    protected Collection<Resource> collectAllReferencedResources(Resource res) {
        Collection<Resource> result = Collections.emptyList();
        if (currentResourceCollector != null) {
            result = currentResourceCollector.getAllReferencedResources(res);
        }
        return result;
    }

    /**
     * Find all the resources referencing by any object from the specified
     * resource. Ignore "http" resources.
     * 
     * @param res
     *            the resource to start from.
     * @return all the resources referencing by elements from res, except "http"
     *         resources.
     */
    protected Collection<Resource> collectAllReferencingResources(Resource res) {
        Collection<Resource> result = Collections.emptyList();
        if (currentResourceCollector != null) {
            result = currentResourceCollector.getAllReferencingResources(res);
        }
        return result;
    }

    @Override
    public synchronized void addSemanticResource(URI semanticModelURI, IProgressMonitor monitor) {
        if (semanticModelURI != null) {
            if (new FileQuery(semanticModelURI.fileExtension()).isSessionResourceFile()) {
                throw new IllegalArgumentException(Messages.DAnalysisSessionImpl_addSemanticErrorMsg);
            }
            ResourceSet resourceSet = transactionalEditingDomain.getResourceSet();
            try {
                monitor.beginTask(MessageFormat.format(Messages.DAnalysisSessionImpl_addSemanticResourceMsg,
                        semanticModelURI.lastSegment()), 3);

                Resource newSemanticResource = resourceSet.getResource(semanticModelURI, false);
                if (newSemanticResource != null && newSemanticResource.getContents().isEmpty()) {
                    // The resource is probably loaded (created) with a proxy
                    // resolution. Indeed, in case of proxy, the method
                    // eResolveProxy causes a creation of an empty resource in
                    // the resourceSet.
                    // So we must unload it before load it again.
                    // resourceSet.
                    newSemanticResource.unload();
                }
                monitor.worked(1);
                // Make ResourceSet aware of resource loading with progress
                // monitor
                ResourceSetUtil.setProgressMonitor(resourceSet, new SubProgressMonitor(monitor, 2));
                newSemanticResource = resourceSet.getResource(semanticModelURI, true);
                // If it is a new resource, register it with all its referenced
                // resources as semantic models.
                if (!getSemanticResources().contains(newSemanticResource)) {
                    doAddSemanticResource(newSemanticResource, resourceSet);
                    for (Resource res : collectAllReferencedResources(newSemanticResource)) {
                        doAddSemanticResource(res, resourceSet);
                    }
                }
            } finally {
                monitor.done();
                ResourceSetUtil.resetProgressMonitor(resourceSet);
            }
        }
    }

    /**
     * Registers the specified resource as a semantic resource.
     * 
     * @param newResource
     *            the semantic resource.
     * @param set
     *            the ResourceSet in which it should be added if needed.
     */
    protected void doAddSemanticResource(final Resource newResource, final ResourceSet set) {
        if (new ResourceQuery(newResource).isRepresentationsResource()) {
            throw new IllegalArgumentException(Messages.DAnalysisSessionImpl_addSemanticErrorMsg);
        }
        if (newResource.getResourceSet() != set) {
            set.getResources().add(newResource);
        }
        if (newResource.getContents().size() > 0) {
            notifyNewMetamodels(newResource);
            for (final DAnalysis analysis : this.allAnalyses()) {
                analysis.getSemanticResources().add(new ResourceDescriptor(newResource.getURI()));
            }
        }

        ControlledResourcesDetector.refreshControlledResources(this);

        registerResourceInCrossReferencer(newResource);
    }

    private void notifyNewMetamodels(final Resource newResource) {
        if (Boolean.valueOf(System.getProperty("org.eclipse.sirius.enableUnsafeOptimisations", "false"))) { //$NON-NLS-1$ //$NON-NLS-2$
            return;
        }
        final Collection<EPackage> collectedMetamodels = collectMetamodels(newResource.getAllContents());
        final ModelAccessor accessor = getModelAccessor();
        if (accessor != null) {
            final Collection<EcoreMetamodelDescriptor> descriptors = new ArrayList<EcoreMetamodelDescriptor>();
            for (final EPackage package1 : collectedMetamodels) {
                descriptors.add(new EcoreMetamodelDescriptor(package1));
            }
            accessor.activateMetamodels(descriptors);
        }
    }

    private Collection<EPackage> collectMetamodels(final TreeIterator<EObject> allContents) {
        final Collection<EPackage> result = new LinkedHashSet<EPackage>();
        while (allContents.hasNext()) {
            result.add(allContents.next().eClass().getEPackage());
        }
        return result;
    }

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

    @Override
    public Collection<Resource> getSemanticResources() {
        if (tracker != null) {
            return tracker.getSemanticResources();
        } else {
            return Collections.emptyList();
        }
    }

    @Override
    public void removeSemanticResource(Resource semanticResource, IProgressMonitor monitor,
            boolean removeReferencingResources) {
        if (removeReferencingResources) {
            for (final Resource res : collectAllReferencingResources(semanticResource)) {
                doRemoveSemanticResource(res);
            }
        }
        doRemoveSemanticResource(semanticResource);
    }

    /**
     * Unregisters the resource from the list of semantic resources and remove
     * the resource from its ResourceSet.
     * 
     * @param res
     *            the semantic resource to unregister.
     */
    protected void doRemoveSemanticResource(final Resource res) {
        ResourceSet resourceSet = res.getResourceSet();
        if (resourceSet != null) {
            // update models in aird resource
            for (final DAnalysis analysis : this.allAnalyses()) {
                analysis.getSemanticResources().remove(new ResourceDescriptor(res.getURI()));
            }

            unregisterResourceInCrossReferencer(res);
            disableCrossReferencerResolve(res);
            ResourceStrategyRegistry.getInstance().unloadAtResourceSetDispose(res, new NullProgressMonitor());
            enableCrossReferencerResolve(res);

            resourceSet.getResources().remove(res);

            ControlledResourcesDetector.refreshControlledResources(this);
        }
    }

    void discoverAutomaticallyLoadedResources(List<Resource> allResources) {
        SessionResourcesTracker.manageAutomaticallyLoadedResources(this, allResources);
    }

    // *******************
    // Session Resources
    // *******************
    @Override
    public Resource getSessionResource() {
        return sessionResource;
    }

    @Override
    public Set<Resource> getReferencedSessionResources() {
        return getSessionResources(false);
    }

    @Override
    public Set<Resource> getAllSessionResources() {
        return getSessionResources(true);
    }

    private Set<Resource> getSessionResources(boolean includeMainResource) {
        List<Resource> result = Lists.newArrayList();
        for (DAnalysis analysis : allAnalyses()) {
            Resource res = analysis.eResource();
            if (res != null && (includeMainResource || res != sessionResource)) {
                result.add(res);
            }
        }
        return ImmutableSet.copyOf(result);
    }

    // *******************
    // Saving and Synchronization
    // *******************
    /**
     * Sets the Synchronization status of every resources of this Session's
     * resourceSet to SYNC or changed regarding their modified status.
     */
    protected void setSynchronizeStatusofEveryResource() {
        setSynchronizeStatusofEveryResource(transactionalEditingDomain.getResourceSet().getResources());
    }

    /**
     * Sets the Synchronization status of considered resources of this Session's
     * resourceSet to SYNC or changed regarding their modified status.
     * 
     * Should only be called from setSynchronizeStatusofEveryResource method
     * (and overriding ones).
     * 
     * @param resourcesToConsider
     *            the resources to consider.
     */
    protected final void setSynchronizeStatusofEveryResource(Iterable<Resource> resourcesToConsider) {
        ResourceSetSync rsSetSync = ResourceSetSync.getOrInstallResourceSetSync(transactionalEditingDomain);
        Collection<ResourceSyncClient.ResourceStatusChange> changes = Lists.newArrayList();
        for (Resource resource : Sets.newHashSet(resourcesToConsider)) {
            ResourceStatus oldStatus = ResourceSetSync.getStatus(resource);
            ResourceStatus newStatus = resource.isModified() ? ResourceStatus.CHANGED : ResourceStatus.SYNC;
            changes.add(new ResourceSyncClient.ResourceStatusChange(resource, newStatus, oldStatus));
        }
        rsSetSync.statusesChanged(changes);
    }

    @Override
    public final void save(IProgressMonitor monitor) {
        save((Map<?, ?>) null, monitor);
    }

    @Override
    public void save(Map<?, ?> options, IProgressMonitor monitor) {
        saver.save(options, monitor);
    }

    /**
     * Performs the save immediately.
     * 
     * @param options
     *            the options to use to save the resources.
     * @param monitor
     *            the monitor to use to report progress.
     * @param runExclusive
     *            whether or not to execute the saving in an exclusive
     *            transaction.
     */
    protected void doSave(final Map<?, ?> options, final IProgressMonitor monitor, boolean runExclusive) {
        try {
            monitor.beginTask(Messages.DAnalysisSessionImpl_saveMsg, 3);
            final Collection<Resource> allResources = Lists.newArrayList();
            allResources.addAll(getAllSessionResources());
            Collection<Resource> semanticResourcesCollection = getSemanticResources();
            allResources.addAll(semanticResourcesCollection);
            allResources.addAll(getControlledResources());
            monitor.worked(1);
            RunnableWithResult<Collection<Resource>> save = new RunnableWithResult.Impl<Collection<Resource>>() {
                @Override
                public void run() {
                    Collection<Resource> savedResources = getSavingPolicy().save(allResources, options,
                            new SubProgressMonitor(monitor, 7));
                    setResult(savedResources);
                }
            };
            if (runExclusive && !saver.domainDisposed.get()) {
                /*
                 * launching the save itself in a read-only transaction will
                 * block any other operation on the model which could come in
                 * the meantime.
                 */
                getTransactionalEditingDomain().runExclusive(save);
            } else {
                save.run();
            }

            Collection<Resource> savedResources = save.getResult();
            if (savedResources != null) {
                CommandStack commandStack = transactionalEditingDomain.getCommandStack();
                if (commandStack instanceof BasicCommandStack) {
                    ((BasicCommandStack) commandStack).saveIsDone();
                }
                if (allResourcesAreInSync()) {
                    notifyListeners(SessionListener.SYNC);
                } else {
                    notifyListeners(SessionListener.DIRTY);
                }
                monitor.worked(1);
            }
        } catch (InterruptedException e) {
            SiriusPlugin.getDefault().warning(Messages.DAnalysisSessionImpl_saveInterruptedMsg, e);
        } finally {
            monitor.done();
        }
    }

    @Override
    public void statusChanged(Resource resource, ResourceStatus oldStatus, ResourceStatus newStatus) {
        resourcesSynchronizer.statusChanged(resource, oldStatus, newStatus);
    }

    @Override
    public void statusesChanged(Collection<ResourceStatusChange> changes) {
        resourcesSynchronizer.statusesChanged(changes);
    }

    /**
     * Tells if the specified resource is one of
     * {@link Session#getSemanticResources()},
     * {@link Session#getAllSessionResources()} or
     * DAnalysisSessionEObject#getControlledResources().
     * 
     * @param resource
     *            the specified {@link Resource}
     * @param resources
     *            the session resources
     * @return true if the specified {@link Resource} is one of the
     *         {@link Session}, false otherwise
     */
    protected boolean isResourceOfSession(Resource resource, Iterable<Resource> resources) {
        for (Resource input : resources) {
            if (resource == input || (input.getURI() != null && Objects.equal(resource.getURI(), input.getURI()))) {
                return true;
            }
        }
        return false;
    }

    void sessionResourceReloaded(final Resource newSessionResource) {
        // sessionResource's contents before reload can be proxy
        // then need to be reassigned with reloaded
        // sessionResource reference.
        sessionResource = newSessionResource;
        mainDAnalysis = (DAnalysis) sessionResource.getContents().get(0);
    }

    @Override
    public void setReloadingPolicy(ReloadingPolicy reloadingPolicy) {
        this.reloadingPolicy = reloadingPolicy;
    }

    @Override
    public ReloadingPolicy getReloadingPolicy() {
        return reloadingPolicy != null ? reloadingPolicy : new ReloadingPolicyImpl(new NoUICallback());
    }

    @Override
    public void setSavingPolicy(SavingPolicy savingPolicy) {
        this.savingPolicy = savingPolicy;
    }

    /**
     * Returns the custom saving policy the session should use ; if no
     * SavingPolicy has been defined, creates a default one.<br/>
     * Subclasses can override this method to define a new default Saving
     * Policy.
     * 
     * @return the custom saving policy the session should use
     */
    @Override
    public SavingPolicy getSavingPolicy() {
        return savingPolicy != null ? savingPolicy : new IsModifiedSavingPolicy(transactionalEditingDomain);
    }

    /**
     * Indicates whether all resources (semantic and Danalysises) of this
     * Session are whether {@link ResourceStatus#SYNC} or
     * {@link ResourceStatus#READONLY}.
     * 
     * @return true if all resources (semantic and Danalysises) of this Session
     *         are whether {@link ResourceStatus#SYNC} or
     *         {@link ResourceStatus#READONLY}, false otherwise
     */
    protected boolean allResourcesAreInSync() {
        return resourcesSynchronizer.allResourcesAreInSync();
    }

    /**
     * Indicates whether considered resources are whether
     * {@link ResourceStatus#SYNC} or {@link ResourceStatus#READONLY}.
     * 
     * @param resourcesToConsider
     *            the resources to inspect.
     * @return true if all considered are whether {@link ResourceStatus#SYNC} or
     *         {@link ResourceStatus#READONLY}, false otherwise
     */
    protected final boolean checkResourcesAreInSync(Iterable<? extends Resource> resourcesToConsider) {
        return resourcesSynchronizer.checkResourcesAreInSync(resourcesToConsider);
    }

    @Override
    public SessionStatus getStatus() {
        if (allResourcesAreInSync()) {
            return SessionStatus.SYNC;
        } else {
            return SessionStatus.DIRTY;
        }
    }

    public void setDeferSaveToPostCommit(boolean deferSaveOnPostCommit) {
        this.saver.deferSaveToPostCommit = deferSaveOnPostCommit;
    }

    public boolean isDeferSaveToPostCommit() {
        return this.saver.deferSaveToPostCommit;
    }

    /**
     * Set to true to do saving in a read-only EMF Transaction, false otherwise.
     * Note that if the {@link SavingPolicy} execute some EMF Command, this must
     * be at false.
     * 
     * @param saveInExclusiveTransaction
     *            specify if the saving is done in a read-only transaction
     */
    public void setSaveInExclusiveTransaction(boolean saveInExclusiveTransaction) {
        this.saver.saveInExclusiveTransaction = saveInExclusiveTransaction;
    }

    public boolean isSaveInExclusiveTransaction() {
        return this.saver.saveInExclusiveTransaction;
    }

    // *******************
    // Model Accessor
    // *******************

    private void initializeAccessor() {
        ModelAccessor accessor = getModelAccessor();
        if (accessor != null) {
            accessor.init(transactionalEditingDomain.getResourceSet());
        }
    }

    @Override
    public ModelAccessor getModelAccessor() {
        return SiriusPlugin.getDefault().getModelAccessorRegistry()
                .getModelAccessor(transactionalEditingDomain.getResourceSet());
    }

    // *******************
    // Events, Triggers and Listeners
    // *******************
    /**
     * This method allows adding {@code ModelChangeTrigger} to the current
     * session {@link SessionEventBroker}. This method is called during the
     * opening of the Session, before setting the open attribute to true and
     * before launching the SessionListener.OPENED notifications.
     */
    protected void initLocalTriggers() {
        Predicate<Notification> danglingRemovalPredicate = Predicates.or(DanglingRefRemovalTrigger.IS_DETACHMENT,
                DanglingRefRemovalTrigger.IS_ATTACHMENT);
        DanglingRefRemovalTrigger danglingRemovalTrigger = new DanglingRefRemovalTrigger(this);
        getEventBroker().addLocalTrigger(SessionEventBrokerImpl.asFilter(danglingRemovalPredicate),
                danglingRemovalTrigger);

        addRefreshEditorsListener();
        /*
         * Make sure these adapters are added after the rest, and in particular
         * after the semantic cross-referencer, so that they can rely on an
         * up-to-date cross-referencer when invoked.
         */
        for (DAnalysis analysis : allAnalyses()) {
            addAdaptersOnAnalysis(analysis);
        }
    }

    @Override
    public void addListener(final SessionListener listener) {
        listeners.add(listener);
    }

    @Override
    public void removeListener(final SessionListener listener) {
        listeners.remove(listener);
    }

    /**
     * Notify all the registered listeners of the specified event.
     * 
     * @param notification
     *            the event to notify the listeners of.
     */
    public void notifyListeners(final int notification) {
        if (notification == SessionListener.REPRESENTATION_CHANGE
                || notification == SessionListener.SELECTED_VIEWS_CHANGE_KIND
                || notification == SessionListener.VSM_UPDATED || notification != lastNotification) {
            for (final SessionListener listener : Iterables.filter(Lists.newArrayList(listeners.getListeners()),
                    SessionListener.class)) {
                listener.notify(notification);
            }
            lastNotification = notification;
        }
    }

    @Override
    public void notifyControlledModel(final Resource newControlled) {
        // Set the already controlled resource to modified because they can
        // reference the new resource.
        for (final Resource controlledResource : super.getControlledResources()) {
            controlledResource.setModified(true);
        }
        super.getControlledResources().add(newControlled);
        notifyListeners(SessionListener.SEMANTIC_CHANGE);
    }

    @Override
    public void notifyUnControlledModel(final EObject uncontrolled, final Resource resource) {
        if (resource.getContents().size() == 0) {
            super.getControlledResources().remove(resource);
        }
        notifyListeners(SessionListener.SEMANTIC_CHANGE);
    }

    @Override
    public SessionEventBroker getEventBroker() {
        if (broker == null) {
            broker = new SessionEventBrokerImpl(transactionalEditingDomain);
        }
        return broker;
    }

    /**
     * Add the refresh editors preCommit listener to the editingDomain.
     */
    protected void addRefreshEditorsListener() {
        if (refreshEditorsListeners == null) {
            refreshEditorsListeners = new RefreshEditorsPrecommitListener(transactionalEditingDomain);
            getEventBroker().addLocalTrigger(RefreshEditorsPrecommitListener.IS_IMPACTING, refreshEditorsListeners);
            this.addListener(refreshEditorsListeners);
        }
    }

    @Override
    public RefreshEditorsPrecommitListener getRefreshEditorsListener() {
        return refreshEditorsListeners;
    }

    // *******************
    // Session Configuration
    // *******************

    @Override
    public void setAnalysisSelector(final DAnalysisSelector selector) {
        if (this.getServices() instanceof DAnalysisSessionService) {
            ((DAnalysisSessionService) this.getServices()).setAnalysisSelector(selector);
        }
    }

    public void setResourceCollector(IResourceCollector collector) {
        this.currentResourceCollector = collector;
    }

    // *******************
    // Viewpoint Selection and DView Management
    // *******************
    @Override
    public Collection<Viewpoint> getSelectedViewpoints(boolean includeReferencedAnalysis) {
        return DViewOperations.on(this).getSelectedViewpoints(includeReferencedAnalysis);
    }

    /**
     * Get the selected viewpoints sorted form more specifis to generics.
     * 
     * @return a collection of selected viewpoints for this session.
     */
    public Collection<Viewpoint> getSelectedViewpointsSpecificToGeneric() {
        return DViewOperations.on(this).getSelectedViewpointsSpecificToGeneric();
    }

    @Override
    public Collection<DView> getSelectedViews() {
        return DViewOperations.on(this).getSelectedViews(allAnalyses());
    }

    @Override
    public void addSelectedView(DView view, IProgressMonitor monitor) throws IllegalArgumentException {
        DViewOperations.on(this).addSelectedView(view, monitor);
    }

    @Override
    public void removeSelectedView(final DView view, IProgressMonitor monitor) {
        DViewOperations.on(this).removeSelectedView(view, monitor);
    }

    @Override
    public Collection<DView> getOwnedViews() {
        return DViewOperations.on(this).getOwnedViews();
    }

    @Override
    public void createView(Viewpoint viewpoint, Collection<EObject> semantics, IProgressMonitor monitor) {
        createView(viewpoint, semantics, true, monitor);
    }

    @Override
    public void createView(final Viewpoint viewpoint, final Collection<EObject> semantics,
            final boolean createNewRepresentations, IProgressMonitor monitor) {
        DViewOperations.on(this).createView(viewpoint, semantics, createNewRepresentations, monitor);
    }

    // *******************
    // Session opening and closing
    // *******************

    @Override
    public void open(IProgressMonitor monitor) {
        try {
            monitor.beginTask(Messages.DAnalysisSessionImpl_openMsg, 33);
            SessionManager.INSTANCE.add(this);
            monitor.worked(1);
            notifyListeners(SessionListener.OPENING);
            monitor.worked(1);
            DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.OPEN_SESSION_KEY);

            ResourceSetSync.getOrInstallResourceSetSync(transactionalEditingDomain)
                    .registerClient(resourcesSynchronizer);
            monitor.worked(1);
            this.representationNameListener = new RepresentationNameListener(this);
            monitor.worked(1);

            tracker.initialize(monitor);
            monitor.worked(1);

            setSynchronizeStatusofEveryResource();
            monitor.worked(1);

            configureInterpreter();
            monitor.worked(1);

            initializeAccessor();
            monitor.worked(1);

            ViewpointRegistry.getInstance().addListener(this.vsmUpdater);
            // Setup ResourceModifiedFieldUpdater
            TransactionalEditingDomain.DefaultOptions options = TransactionUtil
                    .getAdapter(getTransactionalEditingDomain(), TransactionalEditingDomain.DefaultOptions.class);
            if (options != null) {
                Object value = options.getDefaultTransactionOptions().get(Transaction.OPTION_VALIDATE_EDIT);
                ValidateEditSupport delegate = null;
                if (value instanceof ValidateEditSupport) {
                    delegate = (ValidateEditSupport) value;
                }
                if (!(delegate instanceof ResourceModifiedFieldUpdater)
                        && getTransactionalEditingDomain() instanceof InternalTransactionalEditingDomain) {
                    InternalTransactionalEditingDomain internalDomain = (InternalTransactionalEditingDomain) getTransactionalEditingDomain();
                    new ResourceModifiedFieldUpdater(internalDomain, delegate);
                }
            }

            DViewOperations.on(this).updateSelectedViewpointsData(new SubProgressMonitor(monitor, 10));
            initLocalTriggers();

            super.setOpen(true);
            DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.OPEN_SESSION_KEY);
            notifyListeners(SessionListener.OPENED);
            monitor.worked(1);
            // CHECKSTYLE:OFF
        } catch (RuntimeException e) {
            // CHECKSTYLE:ON
            super.setOpen(true);
            close(new SubProgressMonitor(monitor, 10));
            throw e;
        } finally {
            monitor.done();
        }
    }

    @Override
    public void close(IProgressMonitor monitor) {
        if (!isOpen()) {
            return;
        }
        ViewpointRegistry.getInstance().removeListener(this.vsmUpdater);
        this.vsmUpdater = null;
        notifyListeners(SessionListener.CLOSING);
        disableAndRemoveECrossReferenceAdapters();

        if (getRefreshEditorsListener() != null) {
            removeListener(getRefreshEditorsListener());
        }
        refreshEditorsListeners = null;
        reloadingPolicy = null;
        savingPolicy = null;
        if (interpreter != null) {
            interpreter.dispose();
        }
        ResourceSetSync.getOrInstallResourceSetSync(transactionalEditingDomain)
                .unregisterClient(resourcesSynchronizer);
        // We do not reset resourcesSynchronizer to null as some of the session
        // methods which are delegated to it must still be availble when the
        // session is closed. It does not hold to any state or resource so
        // that's OK.
        ResourceSetSync.uninstallResourceSetSync(transactionalEditingDomain);
        super.setOpen(false);
        /*
         * Let's clear the cross referencer of the VSM resource if it's still
         * there (added by the updateSelectedViewpointsData).
         */
        ResourceSet resourceSet = getTransactionalEditingDomain().getResourceSet();

        if (currentResourceCollector != null) {
            currentResourceCollector.dispose();
            currentResourceCollector = null;
        }
        interpreter = null;
        if (representationNameListener != null) {
            representationNameListener.dispose();
            representationNameListener = null;
        }
        representationsChangeAdapter = null;
        // dispose the SessionEventBroker
        if (broker != null) {
            broker.dispose();
            broker = null;
        }

        flushOperations(transactionalEditingDomain);
        // Unload all referenced resources
        unloadAllResources(monitor);

        // Notify that the session is closed.
        notifyListeners(SessionListener.CLOSED);
        SessionManager.INSTANCE.remove(this);
        if (tracker != null) {
            tracker.dispose();
            tracker = null;
        }
        crossReferencer = null;
        saver.dispose();

        transactionalEditingDomain.dispose();
        doDisposePermissionAuthority(resourceSet);
        transactionalEditingDomain = null;
        getActivatedViewpoints().clear();
        services = null;
        sessionResource = null;
        mainDAnalysis = null;
    }

    /**
     * Disable {@link SiriusCrossReferenceAdapter} resolveProxy capability on
     * resource and all its contents
     * 
     * @param resource
     *            the resource
     */
    void disableCrossReferencerResolve(Resource resource) {
        // Disable resolveProxy for SiriusCrossreferencerAdapter.
        // SiriusCrossreferencerAdapter on EObject are also on resource,
        // consequently we manage only the resource itself.
        for (Adapter adapter : resource.eAdapters()) {
            if (adapter instanceof SiriusCrossReferenceAdapter) {
                ((SiriusCrossReferenceAdapter) adapter).disableResolveProxy();
            }
        }
    }

    /**
     * Enable {@link SiriusCrossReferenceAdapter} resolveProxy capability on
     * resource and all its contents
     * 
     * @param resource
     *            the resource
     */
    void enableCrossReferencerResolve(Resource resource) {
        // Enable resolveProxy for SiriusCrossreferencerAdapter.
        // SiriusCrossreferencerAdapter on EObject are also on resource,
        // consequently we manage only the resource itself.
        for (Adapter adapter : resource.eAdapters()) {
            if (adapter instanceof SiriusCrossReferenceAdapter) {
                ((SiriusCrossReferenceAdapter) adapter).enableResolveProxy();
            }
        }
    }

    private static void flushOperations(TransactionalEditingDomain ted) {
        CommandStack commandStack = ted.getCommandStack();
        ResourceSet resourceSet = ted.getResourceSet();
        if (commandStack != null) {
            // Remove also ResourceUndoContext to have operations really
            // removed from IOperationHistory
            // This must be done before commandStack.flush(); to have
            // the Undo/RedoActionHandler update the actions
            if (commandStack instanceof IWorkspaceCommandStack) {
                IWorkspaceCommandStack workspaceCommandStack = (IWorkspaceCommandStack) commandStack;
                for (Resource resource : new ArrayList<Resource>(resourceSet.getResources())) {
                    workspaceCommandStack.getOperationHistory().dispose(new ResourceUndoContext(ted, resource),
                            true, true, true);
                }
            }
            commandStack.flush();
        }
    }

    /**
     * Disposes the permission authority corresponding to this session (if any
     * found).
     * 
     * @param resourceSet
     *            the resourceSet associated to the current session (given in
     *            parameter as the EditingDomain may already have been disposed)
     */
    protected void doDisposePermissionAuthority(ResourceSet resourceSet) {
        PermissionAuthorityRegistry.getDefault().getPermissionAuthority(resourceSet).dispose(resourceSet);
    }

    /**
     * Method called at {@link Session#close(IProgressMonitor)} to unload all
     * referenced {@link Resource}s.
     * 
     * @param monitor
     */
    private void unloadAllResources(IProgressMonitor monitor) {
        ResourceSet rs = transactionalEditingDomain.getResourceSet();
        for (Resource resource : new ArrayList<Resource>(rs.getResources())) {
            ResourceStrategyRegistry.getInstance().unloadAtResourceSetDispose(resource, monitor);
            rs.getResources().remove(resource);
        }
        super.getAnalyses().clear();
        super.getResources().clear();
        super.getControlledResources().clear();
    }

    // *******************
    // Basic Session services
    // *******************

    @Override
    public TransactionalEditingDomain getTransactionalEditingDomain() {
        return transactionalEditingDomain;
    }

    @Override
    public SessionService getServices() {
        if (services == null) {
            services = new DAnalysisSessionServicesImpl(this);
        }
        return services;
    }

    @Override
    public String getID() {
        return sessionResource.getURI().toString();
    }

    @Override
    public String toString() {
        return MessageFormat.format(Messages.DAnalysisSessionImpl_toStringMsg, getID());
    }

    /**
     * Get collection of available {@link DView} for the
     * {@link RepresentationDescription}.
     * 
     * @param representationDescription
     *            the representation description.
     * @return available representation containers
     */
    public Collection<DView> getAvailableRepresentationContainers(
            RepresentationDescription representationDescription) {
        final Viewpoint viewpoint = new RepresentationDescriptionQuery(representationDescription)
                .getParentViewpoint();
        Collection<DAnalysis> allAnalysis = allAnalyses();

        final List<DView> containers = new ArrayList<DView>();

        for (DAnalysis analysis : allAnalysis) {
            DView container = null;

            for (final DView view : analysis.getOwnedViews()) {
                if (view instanceof DView && viewpoint == view.getViewpoint()
                        && view.eContainer() instanceof DAnalysis) {
                    container = (DView) view;
                    break;
                }
            } // for

            if (container != null) {
                containers.add(container);
            }
        }

        return containers;
    }
}