001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.util;
020:
021: import java.util.ArrayList;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.restlet.data.Parameter;
029:
030: /**
031: * Modifiable list of entries with many helper methods. Note that this class
032: * uses the Parameter class as the template type. This allows you to use an
033: * instance of this class as any other java.util.List, in particular all the
034: * helper methods in java.util.Collections.
035: *
036: * @author Jerome Louvel (contact@noelios.com)
037: * @see org.restlet.data.Parameter
038: * @see java.util.Collections
039: * @see java.util.List
040: */
041: public abstract class Series<E extends Parameter> extends
042: WrapperList<E> {
043: /**
044: * A marker for empty values to differentiate from non existing values
045: * (null).
046: */
047: public static final Object EMPTY_VALUE = new Object();
048:
049: /**
050: * Constructor.
051: */
052: public Series() {
053: super ();
054: }
055:
056: /**
057: * Constructor.
058: *
059: * @param initialCapacity
060: * The initial list capacity.
061: */
062: public Series(int initialCapacity) {
063: super (initialCapacity);
064: }
065:
066: /**
067: * Constructor.
068: *
069: * @param delegate
070: * The delegate list.
071: */
072: public Series(List<E> delegate) {
073: super (delegate);
074: }
075:
076: /**
077: * Creates a new entry.
078: *
079: * @param name
080: * The name of the entry.
081: * @param value
082: * The value of the entry.
083: * @return A new entry.
084: */
085: public abstract E createEntry(String name, String value);
086:
087: /**
088: * Creates a new series.
089: *
090: * @param delegate
091: * Optional delegate series.
092: * @return A new series.
093: */
094: public abstract Series<E> createSeries(List<E> delegate);
095:
096: /**
097: * Creates then adds a parameter at the end of the list.
098: *
099: * @param name
100: * The parameter name.
101: * @param value
102: * The parameter value.
103: * @return True (as per the general contract of the Collection.add method).
104: */
105: public boolean add(String name, String value) {
106: return add(createEntry(name, value));
107: }
108:
109: /**
110: * Copies the parameters whose name is a key in the given map.<br/> If a
111: * matching parameter is found, its value is put in the map.<br/> If
112: * multiple values are found, a list is created and set in the map.
113: *
114: * @param params
115: * The map controlling the copy.
116: */
117: @SuppressWarnings("unchecked")
118: public void copyTo(Map<String, Object> params) {
119: Parameter param;
120: Object currentValue = null;
121: for (Iterator<E> iter = iterator(); iter.hasNext();) {
122: param = iter.next();
123:
124: if (params.containsKey(param.getName())) {
125: currentValue = params.get(param.getName());
126:
127: if (currentValue != null) {
128: List<Object> values = null;
129:
130: if (currentValue instanceof List) {
131: // Multiple values already found for this entry
132: values = (List<Object>) currentValue;
133: } else {
134: // Second value found for this entry
135: // Create a list of values
136: values = new ArrayList<Object>();
137: values.add(currentValue);
138: params.put(param.getName(), values);
139: }
140:
141: if (param.getValue() == null) {
142: values.add(Series.EMPTY_VALUE);
143: } else {
144: values.add(param.getValue());
145: }
146: } else {
147: if (param.getValue() == null) {
148: params.put(param.getName(), Series.EMPTY_VALUE);
149: } else {
150: params.put(param.getName(), param.getValue());
151: }
152: }
153: }
154: }
155: }
156:
157: /**
158: * Tests the equality of two string, potentially null, which a case
159: * sensitivity flag.
160: *
161: * @param value1
162: * The first value.
163: * @param value2
164: * The second value.
165: * @param ignoreCase
166: * Indicates if the test should be case insensitive.
167: * @return True if both values are equal.
168: */
169: private boolean equals(String value1, String value2,
170: boolean ignoreCase) {
171: boolean result = (value1 == value2);
172:
173: if (!result) {
174: if ((value1 != null) && (value2 != null)) {
175: if (ignoreCase) {
176: result = value1.equalsIgnoreCase(value2);
177: } else {
178: result = value1.equals(value2);
179: }
180: }
181: }
182:
183: return result;
184: }
185:
186: /**
187: * Returns the first parameter found with the given name.
188: *
189: * @param name
190: * The parameter name (case sensitive).
191: * @return The first parameter found with the given name.
192: */
193: public E getFirst(String name) {
194: return getFirst(name, false);
195: }
196:
197: /**
198: * Returns the first parameter found with the given name.
199: *
200: * @param name
201: * The parameter name.
202: * @param ignoreCase
203: * Indicates if the name comparison is case sensitive.
204: * @return The first parameter found with the given name.
205: */
206: public E getFirst(String name, boolean ignoreCase) {
207: for (E param : this ) {
208: if (equals(param.getName(), name, ignoreCase)) {
209: return param;
210: }
211: }
212:
213: return null;
214: }
215:
216: /**
217: * Returns the value of the first parameter found with the given name.
218: *
219: * @param name
220: * The parameter name (case sensitive).
221: * @return The value of the first parameter found with the given name.
222: */
223: public String getFirstValue(String name) {
224: return getFirstValue(name, false);
225: }
226:
227: /**
228: * Returns the value of the first parameter found with the given name.
229: *
230: * @param name
231: * The parameter name.
232: * @param ignoreCase
233: * Indicates if the name comparison is case sensitive.
234: * @return The value of the first parameter found with the given name.
235: */
236: public String getFirstValue(String name, boolean ignoreCase) {
237: return getFirstValue(name, ignoreCase, null);
238: }
239:
240: /**
241: * Returns the value of the first parameter found with the given name.
242: *
243: * @param name
244: * The parameter name.
245: * @param ignoreCase
246: * Indicates if the name comparison is case sensitive.
247: * @param defaultValue
248: * The default value to return if no matching parameter found.
249: * @return The value of the first parameter found with the given name or the
250: * default value.
251: */
252: public String getFirstValue(String name, boolean ignoreCase,
253: String defaultValue) {
254: String result = defaultValue;
255: Parameter param = getFirst(name, ignoreCase);
256:
257: if (param != null) {
258: result = param.getValue();
259: }
260:
261: return result;
262: }
263:
264: /**
265: * Returns the value of the first parameter found with the given name.
266: *
267: * @param name
268: * The parameter name (case sensitive).
269: * @param defaultValue
270: * The default value to return if no matching parameter found.
271: * @return The value of the first parameter found with the given name or the
272: * default value.
273: */
274: public String getFirstValue(String name, String defaultValue) {
275: return getFirstValue(name, false, defaultValue);
276: }
277:
278: /**
279: * Returns the set of parameter names (case sensitive).
280: *
281: * @return The set of parameter names.
282: */
283: public Set<String> getNames() {
284: Set<String> result = new HashSet<String>();
285:
286: for (Parameter param : this ) {
287: result.add(param.getName());
288: }
289:
290: return result;
291: }
292:
293: /**
294: * Returns the values of the parameters with a given name. If multiple
295: * parameters with the same name are found, all values are concatenated and
296: * separated by a comma (like for HTTP message headers).
297: *
298: * @param name
299: * The parameter name (case insensitive).
300: * @return The values of the parameters with a given name.
301: */
302: public String getValues(String name) {
303: return getValues(name, ",", true);
304: }
305:
306: /**
307: * Returns the parameter values with a given name. If multiple parameters
308: * with the same name are found, all values are concatenated and separated
309: * by the given separator.
310: *
311: * @param name
312: * The parameter name.
313: * @param separator
314: * The separator character.
315: * @param ignoreCase
316: * Indicates if the name comparison is case sensitive.
317: * @return The sequence of values.
318: */
319: public String getValues(String name, String separator,
320: boolean ignoreCase) {
321: String result = null;
322: StringBuilder sb = null;
323:
324: for (E param : this ) {
325: if (param.getName().equalsIgnoreCase(name)) {
326: if (sb == null) {
327: if (result == null) {
328: result = param.getValue();
329: } else {
330: sb = new StringBuilder();
331: sb.append(result).append(separator).append(
332: param.getValue());
333: }
334: } else {
335: sb.append(separator).append(param.getValue());
336: }
337: }
338: }
339:
340: if (sb != null) {
341: result = sb.toString();
342: }
343:
344: return result;
345: }
346:
347: /**
348: * Removes all the parameters with a given name.
349: *
350: * @param name
351: * The parameter name (case sensitive).
352: * @return True if the list changed.
353: */
354: public boolean removeAll(String name) {
355: return removeAll(name, false);
356: }
357:
358: /**
359: * Removes all the parameters with a given name.
360: *
361: * @param name
362: * The parameter name.
363: * @param ignoreCase
364: * Indicates if the name comparison is case sensitive.
365: * @return True if the list changed.
366: */
367: public boolean removeAll(String name, boolean ignoreCase) {
368: boolean changed = false;
369: Parameter param = null;
370:
371: for (Iterator<E> iter = iterator(); iter.hasNext();) {
372: param = iter.next();
373: if (equals(param.getName(), name, ignoreCase)) {
374: iter.remove();
375: changed = true;
376: }
377: }
378:
379: return changed;
380: }
381:
382: /**
383: * Removes from this list the first entry whose name equals the specified
384: * name ignoring the case.
385: *
386: * @param name
387: * The name of the entries to be removed (case sensitive).
388: * @return false if no entry has been removed, true otherwise.
389: */
390: public boolean removeFirst(String name) {
391: return removeFirst(name, false);
392: }
393:
394: /**
395: * Removes from this list the first entry whose name equals the specified
396: * name ignoring the case or not.
397: *
398: * @param name
399: * The name of the entries to be removed.
400: * @param ignoreCase
401: * true if the comparison ignores the case, false otherwise.
402: * @return false if no entry has been removed, true otherwise.
403: */
404: public boolean removeFirst(String name, boolean ignoreCase) {
405: boolean changed = false;
406: Parameter param = null;
407:
408: for (Iterator<E> iter = iterator(); iter.hasNext() && !changed;) {
409: param = iter.next();
410: if (equals(param.getName(), name, ignoreCase)) {
411: iter.remove();
412: changed = true;
413: }
414: }
415:
416: return changed;
417: }
418:
419: /**
420: * Replaces the value of the first parameter with the given name and removes
421: * all other parameters with the same name.
422: *
423: * @param name
424: * The parameter name.
425: * @param value
426: * The value to set.
427: * @param ignoreCase
428: * Indicates if the name comparison is case sensitive.
429: * @return The parameter set or added.
430: */
431: public E set(String name, String value, boolean ignoreCase) {
432: E result = null;
433: E param = null;
434: boolean found = false;
435:
436: for (Iterator<E> iter = iterator(); iter.hasNext();) {
437: param = iter.next();
438:
439: if (equals(param.getName(), name, ignoreCase)) {
440: if (found) {
441: // Remove other entries with the same name
442: iter.remove();
443: } else {
444: // Change the value of the first matching entry
445: found = true;
446: param.setValue(value);
447: result = param;
448: }
449: }
450: }
451:
452: if (!found) {
453: add(name, value);
454: }
455:
456: return result;
457: }
458:
459: /**
460: * Returns a view of the portion of this list between the specified
461: * fromIndex, inclusive, and toIndex, exclusive.
462: *
463: * @param fromIndex
464: * The start position.
465: * @param toIndex
466: * The end position (exclusive).
467: * @return The sub-list.
468: */
469: @Override
470: public Series<E> subList(int fromIndex, int toIndex) {
471: return createSeries(getDelegate().subList(fromIndex, toIndex));
472: }
473:
474: /**
475: * Returns a list of all the values associated to the parameter name.
476: *
477: * @param name
478: * The parameter name (case sensitive).
479: * @return The list of values.
480: */
481: public Series<E> subList(String name) {
482: return subList(name, false);
483: }
484:
485: /**
486: * Returns a list of all the values associated to the parameter name.
487: *
488: * @param name
489: * The parameter name.
490: * @param ignoreCase
491: * Indicates if the name comparison is case sensitive.
492: * @return The list of values.
493: */
494: public Series<E> subList(String name, boolean ignoreCase) {
495: Series<E> result = createSeries(null);
496:
497: for (E param : this) {
498: if (equals(param.getName(), name, ignoreCase)) {
499: result.add(param);
500: }
501: }
502:
503: return result;
504: }
505:
506: }
|