예제 #1
0
  /**
   * Appends the method that calls the {@code @PageHidden} method of the widget.
   *
   * @param pageImplBuilder The class builder for the implementation of PageNode we are adding the
   *     method to.
   * @param pageClass The "content type" (Widget subclass) of the page. This is the type the user
   *     annotated with {@code @Page}.
   */
  private void appendPageHiddenMethod(
      AnonymousClassStructureBuilder pageImplBuilder, MetaClass pageClass) {
    BlockBuilder<?> method =
        pageImplBuilder
            .publicMethod(
                void.class,
                createMethodNameFromAnnotation(PageHidden.class),
                Parameter.of(pageClass, "widget"))
            .body();
    checkMethodAndAddPrivateAccessors(
        pageImplBuilder, method, pageClass, PageHidden.class, HistoryToken.class, "state");

    if (pageClass.getAnnotation(Singleton.class) == null
        && pageClass.getAnnotation(ApplicationScoped.class) == null
        && pageClass.getAnnotation(EntryPoint.class) == null) {
      method.append(Stmt.loadVariable("bm").invoke("destroyBean", Stmt.loadVariable("widget")));
    }
    method.finish();
  }
예제 #2
0
  /**
   * Renders the page-to-page navigation graph into the file {@code navgraph.gv} in the {@code
   * .errai} cache directory.
   */
  private void renderNavigationToDotFile(BiMap<String, MetaClass> pages) {
    final File dotFile = new File(RebindUtils.getErraiCacheDir().getAbsolutePath(), "navgraph.gv");
    PrintWriter out = null;
    try {
      out = new PrintWriter(dotFile);
      out.println("digraph Navigation {");
      final MetaClass transitionToType = MetaClassFactory.get(TransitionTo.class);
      final MetaClass transitionAnchorType = MetaClassFactory.get(TransitionAnchor.class);
      final MetaClass transitionAnchorFactoryType =
          MetaClassFactory.get(TransitionAnchorFactory.class);
      for (Map.Entry<String, MetaClass> entry : pages.entrySet()) {
        String pageName = entry.getKey();
        MetaClass pageClass = entry.getValue();

        // entry for the node itself
        out.print("\"" + pageName + "\"");

        Page pageAnnotation = pageClass.getAnnotation(Page.class);
        List<Class<? extends PageRole>> roles = Arrays.asList(pageAnnotation.role());
        if (roles.contains(DefaultPage.class)) {
          out.print(" [penwidth=3]");
        }
        out.println();

        for (MetaField field : getAllFields(pageClass)) {
          if (field.getType().getErased().equals(transitionToType)
              || field.getType().getErased().equals(transitionAnchorType)
              || field.getType().getErased().equals(transitionAnchorFactoryType)) {
            MetaType targetPageType = field.getType().getParameterizedType().getTypeParameters()[0];
            String targetPageName = pages.inverse().get(targetPageType);

            // entry for the link between nodes
            out.println(
                "\""
                    + pageName
                    + "\" -> \""
                    + targetPageName
                    + "\" [label=\""
                    + field.getName()
                    + "\"]");
          }
        }
      }
      out.println("}");
    } catch (FileNotFoundException e) {
      throw new RuntimeException(e);
    } finally {
      if (out != null) {
        out.close();
      }
    }
  }
예제 #3
0
 private String getPageName(MetaClass pageClass) {
   final Page annotation = pageClass.getAnnotation(Page.class);
   return annotation.path().equals("") ? pageClass.getName() : annotation.path();
 }
예제 #4
0
  @Override
  protected String generate(TreeLogger logger, GeneratorContext context) {
    final ClassStructureBuilder<?> classBuilder =
        Implementations.extend(NavigationGraph.class, GENERATED_CLASS_NAME);

    // accumulation of (name, pageclass) mappings for dupe detection and dot file generation
    BiMap<String, MetaClass> pageNames = HashBiMap.create();

    // accumulation UniquePageRoles for ensuring there is exactly one.
    Multimap<Class<?>, MetaClass> pageRoles = ArrayListMultimap.create();

    ConstructorBlockBuilder<?> ctor = classBuilder.publicConstructor();
    final Collection<MetaClass> pages = ClassScanner.getTypesAnnotatedWith(Page.class, context);
    for (MetaClass pageClass : pages) {
      if (!pageClass.isAssignableTo(IsWidget.class)) {
        throw new GenerationException(
            "Class "
                + pageClass.getFullyQualifiedName()
                + " is annotated with @Page, so it must implement IsWidget");
      }
      Page annotation = pageClass.getAnnotation(Page.class);
      String pageName = getPageName(pageClass);
      List<Class<? extends PageRole>> annotatedPageRoles = Arrays.asList(annotation.role());

      MetaClass prevPageWithThisName = pageNames.put(pageName, pageClass);
      if (prevPageWithThisName != null) {
        throw new GenerationException(
            "Page names must be unique, but "
                + prevPageWithThisName
                + " and "
                + pageClass
                + " are both named ["
                + pageName
                + "]");
      }
      Statement pageImplStmt = generateNewInstanceOfPageImpl(pageClass, pageName);
      if (annotatedPageRoles.contains(DefaultPage.class)) {
        // need to assign the page impl to a variable and add it to the map twice
        ctor.append(Stmt.declareFinalVariable("defaultPage", PageNode.class, pageImplStmt));
        pageImplStmt = Variable.get("defaultPage");
        ctor.append(Stmt.nestedCall(Refs.get("pagesByName")).invoke("put", "", pageImplStmt));
        ctor.append(
            Stmt.nestedCall(Refs.get("pagesByRole"))
                .invoke("put", DefaultPage.class, pageImplStmt));
      } else if (pageName.equals("")) {
        throw new GenerationException(
            "Page "
                + pageClass.getFullyQualifiedName()
                + " has an empty path. Only the"
                + " page with startingPage=true is permitted to have an empty path.");
      }

      final String fieldName = StringUtils.uncapitalize(pageClass.getName());
      ctor.append(Stmt.declareFinalVariable(fieldName, PageNode.class, pageImplStmt));
      ctor.append(
          Stmt.nestedCall(Refs.get("pagesByName")).invoke("put", pageName, Refs.get(fieldName)));

      for (Class<? extends PageRole> annotatedPageRole : annotatedPageRoles) {
        pageRoles.put(annotatedPageRole, pageClass);
        // DefaultPage is already added above.
        if (!annotatedPageRole.equals(DefaultPage.class))
          ctor.append(
              Stmt.nestedCall(Refs.get("pagesByRole"))
                  .invoke("put", annotatedPageRole, Refs.get(fieldName)));
      }
    }
    ctor.finish();

    renderNavigationToDotFile(pageNames);

    validateDefaultPagePresent(pages, pageRoles);
    validateUnique(pageRoles);

    return classBuilder.toJavaString();
  }