@Test
  public void testParameterPassthroughIfTypeIsShared() throws Exception {
    AddonRegistry registry =
        LocalServices.getFurnace(getClass().getClassLoader()).getAddonRegistry();
    ClassLoader thisLoader = ClassLoaderAdapterPassthroughTest.class.getClassLoader();
    ClassLoader loader1 = registry.getAddon(AddonId.from("dep", "1")).getClassLoader();

    ClassWithGetterAndSetter local = new ClassWithGetterAndSetter();
    local.setPassthrough(
        (ClassWithPassthroughMethod)
            loader1.loadClass(ClassWithPassthroughMethod.class.getName()).newInstance());

    Object delegate = loader1.loadClass(ClassWithGetterAndSetter.class.getName()).newInstance();
    ClassWithGetterAndSetter enhanced =
        (ClassWithGetterAndSetter)
            ClassLoaderAdapterBuilder.callingLoader(thisLoader)
                .delegateLoader(loader1)
                .enhance(delegate);

    enhanced.setPassthrough(new ClassWithPassthroughMethod());

    Assert.assertNotNull(enhanced);
    Assert.assertNotNull(enhanced.getPassthrough());
    Assert.assertFalse(Proxies.isForgeProxy(enhanced.getPassthrough()));
    Assert.assertFalse(enhanced.assertPassthroughNotProxied());
  }
  @Test
  public void testSharedImplementationTypeIncludedInProxy() throws Exception {
    AddonRegistry registry =
        LocalServices.getFurnace(getClass().getClassLoader()).getAddonRegistry();
    ClassLoader thisLoader = ClassLoaderAdapterExceptionProxyTest.class.getClassLoader();
    ClassLoader dep1Loader = registry.getAddon(AddonId.from("dep", "1")).getClassLoader();

    Class<?> foreignType = dep1Loader.loadClass(ExceptionFactory.class.getName());
    try {
      ExceptionFactory factory = (ExceptionFactory) foreignType.newInstance();

      Assert.fail(
          "Should have received a "
              + ClassCastException.class.getName()
              + " but got a real object ["
              + factory
              + "]");
    } catch (ClassCastException e) {
    } catch (Exception e) {
      Assert.fail(
          "Should have received a " + ClassCastException.class.getName() + " but was: " + e);
    }

    Object delegate = foreignType.newInstance();
    ExceptionFactory enhancedFactory =
        (ExceptionFactory)
            ClassLoaderAdapterBuilder.callingLoader(thisLoader)
                .delegateLoader(dep1Loader)
                .enhance(delegate);

    Assert.assertTrue(Proxies.isForgeProxy(enhancedFactory));

    String message = "AbstractA message.";
    try {
      enhancedFactory.throwException(message);
    } catch (MockException e) {
      Assert.assertTrue(Proxies.isForgeProxy(e));
      Assert.assertEquals(message, e.getMessage());
    } catch (Exception e) {
      Assert.fail("Exception was not of a compatible type.");
    }
  }
Example #3
0
  public AbstractRuleProvider() {
    /*
     * In the case of a proxy, the no-args constructor will be called. This is the case even if the provider
     * itself would normally have a metadata param passed in.
     *
     * Once completed, the getMetadata() method will be proxied correctly, so this is ok. Just allow it to pass
     * in this case.
     */
    if (Proxies.isForgeProxy(this)
        && !Annotations.isAnnotationPresent(getClass(), RuleMetadata.class)) return;

    if (!Annotations.isAnnotationPresent(getClass(), RuleMetadata.class)) {
      throw new IllegalStateException(
          getClass().getName()
              + " must either "
              + "be abstract, or specify @"
              + RuleMetadata.class.getName()
              + ", or call a super() constructor and provide "
              + RuleProviderMetadata.class.getName());
    }
    this.metadata = MetadataBuilder.forProvider(getClass());
  }
Example #4
0
  /**
   * Returns a list of visitors, sorted by the phase and dependency. Note that this does _not_
   * modify the originally passed in list.
   *
   * @param graphVisitorList
   * @return
   */
  public List<GraphVisitor> sort(List<GraphVisitor> graphVisitorList) {
    // add all items to a temporary list (to avoid making gratuitous modifications to the original
    // list)
    List<GraphVisitor> tempList = new ArrayList<GraphVisitor>(graphVisitorList.size());
    tempList.addAll(graphVisitorList);

    // Sort by phase
    Collections.sort(
        tempList,
        new Comparator<GraphVisitor>() {
          @Override
          public int compare(GraphVisitor o1, GraphVisitor o2) {
            return o1.getPhase().getPriority() - o2.getPhase().getPriority();
          }
        });

    // Create a map to get back from Class to Object
    // (this helps as we will sort the dependencies by class, but we want to ultimately return a
    // list of GraphVisitor Objects)
    IdentityHashMap<Class<? extends GraphVisitor>, GraphVisitor> classToVisitorMap =
        new IdentityHashMap<>();

    // Now build a directed graph based upon the dependencies
    DefaultDirectedWeightedGraph<Class<? extends GraphVisitor>, DefaultEdge> g =
        new DefaultDirectedWeightedGraph<>(DefaultEdge.class);
    // Also, keep this around to make sure we didn't accidentally introduce any cyclic dependencies
    CycleDetector<Class<? extends GraphVisitor>, DefaultEdge> cycleDetector =
        new CycleDetector<>(g);

    // Add the initial vertices and the class to object mapping
    for (GraphVisitor v : tempList) {
      @SuppressWarnings("unchecked")
      Class<? extends GraphVisitor> unproxiedClass =
          (Class<? extends GraphVisitor>) Proxies.unwrapProxyTypes(v.getClass());

      classToVisitorMap.put(unproxiedClass, v);
      g.addVertex(unproxiedClass);
    }

    // Keep a list of all visitors from the previous phase
    // This allows us to create edges from nodes in one phase to the next,
    // allowing the topological sort to sort by phases as well.
    List<GraphVisitor> previousPhaseVisitors = new ArrayList<>();
    List<GraphVisitor> currentPhaseVisitors = new ArrayList<>();
    VisitorPhase previousPhase = null;
    for (GraphVisitor v : tempList) {
      @SuppressWarnings("unchecked")
      Class<? extends GraphVisitor> unproxiedClass =
          (Class<? extends GraphVisitor>) Proxies.unwrapProxyTypes(v.getClass());

      if (v.getPhase() != previousPhase) {
        // we've reached a new phase, so move the current phase to the last
        previousPhaseVisitors.clear();
        previousPhaseVisitors.addAll(currentPhaseVisitors);
        currentPhaseVisitors.clear();
      }
      currentPhaseVisitors.add(v);

      // add dependencies for each visitor
      for (Class<? extends GraphVisitor> clz : v.getDependencies()) {
        g.addEdge(clz, unproxiedClass);
      }

      // also, add dependencies onto all visitors from the previous phase
      for (GraphVisitor prevV : previousPhaseVisitors) {
        @SuppressWarnings("unchecked")
        Class<? extends GraphVisitor> unproxiedPreviousClass =
            (Class<? extends GraphVisitor>) Proxies.unwrapProxyTypes(prevV.getClass());

        g.addEdge(unproxiedPreviousClass, unproxiedClass);
      }
      previousPhase = v.getPhase();
    }

    if (cycleDetector.detectCycles()) {
      // if we have cycles, then try to throw an exception with some usable data
      Set<Class<? extends GraphVisitor>> cycles = cycleDetector.findCycles();
      StringBuilder errorSB = new StringBuilder();
      for (Class<? extends GraphVisitor> cycle : cycles) {
        errorSB.append("Found dependency cycle involving: " + cycle + "\n");
        Set<Class<? extends GraphVisitor>> subCycleSet =
            cycleDetector.findCyclesContainingVertex(cycle);
        for (Class<? extends GraphVisitor> subCycle : subCycleSet) {
          errorSB.append("\tSubcycle: " + subCycle + "\n");
        }
      }
      throw new RuntimeException("Dependency cycles detected: " + errorSB.toString());
    }

    // create the final results list
    List<GraphVisitor> result = new ArrayList<GraphVisitor>(tempList.size());
    // use topological ordering to make it all the right order
    TopologicalOrderIterator<Class<? extends GraphVisitor>, DefaultEdge> iterator =
        new TopologicalOrderIterator<>(g);
    while (iterator.hasNext()) {
      Class<? extends GraphVisitor> clz = iterator.next();
      result.add(classToVisitorMap.get(clz));
    }

    return result;
  }