Coverage Report - org.apache.tapestry.components.ForBean
 
Classes in this File Line Coverage Branch Coverage Complexity
ForBean
0%
0/179
0%
0/125
2.625
ForBean$CompleteRepSource
0%
0/2
N/A
2.625
ForBean$KeyExpressionRepSource
0%
0/3
N/A
2.625
ForBean$ReadSourceDataIterator
0%
0/11
0%
0/2
2.625
ForBean$RepSource
N/A
N/A
2.625
ForBean$StoreSourceDataIterator
0%
0/11
N/A
2.625
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry.components;
 16  
 
 17  
 import java.util.ArrayList;
 18  
 import java.util.Collections;
 19  
 import java.util.HashMap;
 20  
 import java.util.Iterator;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.apache.hivemind.ApplicationRuntimeException;
 25  
 import org.apache.hivemind.HiveMind;
 26  
 import org.apache.tapestry.IBinding;
 27  
 import org.apache.tapestry.IForm;
 28  
 import org.apache.tapestry.IMarkupWriter;
 29  
 import org.apache.tapestry.IRequestCycle;
 30  
 import org.apache.tapestry.Tapestry;
 31  
 import org.apache.tapestry.TapestryUtils;
 32  
 import org.apache.tapestry.coerce.ValueConverter;
 33  
 import org.apache.tapestry.engine.NullWriter;
 34  
 import org.apache.tapestry.form.AbstractFormComponent;
 35  
 import org.apache.tapestry.markup.NestedMarkupWriterImpl;
 36  
 import org.apache.tapestry.services.ComponentRenderWorker;
 37  
 import org.apache.tapestry.services.DataSqueezer;
 38  
 import org.apache.tapestry.services.ExpressionEvaluator;
 39  
 import org.apache.tapestry.services.ResponseBuilder;
 40  
 
 41  
 /**
 42  
  * @author mb
 43  
  * @since 4.0
 44  
  * @see org.apache.tapestry.components.IPrimaryKeyConverter
 45  
  * @see org.apache.tapestry.util.DefaultPrimaryKeyConverter
 46  
  */
 47  0
 public abstract class ForBean extends AbstractFormComponent
 48  
 {
 49  
     // constants
 50  
     
 51  
     /**
 52  
      * Prefix on the hidden value stored into the field to indicate the the actual value is stored
 53  
      * (this is used when there is no primary key converter). The remainder of the string is a
 54  
      * {@link DataSqueezer squeezed} representation of the value.
 55  
      */
 56  
     private static final char DESC_VALUE = 'V';
 57  
 
 58  
     /**
 59  
      * Prefix on the hidden value stored into the field that indicates the primary key of the
 60  
      * iterated value is stored; the remainder of the string is a {@link DataSqueezer squeezed}
 61  
      * representation of the primary key. The {@link IPrimaryKeyConverter converter} is used to
 62  
      * obtain the value from this key.
 63  
      */
 64  
     private static final char DESC_PRIMARY_KEY = 'P';
 65  
 
 66  0
     private final RepSource _completeRepSource = new CompleteRepSource();
 67  
 
 68  0
     private final RepSource _keyExpressionRepSource = new KeyExpressionRepSource();
 69  
 
 70  
     // intermediate members
 71  
     private Object _value;
 72  
 
 73  
     private int _index;
 74  
 
 75  
     private boolean _rendering;
 76  
     
 77  0
     private boolean _hasNext = false;
 78  
     
 79  
     // parameters
 80  
     public abstract boolean getRenderTag();
 81  
     
 82  
     public abstract String getElement();
 83  
     
 84  
     public abstract String getKeyExpression();
 85  
 
 86  
     public abstract IPrimaryKeyConverter getConverter();
 87  
 
 88  
     public abstract Object getDefaultValue();
 89  
 
 90  
     public abstract boolean getMatch();
 91  
 
 92  
     public abstract boolean getVolatile();
 93  
 
 94  
     // injects
 95  
     public abstract DataSqueezer getDataSqueezer();
 96  
 
 97  
     public abstract ValueConverter getValueConverter();
 98  
 
 99  
     public abstract ExpressionEvaluator getExpressionEvaluator();
 100  
     
 101  
     public abstract ComponentRenderWorker getRenderWorker();
 102  
     
 103  
     public abstract ResponseBuilder getResponseBuilder();
 104  
     
 105  
     public boolean hasNext()
 106  
     {
 107  0
         return _hasNext;
 108  
     }
 109  
     
 110  
     /**
 111  
      * Gets the source binding and iterates through its values. For each, it updates the value
 112  
      * binding and render's its wrapped elements.
 113  
      */
 114  
     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 115  
     {
 116  
         // form may be null if component is not located in a form
 117  0
         IForm form = (IForm) cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);
 118  
         
 119  
         // If the cycle is rewinding, but not this particular form,
 120  
         // then do nothing (don't even render the body).
 121  
         
 122  0
         boolean cycleRewinding = cycle.isRewinding();
 123  0
         if (cycleRewinding && form != null && !form.isRewinding())
 124  0
             return;
 125  
         
 126  0
         setForm(form);
 127  
         
 128  
         // Get the data to be iterated upon. Store in form if needed.
 129  
         
 130  0
         Iterator dataSource = getData(cycle, form);
 131  
 
 132  
         // Do not iterate if dataSource is null.
 133  
         // The dataSource was either not convertable to Iterator, or was empty.
 134  
         
 135  0
         if (dataSource == null)
 136  0
             return;
 137  
         
 138  0
         if (!cycleRewinding && form != null && !NullWriter.class.isInstance(writer))
 139  0
             form.setFormFieldUpdating(true);
 140  
         
 141  0
         String element = HiveMind.isNonBlank(getElement()) ? getElement() : getTemplateTagName();
 142  
         
 143  0
         boolean render = !cycleRewinding && HiveMind.isNonBlank(element) && getRenderTag();
 144  
         
 145  0
         IMarkupWriter loopWriter = writer;
 146  
         
 147  
         // Perform the iterations
 148  
         try
 149  
         {
 150  0
             _index = 0;
 151  0
             _rendering = true;
 152  
             
 153  0
             while (dataSource.hasNext())
 154  
             {
 155  0
                 _hasNext = true;
 156  
                 
 157  
                 // Get current value
 158  0
                 _value = dataSource.next();
 159  
                 
 160  
                 // Update output component parameters
 161  0
                 updateOutputParameters();
 162  
                 
 163  
                 // Render component
 164  
                 // swap out writers if necessary
 165  
                 
 166  0
                 if (getResponseBuilder().isDynamic()
 167  
                         && getResponseBuilder().contains(this) 
 168  
                         && !NestedMarkupWriterImpl.class.isInstance(writer)) {
 169  
                     
 170  0
                     loopWriter = getResponseBuilder().getWriter(getClientId(), ResponseBuilder.ELEMENT_TYPE);
 171  
                 }
 172  
                 
 173  0
                 if (render) {
 174  
                     
 175  0
                     loopWriter.begin(element);
 176  
                     
 177  0
                     renderInformalParameters(loopWriter, cycle);
 178  0
                     renderIdAttribute(loopWriter, cycle);
 179  
                 }
 180  
                 
 181  0
                 renderBody(loopWriter, cycle);
 182  
                 
 183  0
                 if (render) {
 184  
                     
 185  0
                     loopWriter.end(element);
 186  
                 }
 187  
                 
 188  0
                 _index++;
 189  
                 
 190  0
                 _hasNext = dataSource.hasNext();
 191  
                 
 192  
                 // TODO: Fragile / messy
 193  
                 // Cause unique client id to be generated as well as event connection
 194  
                 // works or other after render workers. (basically reproduce what happens
 195  
                 // inside of AbstractComponent.render() . Perhaps this means it's time for
 196  
                 // refactoring of this logic, like deferring rendering to an actual component
 197  
                 // that can have its proper render() method invoked multiple times.
 198  
                 
 199  0
                 getRenderWorker().renderComponent(cycle, this);
 200  0
                 generateClientId();
 201  
                 
 202  
                 // set loopWriter back to original as the client ids/ etc change on each loop
 203  
                 
 204  0
                 loopWriter = writer;
 205  
             }
 206  
         }
 207  
         finally
 208  
         {
 209  0
             _rendering = false;
 210  0
             _value = null;
 211  0
         }
 212  0
     }
 213  
     
 214  
     /**
 215  
      * Overriden so that RenderWorker doesn't get run as we've been invoking
 216  
      * it manually already.
 217  
      */
 218  
     protected void cleanupAfterRender(IRequestCycle cycle)
 219  
     {
 220  0
     }
 221  
     
 222  
     protected void generateClientId()
 223  
     {
 224  0
         String id = getSpecifiedId();
 225  
         
 226  0
         if (id != null && getPage() != null && getPage().getRequestCycle() != null)
 227  0
              setClientId(getPage().getRequestCycle().getUniqueId(TapestryUtils.convertTapestryIdToNMToken(id)));
 228  0
     }
 229  
     
 230  
     /**
 231  
      * Returns the most recent value extracted from the source parameter.
 232  
      *
 233  
      */
 234  
 
 235  
     public final Object getValue()
 236  
     {
 237  0
         if (!_rendering)
 238  0
             throw Tapestry.createRenderOnlyPropertyException(this, "value");
 239  
 
 240  0
         return _value;
 241  
     }
 242  
 
 243  
     /**
 244  
      * The index number, within the {@link #getStoredData(IRequestCycle, String) }, of the the current value.
 245  
      * 
 246  
      */
 247  
 
 248  
     public int getIndex()
 249  
     {
 250  0
         if (!_rendering)
 251  0
             throw Tapestry.createRenderOnlyPropertyException(this, "index");
 252  
 
 253  0
         return _index;
 254  
     }
 255  
 
 256  
     public boolean isDisabled()
 257  
     {
 258  0
         return false;
 259  
     }
 260  
 
 261  
     /**
 262  
      * Updates the index and value output parameters if bound.
 263  
      */
 264  
     protected void updateOutputParameters()
 265  
     {
 266  0
         IBinding indexBinding = getBinding("index");
 267  0
         if (indexBinding != null)
 268  0
             indexBinding.setObject(new Integer(_index));
 269  
 
 270  0
         IBinding valueBinding = getBinding("value");
 271  0
         if (valueBinding != null)
 272  0
             valueBinding.setObject(_value);
 273  0
     }
 274  
 
 275  
     /**
 276  
      * Updates the primaryKeys parameter if bound.
 277  
      */
 278  
     protected void updatePrimaryKeysParameter(String[] stringReps)
 279  
     {
 280  0
         IBinding primaryKeysBinding = getBinding("primaryKeys");
 281  0
         if (primaryKeysBinding == null)
 282  0
             return;
 283  
 
 284  0
         DataSqueezer squeezer = getDataSqueezer();
 285  
 
 286  0
         int repsCount = stringReps.length;
 287  0
         List primaryKeys = new ArrayList(repsCount);
 288  0
         for (int i = 0; i < stringReps.length; i++)
 289  
         {
 290  0
             String rep = stringReps[i];
 291  0
             if (rep.length() == 0 || rep.charAt(0) != DESC_PRIMARY_KEY)
 292  0
                 continue;
 293  0
             Object primaryKey = squeezer.unsqueeze(rep.substring(1));
 294  0
             primaryKeys.add(primaryKey);
 295  
         }
 296  
 
 297  0
         primaryKeysBinding.setObject(primaryKeys);
 298  0
     }
 299  
 
 300  
     // Do nothing in those methods, but make the JVM happy
 301  
     protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle)
 302  
     {
 303  0
     }
 304  
 
 305  
     protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle)
 306  
     {
 307  0
     }
 308  
 
 309  
     /**
 310  
      * Returns a list with the values to be iterated upon. The list is obtained in different ways: -
 311  
      * If the component is not located in a form or 'volatile' is set to true, then the simply the
 312  
      * values passed to 'source' are returned (same as Foreach) - If the component is in a form, and
 313  
      * the form is rewinding, the values stored in the form are returned -- rewind is then always
 314  
      * the same as render. - If the component is in a form, and the form is being rendered, the
 315  
      * values are stored in the form as Hidden fields.
 316  
      * 
 317  
      * @param cycle
 318  
      *            The current request cycle
 319  
      * @param form
 320  
      *            The form within which the component is located (if any)
 321  
      * @return An iterator with the values to be cycled upon
 322  
      */
 323  
     private Iterator getData(IRequestCycle cycle, IForm form)
 324  
     {
 325  0
         if (form == null || getVolatile())
 326  0
             return evaluateSourceIterator();
 327  
         
 328  0
         String name = form.getElementId(this);
 329  
         
 330  0
         if (cycle.isRewinding())
 331  0
             return getStoredData(cycle, name);
 332  
         
 333  0
         return storeSourceData(form, name);
 334  
     }
 335  
 
 336  
     /**
 337  
      * Returns a list of the values stored as Hidden fields in the form. A conversion is performed
 338  
      * if the primary key of the value is stored.
 339  
      * 
 340  
      * @param cycle
 341  
      *            The current request cycle
 342  
      * @param name
 343  
      *            The name of the HTTP parameter whether the values
 344  
      * @return an iterator with the values stored in the provided Hidden fields
 345  
      */
 346  
     protected Iterator getStoredData(IRequestCycle cycle, String name)
 347  
     {
 348  0
         String[] stringReps = cycle.getParameters(name);
 349  0
         if (stringReps == null)
 350  0
             return null;
 351  
 
 352  0
         updatePrimaryKeysParameter(stringReps);
 353  
 
 354  0
         return new ReadSourceDataIterator(stringReps);
 355  
     }
 356  
 
 357  
     /**
 358  
      * Pulls data from successive strings (posted by client-side hidden fields); each string
 359  
      * representation may be either a value or a primary key.
 360  
      */
 361  
     private class ReadSourceDataIterator implements Iterator
 362  
     {
 363  0
         private final Iterator _sourceIterator = evaluateSourceIterator();
 364  
 
 365  0
         private final Iterator _fullSourceIterator = evaluateFullSourceIterator();
 366  
 
 367  
         private final String[] _stringReps;
 368  
 
 369  0
         private int _index = 0;
 370  
 
 371  0
         private final Map _repToValueMap = new HashMap();
 372  
 
 373  
         ReadSourceDataIterator(String[] stringReps)
 374  0
         {
 375  0
             _stringReps = stringReps;
 376  0
         }
 377  
 
 378  
         public boolean hasNext()
 379  
         {
 380  0
             return _index < _stringReps.length;
 381  
         }
 382  
 
 383  
         public Object next()
 384  
         {
 385  0
             String rep = _stringReps[_index++];
 386  
 
 387  0
             return getValueFromStringRep(_sourceIterator, _fullSourceIterator, _repToValueMap, rep);
 388  
         }
 389  
 
 390  
         public void remove()
 391  
         {
 392  0
             throw new UnsupportedOperationException("remove()");
 393  
         }
 394  
 
 395  
     }
 396  
 
 397  
     /**
 398  
      * Stores the provided data in the form and then returns the data as an iterator. If the primary
 399  
      * key of the value can be determined, then that primary key is saved instead.
 400  
      * 
 401  
      * @param form
 402  
      *            The form where the data will be stored
 403  
      * @param name
 404  
      *            The name under which the data will be stored
 405  
      * @return an iterator with the bound values stored in the form
 406  
      */
 407  
     protected Iterator storeSourceData(IForm form, String name)
 408  
     {
 409  0
         return new StoreSourceDataIterator(form, name, evaluateSourceIterator());
 410  
     }
 411  
 
 412  
     /**
 413  
      * Iterates over a set of values, using {@link ForBean#getStringRepFromValue(Object)} to obtain
 414  
      * the correct client-side string representation, and working with the form to store each
 415  
      * successive value into the form.
 416  
      */
 417  
     private class StoreSourceDataIterator implements Iterator
 418  
     {
 419  
         private final IForm _form;
 420  
 
 421  
         private final String _name;
 422  
 
 423  
         private final Iterator _delegate;
 424  
 
 425  
         StoreSourceDataIterator(IForm form, String name, Iterator delegate)
 426  0
         {
 427  0
             _form = form;
 428  0
             _name = name;
 429  0
             _delegate = delegate;
 430  0
         }
 431  
 
 432  
         public boolean hasNext()
 433  
         {
 434  0
             return _delegate.hasNext();
 435  
         }
 436  
 
 437  
         public Object next()
 438  
         {
 439  0
             Object value = _delegate.next();
 440  
 
 441  
             
 442  
             
 443  0
             String rep = getStringRepFromValue(value);
 444  
 
 445  0
             _form.addHiddenValue(_name, rep);
 446  
 
 447  0
             return value;
 448  
         }
 449  
 
 450  
         public void remove()
 451  
         {
 452  0
             throw new UnsupportedOperationException("remove()");
 453  
         }
 454  
     }
 455  
 
 456  
     /**
 457  
      * Returns the string representation of the value. The first letter of the string representation
 458  
      * shows whether a value or a primary key is being described.
 459  
      * 
 460  
      * @param value
 461  
      * @return The string representation of the given value.
 462  
      */
 463  
     protected String getStringRepFromValue(Object value)
 464  
     {
 465  
         String rep;
 466  
         
 467  0
         DataSqueezer squeezer = getDataSqueezer();
 468  
         
 469  
         // try to extract the primary key from the value
 470  
         
 471  0
         Object pk = getPrimaryKeyFromValue(value);
 472  
         
 473  
         try {
 474  
 
 475  0
             if (pk != null) {
 476  
 
 477  
                 // Primary key was extracted successfully.
 478  0
                 rep = DESC_PRIMARY_KEY + squeezer.squeeze(pk);
 479  
             } else {
 480  
 
 481  
                 // primary key could not be extracted. squeeze value.
 482  0
                 rep = DESC_VALUE + squeezer.squeeze(value);
 483  
             }
 484  
             
 485  0
         } catch (Exception e) {
 486  0
             throw new ApplicationRuntimeException(ComponentMessages.keySqueezeError(this, value, e), this, getLocation(), e);
 487  0
         }
 488  
         
 489  0
         return rep;
 490  
     }
 491  
 
 492  
     /**
 493  
      * Returns the primary key of the given value. Uses the 'keyExpression' or the 'converter' (if
 494  
      * either is provided).
 495  
      * 
 496  
      * @param value
 497  
      *            The value from which the primary key should be extracted
 498  
      * @return The primary key of the value, or null if such cannot be extracted.
 499  
      */
 500  
     protected Object getPrimaryKeyFromValue(Object value)
 501  
     {
 502  0
         if (value == null)
 503  0
             return null;
 504  
         
 505  0
         Object primaryKey = getKeyExpressionFromValue(value);
 506  
         
 507  0
         if (primaryKey == null)
 508  0
             primaryKey = getConverterFromValue(value);
 509  
 
 510  0
         return primaryKey;
 511  
     }
 512  
 
 513  
     /**
 514  
      * Uses the 'keyExpression' parameter to determine the primary key of the given value.
 515  
      * 
 516  
      * @param value
 517  
      *            The value from which the primary key should be extracted
 518  
      * @return The primary key of the value as defined by 'keyExpression', or null if such cannot be
 519  
      *         extracted.
 520  
      */
 521  
     protected Object getKeyExpressionFromValue(Object value)
 522  
     {
 523  0
         String keyExpression = getKeyExpression();
 524  0
         if (keyExpression == null)
 525  0
             return null;
 526  
 
 527  0
         Object primaryKey = getExpressionEvaluator().read(value, keyExpression);
 528  0
         return primaryKey;
 529  
     }
 530  
 
 531  
     /**
 532  
      * Uses the 'converter' parameter to determine the primary key of the given value.
 533  
      * 
 534  
      * @param value
 535  
      *            The value from which the primary key should be extracted
 536  
      * @return The primary key of the value as provided by the converter, or null if such cannot be
 537  
      *         extracted.
 538  
      */
 539  
     protected Object getConverterFromValue(Object value)
 540  
     {
 541  0
         IPrimaryKeyConverter converter = getConverter();
 542  0
         if (converter == null)
 543  0
             return null;
 544  
 
 545  0
         Object primaryKey = converter.getPrimaryKey(value);
 546  
         
 547  0
         return primaryKey;
 548  
     }
 549  
 
 550  
     /**
 551  
      * Determines the value that corresponds to the given string representation. If the 'match'
 552  
      * parameter is true, attempt to find a value in 'source' or 'fullSource' that generates the
 553  
      * same string representation. Otherwise, create a new value from the string representation.
 554  
      * 
 555  
      * @param rep
 556  
      *            the string representation for which a value should be returned
 557  
      * @return the value that corresponds to the provided string representation
 558  
      */
 559  
     protected Object getValueFromStringRep(Iterator sourceIterator, Iterator fullSourceIterator,
 560  
             Map repToValueMap, String rep)
 561  
     {
 562  0
         Object value = null;
 563  0
         DataSqueezer squeezer = getDataSqueezer();
 564  
 
 565  
         // Check if the string rep is empty. If so, just return the default value.
 566  0
         if (rep == null || rep.length() == 0)
 567  0
             return getDefaultValue();
 568  
         
 569  
         // If required, find a value with an equivalent string representation and return it
 570  0
         boolean match = getMatch();
 571  0
         if (match)
 572  
         {
 573  0
             value = findValueWithStringRep( sourceIterator, fullSourceIterator, repToValueMap,
 574  
                     rep, _completeRepSource);
 575  
             
 576  0
             if (value != null)
 577  0
                 return value;
 578  
         }
 579  
 
 580  
         // Matching of the string representation was not successful or was disabled.
 581  
         // Use the standard approaches to obtain the value from the rep.
 582  
         
 583  0
         char desc = rep.charAt(0);
 584  0
         String squeezed = rep.substring(1);
 585  0
         switch (desc)
 586  
         {
 587  
             case DESC_VALUE:
 588  
                 // If the string rep is just the value itself, unsqueeze it
 589  0
                 value = squeezer.unsqueeze(squeezed);
 590  0
                 break;
 591  
                 
 592  
             case DESC_PRIMARY_KEY:
 593  
                 // Perform keyExpression match if not already attempted
 594  0
                 if (!match && getKeyExpression() != null)
 595  0
                     value = findValueWithStringRep(
 596  
                             sourceIterator,
 597  
                             fullSourceIterator,
 598  
                             repToValueMap,
 599  
                             rep,
 600  
                             _keyExpressionRepSource);
 601  
 
 602  
                 // If 'converter' is defined, try to perform conversion from primary key to value
 603  0
                 if (value == null)
 604  
                 {
 605  0
                     IPrimaryKeyConverter converter = getConverter();
 606  0
                     if (converter != null)
 607  
                     {
 608  0
                         Object pk = squeezer.unsqueeze(squeezed);
 609  0
                         value = converter.getValue(pk);
 610  
                     }
 611  
                 }
 612  
                 break;
 613  
         }
 614  
 
 615  0
         if (value == null)
 616  0
             value = getDefaultValue();
 617  
 
 618  0
         return value;
 619  
     }
 620  
 
 621  
     /**
 622  
      * Attempt to find a value in 'source' or 'fullSource' that generates the provided string
 623  
      * representation. Use the RepSource interface to determine what the string representation of a
 624  
      * particular value is.
 625  
      * 
 626  
      * @param rep
 627  
      *            the string representation for which a value should be returned
 628  
      * @param repSource
 629  
      *            an interface providing the string representation of a given value
 630  
      * @return the value in 'source' or 'fullSource' that corresponds to the provided string
 631  
      *         representation
 632  
      */
 633  
     protected Object findValueWithStringRep(Iterator sourceIterator, Iterator fullSourceIterator,
 634  
             Map repToValueMap, String rep, RepSource repSource)
 635  
     {
 636  0
         Object value = repToValueMap.get(rep);
 637  0
         if (value != null)
 638  0
             return value;
 639  
 
 640  0
         value = findValueWithStringRepInIterator(sourceIterator, repToValueMap, rep, repSource);
 641  0
         if (value != null)
 642  0
             return value;
 643  
         
 644  0
         value = findValueWithStringRepInIterator(fullSourceIterator, repToValueMap, rep, repSource);
 645  0
         return value;
 646  
     }
 647  
 
 648  
     /**
 649  
      * Attempt to find a value in the provided collection that generates the required string
 650  
      * representation. Use the RepSource interface to determine what the string representation of a
 651  
      * particular value is.
 652  
      * 
 653  
      * @param rep
 654  
      *            the string representation for which a value should be returned
 655  
      * @param repSource
 656  
      *            an interface providing the string representation of a given value
 657  
      * @param it
 658  
      *            the iterator of the collection in which a value should be searched
 659  
      * @return the value in the provided collection that corresponds to the required string
 660  
      *         representation
 661  
      */
 662  
     protected Object findValueWithStringRepInIterator(Iterator it, Map repToValueMap, String rep,
 663  
             RepSource repSource)
 664  
     {
 665  0
         while (it.hasNext())
 666  
         {
 667  0
             Object sourceValue = it.next();
 668  0
             if (sourceValue == null)
 669  0
                 continue;
 670  
             
 671  0
             String sourceRep = repSource.getStringRep(sourceValue);
 672  0
             repToValueMap.put(sourceRep, sourceValue);
 673  
             
 674  0
             if (rep.equals(sourceRep))
 675  0
                 return sourceValue;
 676  0
         }
 677  
 
 678  0
         return null;
 679  
     }
 680  
 
 681  
     /**
 682  
      * Returns a new iterator of the values in 'source'.
 683  
      * 
 684  
      * @return the 'source' iterator
 685  
      */
 686  
     protected Iterator evaluateSourceIterator()
 687  
     {
 688  0
         Iterator it = null;
 689  0
         Object source = null;
 690  
 
 691  0
         IBinding sourceBinding = getBinding("source");
 692  0
         if (sourceBinding != null)
 693  0
             source = sourceBinding.getObject();
 694  
         
 695  0
         if (source != null)
 696  0
             it = (Iterator) getValueConverter().coerceValue(source, Iterator.class);
 697  
         
 698  0
         if (it == null)
 699  0
             it = Collections.EMPTY_LIST.iterator();
 700  
 
 701  0
         return it;
 702  
     }
 703  
 
 704  
     /**
 705  
      * Returns a new iterator of the values in 'fullSource'.
 706  
      * 
 707  
      * @return the 'fullSource' iterator
 708  
      */
 709  
     protected Iterator evaluateFullSourceIterator()
 710  
     {
 711  0
         Iterator it = null;
 712  0
         Object fullSource = null;
 713  
 
 714  0
         IBinding fullSourceBinding = getBinding("fullSource");
 715  0
         if (fullSourceBinding != null)
 716  0
             fullSource = fullSourceBinding.getObject();
 717  
 
 718  0
         if (fullSource != null)
 719  0
             it = (Iterator) getValueConverter().coerceValue(fullSource, Iterator.class);
 720  
 
 721  0
         if (it == null)
 722  0
             it = Collections.EMPTY_LIST.iterator();
 723  
 
 724  0
         return it;
 725  
     }
 726  
 
 727  
     /**
 728  
      * An interface that provides the string representation of a given value.
 729  
      */
 730  
     protected interface RepSource
 731  
     {
 732  
         String getStringRep(Object value);
 733  
     }
 734  
 
 735  
     /**
 736  
      * An implementation of RepSource that provides the string representation of the given value
 737  
      * using all methods.
 738  
      */
 739  0
     protected class CompleteRepSource implements RepSource
 740  
     {
 741  
         public String getStringRep(Object value)
 742  
         {
 743  0
             return getStringRepFromValue(value);
 744  
         }
 745  
     }
 746  
 
 747  
     /**
 748  
      * An implementation of RepSource that provides the string representation of the given value
 749  
      * using just the 'keyExpression' parameter.
 750  
      */
 751  0
     protected class KeyExpressionRepSource implements RepSource
 752  
     {
 753  
         public String getStringRep(Object value)
 754  
         {
 755  0
             Object pk = getKeyExpressionFromValue(value);
 756  0
             return DESC_PRIMARY_KEY + getDataSqueezer().squeeze(pk);
 757  
         }
 758  
     }
 759  
 
 760  
     /**
 761  
      * For component can not take focus.
 762  
      */
 763  
     protected boolean getCanTakeFocus()
 764  
     {
 765  0
         return false;
 766  
     }
 767  
 
 768  
     public String getDisplayName()
 769  
     {
 770  0
         return null;
 771  
     }
 772  
 
 773  
 }