Package org.richfaces.taglib

Source Code of org.richfaces.taglib.ColumnsHandler

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

/*
* ColumnsHandler.java    Date created: 07.12.2007
* Last modified by: $Author$
* $Revision$  $Date$
*/

package org.richfaces.taglib;

import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.el.ELException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.jsp.JspTagException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.el.ELBuilder;
import org.richfaces.iterator.ForEachIterator;
import org.richfaces.iterator.SimpleForEachIterator;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.FaceletHandler;
import com.sun.facelets.tag.MetaRule;
import com.sun.facelets.tag.MetaRuleset;
import com.sun.facelets.tag.MetaTagHandler;
import com.sun.facelets.tag.Metadata;
import com.sun.facelets.tag.MetadataTarget;
import com.sun.facelets.tag.Tag;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagAttributes;
import com.sun.facelets.tag.jsf.ComponentConfig;



/**
* TODO Class description goes here.
*
* @author "Andrey Markavtsov"
*
*/
public class ColumnsHandler extends MetaTagHandler {

  private static final Log log = LogFactory.getLog(ColumnsHandler.class);
 
  com.sun.facelets.tag.jsf.ComponentHandler handler;

  private static final String ITERATION_INDEX_VARIABLE = "__richfaces_iteration_index_variable";
 
  private static final String ITERATION_INDEX_EXPRESSION = "#{" + ITERATION_INDEX_VARIABLE + "}";

  private static final String F_GENERATION_SERIES_ATTRIBUTE = "org.richfaces.F_COLUMNS_GENERATION_SERIES";

  /** value attribute */
  private TagAttribute value;

  /** end attribute */
  private TagAttribute columns;

  /** begin attribute */
  private TagAttribute begin;

  /** var attribute */
  private TagAttribute var;

  /** index attribute */
  private TagAttribute index;

  /** end attribute */
  private TagAttribute end;

  class IterationContext {

    /** Iterator for columns's tag value attribute */
    public ForEachIterator items; // our 'digested' items

    /** Value attribute value */
    public Object rawItems; // our 'raw' items

    /** Var attr - defines page variable for current item */
    public String _indexId;

    /** Integer value begin attr */
    public Integer _begin;

    /** Integer value end attr */
    public Integer _end;

    /** Integer value of end attr. */
    public Integer _columns;

    /** String value of var attr */
    public String _itemId = null;

    /** Current column counter */
    public Integer _index = 0;

    /** Expression for var item */
    public IteratedExpression iteratedExpression;

    public String valueExpr;

    public String getVarReplacement() {
      if (valueExpr == null) {
        return String.valueOf(index);
      }else if (items.getVarReplacement() != null) {
        return items.getVarReplacement();
      }
      return valueExpr + "[" + _index + "]";
    }

    public String getIndexReplacement() {
      return String.valueOf(_index);
    }
  };

  ThreadLocal<IterationContext> iterationContextLocal = new ThreadLocal<IterationContext>();

  public IterationContext getIterationContext() {
    return iterationContextLocal.get();
  }

  /**
   * TODO Description goes here.
   *
   * @param config
   */
  public ColumnsHandler(final ComponentConfig config) {
    super(config);
   
    final ComponentConfig columnConfig;
   
    TagAttribute idAttribute = config.getTag().getAttributes().get("id");
    if (idAttribute != null && idAttribute.isLiteral()) {
      columnConfig = new ComponentConfig() {

        private Tag tag;

        {
          Tag initialTag = config.getTag();
          TagAttribute[] allInitialAttributes = initialTag.getAttributes().getAll();
          TagAttribute[] attributes = new TagAttribute[allInitialAttributes.length];
          for (int i = 0; i < allInitialAttributes.length; i++) {
            TagAttribute initialAttribute = allInitialAttributes[i];
            String localName = initialAttribute.getLocalName();
            String attributeValue = initialAttribute.getValue();
           
            if ("id".equals(localName)) {
              attributeValue += ITERATION_INDEX_EXPRESSION;
            }
           
            attributes[i] = new TagAttribute(initialAttribute.getLocation(),
                initialAttribute.getNamespace(),
                localName,
                initialAttribute.getQName(),
                attributeValue);
          }
         
          TagAttributes tagAttributes = new TagAttributes(attributes);
          this.tag = new Tag(initialTag, tagAttributes);
        }
       
        public String getComponentType() {
          return config.getComponentType();
        }

        public String getRendererType() {
          return config.getRendererType();
        }

        public FaceletHandler getNextHandler() {
          return config.getNextHandler();
        }

        public Tag getTag() {
          return tag;
        }

        public String getTagId() {
          return config.getTagId();
        }
       
      };
    } else {
      columnConfig = config;
    }
   
    handler = new ColumnTagHandler(columnConfig) {
     
      @Override
      protected MetaRuleset createMetaRuleset(Class type) {
        MetaRuleset ruleset = super.createMetaRuleset(type);
        ruleset.addRule(new MetaRule() {

          @Override
          public Metadata applyRule(final String name,
              final TagAttribute attribute, MetadataTarget meta) {
            if (ColumnsAttributes.FILTER_ATTRIBUTES.indexOf(name) != -1 ||
              ColumnsAttributes.SORT_ATTRIBUTES.indexOf(name) != -1) {
             
              return new Metadata() {

                @Override
                public void applyMetadata(FaceletContext ctx,
                    Object instance) {
                  if (!attribute.isLiteral()) {
                    String expr = attribute.getValue();
                    IterationContext itContext = iterationContextLocal.get();

                    ValueExpression ve = ELBuilder.createValueExpression(expr, Object.class, ctx.getExpressionFactory(), ctx,
                        itContext._itemId, itContext._indexId,
                        itContext.getVarReplacement(), itContext.getIndexReplacement());
                    ((UIComponent)instance).setValueExpression(name, ve);
                  }else {
                    ((UIComponent)instance).getAttributes().put(name, attribute.getValue());
                  }
                }

              };
            }
            return null;
          }

        });
        return ruleset;
      }

      @Override
      protected void applyNextHandler(FaceletContext ctx, UIComponent c)
      throws IOException, FacesException, ELException {
        c.getAttributes().put(F_GENERATION_SERIES_ATTRIBUTE, RequestUniqueIdGenerator.generateId(ctx.getFacesContext()));
        super.applyNextHandler(ctx, c);
      }
    };
  }


  /**
   * Extracts tags attributes values
   */
  private void initVariables(FaceletContext ctx) {
    initColumnsCount(ctx);
    initIndex(ctx);
    initVar(ctx);
    initBegin(ctx);
    initEnd(ctx);
  }

  /**
   * Method prepares all we need for starting of tag rendering
   *
   * @throws JspTagException
   */
  private void prepare(FaceletContext ctx) {

    initVariables(ctx);

    IterationContext itContext = getIterationContext();

    try {

      this.value = getAttribute("value");

      // produce the right sort of ForEachIterator
      if (this.value != null) {
        itContext.valueExpr = ELBuilder.getVarReplacement(this.value.getValue());

        // If this is a deferred expression, make a note and get
        // the 'items' instance.

        itContext.rawItems = this.value.getObject(ctx);

        // extract an iterator over the 'items' we've got
        itContext.items = SimpleForEachIterator
        .supportedTypeForEachIterator(itContext.rawItems);
      } else {
        // no 'items', so use 'begin' and 'end'
        itContext.items = SimpleForEachIterator.beginEndForEachIterator(itContext._columns - 1);
      }
    } catch (Exception e) {
      log.error(e.getLocalizedMessage(), e);
      // TODO: handle exception
    }

    correctFirst(ctx);
  }

  /**
   * Inits first iteration item
   */
  private void correctFirst(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    if (itContext.items != null) {
      if (itContext._begin > 0 && (itContext._index < itContext._begin)) {
        while ((itContext._index < itContext._begin && hasNext())) {
          next(ctx);
        }
        if (!hasNext()) {
          itContext._index = 0;
        }
      }
    }
  }

  /**
   * Return true if we didn't complete column's count
   *
   * @return
   * @throws JspTagException
   */
  private boolean hasNext() {
    IterationContext itContext = getIterationContext();
    try {
      if (itContext._end != 0) {
        return (itContext._index < itContext._end) ? itContext.items.hasNext() : false;
      } else {
        return itContext.items.hasNext();
      }
    } catch (Exception e) {
      return false;
    }

  }

  /**
   * Iterate to next column
   *
   * @return
   * @throws JspTagException
   */
  private Object next(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    try {
      Object o = itContext.items.next();
      itContext._index++;
      return o;
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * Extracts integer value from end attr
   */
  private void initColumnsCount(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    this.columns = getAttribute("columns");
    if (columns != null) {
      try {
        itContext._columns = Integer.parseInt((String) columns.getObject(ctx));
        if (itContext._columns < 0) {
          itContext._columns = 0; // If end is negative set up zero
        }
      } catch (Exception e) {
        itContext._columns = 0;
      }
    } else {
      itContext._columns = 0;
    }
  }

  /**
   * Extracts integer value from begin attr
   */
  private void initBegin(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    this.begin = getAttribute("begin");
    if (begin != null) {
      try {
        Object o = begin.getObject(ctx);
        if (o instanceof Number) {
          itContext._begin = ((Number)o).intValue();
        }else if (o instanceof String) {
          itContext._begin = Integer.parseInt((String) o);
        }
        itContext._begin--;
        if (itContext._begin < 0) {
          itContext._begin = 0; // If end is negative set up zero
        }
      } catch (Exception e) {
        itContext._begin = 0;
      }
    } else {
      itContext._begin = 0;
    }
  }

  /**
   * Extracts integer value from end attr
   */
  private void initEnd(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    this.end = getAttribute("end");
    if (end != null) {
      try {
        Object o = end.getObject(ctx);
        if (o instanceof Number) {
          itContext._end = ((Number)o).intValue();
        }else if ( o instanceof String) {
          itContext._end = Integer.parseInt((String) o);
        }
        if (itContext._end < 0) {
          itContext._end = 0; // If end is negative set up zero
        }
      } catch (Exception e) {
        itContext._end = 0;
      }
    } else {
      itContext._end = 0;
    }
  }

  /**
   * Extracts string value from var attr
   */
  private void initVar(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    this.var = getAttribute("var");
    if (var != null) {
      try {
        itContext._itemId = (String) var.getObject(ctx);
      } catch (ClassCastException e) {
        itContext._itemId = null;
      }

    }
  }

  /**
   * Extracts string value from index attr
   */
  private void initIndex(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    this.index = getAttribute("index");
    if (index != null) {
      try {
        itContext._indexId = (String) index.getObject(ctx);
      } catch (ClassCastException e) {
        itContext._indexId = null;
      }

    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.taglib.ComponentHandler#apply(com.sun.facelets.FaceletContext,
   *      javax.faces.component.UIComponent)
   */
  //@Override
  public void apply(FaceletContext ctx, UIComponent parent)
  throws IOException, FacesException, ELException {

    IterationContext iterationContext = new IterationContext();
    iterationContextLocal.set(iterationContext);

    clearOldColumns(ctx.getFacesContext(), parent);
    prepare(ctx)// prepare data

    try {
      while (hasNext()) {  // for each
        exposeVariables(ctx);
        handler.apply(ctx, parent);
        next(ctx);
      }
    } catch (Exception e) {
      log.error(e.getLocalizedMessage(), e);
      // TODO: handle exception
    } finally {
      release();
      unExposeVariables(ctx);
    }

  }


  private void clearOldColumns(FacesContext context, UIComponent parent) {
    if (parent.getChildCount() > 0) {
      Integer generatedId = RequestUniqueIdGenerator.generateId(context);
     
      Iterator<UIComponent> childrenIt = parent.getChildren().iterator();
      while (childrenIt.hasNext()) {
        UIComponent c = childrenIt.next();

        Object generationSeries = c.getAttributes().get(F_GENERATION_SERIES_ATTRIBUTE);
        if (generationSeries != null && !generationSeries.equals(generatedId)) {
          childrenIt.remove();
        }
      }
    }
  }

  /**
   * Sets page request variables
   *
   * @throws JspTagException
   */
  private void exposeVariables(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    VariableMapper vm = ctx.getVariableMapper();
    int k = itContext._index;

    if (itContext._itemId != null) {
      if (vm != null) {
        if (value != null) {
          ValueExpression srcVE = value.getValueExpression(ctx,
              Object.class);
          ValueExpression ve = getVarExpression(ctx, srcVE);
          vm.setVariable(itContext._itemId, ve);
        }
      }

    }

    // Set up index variable

    if (itContext._indexId != null) {
      if (vm != null) {
        ValueExpression ve = new IteratedIndexExpression(k);
        vm.setVariable(itContext._indexId, ve);
      }

    }

    int componentsCount = itContext._index - itContext._begin;
    if (componentsCount != 0) {
      ValueExpression ve = ctx.getExpressionFactory().createValueExpression(UIViewRoot.UNIQUE_ID_PREFIX + componentsCount, String.class);
      vm.setVariable(ITERATION_INDEX_VARIABLE, ve);
    }
  }

  /**
   * Removes page attributes that we have exposed and, if applicable, restores
   * them to their prior values (and scopes).
   */
  private void unExposeVariables(FaceletContext ctx) {
    IterationContext itContext = getIterationContext();
    VariableMapper vm = ctx.getVariableMapper();
    // "nested" variables are now simply removed
    if (itContext._itemId != null) {
      if (vm != null)
        vm.setVariable(itContext._itemId, null);
    }
    if (itContext._indexId != null) {
      if (vm != null)
        vm.setVariable(itContext._indexId, null);
    }
   
    vm.setVariable(ITERATION_INDEX_VARIABLE, null);
  }

  /**
   * Return expression for page variables
   *
   * @param expr
   * @return
   */
  private ValueExpression getVarExpression(FaceletContext ctx,
      ValueExpression expr/*, IterationContext itContext*/) {
    IterationContext itContext = getIterationContext();
    Object o = expr.getValue(ctx.getFacesContext().getELContext());
    int k = itContext._index;
    if (o.getClass().isArray() || o instanceof List) {
      return new IndexedValueExpression(expr, k);
    }

    if (o instanceof Collection || o instanceof Iterator
        || o instanceof Enumeration || o instanceof Map
        || o instanceof String) {

      if (itContext.iteratedExpression == null) {
        itContext.iteratedExpression = new IteratedExpression(expr, ",");
      }
      return new IteratedValueExpression(itContext.iteratedExpression, k);
    }

    throw new ELException("FOREACH_BAD_ITEMS");
  }

  /**
   * Release iteration variables
   */
  private void release() {
    IterationContext itContext = getIterationContext();
    itContext.items = null;
    itContext._index = 0;
  }

}
TOP

Related Classes of org.richfaces.taglib.ColumnsHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.