예제 #1
0
public class SubviewTag extends UIComponentELTag {

  private static final Logger LOGGER = FacesLogger.TAGLIB.getLogger();

  // ------------------------------------------------------------ Constructors

  public SubviewTag() {

    super();
  }

  // ---------------------------------------------------------- Public Methods

  public String getComponentType() {

    return "javax.faces.NamingContainer";
  }

  public String getRendererType() {

    return null;
  }

  // ------------------------------------------------------- Protected Methods

  protected UIComponent createVerbatimComponentFromBodyContent() {

    UIOutput verbatim = (UIOutput) super.createVerbatimComponentFromBodyContent();
    String value = null;

    FacesContext ctx = getFacesContext();
    Object response = ctx.getExternalContext().getResponse();
    // flush out any content above the view tag
    Method customFlush =
        ReflectionUtils.lookupMethod(
            response.getClass(), "flushContentToWrappedResponse", RIConstants.EMPTY_CLASS_ARGS);
    Method isBytes =
        ReflectionUtils.lookupMethod(response.getClass(), "isBytes", RIConstants.EMPTY_CLASS_ARGS);
    Method isChars =
        ReflectionUtils.lookupMethod(response.getClass(), "isChars", RIConstants.EMPTY_CLASS_ARGS);
    Method resetBuffers =
        ReflectionUtils.lookupMethod(
            response.getClass(), "resetBuffers", RIConstants.EMPTY_CLASS_ARGS);
    Method getChars =
        ReflectionUtils.lookupMethod(response.getClass(), "getChars", RIConstants.EMPTY_CLASS_ARGS);
    boolean cont = true;
    if (isBytes == null) {
      cont = false;
      if (LOGGER.isLoggable(Level.WARNING)) {
        LOGGER.log(Level.WARNING, "jsf.core.taglib.subviewtag.interweaving_failed_isbytes");
      }
    }
    if (isChars == null) {
      cont = false;
      if (LOGGER.isLoggable(Level.WARNING)) {
        LOGGER.log(Level.WARNING, "jsf.core.taglib.subviewtag.interweaving_failed_ischars");
      }
    }
    if (resetBuffers == null) {
      cont = false;
      if (LOGGER.isLoggable(Level.WARNING)) {
        LOGGER.log(Level.WARNING, "jsf.core.taglib.subviewtag.interweaving_failed_resetbuffers");
      }
    }
    if (getChars == null) {
      cont = false;
      if (LOGGER.isLoggable(Level.WARNING)) {
        LOGGER.log(Level.WARNING, "jsf.core.taglib.subviewtag.interweaving_failed_getchars");
      }
    }
    if (customFlush == null) {
      cont = false;
      if (LOGGER.isLoggable(Level.WARNING)) {
        LOGGER.log(Level.WARNING, "jsf.core.taglib.viewtag.interweaving_failed");
      }
    }

    if (cont) {
      try {
        if ((Boolean) isBytes.invoke(response)) {
          customFlush.invoke(response);
        } else if ((Boolean) isChars.invoke(response)) {
          char[] chars = (char[]) getChars.invoke(response);
          if (null != chars && 0 < chars.length) {
            if (null != verbatim) {
              value = (String) verbatim.getValue();
            }
            verbatim = super.createVerbatimComponent();
            if (null != value) {
              verbatim.setValue(value + new String(chars));
            } else {
              verbatim.setValue(new String(chars));
            }
          }
        }
        resetBuffers.invoke(response);

      } catch (Exception e) {
        throw new FacesException("Response interweaving failed!", e);
      }
    }

    return verbatim;
  }

  public int doEndTag() throws JspException {
    int retValue;

    getViewTagStack().pop();
    retValue = super.doEndTag();
    return retValue;
  }

  public int doStartTag() throws JspException {
    int retValue;

    retValue = super.doStartTag();
    getViewTagStack().push(this);

    return retValue;
  }

  /**
   * @return Stack of UIComponentClassicTagBase instances, each of which is a "view" tag. The bottom
   *     most element on the stack is the ViewTag itself. Subsequent instances are SubviewTag
   *     instances.
   */
  static Stack<UIComponentClassicTagBase> getViewTagStack() {

    FacesContext ctx = FacesContext.getCurrentInstance();
    //noinspection unchecked
    Stack<UIComponentClassicTagBase> result =
        (Stack<UIComponentClassicTagBase>)
            RequestStateManager.get(ctx, RequestStateManager.VIEWTAG_STACK_ATTR_NAME);
    if (result == null) {
      result = new Stack<UIComponentClassicTagBase>();
      RequestStateManager.set(ctx, RequestStateManager.VIEWTAG_STACK_ATTR_NAME, result);
    }

    return result;
  }
}
예제 #2
0
public class AttributeHandler extends TagHandlerImpl {

  private final Logger LOGGER = FacesLogger.TAGLIB.getLogger();

  private static final String[] COMPOSITE_ATTRIBUTE_ATTRIBUTES = {
    "required",
    "targets",
    "targetAttributeName",
    "default",
    "displayName",
    "preferred",
    "hidden",
    "expert",
    "shortDescription",
    "method-signature",
    "type",
  };

  private static final PropertyHandlerManager ATTRIBUTE_MANAGER =
      PropertyHandlerManager.getInstance(COMPOSITE_ATTRIBUTE_ATTRIBUTES);

  private TagAttribute name;

  public AttributeHandler(TagConfig config) {
    super(config);
    this.name = this.getRequiredAttribute("name");
  }

  public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
    // only process if it's been created
    if (null == parent
        || (null == (parent = parent.getParent()))
        || !(ComponentHandler.isNew(parent))) {
      return;
    }

    Map<String, Object> attrs = parent.getAttributes();

    CompositeComponentBeanInfo componentBeanInfo =
        (CompositeComponentBeanInfo) attrs.get(UIComponent.BEANINFO_KEY);
    assert (null != componentBeanInfo);
    List<PropertyDescriptor> declaredAttributes = componentBeanInfo.getPropertyDescriptorsList();

    // Get the value of required the name propertyDescriptor
    ValueExpression ve = name.getValueExpression(ctx, String.class);
    String strValue = (String) ve.getValue(ctx);

    // Search the propertyDescriptors for one for this attribute
    for (PropertyDescriptor cur : declaredAttributes) {
      if (strValue.endsWith(cur.getName())) {
        // If we have a match, no need to waste time
        // duplicating and replacing it.
        return;
      }
    }

    PropertyDescriptor propertyDescriptor;
    try {
      propertyDescriptor = new CCAttributePropertyDescriptor(strValue, null, null);
      declaredAttributes.add(propertyDescriptor);
    } catch (IntrospectionException ex) {
      throw new TagException(
          tag, "Unable to create property descriptor for property " + strValue, ex);
    }

    TagAttribute defaultTagAttribute = null;
    PropertyHandler defaultHandler = null;
    for (TagAttribute tagAttribute : this.tag.getAttributes().getAll()) {
      String attributeName = tagAttribute.getLocalName();
      if ("default".equals(attributeName)) {
        // store the TagAttribute and the PropertyHandler for later
        // execution, as the handler for the default-attribute requires,
        // that the PropertyHandler for 'type' - if it exists - has been
        // applied first.
        defaultTagAttribute = tagAttribute;
        defaultHandler = ATTRIBUTE_MANAGER.getHandler(ctx, "default");
      } else {
        PropertyHandler handler = ATTRIBUTE_MANAGER.getHandler(ctx, attributeName);
        if (handler != null) {
          handler.apply(ctx, attributeName, propertyDescriptor, tagAttribute);
        }
      }
    }
    if (defaultHandler != null) {
      // If the 'default'-attribute of cc:attribute was set, apply the
      // previously stored PropertyHandler (see above) now, as now it is
      // guaranteed that if a 'type'-attribute existed, that its handler
      // was already applied
      try {
        defaultHandler.apply(ctx, "default", propertyDescriptor, defaultTagAttribute);
      } catch (IllegalArgumentException ex) {
        // If the type (according to the type-attribute) can not be
        // found, the DefaultPropertyHandler will wrapp the
        // ClassNotFoundException into an IllegalArgumentException,
        // which is unwrapped into a TagException here.
        throw new TagException(
            tag, "'type' could not be resolved: " + ex.getCause(), ex.getCause());
      }
    }

    this.nextHandler.apply(ctx, parent);
  }

  private class CCAttributePropertyDescriptor extends PropertyDescriptor {

    public CCAttributePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
        throws IntrospectionException {
      super(propertyName, readMethod, writeMethod);
    }

    @Override
    public Object getValue(String attributeName) {
      Object result = super.getValue(attributeName);
      if ("type".equals(attributeName)) {
        if ((null != result) && !(result instanceof Class)) {
          FacesContext context = FacesContext.getCurrentInstance();
          ELContext elContext = context.getELContext();
          String classStr = (String) ((ValueExpression) result).getValue(elContext);
          if (null != classStr) {
            try {
              result = ReflectionUtil.forName(classStr);

              this.setValue(attributeName, result);
            } catch (ClassNotFoundException ex) {
              classStr = "java.lang." + classStr;
              boolean throwException = false;
              try {
                result = ReflectionUtil.forName(classStr);

                this.setValue(attributeName, result);
              } catch (ClassNotFoundException ex2) {
                throwException = true;
              }
              if (throwException) {
                String message = "Unable to obtain class for " + classStr;
                if (LOGGER.isLoggable(Level.INFO)) {
                  LOGGER.log(Level.INFO, message, ex);
                }
                throw new TagAttributeException(tag, name, message, ex);
              }
            }
          }
        }
      }
      return result;
    }
  }
}
예제 #3
0
/**
 * Facelet handler responsible for, building the component tree representation of a composite
 * component based on the metadata contained in the composite interface and implementation sections
 * of the composite component template.
 */
public class CompositeComponentTagHandler extends ComponentHandler
    implements CreateComponentDelegate {

  private static final Logger LOGGER = FacesLogger.TAGLIB.getLogger();
  private Resource ccResource;
  private TagAttribute binding;

  // ------------------------------------------------------------ Constructors

  CompositeComponentTagHandler(Resource ccResource, ComponentConfig config) {
    super(config);
    this.ccResource = ccResource;
    this.binding = config.getTag().getAttributes().get("binding");
    ((ComponentTagHandlerDelegateImpl) this.getTagHandlerDelegate())
        .setCreateCompositeComponentDelegate(this);
  }

  // ------------------------------------ Methods from CreateComponentDelegate

  public UIComponent createComponent(FaceletContext ctx) {

    FacesContext context = ctx.getFacesContext();
    UIComponent cc;
    // we have to handle the binding here, as Application doesn't
    // expose a method to do so with Resource.
    if (binding != null) {
      ValueExpression ve = binding.getValueExpression(ctx, UIComponent.class);
      cc = (UIComponent) ve.getValue(ctx);
      if (cc != null && !UIComponent.isCompositeComponent(cc)) {
        if (LOGGER.isLoggable(Level.SEVERE)) {
          LOGGER.log(Level.SEVERE, "jsf.compcomp.binding.eval.non.compcomp", binding.toString());
        }
        cc = null;
      }
      if (cc == null) {
        cc = context.getApplication().createComponent(context, ccResource);
        ve.setValue(ctx, cc);
      }
    } else {
      cc = context.getApplication().createComponent(context, ccResource);
    }
    setCompositeComponent(context, cc);

    return cc;
  }

  // ------------------------------------------- Methods from ComponentHandler

  @Override
  public void applyNextHandler(FaceletContext ctx, UIComponent c)
      throws IOException, FacesException, ELException {

    // attributes need to be applied before any action is taken on
    // nested children handlers or the composite component handlers
    // as there may be an expression evaluated at tree creation time
    // that needs access to these attributes
    setAttributes(ctx, c);

    // Allow any nested elements that reside inside the markup element
    // for this tag to get applied
    super.applyNextHandler(ctx, c);

    // Apply the facelet for this composite component
    applyCompositeComponent(ctx, c);

    // Allow any PDL declared attached objects to be retargeted
    if (ComponentHandler.isNew(c)) {
      FacesContext context = ctx.getFacesContext();
      String viewId = context.getViewRoot().getViewId();
      // PENDING(rlubke): performance
      ViewDeclarationLanguageFactory factory =
          (ViewDeclarationLanguageFactory)
              FactoryFinder.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);

      ViewDeclarationLanguage vdl = factory.getViewDeclarationLanguage(viewId);
      vdl.retargetAttachedObjects(context, c, getAttachedObjectHandlers(c, false));
      vdl.retargetMethodExpressions(context, c);

      // RELEASE_PENDING This is *ugly*.  See my comments in
      // ComponentTagHandlerDelegateImpl at the end of the apply()
      // method
      if (StateContext.getStateContext(context).partialStateSaving(context, viewId)) {
        markInitialState(c);
      }
    }
  }

  // The value of this string, prepended to this.tagId, is used as a
  // key in the FacesContext attributes map, the value for which is
  // the UIComponent that formerly was stored in an instance variable called
  // cc.
  private static final String ccInstanceVariableStandinKey =
      CompositeComponentTagHandler.class.getName() + "_";

  @Override
  public void setCompositeComponent(FacesContext context, UIComponent cc) {
    Map contextMap = context.getAttributes();
    String key = ccInstanceVariableStandinKey + this.tagId;
    if (!contextMap.containsKey(key)) {
      contextMap.put(key, cc);
    }
  }

  public UIComponent getCompositeComponent(FacesContext context) {
    Map contextMap = context.getAttributes();
    String key = ccInstanceVariableStandinKey + this.tagId;
    UIComponent result = (UIComponent) contextMap.get(key);

    return result;
  }

  /**
   * Specialized implementation to prevent caching of the MetaRuleset when ProjectStage is
   * Development.
   */
  @Override
  public void setAttributes(FaceletContext ctx, Object instance) {

    if (instance != null) {
      if (ctx.getFacesContext().isProjectStage(ProjectStage.Development)) {
        Metadata meta = createMetaRuleset(instance.getClass()).finish();
        meta.applyMetadata(ctx, instance);
      } else {
        super.setAttributes(ctx, instance);
      }
    }
  }

  /**
   * This is basically a copy of what's define in ComponentTagHandlerDelegateImpl except for the
   * MetaRuleset implementation that's being used.
   *
   * <p>This also allows us to treat composite component's backed by custom component implementation
   * classes based on their type.
   *
   * @param type the <code>Class</code> for which the <code>MetaRuleset</code> must be created.
   */
  @Override
  protected MetaRuleset createMetaRuleset(Class type) {

    Util.notNull("type", type);
    FacesContext context = FacesContext.getCurrentInstance();
    UIComponent cc = getCompositeComponent(context);
    if (null == cc) {
      FaceletContext faceletContext =
          (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
      cc = createComponent(faceletContext);
      setCompositeComponent(context, cc);
    }
    MetaRuleset m =
        new CompositeComponentMetaRuleset(
            getTag(), type, (BeanInfo) cc.getAttributes().get(UIComponent.BEANINFO_KEY));

    // ignore standard component attributes
    m.ignore("binding").ignore("id");

    m.addRule(CompositeComponentRule.Instance);

    // if it's an ActionSource
    if (ActionSource.class.isAssignableFrom(type)) {
      m.addRule(ActionSourceRule.Instance);
    }

    // if it's a ValueHolder
    if (ValueHolder.class.isAssignableFrom(type)) {
      m.addRule(ValueHolderRule.Instance);

      // if it's an EditableValueHolder
      if (EditableValueHolder.class.isAssignableFrom(type)) {
        m.ignore("submittedValue");
        m.ignore("valid");
        m.addRule(EditableValueHolderRule.Instance);
      }
    }

    // if it's a selectone or selectmany
    if (UISelectOne.class.isAssignableFrom(type) || UISelectMany.class.isAssignableFrom(type)) {
      m.addRule(RenderPropertyRule.Instance);
    }

    return m;
  }

  // ---------------------------------------------------------- Public Methods

  public static List<AttachedObjectHandler> getAttachedObjectHandlers(UIComponent component) {

    return getAttachedObjectHandlers(component, true);
  }

  @SuppressWarnings({"unchecked"})
  public static List<AttachedObjectHandler> getAttachedObjectHandlers(
      UIComponent component, boolean create) {
    Map<String, Object> attrs = component.getAttributes();
    List<AttachedObjectHandler> result =
        (List<AttachedObjectHandler>) attrs.get("javax.faces.RetargetableHandlers");

    if (result == null) {
      if (create) {
        result = new ArrayList<AttachedObjectHandler>();
        attrs.put("javax.faces.RetargetableHandlers", result);
      } else {
        result = Collections.EMPTY_LIST;
      }
    }
    return result;
  }

  // --------------------------------------------------------- Private Methods

  private void applyCompositeComponent(FaceletContext ctx, UIComponent c) throws IOException {

    FacesContext facesContext = ctx.getFacesContext();
    FaceletFactory factory =
        (FaceletFactory) RequestStateManager.get(facesContext, RequestStateManager.FACELET_FACTORY);
    VariableMapper orig = ctx.getVariableMapper();

    UIPanel facetComponent;
    if (ComponentHandler.isNew(c)) {
      facetComponent = (UIPanel) facesContext.getApplication().createComponent("javax.faces.Panel");
      facetComponent.setRendererType("javax.faces.Group");
      c.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facetComponent);
    } else {
      facetComponent = (UIPanel) c.getFacets().get(UIComponent.COMPOSITE_FACET_NAME);
    }
    assert (null != facetComponent);

    try {
      Facelet f = factory.getFacelet(ccResource.getURL());

      VariableMapper wrapper =
          new VariableMapperWrapper(orig) {

            @Override
            public ValueExpression resolveVariable(String variable) {
              return super.resolveVariable(variable);
            }
          };
      ctx.setVariableMapper(wrapper);
      f.apply(facesContext, facetComponent);
    } finally {
      ctx.setVariableMapper(orig);
    }
  }

  private void markInitialState(UIComponent c) {
    if (!c.initialStateMarked()) {
      c.markInitialState();
      for (Iterator<UIComponent> i = c.getFacetsAndChildren(); i.hasNext(); ) {
        markInitialState(i.next());
      }
    }
  }

  // ---------------------------------------------------------- Nested Classes

  /**
   * Specialized MetaRulesetImpl to return CompositeMetadataTarget for component attribute handling.
   */
  private static final class CompositeComponentMetaRuleset extends MetaRulesetImpl {

    private BeanInfo compBeanInfo;
    private Class<?> type;

    public CompositeComponentMetaRuleset(Tag tag, Class<?> type, BeanInfo compBeanInfo) {

      super(tag, type);
      this.compBeanInfo = compBeanInfo;
      this.type = type;
    }

    @Override
    protected MetadataTarget getMetadataTarget() {
      try {
        return new CompositeMetadataTarget(type, compBeanInfo);
      } catch (IntrospectionException ie) {
        throw new FacesException(ie);
      }
    }

    // ------------------------------------------------------ Nested Classes

    /**
     * This class is responsible for creating ValueExpression instances with the expected type based
     * off the following:
     *
     * <p>- if the composite:attribute metadata is present, then use the type if specified by the
     * author, or default to Object.class - if no composite:attribute is specified, then attempt to
     * return the type based off the bean info for this component
     */
    private static final class CompositeMetadataTarget extends MetadataTargetImpl {

      private BeanInfo compBeanInfo;

      // ---------------------------------------------------- Construcrors

      public CompositeMetadataTarget(Class<?> type, BeanInfo compBeanInfo)
          throws IntrospectionException {

        super(type);
        this.compBeanInfo = compBeanInfo;
      }

      // --------------------------------- Methods from MetadataTargetImpl

      @Override
      public Class getPropertyType(String name) {
        PropertyDescriptor compDescriptor = findDescriptor(name);
        if (compDescriptor != null) {
          // composite:attribute declaration...
          ValueExpression typeVE = (ValueExpression) compDescriptor.getValue("type");
          if (typeVE == null) {
            return Object.class;
          } else {
            String className =
                (String) typeVE.getValue(FacesContext.getCurrentInstance().getELContext());
            if (className != null) {
              className = prefix(className);
              try {
                return ReflectionUtil.forName(className);
              } catch (ClassNotFoundException cnfe) {
                throw new FacesException(cnfe);
              }
            } else {
              return Object.class;
            }
          }
        } else {
          // defer to the default processing which will inspect the
          // PropertyDescriptor of the UIComponent type
          return super.getPropertyType(name);
        }
      }

      // ------------------------------------------------- Private Methods

      private PropertyDescriptor findDescriptor(String name) {

        for (PropertyDescriptor pd : compBeanInfo.getPropertyDescriptors()) {

          if (pd.getName().equals(name)) {
            return pd;
          }
        }
        return null;
      }

      private String prefix(String className) {

        if (className.indexOf('.') == -1 && Character.isUpperCase(className.charAt(0))) {
          return ("java.lang." + className);
        } else {
          return className;
        }
      }
    }
  } // END CompositeComponentMetaRuleset

  /** <code>MetaRule</code> for populating the ValueExpression map of a composite component. */
  private static class CompositeComponentRule extends MetaRule {

    private static final CompositeComponentRule Instance = new CompositeComponentRule();

    // ------------------------------------------ Methods from ComponentRule

    public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget meta) {

      if (meta.isTargetInstanceOf(UIComponent.class)) {
        Class type = meta.getPropertyType(name);
        if (type == null) {
          type = Object.class;
        }

        if (!attribute.isLiteral()) {
          return new CompositeExpressionMetadata(name, type, attribute);
        } else {
          return new LiteralAttributeMetadata(name, type, attribute);
        }
      }
      return null;
    }

    // ------------------------------------------------------ Nested Classes

    /**
     * For literal expressions, coerce the literal value to the type as provided to the constructor
     * prior to setting the value into the component's attribute map.
     */
    private static final class LiteralAttributeMetadata extends Metadata {

      private String name;
      private Class<?> type;
      private TagAttribute attribute;

      // ---------------------------------------------------- Constructors

      public LiteralAttributeMetadata(String name, Class<?> type, TagAttribute attribute) {

        this.name = name;
        this.type = type;
        this.attribute = attribute;
      }

      // ------------------------------------------- Methods from Metadata

      public void applyMetadata(FaceletContext ctx, Object instance) {

        UIComponent c = (UIComponent) instance;
        Object value = attribute.getObject(ctx, type);
        // don't set the attributes value in the components attributemap
        // if it is null, as this will throw a NullPointerException.
        if (value != null) {
          c.getAttributes().put(name, value);
        }
      }
    } // END LiteralAttributeMetadata

    /**
     * CompositeExpressionMetadata sets up specialized wrapper ValueExpression instances around the
     * source ValueExpression that, when evaluated, will cause the parent composite component of the
     * currently available composite component to be pushed onto a stack that the
     * ImplicitObjectELResolver will check for.
     */
    private static final class CompositeExpressionMetadata extends Metadata {

      private String name;
      private Class<?> type;
      private TagAttribute attr;

      // ---------------------------------------------------- Constructors

      public CompositeExpressionMetadata(String name, Class<?> type, TagAttribute attr) {
        this.name = name;
        this.type = type;
        this.attr = attr;
      }

      // ------------------------------------------- Methods from Metadata

      public void applyMetadata(FaceletContext ctx, Object instance) {

        ValueExpression ve = attr.getValueExpression(ctx, type);
        UIComponent cc = (UIComponent) instance;
        assert (UIComponent.isCompositeComponent(cc));
        Map<String, Object> attrs = cc.getAttributes();
        BeanInfo componentMetadata = (BeanInfo) attrs.get(UIComponent.BEANINFO_KEY);
        BeanDescriptor desc = componentMetadata.getBeanDescriptor();
        Collection<String> attributesWithDeclaredDefaultValues =
            (Collection<String>) desc.getValue(RIConstants.ATTRS_WITH_DECLARED_DEFAULT_VALUES);
        if (null != attributesWithDeclaredDefaultValues
            && attributesWithDeclaredDefaultValues.contains(name)) {
          // It is necessary to remove the value from the attribute
          // map because the ELexpression transparancy doesn't know
          // about the value's existence.
          attrs.remove(name);
        }
        cc.setValueExpression(name, ve);
      }
    } // END CompositeExpressionMetadata
  } // END CompositeComponentRule
}