List.java |
/* * $Id: List.java,v 1.30 2010/09/29 17:21:47 agoubard Exp $ * * See the COPYRIGHT file for redistribution and use restrictions. */ package org.xins.common.types; import java.util.StringTokenizer; import org.xins.common.MandatoryArgumentChecker; import org.xins.common.Utils; import org.xins.common.text.FormatException; import org.xins.common.text.URLEncoding; import org.xins.common.types.standard.Text; /** * Abstract base class for list types. * * @version $Revision: 1.30 $ $Date: 2010/09/29 17:21:47 $ * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a> * * @since XINS 1.0.0 */ public abstract class List extends Type { /** * The type for the values. Cannot be <code>null</code>. */ private final Type _itemType; /** * Constructs a new <code>List</code> object (constructor for * subclasses). * * @param name * the name of this type, cannot be <code>null</code>. * * @param itemType * the type for the values, or <code>null</code> if {@link Text} * should be assumed. */ protected List(String name, Type itemType) { super(name, ItemList.class); _itemType = itemType == null ? Text.SINGLETON : itemType; } /** * Determines if the specified <code>String</code> value is considered * valid for this type (implementation method). * * <p>This method is called from {@link #isValidValue(String)}. When * called from that method, it is guaranteed that the argument is not * <code>null</code>. * * @param string * the <code>String</code> value that should be checked for validity, * never <code>null</code>. * * @return * <code>true</code> if and only if the specified <code>String</code> * value is valid, <code>false</code> otherwise. */ protected final boolean isValidValueImpl(String string) { if (string == null) { return false; } // Separate the string by ampersands StringTokenizer tokenizer = new StringTokenizer(string, "&"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); try { String item = URLEncoding.decode(token); if (!_itemType.isValidValue(item)) { return false; } } catch (FormatException fe) { return false; } catch (IllegalArgumentException iae) { return false; } } return true; } /** * Converts from a <code>String</code> to an instance of the value class * for this type (implementation method). * * <p>This method is not required to check the validity of the specified * value (since {@link #isValidValueImpl(String)} should have been called * before) but if it does, then it may throw a {@link TypeValueException}. * * @param string * the string to convert to an instance of the value class, guaranteed * to be not <code>null</code> and guaranteed to have been passed to * {@link #isValidValueImpl(String)} without getting an exception. * * @return * an instance of the value class, cannot be <code>null</code>. * * @throws TypeValueException * if <code>string</code> is considered to be an invalid value for this * type. */ protected final Object fromStringImpl(String string) throws TypeValueException { // Construct a ItemList to store the values in ItemList list = createList(); // Separate the string by ampersands StringTokenizer tokenizer = new StringTokenizer(string, "&"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); try { String itemString = URLEncoding.decode(token); Object item = _itemType.fromString(itemString); list.addItem(item); } catch (FormatException fe) { throw new TypeValueException(this, string, fe.getReason()); } catch (IllegalArgumentException iae) { throw Utils.logProgrammingError(iae); } } return list; } /** * Creates a new <code>ItemList</code>. * * @return * the new list created, never <code>null</code>. */ public abstract ItemList createList(); /** * Converts the specified <code>ItemList</code> to a string. * * @param value * the value to convert, can be <code>null</code>. * * @return * the textual representation of the value, or <code>null</code> if and * only if <code>value == null</code>. */ public String toString(ItemList value) { // Short-circuit if the argument is null if (value == null) { return null; } // Use a buffer to create the string StringBuffer buffer = new StringBuffer(255); // Iterate over the list int listSize = value.getSize(); for (int i=0; i < listSize; i++) { if (i != 0) { buffer.append('&'); } Object nextItem = value.getItem(i); String stringItem; try { stringItem = _itemType.toString(nextItem); } catch (Exception ex) { // Should never happens as only add() is able to add items in the list. throw new IllegalArgumentException("Incorrect value for type: " + nextItem); } buffer.append(URLEncoding.encode(stringItem)); } return buffer.toString(); } /** * Generates a string representation of the specified value for this type. * The specified value must be an instance of the value class for this type * (see {@link #getValueClass()}). Also, it may have to fall within a * certain range of valid values, depending on the type. * * @param value * the value, cannot be <code>null</code>. * * @return * the string representation of the specified value for this type, * cannot be <code>null</code>. * * @throws IllegalArgumentException * if <code>value == null</code>. * * @throws ClassCastException * if <code>getValueClass().isInstance(value) == false</code>. * * @throws TypeValueException * if the specified value is not in the allowed range. */ public final String toString(Object value) throws IllegalArgumentException, ClassCastException, TypeValueException { // Check preconditions MandatoryArgumentChecker.check("value", value); // The argument must be a ItemList return toString((ItemList) value); } }