org.eclipse.xtext.scoping.impl.ImportScope.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.scoping.impl.ImportScope.java

Source

/*******************************************************************************
 * Copyright (c) 2010 itemis AG (http://www.itemis.eu) 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
 *******************************************************************************/
package org.eclipse.xtext.scoping.impl;

import static com.google.common.collect.Iterables.*;
import static com.google.common.collect.Lists.*;
import static com.google.common.collect.Sets.*;
import static java.util.Collections.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.ISelectable;
import org.eclipse.xtext.resource.impl.AliasedEObjectDescription;
import org.eclipse.xtext.scoping.IScope;

import com.google.common.base.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

/**
 * @author Sven Efftinge - Initial contribution and API
 * @author Sebastian Zarnekow
 */
public class ImportScope extends AbstractScope {

    private final List<ImportNormalizer> normalizers;

    private final ISelectable importFrom;

    private final EClass type;

    public ImportScope(List<ImportNormalizer> namespaceResolvers, IScope parent, ISelectable importFrom,
            EClass type, boolean ignoreCase) {
        super(parent, ignoreCase);
        this.type = type;
        this.normalizers = removeDuplicates(namespaceResolvers);
        this.importFrom = importFrom;
    }

    protected List<ImportNormalizer> removeDuplicates(List<ImportNormalizer> namespaceResolvers) {
        ArrayList<ImportNormalizer> list = newArrayList();
        for (ImportNormalizer importNormalizer : namespaceResolvers) {
            if (!list.contains(importNormalizer))
                list.add(importNormalizer);
        }
        return list;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + normalizers + " imports from " + importFrom + " for type "
                + type.getName();
    }

    @Override
    public Iterable<IEObjectDescription> getAllElements() {
        final Iterable<IEObjectDescription> globalElements = getParent().getAllElements();
        Iterable<IEObjectDescription> aliased = getAllLocalElements();
        final Set<QualifiedName> elements = newHashSet();
        for (IEObjectDescription from : aliased) {
            QualifiedName qn = getIgnoreCaseAwareQualifiedName(from);
            elements.add(qn);
        }
        return concat(aliased, filter(globalElements, new Predicate<IEObjectDescription>() {
            @Override
            public boolean apply(IEObjectDescription input) {
                return !elements.contains(getIgnoreCaseAwareQualifiedName(input));
            }
        }));
    }

    protected QualifiedName getIgnoreCaseAwareQualifiedName(IEObjectDescription from) {
        return isIgnoreCase() ? from.getName().toLowerCase() : from.getName();
    }

    @Override
    protected Iterable<IEObjectDescription> getAllLocalElements() {
        final Iterable<IEObjectDescription> exportedObjects = getImportFrom().getExportedObjectsByType(type);
        return getAliasedElements(exportedObjects);
    }

    @Override
    protected Iterable<IEObjectDescription> getLocalElementsByEObject(final EObject object, final URI uri) {
        Iterable<IEObjectDescription> candidates = getImportFrom().getExportedObjectsByObject(object);
        final Iterable<IEObjectDescription> aliasedElements = getAliasedElements(candidates);
        // make sure that the element is returned when asked by name.
        return filter(aliasedElements, new Predicate<IEObjectDescription>() {
            @Override
            public boolean apply(IEObjectDescription input) {
                IEObjectDescription description = getSingleLocalElementByName(input.getName());
                if (description == null)
                    return false;
                if (description.getEObjectOrProxy() == input.getEObjectOrProxy())
                    return true;
                if (input.getEObjectURI().equals(description.getEObjectURI()))
                    return true;
                return false;
            }
        });
    }

    protected Iterable<IEObjectDescription> getAliasedElements(Iterable<IEObjectDescription> candidates) {
        Multimap<QualifiedName, IEObjectDescription> keyToDescription = LinkedHashMultimap.create();
        Multimap<QualifiedName, ImportNormalizer> keyToNormalizer = HashMultimap.create();

        for (IEObjectDescription imported : candidates) {
            QualifiedName fullyQualifiedName = imported.getName();
            for (ImportNormalizer normalizer : normalizers) {
                QualifiedName alias = normalizer.deresolve(fullyQualifiedName);
                if (alias != null) {
                    QualifiedName key = alias;
                    if (isIgnoreCase()) {
                        key = key.toLowerCase();
                    }
                    keyToDescription.put(key, new AliasedEObjectDescription(alias, imported));
                    keyToNormalizer.put(key, normalizer);
                }
            }
        }
        for (QualifiedName name : keyToNormalizer.keySet()) {
            if (keyToNormalizer.get(name).size() > 1)
                keyToDescription.removeAll(name);
        }
        return keyToDescription.values();
    }

    @Override
    protected IEObjectDescription getSingleLocalElementByName(QualifiedName name) {
        Iterator<IEObjectDescription> iterator = getLocalElementsByName(name).iterator();
        return iterator.hasNext() ? iterator.next() : null;
    }

    @Override
    protected Iterable<IEObjectDescription> getLocalElementsByName(QualifiedName name) {
        List<IEObjectDescription> result = newArrayList();
        QualifiedName resolvedQualifiedName = null;
        ISelectable importFrom = getImportFrom();
        for (ImportNormalizer normalizer : normalizers) {
            final QualifiedName resolvedName = normalizer.resolve(name);
            if (resolvedName != null) {
                Iterable<IEObjectDescription> resolvedElements = importFrom.getExportedObjects(type, resolvedName,
                        isIgnoreCase());
                for (IEObjectDescription resolvedElement : resolvedElements) {
                    if (resolvedQualifiedName == null)
                        resolvedQualifiedName = resolvedName;
                    else if (!resolvedQualifiedName.equals(resolvedName)) {
                        if (result.get(0).getEObjectOrProxy() != resolvedElement.getEObjectOrProxy()) {
                            return emptyList();
                        }
                    }
                    QualifiedName alias = normalizer.deresolve(resolvedElement.getName());
                    if (alias == null)
                        throw new IllegalStateException(
                                "Couldn't deresolve " + resolvedElement.getName() + " with import " + normalizer);
                    final AliasedEObjectDescription aliasedEObjectDescription = new AliasedEObjectDescription(alias,
                            resolvedElement);
                    result.add(aliasedEObjectDescription);
                }
            }
        }
        return result;
    }

    protected ISelectable getImportFrom() {
        ISelectable importFrom = this.importFrom;
        if (importFrom == null) {
            importFrom = new ScopeBasedSelectable(getParent());
        }
        return importFrom;
    }

}