001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: InternalValue.java 3634 2007-01-08 21:42:24Z gbevin $
007: */
008: package com.uwyn.rife.template;
009:
010: import com.uwyn.rife.template.exceptions.BlockUnknownException;
011: import com.uwyn.rife.template.exceptions.CircularContructionException;
012: import com.uwyn.rife.template.exceptions.TemplateException;
013: import java.util.ArrayList;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.text.NumberFormat;
017:
018: /**
019: * An anonymous value inside a template, which is not referenced anywhere in
020: * the template, but can be used to produce intermediate strings using the
021: * template engine. To obtain an <code>InternalValue</code>, you should use
022: * {@link Template#createInternalValue()}.
023: *
024: * @author Keith Lea <keith[remove] at cs dot oswego dot edu>
025: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
026: * @version $Revision: 3634 $
027: * @since 1.0
028: */
029: public class InternalValue {
030: private AbstractTemplate mTemplate = null;
031: private ArrayList<CharSequence> mConstruction = new ArrayList<CharSequence>();
032: private ArrayList<CharSequence> mValueIds = new ArrayList<CharSequence>();
033: private ArrayList<CharSequence> mValueTags = new ArrayList<CharSequence>();
034:
035: /**
036: * Appends the content of a block to this value. The values used by the
037: * block will be captured when this method is called, so any future
038: * changes to template values will not affect text which was appended when
039: * this method is called.
040: *
041: * @param blockId the ID of the block whose value should be appended to
042: * the specified value
043: * @exception TemplateException if the specified block does not exist in
044: * the corresponding template
045: * @since 1.0
046: */
047: public void appendBlock(String blockId) throws TemplateException {
048: if (null == blockId)
049: throw new IllegalArgumentException("blockId can't be null.");
050: if (0 == blockId.length())
051: throw new IllegalArgumentException(
052: "blockId can't be empty.");
053:
054: if (!mTemplate.appendBlockInternalForm(blockId, this )) {
055: throw new BlockUnknownException(blockId);
056: }
057: }
058:
059: /**
060: * Appends to this value the value of the given internal value.
061: *
062: * @param value an internal value
063: * @since 1.0
064: */
065: public void appendValue(InternalValue value) {
066: if (null == value)
067: throw new IllegalArgumentException("value can't be null.");
068:
069: appendConstructedValue(value);
070: }
071:
072: /**
073: * Appends the result of calling {@link String#valueOf(Object)
074: * String.valueOf} on the given <code>value</code> to this value in this
075: * template.
076: *
077: * @param value an object
078: * @since 1.0
079: */
080: public void appendValue(Object value) {
081: appendValue(String.valueOf(value));
082: }
083:
084: /**
085: * Appends <code>"true"</code> or <code>"false"</code> to this value,
086: * depending on the given <code>value</code>.
087: *
088: * @param value a boolean value
089: * @since 1.0
090: */
091: public void appendValue(boolean value) {
092: appendValue(String.valueOf(value));
093: }
094:
095: /**
096: * Appends the single specified character to this value.
097: *
098: * @param value a character
099: * @since 1.0
100: */
101: public void appendValue(char value) {
102: appendValue(String.valueOf(value));
103: }
104:
105: /**
106: * Appends the given characters to this value.
107: *
108: * @param value a string of characters
109: * @since 1.0
110: */
111: public void appendValue(char[] value) {
112: appendValue(String.valueOf(value));
113: }
114:
115: /**
116: * Appends the specified range of the given character string to this
117: * value. The specified number of bytes from <code>value</code> will be
118: * used, starting at the character specified by <code>offset</code>.
119: *
120: * @param value a character string
121: * @param offset the index in <code>value</code> of the first character to
122: * use
123: * @param count the number of characters to use
124: * @since 1.0
125: */
126: public void appendValue(char[] value, int offset, int count) {
127: appendValue(String.valueOf(value, offset, count));
128: }
129:
130: /**
131: * Appends the given double precision floating point value to this value.
132: * This method uses the {@linkplain String#valueOf(double) String.valueOf}
133: * method to print the given value, which probably prints more digits than
134: * you like. You probably want {@link String#format String.format} or
135: * {@link NumberFormat} instead.
136: *
137: * @param value a floating point value
138: * @since 1.0
139: */
140: public void appendValue(double value) {
141: appendValue(String.valueOf(value));
142: }
143:
144: /**
145: * Appends the given floating point value to this value. This method uses
146: * the {@linkplain String#valueOf(float) String.valueOf} method to print
147: * the given value, which probably prints more digits than you like. You
148: * probably want {@link String#format String.format} or {@link
149: * NumberFormat} instead.
150: *
151: * @param value a floating point value
152: * @since 1.0
153: */
154: public void appendValue(float value) {
155: appendValue(String.valueOf(value));
156: }
157:
158: /**
159: * Appends the given integer to this value.
160: *
161: * @param value an integer
162: * @since 1.0
163: */
164: public void appendValue(int value) {
165: appendValue(String.valueOf(value));
166: }
167:
168: /**
169: * Appends the given long to this value.
170: *
171: * @param value a long
172: * @since 1.0
173: */
174: public void appendValue(long value) {
175: appendValue(String.valueOf(value));
176: }
177:
178: /**
179: * Appends the given string to this value. The given string cannot be
180: * null.
181: *
182: * @param value a string
183: * @since 1.0
184: */
185: public void appendValue(String value) {
186: if (null == value)
187: throw new IllegalArgumentException("value can't be null.");
188:
189: appendText(value);
190: }
191:
192: /**
193: * Appends the given character sequence to this value. The given
194: * character sequence cannot be null.
195: *
196: * @param value a character sequence
197: * @since 1.5
198: */
199: public void appendValue(CharSequence value) {
200: if (null == value)
201: throw new IllegalArgumentException("value can't be null.");
202:
203: appendText(value);
204: }
205:
206: InternalValue(AbstractTemplate template) {
207: super ();
208:
209: mTemplate = template;
210: }
211:
212: InternalValue(AbstractTemplate template,
213: List<CharSequence> deferredContent) {
214: super ();
215:
216: mTemplate = template;
217: if (deferredContent != null) {
218: mConstruction.addAll(deferredContent);
219: }
220: }
221:
222: void increasePartsCapacity(int size) {
223: mConstruction.ensureCapacity(size + mConstruction.size());
224: }
225:
226: void increaseValuesCapacity(int size) {
227: mValueIds.ensureCapacity(size + mValueIds.size());
228: mValueTags.ensureCapacity(size + mValueTags.size());
229: }
230:
231: int partsSize() {
232: return mConstruction.size();
233: }
234:
235: int valuesSize() {
236: return mValueIds.size();
237: }
238:
239: void appendExternalForm(ExternalValue result) {
240: String value_id = null;
241: String value_tag = null;
242: int value_count = 0;
243:
244: for (CharSequence part : mConstruction) {
245: // part is a value
246: if (null == part) {
247: value_id = mValueIds.get(value_count).toString();
248: value_tag = mValueTags.get(value_count).toString();
249: value_count++;
250:
251: // check if the template contains content for the value
252: mTemplate.appendValueExternalForm(value_id, value_tag,
253: result);
254: }
255: // part is just text
256: else {
257: result.add(part);
258: }
259: }
260: }
261:
262: void appendText(CharSequence text) {
263: mConstruction.add(text);
264: }
265:
266: void appendValueId(String id, String tag) {
267: mConstruction.add(null);
268: mValueIds.add(id);
269: mValueTags.add(tag);
270: }
271:
272: void appendConstructedValue(InternalValue constructedValue) {
273: // prevent concurrent modification errors
274: if (this == constructedValue
275: || mValueIds == constructedValue.mValueIds) {
276: throw new CircularContructionException();
277: }
278:
279: increasePartsCapacity(constructedValue.partsSize());
280: increaseValuesCapacity(constructedValue.valuesSize());
281:
282: for (CharSequence charsequence : constructedValue.mConstruction) {
283: mConstruction.add(charsequence);
284: }
285:
286: for (CharSequence charsequence : constructedValue.mValueIds) {
287: mValueIds.add(charsequence);
288: }
289:
290: for (CharSequence charsequence : constructedValue.mValueTags) {
291: mValueTags.add(charsequence);
292: }
293: }
294:
295: /**
296: * Returns whether this value contains no cnotent. This method will return
297: * <code>false</code> for newly created values as well as values for whom
298: * {@link #clear} has just been called.
299: *
300: * @return whether this value has no contents
301: * @since 1.0
302: */
303: public boolean isEmpty() {
304: return 0 == mConstruction.size();
305: }
306:
307: /**
308: * Removes all content from this value.
309: */
310: public void clear() {
311: mConstruction = new ArrayList<CharSequence>();
312: mValueIds = new ArrayList<CharSequence>();
313: mValueTags = new ArrayList<CharSequence>();
314: }
315:
316: public boolean equals(Object object) {
317: if (null == object) {
318: return false;
319: }
320:
321: if (object == this ) {
322: return true;
323: }
324:
325: if (object.getClass() != this .getClass()) {
326: return false;
327: }
328:
329: InternalValue other = (InternalValue) object;
330: if (this .mConstruction.size() != other.mConstruction.size()) {
331: return false;
332: }
333:
334: Iterator<CharSequence> this _it = null;
335: Iterator<CharSequence> other_it = null;
336:
337: CharSequence this _value = null;
338: CharSequence other_value = null;
339: this _it = this .mConstruction.iterator();
340: other_it = other.mConstruction.iterator();
341: while (this _it.hasNext()) {
342: if (!other_it.hasNext()) {
343: return false;
344: }
345: this _value = this _it.next();
346: other_value = other_it.next();
347: if (null == this _value && null == other_value) {
348: continue;
349: }
350: if (null == this _value || null == other_value) {
351: return false;
352: }
353: if (!this _value.equals(other_value)) {
354: return false;
355: }
356: }
357:
358: CharSequence this _valueid = null;
359: CharSequence other_valueid = null;
360: this _it = this .mValueIds.iterator();
361: other_it = other.mValueIds.iterator();
362: while (this _it.hasNext()) {
363: if (!other_it.hasNext()) {
364: return false;
365: }
366: this _valueid = this _it.next();
367: other_valueid = other_it.next();
368: if (null == this _valueid && null == other_valueid) {
369: continue;
370: }
371: if (null == this _valueid || null == other_valueid) {
372: return false;
373: }
374: if (!this _valueid.equals(other_valueid)) {
375: return false;
376: }
377: }
378:
379: CharSequence this _valuetag = null;
380: CharSequence other_valuetag = null;
381: this _it = this .mValueTags.iterator();
382: other_it = other.mValueTags.iterator();
383: while (this _it.hasNext()) {
384: if (!other_it.hasNext()) {
385: return false;
386: }
387: this _valuetag = this _it.next();
388: other_valuetag = other_it.next();
389: if (null == this _valuetag && null == other_valuetag) {
390: continue;
391: }
392: if (null == this _valuetag || null == other_valuetag) {
393: return false;
394: }
395: if (!this _valuetag.equals(other_valuetag)) {
396: return false;
397: }
398: }
399:
400: return true;
401: }
402: }
|