Exemplo n.º 1
0
 public <D extends Definition> CompilingDef<D> getCompiling(DefDescriptor<D> descriptor) {
   @SuppressWarnings("unchecked")
   CompilingDef<D> cd = (CompilingDef<D>) compiled.get(descriptor);
   if (cd == null) {
     cd = new CompilingDef<D>();
     compiled.put(descriptor, cd);
   }
   cd.descriptor = descriptor;
   return cd;
 }
Exemplo n.º 2
0
 /**
  * Typesafe helper for getDef.
  *
  * <p>This adds new definitions (unvalidated) to the list passed in. Definitions that were
  * previously built are simply added to the local cache.
  *
  * <p>The quick fix exception case is actually a race condition where we previously had a set of
  * depenendencies, and something changed, making our set inconsistent. There are no guarantees
  * that during a change all MDRs will have a correct set of definitions.
  *
  * @param context The aura context for the compiling def.
  * @param descriptor the descriptor for which we need a definition.
  * @return A compilingDef for the definition, or null if not needed.
  * @throws QuickFixException if something has gone terribly wrong.
  */
 private <D extends Definition> void validateHelper(
     AuraContext context, DefDescriptor<D> descriptor, List<CompilingDef<?>> compiled)
     throws QuickFixException {
   CompilingDef<D> compiling = new CompilingDef<D>();
   compiling.descriptor = descriptor;
   if (!fillCompilingDef(compiling, context)) {
     throw new DefinitionNotFoundException(descriptor);
   }
   if (compiling.built) {
     compiled.add(compiling);
   } else {
     defs.put(compiling.descriptor, compiling.def);
   }
 }
Exemplo n.º 3
0
  /**
   * A private helper routine to make the compiler code more sane.
   *
   * <p>This processes a single definition in a dependency tree. It works as a single step in a
   * breadth first traversal of the tree, accumulating children in the 'deps' set, and updating the
   * compile context with the current definition.
   *
   * <p>Note that once the definition has been retrieved, this code uses the 'canonical' descriptor
   * from the definition, discarding the incoming descriptor.
   *
   * @param descriptor the descriptor that we are currently handling, must not be in the compiling
   *     defs.
   * @param cc the compile context to allow us to accumulate information.
   * @param deps the set of dependencies that we are accumulating.
   * @throws QuickFixException if the definition is not found, or validateDefinition() throws one.
   */
  private <D extends Definition> D getHelper(
      DefDescriptor<D> descriptor, CompileContext cc, Set<DefDescriptor<?>> deps)
      throws QuickFixException {
    CompilingDef<D> cd = cc.getCompiling(descriptor);

    if (cd.def != null) {
      return cd.def;
    }
    try {
      if (!fillCompilingDef(cd, cc.context)) {
        //
        // At this point, we have failed to get the def, so we should throw an
        // error. The first stanza is to provide a more useful error description
        // including the set of components using the missing component.
        //
        if (!cd.parents.isEmpty()) {
          StringBuilder sb = new StringBuilder();
          Location handy = null;
          for (Definition parent : cd.parents) {
            handy = parent.getLocation();
            if (sb.length() != 0) {
              sb.append(", ");
            }
            sb.append(parent.getDescriptor().toString());
          }
          throw new DefinitionNotFoundException(descriptor, handy, sb.toString());
        }
        throw new DefinitionNotFoundException(descriptor);
      }
      //
      // Ok. We have a def. let's figure out what to do with it.
      //
      Set<DefDescriptor<?>> newDeps = Sets.newHashSet();
      cd.def.appendDependencies(newDeps);
      //
      // FIXME: this code will go away with preloads.
      // This pulls in the context preloads. not pretty, but it works.
      //
      if (!cc.addedPreloads && cd.descriptor.getDefType().equals(DefType.APPLICATION)) {
        cc.addedPreloads = true;
        Set<String> preloads = cc.context.getPreloads();
        for (String preload : preloads) {
          if (!preload.contains("_")) {
            DependencyDefImpl.Builder ddb = new DependencyDefImpl.Builder();
            ddb.setResource(preload);
            ddb.setType("APPLICATION,COMPONENT,STYLE,EVENT");
            ddb.build().appendDependencies(newDeps);
          }
        }
      }
      for (DefDescriptor<?> dep : newDeps) {
        if (!defs.containsKey(dep)) {
          CompilingDef<?> depcd = cc.getCompiling(dep);
          depcd.parents.add(cd.def);
        }
      }
      deps.addAll(newDeps);
      cc.dependencies.put(cd.descriptor, cd.def);
      return cd.def;
    } catch (DefinitionNotFoundException dnfe) {
      //
      // In the case that we have a DefinitionNotFoundException for our current descriptor,
      // cache the fact that we didn't find one.
      //
      if (dnfe.getDescriptor().equals(descriptor)) {
        cd.def = null;
        defs.put(descriptor, cd.def);
        if (cd.cacheable) {
          defsCache.put(descriptor, Optional.fromNullable(cd.def));
        }
      }
      throw dnfe;
    }
  }
Exemplo n.º 4
0
  /**
   * Fill a compiling def for a descriptor.
   *
   * <p>This makes sure that we can get a registry for a given def, then tries to get the def from
   * the global cache, if that fails, it retrieves from the registry, and marks the def as locally
   * built.
   *
   * @param compiling the current compiling def (if there is one).
   * @throws QuickFixException if validateDefinition caused a quickfix.
   */
  private <D extends Definition> boolean fillCompilingDef(
      CompilingDef<D> compiling, AuraContext context) throws QuickFixException {
    assert compiling.def == null;
    {
      //
      // First, check our local cached defs to see if we have a fully compiled version.
      // in this case, we don't care about caching, since we are done.
      //
      @SuppressWarnings("unchecked")
      D localDef = (D) defs.get(compiling.descriptor);
      if (localDef != null) {
        compiling.def = localDef;
        compiling.built = !localDef.isValid();
        if (compiling.built) {
          localDef.validateDefinition();
        }
        return true;
      }
    }

    //
    // If there is no local cache, we must first check to see if there is a registry, as we may not
    // have
    // a registry (depending on configuration). In the case that we don't find one, we are done
    // here.
    //
    DefRegistry<D> registry = getRegistryFor(compiling.descriptor);
    if (registry == null) {
      defs.put(compiling.descriptor, null);
      return false;
    }

    //
    // Now, check if we can cache the def later, as we won't have the registry to check at a later
    // time.
    // If we can cache, look it up in the cache. If we find it, we have a built definition.
    //
    if (isCacheable(registry)) {
      compiling.cacheable = true;

      @SuppressWarnings("unchecked")
      Optional<D> opt = (Optional<D>) defsCache.getIfPresent(compiling.descriptor);
      if (opt != null) {
        D cachedDef = opt.orNull();

        if (cachedDef != null) {
          @SuppressWarnings("unchecked")
          DefDescriptor<D> canonical = (DefDescriptor<D>) cachedDef.getDescriptor();

          compiling.def = cachedDef;
          compiling.descriptor = canonical;
          compiling.built = false;
          defs.put(canonical, cachedDef);
          return true;
        } else {
          return false;
        }
      }
    }

    //
    // The last case. This is our first compile or the def is uncacheable.
    // In this case, we make sure that the initial validation is called, and put
    // the def in the non-validated set.
    //
    compiling.def = registry.getDef(compiling.descriptor);
    if (compiling.def == null) {
      return false;
    }
    @SuppressWarnings("unchecked")
    DefDescriptor<D> canonical = (DefDescriptor<D>) compiling.def.getDescriptor();
    compiling.descriptor = canonical;

    // cc.loggingService.incrementNum(LoggingService.DEF_COUNT);
    // FIXME: setting the current namespace on the context seems
    // extremely hackish
    context.setCurrentNamespace(canonical.getNamespace());
    compiling.def.validateDefinition();
    compiling.built = true;
    defs.put(canonical, compiling.def);
    return true;
  }