001: /*
002: * $Id: List.java,v 1.28 2007/09/18 08:45:07 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common.types;
008:
009: import java.util.StringTokenizer;
010:
011: import org.xins.common.MandatoryArgumentChecker;
012: import org.xins.common.Utils;
013: import org.xins.common.text.FormatException;
014: import org.xins.common.text.URLEncoding;
015: import org.xins.common.types.standard.Text;
016:
017: /**
018: * Abstract base class for list types.
019: *
020: * @version $Revision: 1.28 $ $Date: 2007/09/18 08:45:07 $
021: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
022: *
023: * @since XINS 1.0.0
024: */
025: public abstract class List extends Type {
026:
027: /**
028: * The type for the values. Cannot be <code>null</code>.
029: */
030: private final Type _itemType;
031:
032: /**
033: * Constructs a new <code>List</code> object (constructor for
034: * subclasses).
035: *
036: * @param name
037: * the name of this type, cannot be <code>null</code>.
038: *
039: * @param itemType
040: * the type for the values, or <code>null</code> if {@link Text}
041: * should be assumed.
042: */
043: protected List(String name, Type itemType) {
044: super (name, ItemList.class);
045:
046: _itemType = itemType == null ? Text.SINGLETON : itemType;
047: }
048:
049: /**
050: * Determines if the specified <code>String</code> value is considered
051: * valid for this type (implementation method).
052: *
053: * <p>This method is called from {@link #isValidValue(String)}. When
054: * called from that method, it is guaranteed that the argument is not
055: * <code>null</code>.
056: *
057: * @param string
058: * the <code>String</code> value that should be checked for validity,
059: * never <code>null</code>.
060: *
061: * @return
062: * <code>true</code> if and only if the specified <code>String</code>
063: * value is valid, <code>false</code> otherwise.
064: */
065: protected final boolean isValidValueImpl(String string) {
066:
067: if (string == null) {
068: return false;
069: }
070:
071: // Separate the string by ampersands
072: StringTokenizer tokenizer = new StringTokenizer(string, "&");
073: while (tokenizer.hasMoreTokens()) {
074: String token = tokenizer.nextToken();
075: try {
076: String item = URLEncoding.decode(token);
077: if (!_itemType.isValidValue(item)) {
078: return false;
079: }
080: } catch (FormatException fe) {
081: return false;
082: } catch (IllegalArgumentException iae) {
083: return false;
084: }
085: }
086: return true;
087: }
088:
089: /**
090: * Converts from a <code>String</code> to an instance of the value class
091: * for this type (implementation method).
092: *
093: * <p>This method is not required to check the validity of the specified
094: * value (since {@link #isValidValueImpl(String)} should have been called
095: * before) but if it does, then it may throw a {@link TypeValueException}.
096: *
097: * @param string
098: * the string to convert to an instance of the value class, guaranteed
099: * to be not <code>null</code> and guaranteed to have been passed to
100: * {@link #isValidValueImpl(String)} without getting an exception.
101: *
102: * @return
103: * an instance of the value class, cannot be <code>null</code>.
104: *
105: * @throws TypeValueException
106: * if <code>string</code> is considered to be an invalid value for this
107: * type.
108: */
109: protected final Object fromStringImpl(String string)
110: throws TypeValueException {
111:
112: // Construct a ItemList to store the values in
113: ItemList list = createList();
114:
115: // Separate the string by ampersands
116: StringTokenizer tokenizer = new StringTokenizer(string, "&");
117: while (tokenizer.hasMoreTokens()) {
118: String token = tokenizer.nextToken();
119: try {
120: String itemString = URLEncoding.decode(token);
121: Object item = _itemType.fromString(itemString);
122: list.addItem(item);
123: } catch (FormatException fe) {
124: throw new TypeValueException(this , string, fe
125: .getReason());
126: } catch (IllegalArgumentException iae) {
127: throw Utils.logProgrammingError(iae);
128: }
129: }
130:
131: return list;
132: }
133:
134: /**
135: * Creates a new <code>ItemList</code>.
136: *
137: * @return
138: * the new list created, never <code>null</code>.
139: */
140: public abstract ItemList createList();
141:
142: /**
143: * Converts the specified <code>ItemList</code> to a string.
144: *
145: * @param value
146: * the value to convert, can be <code>null</code>.
147: *
148: * @return
149: * the textual representation of the value, or <code>null</code> if and
150: * only if <code>value == null</code>.
151: */
152: public String toString(ItemList value) {
153:
154: // Short-circuit if the argument is null
155: if (value == null) {
156: return null;
157: }
158:
159: // Use a buffer to create the string
160: StringBuffer buffer = new StringBuffer(255);
161:
162: // Iterate over the list
163: int listSize = value.getSize();
164: for (int i = 0; i < listSize; i++) {
165: if (i != 0) {
166: buffer.append('&');
167: }
168:
169: Object nextItem = value.getItem(i);
170: String stringItem;
171: try {
172: stringItem = _itemType.toString(nextItem);
173: } catch (Exception ex) {
174:
175: // Should never happens as only add() is able to add items in the list.
176: throw new IllegalArgumentException(
177: "Incorrect value for type: " + nextItem);
178: }
179: buffer.append(URLEncoding.encode(stringItem));
180: }
181:
182: return buffer.toString();
183: }
184:
185: /**
186: * Generates a string representation of the specified value for this type.
187: * The specified value must be an instance of the value class for this type
188: * (see {@link #getValueClass()}). Also, it may have to fall within a
189: * certain range of valid values, depending on the type.
190: *
191: * @param value
192: * the value, cannot be <code>null</code>.
193: *
194: * @return
195: * the string representation of the specified value for this type,
196: * cannot be <code>null</code>.
197: *
198: * @throws IllegalArgumentException
199: * if <code>value == null</code>.
200: *
201: * @throws ClassCastException
202: * if <code>getValueClass().isInstance(value) == false</code>.
203: *
204: * @throws TypeValueException
205: * if the specified value is not in the allowed range.
206: */
207: public final String toString(Object value)
208: throws IllegalArgumentException, ClassCastException,
209: TypeValueException {
210:
211: // Check preconditions
212: MandatoryArgumentChecker.check("value", value);
213:
214: // The argument must be a ItemList
215: return toString((ItemList) value);
216: }
217: }
|