KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > template > SimpleSequence


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.template;
54
55 import java.io.Serializable JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import java.util.Collection JavaDoc;
58 import java.util.Collections JavaDoc;
59 import java.util.List JavaDoc;
60
61 import freemarker.ext.beans.BeansWrapper;
62
63 /**
64  * <p>A convenient implementation of a list. This
65  * object implements {@link TemplateSequenceModel}, using an underlying
66  * <tt>java.util.List</tt> implementation.</p>
67  *
68  * <p>A <tt>SimpleSequence</tt> can act as a cache for a
69  * <tt>TemplateCollectionModel</tt>, e.g. one that gets data from a
70  * database. When passed a <tt>TemplateCollectionModel</tt> as an
71  * argument to its constructor, the <tt>SimpleSequence</tt> immediately
72  * copies all the elements and discards the <tt>TemplateCollectionModel</tt>.</p>
73  *
74  * <p>This class is thread-safe if you don't call the <tt>add</tt> method after you
75  * have made the object available for multiple threads.
76  *
77  * <p><b>Note:</b><br />
78  * As of 2.0, this class is unsynchronized by default.
79  * To obtain a synchronized wrapper, call the {@link #synchronizedWrapper} method.</p>
80  *
81  * @version $Id: SimpleSequence.java,v 1.53 2005/06/21 18:17:54 ddekany Exp $
82  * @see SimpleHash
83  * @see SimpleScalar
84  */

85 public class SimpleSequence extends WrappingTemplateModel
86 implements TemplateSequenceModel, Serializable JavaDoc {
87
88     /**
89      * @serial The <tt>List</tt> that this <tt>SimpleSequence</tt> wraps.
90      */

91     protected final List JavaDoc list;
92     private List JavaDoc unwrappedList;
93
94     /**
95      * Constructs an empty simple sequence that will use the the default object
96      * wrapper set in
97      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}.
98      */

99     public SimpleSequence() {
100         this((ObjectWrapper) null);
101     }
102
103     /**
104      * Constructs an empty simple sequence with preallocated capacity and using
105      * the default object wrapper set in
106      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}.
107      */

108     public SimpleSequence(int capacity) {
109         list = new ArrayList JavaDoc(capacity);
110     }
111
112     /**
113      * Constructs a simple sequence that will contain the elements
114      * from the specified {@link Collection} and will use the the default
115      * object wrapper set in
116      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}.
117      * @param collection the collection containing initial values. Note that a
118      * copy of the collection is made for internal use.
119      */

120     public SimpleSequence(Collection JavaDoc collection) {
121         this(collection, null);
122     }
123     
124     /**
125      * Constructs a simple sequence from the passed collection model using the
126      * default object wrapper set in
127      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}.
128      */

129     public SimpleSequence(TemplateCollectionModel tcm) throws TemplateModelException {
130         ArrayList JavaDoc alist = new ArrayList JavaDoc();
131         for (TemplateModelIterator it = tcm.iterator(); it.hasNext();) {
132             alist.add(it.next());
133         }
134         alist.trimToSize();
135         list = alist;
136     }
137
138     /**
139      * Constructs an empty simple sequence using the specified object wrapper.
140      * @param wrapper The object wrapper to use to wrap objects into
141      * {@link TemplateModel} instances. If null, the default wrapper set in
142      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is
143      * used.
144      */

145     public SimpleSequence(ObjectWrapper wrapper) {
146         super(wrapper);
147         list = new ArrayList JavaDoc();
148     }
149     
150     /**
151      * Constructs a simple sequence that will contain the elements
152      * from the specified {@link Collection} and will use the specified object
153      * wrapper.
154      * @param collection the collection containing initial values. Note that a
155      * copy of the collection is made for internal use.
156      * @param wrapper The object wrapper to use to wrap objects into
157      * {@link TemplateModel} instances. If null, the default wrapper set in
158      * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is
159      * used.
160      */

161     public SimpleSequence(Collection JavaDoc collection, ObjectWrapper wrapper) {
162         super(wrapper);
163         list = new ArrayList JavaDoc(collection);
164     }
165
166     /**
167      * Adds an arbitrary object to the end of this <tt>SimpleSequence</tt>.
168      * If the object itself does not implement the {@link TemplateModel}
169      * interface, it will be wrapped into an appropriate adapter on the first
170      * call to {@link #get(int)}.
171      *
172      * @param obj the boolean to be added.
173      */

174     public void add(Object JavaDoc obj) {
175         list.add(obj);
176         unwrappedList = null;
177     }
178
179     /**
180      * Adds a boolean to the end of this <tt>SimpleSequence</tt>, by
181      * coercing the boolean into {@link TemplateBooleanModel#TRUE} or
182      * {@link TemplateBooleanModel#FALSE}.
183      *
184      * @param b the boolean to be added.
185      */

186     public void add(boolean b) {
187         if (b) {
188             add(TemplateBooleanModel.TRUE);
189         }
190         else {
191             add(TemplateBooleanModel.FALSE);
192         }
193     }
194     
195     /**
196      * Note that this method creates and returns a deep-copy of the underlying list used
197      * internally. This could be a gotcha for some people
198      * at some point who want to alter something in the data model,
199      * but we should maintain our immutability semantics (at least using default SimpleXXX wrappers)
200      * for the data model. It will recursively unwrap the stuff in the underlying container.
201      */

202     public List JavaDoc toList() throws TemplateModelException {
203         if (unwrappedList == null) {
204             Class JavaDoc listClass = list.getClass();
205             List JavaDoc result = null;
206             try {
207                 result = (List JavaDoc) listClass.newInstance();
208             } catch (Exception JavaDoc e) {
209                 throw new TemplateModelException("Error instantiating an object of type " + listClass.getName() + "\n" + e.getMessage());
210             }
211             BeansWrapper bw = BeansWrapper.getDefaultInstance();
212             for (int i=0; i<list.size(); i++) {
213                 Object JavaDoc elem = list.get(i);
214                 if (elem instanceof TemplateModel) {
215                     elem = bw.unwrap((TemplateModel) elem);
216                 }
217                 result.add(elem);
218             }
219             unwrappedList = result;
220         }
221         return unwrappedList;
222     }
223     
224     /**
225      * @return the specified index in the list
226      */

227     public TemplateModel get(int i) throws TemplateModelException {
228         try {
229             Object JavaDoc value = list.get(i);
230             if (value instanceof TemplateModel) {
231                 return (TemplateModel) value;
232             }
233             TemplateModel tm = wrap(value);
234             list.set(i, tm);
235             return tm;
236         }
237         catch(IndexOutOfBoundsException JavaDoc e) {
238             return null;
239 // throw new TemplateModelException(i + " out of bounds [0, " + list.size() + ")");
240
}
241     }
242
243     public int size() {
244         return list.size();
245     }
246
247     /**
248      * @return a synchronized wrapper for list.
249      */

250     public SimpleSequence synchronizedWrapper() {
251         return new SynchronizedSequence();
252     }
253     
254     public String JavaDoc toString() {
255         return list.toString();
256     }
257
258     private class SynchronizedSequence extends SimpleSequence {
259
260         public void add(Object JavaDoc obj) {
261             synchronized (SimpleSequence.this) {
262                 SimpleSequence.this.add(obj);
263             }
264         }
265
266         public TemplateModel get(int i) throws TemplateModelException {
267             synchronized (SimpleSequence.this) {
268                 return SimpleSequence.this.get(i);
269             }
270         }
271         
272         public int size() {
273             synchronized (SimpleSequence.this) {
274                 return SimpleSequence.this.size();
275             }
276         }
277         public List JavaDoc toList() throws TemplateModelException {
278             synchronized (SimpleSequence.this) {
279                 return SimpleSequence.this.toList();
280             }
281         }
282     }
283 }
Popular Tags