Package com.puppetlabs.geppetto.pp.dsl.linking

Source Code of com.puppetlabs.geppetto.pp.dsl.linking.PPResourceDescription

/**
* Copyright (c) 2013 Puppet Labs, Inc. and other contributors, as listed below.
* 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:
*   Puppet Labs
*/
package com.puppetlabs.geppetto.pp.dsl.linking;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.puppetlabs.geppetto.pp.dsl.adapters.CrossReferenceAdapterFactory;
import com.puppetlabs.geppetto.pp.dsl.adapters.PPImportedNamesAdapter;
import com.puppetlabs.geppetto.pp.dsl.adapters.PPImportedNamesAdapterFactory;
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.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.impl.DefaultReferenceDescription;
import org.eclipse.xtext.resource.impl.DefaultResourceDescription;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.util.IResourceScopeCache;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Provider;

/**
* A ResourceDescription for PP that adds specially imported names via resource adapter.
*
*/
public class PPResourceDescription extends DefaultResourceDescription {
  private IResourceScopeCache cache;

  private PPResourceDescriptionStrategy strategy;

  private static final String PPREFERENCE_DESCRIPTIONS_CACHE_KEY = DefaultReferenceDescription.class.getName() +
      "#getPPReferenceDescriptions";

  public PPResourceDescription(Resource resource, IDefaultResourceDescriptionStrategy strategy,
      IResourceScopeCache cache) {
    super(resource, strategy, cache);
    this.cache = cache;
    if(strategy instanceof PPResourceDescriptionStrategy)
      this.strategy = (PPResourceDescriptionStrategy) strategy;

  }

  protected List<PPReferenceDescription> computePPReferenceDescriptions() {
    if(strategy == null)
      throw new IllegalStateException(
        "Configuration not correct. PPResourceDescription requires a PPResourceDescriptionStrategy");

    final List<PPReferenceDescription> referenceDescriptions = Lists.newArrayList();
    IAcceptor<PPReferenceDescription> acceptor = new IAcceptor<PPReferenceDescription>() {
      public void accept(PPReferenceDescription referenceDescription) {
        referenceDescriptions.add(referenceDescription);
      }
    };

    EcoreUtil2.resolveLazyCrossReferences(getResource(), CancelIndicator.NullImpl);
    final Iterable<IEObjectDescription> allExported = getExportedObjects();

    Map<EObject, IEObjectDescription> eObject2exportedEObjects = createEObject2ExportedEObjectsMap(allExported);
    TreeIterator<EObject> contents = EcoreUtil.getAllProperContents(getResource(), true);
    while(contents.hasNext()) {
      EObject eObject = contents.next();
      List<IEObjectDescription> referenced = CrossReferenceAdapterFactory.eINSTANCE.get(eObject);
      if(referenced == null || referenced.isEmpty())
        continue;
      IEObjectDescription sourceContainer = findClosestExportedContainerDescriptor(
        eObject2exportedEObjects.get(eObject), allExported);
      for(IEObjectDescription targetDescriptor : referenced)
        if(!strategy.createPPReferenceDescriptions(eObject, sourceContainer, targetDescriptor, acceptor))
          contents.prune();
    }
    return referenceDescriptions;
  }

  /**
   * Returns the length of a containing URI's fragment or 0 if the candidate is not a container.
   *
   * @param contained
   * @param containerCandidate
   * @return
   */
  private int containerSpecificity(IEObjectDescription contained, IEObjectDescription containerCandidate) {
    URI containedURI = contained.getEObjectURI();
    URI containerURI = containerCandidate.getEObjectURI();
    if(!containedURI.path().equals(containerURI.path()))
      return 0;
    // same resource, if desc's fragment is in at the start of the path, then contained is contained by containerCandidate
    if(containerURI.fragment().startsWith(containedURI.fragment()))
      return containerURI.fragment().length();
    return 0;
  }

  public IEObjectDescription findClosestExportedContainerDescriptor(IEObjectDescription element,
      Iterable<IEObjectDescription> exportedElements) {
    IEObjectDescription closest = null;
    int maxSpecificity = 0;
    for(IEObjectDescription containerCandidate : exportedElements) {
      int specificity = containerSpecificity(element, containerCandidate);
      if(specificity > maxSpecificity) {
        maxSpecificity = specificity;
        closest = containerCandidate;
      }
    }
    return closest;
  }

  /**
   * Override that adds the specially imported names to the default.
   *
   * @see org.eclipse.xtext.resource.impl.DefaultResourceDescription#getImportedNames()
   */
  @Override
  public Iterable<QualifiedName> getImportedNames() {
    Iterable<QualifiedName> superResult = super.getImportedNames();
    PPImportedNamesAdapter adapter = PPImportedNamesAdapterFactory.eINSTANCE.adapt(getResource());
    if(adapter != null) {
      Collection<QualifiedName> imported = adapter.getNames();
      if(imported.isEmpty())
        return superResult;
      return Iterables.concat(superResult, ImmutableSet.copyOf(imported));
    }
    return superResult;
  }

  /**
   * Gets an Iterable over PPReferenceDescriptions. This is similar to {@link #getReferenceDescriptions()} but works
   * with adapters and IEObjectDescription.
   */
  public Iterable<PPReferenceDescription> getPPReferenceDescriptions() {
    return cache.get(
      PPREFERENCE_DESCRIPTIONS_CACHE_KEY, getResource(), new Provider<List<PPReferenceDescription>>() {
        public List<PPReferenceDescription> get() {
          return computePPReferenceDescriptions();
        }
      });
  }

}
TOP

Related Classes of com.puppetlabs.geppetto.pp.dsl.linking.PPResourceDescription

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.