KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > starters > StringItemList


1 /**
2  * $Id: StringItemList.java 186 2007-03-16 13:42:35Z ssmc $
3  * Copyright 2003-2005 iDare Media, Inc. All rights reserved.
4  *
5  * Originally written by iDare Media, Inc. for release into the public domain. This
6  * library, source form and binary form, is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation; either version 2.1 of the License, or (at your option) any
9  * later version.<p>
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU LGPL (GNU Lesser General Public License) for more details.<p>
14  *
15  * You should have received a copy of the GNU Lesser General Public License along with this
16  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite
17  * 330, Boston, MA 02111-1307 USA. The LGPL can be found online at
18  * http://www.fsf.org/copyleft/lesser.html<p>
19  *
20  * This product has been influenced by several projects within the open-source community.
21  * The JWare developers wish to acknowledge the open-source community's support. For more
22  * information regarding the open-source products used within JWare, please visit the
23  * JWare website.
24  *----------------------------------------------------------------------------------------*
25  * WEBSITE- http://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.starters;
30
31 import java.io.BufferedReader JavaDoc;
32 import java.io.ByteArrayInputStream JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.InputStreamReader JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.List JavaDoc;
39
40 import org.apache.tools.ant.BuildException;
41 import org.apache.tools.ant.Project;
42
43 import com.idaremedia.antx.AntX;
44 import com.idaremedia.antx.AssertableDataType;
45 import com.idaremedia.antx.FixtureComponent;
46 import com.idaremedia.antx.FlexString;
47 import com.idaremedia.antx.helpers.ArrayIterator;
48 import com.idaremedia.antx.helpers.Empties;
49 import com.idaremedia.antx.helpers.InnerString;
50 import com.idaremedia.antx.helpers.InputFileLoader;
51 import com.idaremedia.antx.helpers.Tk;
52 import com.idaremedia.antx.ownhelpers.LocalTk;
53
54 /**
55  * A structured collection of strings or string-representations as a formal Ant type.
56  * <p>
57  * StringItemLists bring formal structure to a sequence of items that are (initially)
58  * represented as strings in a build script. StringItemLists can be subclassed to
59  * create live (non-string) entities from the strings; for example, a list of URLs
60  * or Files can start life in a build script as strings. The StringItemList allows
61  * the real types to be created and verified when the data is declared instead of the
62  * first time the declaration is used (or referenced).
63  *
64  * @since JWare/AntX 0.3
65  * @author ssmc, &copy;2003-2005 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
66  * @version 0.5
67  * @.safety single
68  * @.group impl,helper
69  **/

70
71 public abstract class StringItemList extends AssertableDataType
72     implements Cloneable JavaDoc, FixtureComponent
73 {
74     /** Flag passed to {@linkplain #copyOfStrings copyOfStrings}. **/
75     public final static Boolean JavaDoc PROCESSED=Boolean.FALSE;
76     
77     /** Flag passed to {@linkplain #copyOfStrings copyOfStrings}. **/
78     public final static Boolean JavaDoc RAW= Boolean.TRUE;
79
80
81
82     /**
83      * Initializes a string item list.
84      **/

85     protected StringItemList()
86     {
87         super(AntX.starters);
88         m_strings= new ArrayList JavaDoc(10);
89     }
90
91
92
93     /**
94      * Initializes a CV-labeled string item list.
95      * @param iam CV-label (non-null)
96      **/

97     protected StringItemList(String JavaDoc iam)
98     {
99         super(iam);
100         m_strings= new ArrayList JavaDoc(10);
101     }
102
103
104
105     /**
106      * Initializes a new pre-initialized string item list.
107      * @param iam CV-label (non-null)
108      * @param list comma-delimited list of strings (non-null)
109      **/

110     protected StringItemList(String JavaDoc iam, String JavaDoc list)
111     {
112         super();
113         List JavaDoc l = Tk.splitList(list,AntX.DEFAULT_DELIMITER);
114         if (l instanceof ArrayList JavaDoc) {
115             m_strings = (ArrayList JavaDoc)l;
116         } else {
117             m_strings= new ArrayList JavaDoc(l);
118             l= null;
119         }
120     }
121
122
123
124     /**
125      * Returns a deep-clone of this string item list. Underlying
126      * elements are also cloned. If this item is a reference to
127      * another object, that object's clone method is invoked.
128      **/

129     public Object JavaDoc clone()
130     {
131         if (isReference()) {
132             return getOtherItemList(getClass()).clone();
133         }
134         try {
135             StringItemList copy = (StringItemList)super.clone();
136             copy.m_strings = (ArrayList JavaDoc)m_strings.clone();
137             cloneInternals(copy);
138             return copy;
139         } catch(CloneNotSupportedException JavaDoc clnx) {
140             throw new Error JavaDoc(uistrs().get(AntX.CLONE_BROKEN_MSGID));
141         }
142     }
143
144
145
146     /**
147      * Capture our identifier for feedback since types don't always
148      * get correct location information.
149      * @param id our identifier (via build script)
150      **/

151     public void setId(String JavaDoc id)
152     {
153         m_Id= id;
154     }
155
156
157
158     /**
159      * Tries to return an unique identifier for this type. Looks
160      * for a build-script identifier; if none found creates a
161      * unique string based on type's class name and instance
162      * reference.
163      **/

164     public final String JavaDoc getId()
165     {
166         if (m_Id!=null) {
167             return m_Id;
168         }
169         if (isReference()) {
170             return getOtherItemList(getClass()).getId();
171         }
172         return super.getId();
173     }
174
175
176
177     /**
178      * Returns <i>true</i> if this string item list is empty.
179      **/

180     public final boolean isEmpty()
181     {
182         if (isReference()) {
183             return getOtherItemList(getClass()).isEmpty();
184         }
185         return m_strings.isEmpty();
186     }
187
188
189
190     /**
191      * Returns the current size of this string item list.
192      **/

193     public final int size()
194     {
195         if (isReference()) {
196             return getOtherItemList(getClass()).size();
197         }
198         return m_strings.size();
199     }
200
201
202
203     /**
204      * Returns an iterator for a <em>snapshot</em> of this string
205      * item list's current converted contents. Modifications via
206      * the returned iterator are <em>not</em> reflected in this
207      * list.
208      * @see #copyOfItems copyOfItems
209      **/

210     public final Iterator JavaDoc readonlyIterator()
211     {
212         if (isReference()) {
213             return getOtherItemList(getClass()).readonlyIterator();
214         }
215         return copyOfItems(getProject()).iterator();
216     }
217
218
219
220     /**
221      * Returns an iterator for an <em>snapshot</em> of this item
222      * list's current strings. Modifications via the returned iterator
223      * are <em>not</em> reflected in this list.
224      * @see #copyOfStrings copyOfStrings
225      **/

226     public final Iterator JavaDoc readonlyStringIterator()
227     {
228         if (isReference()) {
229             return getOtherItemList(getClass()).readonlyStringIterator();
230         }
231         return new ArrayIterator(copyOfStrings(getProject(),PROCESSED));
232     }
233
234
235
236     /**
237      * Returns an iterator for an <em>snapshot</em> of this item
238      * list's current strings. Modifications via the returned iterator
239      * are <em>not</em> reflected in this list.
240      * @param p [optional] project against which property references resolved.
241      * @see #copyOfStrings copyOfStrings
242      * @since JWare/AntX 0.5
243      **/

244     public final Iterator JavaDoc readonlyStringIterator(Project p)
245     {
246         if (isReference()) {
247             return getOtherItemList(getClass()).readonlyStringIterator(p);
248         }
249         return new ArrayIterator(copyOfStrings(p,PROCESSED));
250     }
251
252
253
254     /**
255      * Returns an iterator for an <em>snapshot</em> of this item
256      * list's current strings. Modifications via the returned iterator
257      * are <em>not</em> reflected in this list.
258      * @param p [optional] project against which property references resolved.
259      * @param how flag for whether or not prefix/suffix applied
260      * @see #copyOfStrings copyOfStrings
261      * @see #RAW
262      * @see #PROCESSED
263      * @since JWare/AntX 0.5
264      **/

265     public final Iterator JavaDoc readonlyStringIterator(Project p, Boolean JavaDoc how)
266     {
267         if (isReference()) {
268             return getOtherItemList(getClass()).readonlyStringIterator(p,how);
269         }
270         require_(how!=null,"readonlyItr- nonzro how flag");
271         return new ArrayIterator(copyOfStrings(p,how));
272     }
273
274
275
276     /**
277      * Appends given item's string (without property substitution).
278      * This method should be called by the subclasses' script-facing
279      * equivalent.
280      * @param item new item
281      * @throws BuildException if this item is a reference
282      **/

283     protected void addItem(InnerString item)
284     {
285         require_(item!=null,"addItm- nonzro itm");
286         if (isReference()) {
287             throw tooManyAttributes();
288         }
289         addItemFinal(item.toString());
290         edited();
291     }
292
293
294
295     /**
296      * Appends given item's string with property substitution
297      * using given project as property value source.
298      * This method should be called by the subclasses' script-facing
299      * equivalent.
300      * @param item new item
301      * @param theProject source project for replaced properties
302      * @throws BuildException if this item is a reference
303      **/

304     protected void addItem(InnerString item, Project theProject)
305     {
306         require_(item!=null,"addItm- nonzro itm");
307         if (isReference()) {
308             throw tooManyAttributes();
309         }
310         addItemFinal(item.toString(theProject));
311         edited();
312     }
313
314
315
316     /**
317      * Appends a flex string's determined value.
318      * Caller must configure flex string's project information
319      * before calling this method. This method should be
320      * called by the subclasses' script-facing equivalent.
321      * @param item new item
322      * @throws BuildException if this item is a reference
323      **/

324     protected void addItem(FlexString item)
325     {
326         require_(item!=null,"addItm- nonzro itm");
327         if (isReference()) {
328             throw tooManyAttributes();
329         }
330         addItemFinal(item.getValue());
331         edited();
332     }
333
334
335
336     /**
337      * Adds the contents of an byte-encoded character buffer to this list.
338      * The stream must contain newline-delimited strings in the current
339      * runtime's character encoding. This method acts as a no-op if
340      * the stream is empty.
341      * @param allStrings the characters to be read (non-null)
342      * @return <i>true</i> if at least one item added to this list
343      * @throws BuildException if unable to read file once opened
344      * @since JWare/AntX 0.4
345      **/

346     private boolean addBuffer(byte[] allStrings)
347     {
348         require_(allStrings!=null,"addBfr- nonzro byt[]");
349         BufferedReader JavaDoc r= new BufferedReader JavaDoc
350                 (new InputStreamReader JavaDoc(new ByteArrayInputStream JavaDoc(allStrings)));
351         int N=0;
352         try {
353             String JavaDoc ln;
354             while ((ln=r.readLine())!=null) {
355                 addItemFinal(ln);
356                 N++;
357             }
358         } catch(IOException JavaDoc iox) {
359             throw new BuildException(iox);
360         } finally {
361             if (N!=0) {
362                 edited();
363             }
364         }
365         return N!=0;
366     }
367
368
369
370     /**
371      * Adds the contents of the given file to this list. The file
372      * must contain newline-delimited strings. This method acts as
373      * a no-op if the file does not exist or is empty.
374      * @param f file path or URL string to be read (non-null)
375      * @return <i>true</i> if at least one item added to this list
376      * @throws BuildException if unable to read file once opened
377      * @since JWare/AntX 0.4
378      **/

379     protected boolean addFileOrURL(String JavaDoc f)
380     {
381         require_(f!=null,"addFil- nonzro filnam");
382         if (isReference()) {
383             throw tooManyAttributes();
384         }
385         byte[] bytes=null;
386         try {
387             bytes = new InputFileLoader().loadFile(f);
388         } catch(IOException JavaDoc iox) {
389             String JavaDoc warning = uistrs().get
390                 ("solo.list.filenotfound", getId(), f);
391             log(warning,Project.MSG_WARN);
392             return false;
393         }
394         return addBuffer(bytes);
395     }
396
397
398
399     /**
400      * Adds the contents of the given resource file to this list.
401      * The resource file must contain newline-delimited strings.
402      * This method acts as a no-op if the no such resource exists.
403      * @param rn (subpath) name of resoure (non-null)
404      * @throws BuildException if unable to read resoure once opened
405      * @since JWare/AntX 0.4
406      **/

407     protected boolean addResource(String JavaDoc rn)
408     {
409         require_(rn!=null,"addRsrc- nonzro name");
410         if (isReference()) {
411             throw tooManyAttributes();
412         }
413         InputStream JavaDoc is = LocalTk.getSystemResourceAsStream(rn, getProject());
414         if (is==null) {
415             return false;
416         }
417         byte[] bytes=null;
418         try {
419             bytes = new InputFileLoader().load(is);
420         } catch(IOException JavaDoc iox) {
421             String JavaDoc error = uistrs().get
422                 ("solo.list.reznotfound", getId(), rn);
423             log(error,Project.MSG_ERR);
424             throw new BuildException(error,iox);
425         }
426         return addBuffer(bytes);
427     }
428
429
430
431     /**
432      * Appends given string (as-is) to this string item list.
433      * @param string string to append (non-null)
434      **/

435     protected final void addItemFinal(String JavaDoc string)
436     {
437         if (!includeItem(string)) {
438             String JavaDoc error = uistrs().get("solo.list.invalid.item",getId(),
439                                         String.valueOf(string));
440             log(error,Project.MSG_ERR);
441             throw new BuildException(error);
442         }
443         m_strings.add(string);
444     }
445
446
447
448     /**
449      * Filter to prevent illegal string forms from making it into
450      * this list. Called by {@linkplain #addItemFinal addItemFinal()}
451      * just before appending to underlying list. By default, allows
452      * any non-null string (even empty ones).
453      **/

454     protected boolean includeItem(String JavaDoc candidate)
455     {
456         return candidate!=null;
457     }
458
459
460
461     /**
462      * Returns a copy of this string item list's underlying
463      * strings. Caller assumes ownership of returned array.
464      * Never returns <i>null</i>. Returned strings have had
465      * any prefix and/or suffix modifications applied.
466      * @param p [optional] project from which property references read.
467      * @param how [optional] flag for whether or not prefix/suffix applied
468      * @see #isCustom
469      * @see #PROCESSED
470      * @see #RAW
471      **/

472     protected String JavaDoc[] copyOfStrings(Project p, Boolean JavaDoc how)
473     {
474         verify_(!isReference(),"copyOfStrs- standalone");//?
475
String JavaDoc[] sl=null;
476         if (how==PROCESSED && isCustom()) {
477             sl = new String JavaDoc[m_strings.size()];
478             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(150);
479             for (int i=0;i<sl.length;i++) {
480                 sb.append(getPrefixString());
481                 sb.append(Tk.resolveString(p,m_strings.get(i).toString(),true));
482                 sb.append(getSuffixString());
483                 sl[i]= sb.substring(0);
484                 sb.delete(0,sb.length());
485             }
486         } else if (p!=null) {//NB:resolve any @(...) references! AntX-0.5
487
sl = new String JavaDoc[m_strings.size()];
488             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(150);
489             for (int i=0;i<sl.length;i++) {
490                 sb.append(Tk.resolveString(p,m_strings.get(i).toString(),true));
491                 sl[i]= sb.substring(0);
492                 sb.delete(0,sb.length());
493             }
494         } else {
495             sl = (String JavaDoc[])m_strings.toArray(Empties.EMPTY_STRING_ARRAY);
496         }
497         return sl;
498     }
499
500
501
502     /**
503      * Returns a copy of this string item list's underlying
504      * strings as converted matching objects. Caller assumes
505      * ownership of returned array. Never returns <i>null</i>.
506      * Returned items have had any prefix and/or suffix
507      * modifications applied.
508      * @param p [optional] project from which property references read.
509      * @see #isCustom
510      **/

511     protected List JavaDoc copyOfItems(Project p)
512     {
513         verify_(!isReference(),"copyOfItms- standalone");//?
514
String JavaDoc[] sl = copyOfStrings(p,PROCESSED);
515         ArrayList JavaDoc copy = new ArrayList JavaDoc(sl.length);
516         for (int i=0;i<sl.length;i++) {
517             copy.add(sl[i]);
518             sl[i]= null;
519         }
520         sl=null;
521         return copy;
522     }
523
524
525
526     /**
527      * Return the raw underlying list of strings. Should never
528      * be exposed via any public interface. Never returns
529      * <i>null</i>.
530      **/

531     protected final List JavaDoc rawStringsList()
532     {
533         return m_strings;
534     }
535
536
537
538     /**
539      * Sets a prefix that will be prepended to all strings
540      * returned by {@linkplain #copyOfStrings copyOfStrings} and
541      * {@linkplain #copyOfItems copyOfItems}. This
542      * method should be called by the subclasses' script-facing
543      * equivalent.
544      * @param prefix the prefix (non-null)
545      * @throws BuildException if this item is a reference
546      **/

547     protected void setPrefixString(String JavaDoc prefix)
548     {
549         if (isReference()) {
550             throw tooManyAttributes();
551         }
552         m_prefix = prefix==null ? "" : prefix;
553         edited();
554     }
555
556
557
558     /**
559      * Returns this string item list's prefix or the empty
560      * string if never set (or reset). Never returns <i>null</i>.
561      **/

562     protected final String JavaDoc getPrefixString()
563     {
564         return m_prefix;
565     }
566
567
568
569     /**
570      * Sets a suffix that will be appended to all strings
571      * returned by {@linkplain #copyOfStrings copyOfStrings} and
572      * {@linkplain #copyOfItems copyOfItems}. This
573      * method should be called by the subclasses' script-facing
574      * equivalent.
575      * @param suffix the suffix (non-null)
576      * @throws BuildException if this item is a reference
577      **/

578     protected void setSuffixString(String JavaDoc suffix)
579     {
580         if (isReference()) {
581             throw tooManyAttributes();
582         }
583         m_suffix = suffix==null ? "" : suffix;
584         edited();
585     }
586
587
588
589     /**
590      * Returns this string item list's suffix or the empty
591      * string if never set (or reset). Never returns <i>null</i>.
592      **/

593     protected final String JavaDoc getSuffixString()
594     {
595         return m_suffix;
596     }
597
598
599
600     /**
601      * Called to by {@linkplain #clone clone()} to copy converted
602      * string information. The calling method has already cloned
603      * the raw underlying string list and other fields. A hook
604      * for subclasses; by default does nothing.
605      * @param cloned the cloned item (non-null)
606      **/

607     protected void cloneInternals(StringItemList cloned)
608     {
609         //nothing for strings.
610
}
611
612
613
614     /**
615      * Returns the StringItemList referenced by this instance.
616      * @param c required class of referred-to thingy (non-null)
617      **/

618     protected final StringItemList getOtherItemList(Class JavaDoc c)
619     {
620         return (StringItemList)getCheckedRef(c,getTypicalName(c));
621     }
622
623
624
625     /**
626      * Returns <i>true</i> if cannot ignore modifier string.
627      **/

628     private boolean willModify(String JavaDoc it)
629     {
630         return it!=null && it.length()>0;
631     }
632
633
634
635     /**
636      * Returns <i>true</i> if this list should modify raw strings
637      * with prefix and/or suffix additions.
638      * @see #rawStringsList
639      **/

640     protected final boolean shouldModifyStrings()
641     {
642         return willModify(getPrefixString()) || willModify(getSuffixString());
643     }
644
645
646
647     /**
648      * Returns <i>true</i> if this item list's is not empty
649      * and {@linkplain #shouldModifyStrings shouldModifyStrings} has
650      * returned <i>true</i>.
651      **/

652     protected final boolean isCustom()
653     {
654         return (!m_strings.isEmpty()) && shouldModifyStrings();
655     }
656
657
658
659     /**
660      * Returns a user-readable name for this type. By default
661      * returns the lowercased leaf name of this item's class. Never
662      * returns <i>null</i>.
663      **/

664     protected String JavaDoc getTypicalName(Class JavaDoc c)
665     {
666         if (c==null) { c = getClass(); }
667         return Tk.lowercaseFrom(Tk.leafNameFrom(c));
668     }
669
670
671
672     private String JavaDoc m_Id;
673     private ArrayList JavaDoc m_strings= new ArrayList JavaDoc(10);
674     private String JavaDoc m_prefix="", m_suffix="";
675 }
676
677 /* end-of-StringItemList.java */
678
Popular Tags