示例#1
0
  private void bindParameterFromTemplate(ComponentPageElement component, AttributeToken token) {
    String name = token.getName();
    ComponentResources resources = component.getComponentResources();

    // If already bound (i.e., from the component class, via @Component), then
    // ignore the value in the template. This may need improving to just ignore
    // the value if it is an unprefixed literal string.

    if (resources.isBound(name)) return;

    // Meta default of literal for the template.

    String defaultBindingPrefix =
        determineDefaultBindingPrefix(component, name, BindingConstants.LITERAL);

    Binding binding =
        findBinding(
            loadingElement,
            component,
            name,
            token.getValue(),
            defaultBindingPrefix,
            token.getLocation());

    if (binding != null) {
      component.bindParameter(name, binding);

      Map<String, Binding> bindingMap = componentIdToBindingMap.get(component.getCompleteId());
      bindingMap.put(name, binding);
    }
  }
示例#2
0
  private void block(BlockToken token) {

    String id = token.getId();
    // Don't use the page element factory here becauses we need something that is both Block and
    // BodyPageElement and don't want to use casts.

    String description =
        id == null
            ? String.format("Anonymous within %s", loadingElement.getCompleteId())
            : String.format("%s within %s", id, loadingElement.getCompleteId());

    BlockImpl block = new BlockImpl(token.getLocation(), description);

    if (id != null) loadingElement.addBlock(id, block);

    setupBlock(block);
  }
示例#3
0
  /**
   * Creates a new binding, or returns an existing binding (or null) for the "inherit:" binding prefix. Mostly a
   * wrapper around {@link BindingSource#newBinding(String, ComponentResources, ComponentResources, String, String,
   * Location)
   *
   * @return the new binding, or an existing binding (if inherited), or null (if inherited, and the containing
   *         parameter is not bound)
   */
  private Binding findBinding(
      ComponentPageElement loadingComponent,
      ComponentPageElement component,
      String name,
      String value,
      String defaultBindingPrefix,
      Location location) {
    if (value.startsWith(INHERIT_PREFIX)) {
      String loadingParameterName = value.substring(INHERIT_PREFIX.length());
      Map<String, Binding> loadingComponentBindingMap =
          componentIdToBindingMap.get(loadingComponent.getCompleteId());

      // This may return null if the parameter is not bound in the loading component.

      Binding existing = loadingComponentBindingMap.get(loadingParameterName);

      if (existing == null) return null;

      String description =
          String.format(
              "InheritedBinding[parameter %s %s(inherited from %s of %s)]",
              name,
              component.getCompleteId(),
              loadingParameterName,
              loadingComponent.getCompleteId());

      // This helps with debugging, and re-orients any thrown exceptions
      // to the location of the inherited binding, rather than the container component's
      // binding.

      return new InheritedBinding(description, existing, location);
    }

    return pageElementFactory.newBinding(
        name,
        loadingComponent.getComponentResources(),
        component.getComponentResources(),
        defaultBindingPrefix,
        value,
        location);
  }
示例#4
0
  private void parameter(ParameterToken token) {
    ComponentPageElement element = activeElementStack.peek();
    String name = token.getName();

    BlockImpl block =
        new BlockImpl(
            token.getLocation(), String.format("Parmeter %s of %s", name, element.getCompleteId()));

    Binding binding = new LiteralBinding("block parameter " + name, block, token.getLocation());

    // TODO: Check that the t:parameter doesn't appear outside of an embedded component.

    element.bindParameter(name, binding);

    setupBlock(block);
  }
示例#5
0
  private void startComponent(StartComponentToken token) {
    String elementName = token.getElementName();

    // Initial guess: the type from the token (but this may be null in many cases).
    String embeddedType = token.getComponentType();

    // This may be null for an anonymous component.
    String embeddedId = token.getId();

    String embeddedComponentClassName = null;

    final EmbeddedComponentModel embeddedModel =
        embeddedId == null ? null : loadingComponentModel.getEmbeddedComponentModel(embeddedId);

    // We know that if embeddedId is null, embeddedType is not.

    if (embeddedId == null) embeddedId = generateEmbeddedId(embeddedType, idAllocator);

    if (embeddedModel != null) {
      String modelType = embeddedModel.getComponentType();

      if (InternalUtils.isNonBlank(modelType) && embeddedType != null)
        throw new TapestryException(
            ServicesMessages.compTypeConflict(embeddedId, embeddedType, modelType), token, null);

      embeddedType = modelType;
      embeddedComponentClassName = embeddedModel.getComponentClassName();
    }

    // We only have the embeddedModel if the embeddedId was specified.  If embeddedType was ommitted
    // and

    if (InternalUtils.isBlank(embeddedType) && embeddedModel == null)
      throw new TapestryException(
          ServicesMessages.noTypeForEmbeddedComponent(
              embeddedId, loadingComponentModel.getComponentClassName()),
          token,
          null);

    final ComponentPageElement newComponent =
        pageElementFactory.newComponentElement(
            page,
            loadingElement,
            embeddedId,
            embeddedType,
            embeddedComponentClassName,
            elementName,
            token.getLocation());

    addMixinsToComponent(newComponent, embeddedModel, token.getMixins());

    final Map<String, Binding> newComponentBindings = CollectionFactory.newMap();
    componentIdToBindingMap.put(newComponent.getCompleteId(), newComponentBindings);

    if (embeddedModel != null)
      bindParametersFromModel(embeddedModel, loadingElement, newComponent, newComponentBindings);

    addToBody(newComponent);

    // Remember to load the template for this new component
    componentQueue.push(newComponent);

    // Any attribute tokens that immediately follow should be
    // used to bind parameters.

    addAttributesAsComponentBindings = true;

    // Any attributes (including component parameters) that come up belong on this component.

    activeElementStack.push(newComponent);

    // Set things up so that content inside the component is added to the component's body.

    bodyPageElementStack.push(newComponent);

    // And clean that up when the end element is reached.

    final ComponentModel newComponentModel =
        newComponent.getComponentResources().getComponentModel();

    // If the component was from an embedded @Component annotation, and it is inheritting informal
    // parameters,
    // and the component in question supports informal parameters, than get those inheritted
    // informal parameters ...
    // but later (this helps ensure that <t:parameter> elements that may provide informal parameters
    // are
    // visible when the informal parameters are copied to the child component).

    if (embeddedModel != null
        && embeddedModel.getInheritInformalParameters()
        && newComponentModel.getSupportsInformalParameters()) {
      final ComponentPageElement loadingElement = this.loadingElement;

      Runnable finalizer =
          new Runnable() {
            public void run() {
              handleInformalParameters(
                  loadingElement,
                  embeddedModel,
                  newComponent,
                  newComponentModel,
                  newComponentBindings);
            }
          };

      finalization.add(finalizer);
    }

    Runnable cleanup =
        new Runnable() {
          public void run() {
            // May need a separate queue for this, to execute at the very end of page loading.

            activeElementStack.pop();
            bodyPageElementStack.pop();
          }
        };

    // The start tag is not added to the body of the component, so neither should
    // the end tag.
    configureEnd(true, cleanup);
  }