Package org.apache.tapestry.components

Source Code of org.apache.tapestry.components.ForBean$KeyExpressionRepSource

// Copyright 2004, 2005 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry.components;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.tapestry.IBinding;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.coerce.ValueConverter;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.services.DataSqueezer;
import org.apache.tapestry.services.ExpressionEvaluator;

/**
* @author mb
*/
public abstract class ForBean extends AbstractFormComponent {
  // constants
    private static final char DESC_VALUE = 'V';
  private static final char DESC_PRIMARY_KEY = 'P';

    private final RepSource COMPLETE_REP_SOURCE = new CompleteRepSource();
    private final RepSource KEY_EXPRESSION_REP_SOURCE = new KeyExpressionRepSource();
   
  // parameters
  public abstract Object getSource();
  public abstract Object getFullSource();
    public abstract String getElement();
    public abstract String getKeyExpression();
    public abstract IPrimaryKeyConverter getConverter();
    public abstract Object getDefaultValue();
    public abstract boolean getMatch();
    public abstract boolean getVolatile();

    // properties
    public abstract Iterator getSourceIterator();
    public abstract void setSourceIterator(Iterator sourceIterator);
   
    public abstract Iterator getFullSourceIterator();
    public abstract void setFullSourceIterator(Iterator fullSourceIterator);
   
    public abstract Map getRepToValueMap();
    public abstract void setRepToValueMap(Map repToValue);
   
    // injects
    public abstract DataSqueezer getDataSqueezer();
    public abstract ValueConverter getValueConverter();
    public abstract ExpressionEvaluator getExpressionEvaluator();

    // intermediate members
    private Object _value;
    private int _index;
    private boolean _rendering;

   
    /**
     *  Gets the source binding and iterates through
     *  its values.  For each, it updates the value binding and render's its wrapped elements.
     *
     **/
    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
    {
      // Clear the cache between rewind and render.
      // This allows the value of 'source' to be changed by the form listeners.
      setSourceIterator(null);
     
        // form may be null if component is not located in a form
        IForm form = (IForm) cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);

        // If the cycle is rewinding, but not this particular form,
        // then do nothing (don't even render the body).
        boolean cycleRewinding = cycle.isRewinding();
        if (cycleRewinding && form != null && !form.isRewinding())
            return;

        // Get the data to be iterated upon. Store in form if needed.
        Iterator dataSource = getData(cycle, form);
       
        // Do not iterate if dataSource is null.
        // The dataSource was either not convertable to Iterator, or was empty.
        if (dataSource == null)
            return;

        String element = getElement();

        // Perform the iterations
        try
        {
            _index = 0;
            _rendering = true;

            while (dataSource.hasNext())
            {
              // Get current value
                _value = dataSource.next();

                // Update output component parameters
                updateOutputParameters();
             
                // Render component
                if (element != null)
                {
                    writer.begin(element);
                    renderInformalParameters(writer, cycle);
                }

                renderBody(writer, cycle);

                if (element != null)
                    writer.end();

                _index++;
            }
        }
        finally
        {
            _rendering = false;
            _value = null;
        }
    }
   
   
    /**
     *  Returns the most recent value extracted from the source parameter.
     *
     *  @throws org.apache.tapestry.ApplicationRuntimeException if the For is not currently rendering.
     *
     **/

    public final Object getValue()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this, "value");
 
        return _value;
    }

    /**
     *  The index number, within the {@link #getSource() source}, of the
     *  the current value.
     *
     *  @throws org.apache.tapestry.ApplicationRuntimeException if the For is not currently rendering.
     *
     **/
   
    public int getIndex()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this, "index");
       
        return _index;
    }

    public boolean isDisabled()
    {
        return false;
    }

    /**
     * Updates the index and value output parameters if bound.
     */
    protected void updateOutputParameters()
    {
      IBinding indexBinding = getBinding("index");
      if (indexBinding != null)
        indexBinding.setObject(new Integer(_index));

      IBinding valueBinding = getBinding("value");
      if (valueBinding != null)
        valueBinding.setObject(_value);
    }

    /**
     * Updates the primaryKeys parameter if bound.
     */
    protected void updatePrimaryKeysParameter(String[] stringReps)
    {
      IBinding primaryKeysBinding = getBinding("primaryKeys");
      if (primaryKeysBinding == null)
        return;

      DataSqueezer squeezer = getDataSqueezer();
     
        int repsCount = stringReps.length;
        List primaryKeys = new ArrayList(repsCount);
      for (int i = 0; i < stringReps.length; i++) {
      String rep = stringReps[i];
      if (rep.length() == 0 || rep.charAt(0) != DESC_PRIMARY_KEY)
        continue;
      Object primaryKey = squeezer.unsqueeze(rep.substring(1));
      primaryKeys.add(primaryKey);
    }
     
      primaryKeysBinding.setObject(primaryKeys);
    }
   
  // Do nothing in those methods, but make the JVM happy
    protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle) { }
    protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle) { }

   
   
   
    /**
     * Returns a list with the values to be iterated upon.
     *
     * The list is obtained in different ways:
     * - If the component is not located in a form or 'volatile' is set to true,
     *   then the simply the values passed to 'source' are returned (same as Foreach)
     * - If the component is in a form, and the form is rewinding, the values stored
     *    in the form are returned -- rewind is then always the same as render.
     * - If the component is in a form, and the form is being rendered, the values
     *   are stored in the form as Hidden fields.
     *
     * @param cycle The current request cycle
     * @param form The form within which the component is located (if any)
     * @return An iterator with the values to be cycled upon
     **/
    private Iterator getData(IRequestCycle cycle, IForm form) {
        if (form == null || getVolatile())
          return getSourceIteratorValue();
       
        String name = form.getElementId(this);
        if (cycle.isRewinding())
          return getStoredData(cycle, name);
         return storeSourceData(form, name);
    }

    /**
     *  Returns a list of the values stored as Hidden fields in the form.
     *  A conversion is performed if the primary key of the value is stored.
     * 
     *  @param cycle The current request cycle
     *  @param name The name of the HTTP parameter whether the values
     *  @return an iterator with the values stored in the provided Hidden fields
     **/
    protected Iterator getStoredData(IRequestCycle cycle, String name)
    {
        String[] stringReps = cycle.getParameters(name);
       
        updatePrimaryKeysParameter(stringReps);
       
        int valueCount = stringReps.length;
        List values = new ArrayList(valueCount);
        for (int i = 0; i < valueCount; i++) {
      String rep = stringReps[i];
      Object value = getValueFromStringRep(rep);
      values.add(value);
    }
       
        return values.iterator();
    }
   
    /**
     *  Stores the provided data in the form and then returns the data as an iterator.
     *  If the primary key of the value can be determined,
     *  then that primary key is saved instead.
     *  
     *  @param form The form where the data will be stored
     *  @param name The name under which the data will be stored
     *  @return an iterator with the bound values stored in the form
     **/
    protected Iterator storeSourceData(IForm form, String name)
    {
        List values = new ArrayList();
     
        Iterator it = getSourceIteratorValue();
      while (it.hasNext()) {
        Object value = it.next();
        values.add(value);
       
        String rep = getStringRepFromValue(value);
        form.addHiddenValue(name, rep);
      }
     
      return values.iterator();
    }

   
    /**
     * Returns the string representation of the value.
     * 
     * The first letter of the string representation shows whether a value
     * or a primary key is being described.
     *
     * @param value
     * @return
     */
    protected String getStringRepFromValue(Object value) {
      String rep;
      DataSqueezer squeezer = getDataSqueezer();
     
      // try to extract the primary key from the value
      Object pk = getPrimaryKeyFromValue(value);
      if (pk != null)
        // Primary key was extracted successfully.
        rep = DESC_PRIMARY_KEY + squeezer.squeeze(pk);
      else
        // primary key could not be extracted. squeeze value.
        rep = DESC_VALUE + squeezer.squeeze(value);
     
      return rep;
    }

    /**
     * Returns the primary key of the given value.
     * Uses the 'keyExpression' or the 'converter' (if either is provided).
     *
     * @param value The value from which the primary key should be extracted
     * @return The primary key of the value, or null if such cannot be extracted.
     */
    protected Object getPrimaryKeyFromValue(Object value) {
      if (value == null)
        return null;
     
      Object primaryKey = getKeyExpressionFromValue(value);
    if (primaryKey == null)
      primaryKey = getConverterFromValue(value);

      return primaryKey;
    }
   
    /**
     * Uses the 'keyExpression' parameter to determine the primary key of the given value
     *
     * @param value The value from which the primary key should be extracted
     * @return The primary key of the value as defined by 'keyExpression',
     * or null if such cannot be extracted.
     */
    protected Object getKeyExpressionFromValue(Object value) {
      String keyExpression = getKeyExpression();
    if (keyExpression == null)
      return null;
   
    Object primaryKey = getExpressionEvaluator().read(value, keyExpression);
    return primaryKey;
    }
   
    /**
     * Uses the 'converter' parameter to determine the primary key of the given value
     *
     * @param value The value from which the primary key should be extracted
     * @return The primary key of the value as provided by the converter,
     * or null if such cannot be extracted.
     */
    protected Object getConverterFromValue(Object value) {
      IPrimaryKeyConverter converter = getConverter();
    if (converter == null)
      return null;
   
    Object primaryKey = converter.getPrimaryKey(value);
    return primaryKey;
    }
   
    /**
     * Determines the value that corresponds to the given string representation.
     *
     * If the 'match' parameter is true, attempt to find a value in 'source'
     * or 'fullSource' that generates the same string representation.
     *
     * Otherwise, create a new value from the string representation.
     *
     * @param rep the string representation for which a value should be returned
     * @return the value that corresponds to the provided string representation
     */
    protected Object getValueFromStringRep(String rep) {
      Object value = null;
      DataSqueezer squeezer = getDataSqueezer();
     
      // Check if the string rep is empty. If so, just return the default value.
      if (rep == null || rep.length() == 0)
        return getDefaultValue();
     
      // If required, find a value with an equivalent string representation and return it
      boolean match = getMatch();
    if (match) {
      value = findValueWithStringRep(rep, COMPLETE_REP_SOURCE);
      if (value != null)
        return value;
    }

    // Matching of the string representation was not successful or was disabled.
    // Use the standard approaches to obtain the value from the rep.
    char desc = rep.charAt(0);
    String squeezed = rep.substring(1);
      switch (desc) {
        case DESC_VALUE:
          // If the string rep is just the value itself, unsqueeze it
          value = squeezer.unsqueeze(squeezed);
          break;
         
        case DESC_PRIMARY_KEY:
          // Perform keyExpression match if not already attempted
          if (!match && getKeyExpression() != null)
            value = findValueWithStringRep(rep, KEY_EXPRESSION_REP_SOURCE);

          // If 'converter' is defined, try to perform conversion from primary key to value
          if (value == null) {
            IPrimaryKeyConverter converter = getConverter();
            if (converter != null) {
              Object pk = squeezer.unsqueeze(squeezed);
              value = converter.getValue(pk);
            }
          }
          break;
      }
     
      if (value == null)
        value = getDefaultValue();
     
      return value;
    }
   
    /**
     * Attempt to find a value in 'source' or 'fullSource' that generates
     * the provided string representation.
     *
     * Use the RepSource interface to determine what the string representation
     * of a particular value is.
     *
     * @param rep the string representation for which a value should be returned
     * @param repSource an interface providing the string representation of a given value
     * @return the value in 'source' or 'fullSource' that corresponds
     * to the provided string representation
     */
    protected Object findValueWithStringRep(String rep, RepSource repSource) {
      Map repToValueMap = getRepToValueMap();
     
      Object value = repToValueMap.get(rep);
      if (value != null)
        return value;

    Iterator it = getSourceIteratorValue();
    value = findValueWithStringRepInIterator(rep, repSource, it);
      if (value != null)
        return value;
   
    it = getFullSourceIteratorValue();
    value = findValueWithStringRepInIterator(rep, repSource, it);
       return value;
    }

    /**
     * Attempt to find a value in the provided collection that generates
     * the required string representation.
     *
     * Use the RepSource interface to determine what the string representation
     * of a particular value is.
     *
     * @param rep the string representation for which a value should be returned
     * @param repSource an interface providing the string representation of a given value
     * @param it the iterator of the collection in which a value should be searched
     * @return the value in the provided collection that corresponds
     * to the required string representation
     */
    protected Object findValueWithStringRepInIterator(String rep, RepSource repSource, Iterator it) {
      Map repToValueMap = getRepToValueMap();
     
    while (it.hasNext()) {
        Object sourceValue = it.next();
        if (sourceValue == null)
          continue;
       
        String sourceRep = repSource.getStringRep(sourceValue);
           repToValueMap.put(sourceRep, sourceValue);
         
          if (rep.equals(sourceRep))
            return sourceValue;
    }
   
    return null;
    }
   
    /**
     * Returns the cached 'source' iterator. The value is initialized
     * with the iterator provided by the 'source' parameter 
     *
     * @return the cached 'source' iterator
     */
    protected Iterator getSourceIteratorValue()
    {
    Iterator it = getSourceIterator();
    if (it == null) {
      it = (Iterator) getValueConverter().coerceValue(getSource(), Iterator.class);
      if (it == null)
        it = Collections.EMPTY_LIST.iterator();
      setSourceIterator(it);
    }
     
    return it;
    }
   
    /**
     * Returns the cached 'fullSource' iterator. The value is initialized
     * with the iterator provided by the 'fullSource' parameter 
     *
     * @return the cached 'fullSource' iterator
     */
    protected Iterator getFullSourceIteratorValue()
    {
    Iterator it = getFullSourceIterator();
    if (it == null) {
      it = (Iterator) getValueConverter().coerceValue(getFullSource(), Iterator.class);
      if (it == null)
        it = Collections.EMPTY_LIST.iterator();
      setFullSourceIterator(it);
    }
     
    return it;
    }
   
    /**
     * An interface that provides the string representation of a given value
     */
    protected interface RepSource {
      String getStringRep(Object value);
    }
   
    /**
     * An implementation of RepSource that provides the string representation
     * of the given value using all methods.
     */
    protected class CompleteRepSource implements RepSource {
      public String getStringRep(Object value) {
        return getStringRepFromValue(value);
      }
    }
   
    /**
     * An implementation of RepSource that provides the string representation
     * of the given value using just the 'keyExpression' parameter.
     */
    protected class KeyExpressionRepSource implements RepSource {
      public String getStringRep(Object value) {
        Object pk = getKeyExpressionFromValue(value);
        return DESC_PRIMARY_KEY + getDataSqueezer().squeeze(pk);
      }
    }

    /**
     * For component can not take focus.
     */
    protected boolean getCanTakeFocus() {
        return false;
    }
   
    public String getClientId()
    {
        // TODO Auto-generated method stub
        return null;
    }
    public String getDisplayName()
    {
        // TODO Auto-generated method stub
        return null;
    }
   
   
}
TOP

Related Classes of org.apache.tapestry.components.ForBean$KeyExpressionRepSource

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.