1 // ========================================================================
2 // $Id: Composite.java,v 1.6 2004/05/09 20:31:28 gregwilkins Exp $
3 // Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 package org.mortbay.html;
17 import java.io.IOException;
18 import java.io.OutputStream;
19 import java.io.OutputStreamWriter;
20 import java.io.Writer;
21 import java.util.ArrayList;
22
23
24 /* -------------------------------------------------------------------- */
25 /** HTML Composite Element.
26 * <p>This class is can be used a either an abstract or concrete
27 * holder of other HTML elements.
28 * Used directly, it allow multiple HTML Elements to be added which
29 * are produced sequentially.
30 * Derived used of Composite may wrap each contain Element in
31 * special purpose HTML tags (e.g. list).
32 *
33 * <p>Notes<br>
34 * Elements are added to the Composite either as HTML Elements or as
35 * Strings. Other objects added to the Composite are converted to Strings
36 * @see Element
37 * @version $Id: Composite.java,v 1.6 2004/05/09 20:31:28 gregwilkins Exp $
38 * @author Greg Wilkins
39 */
40 public class Composite extends Element
41 {
42 /* ----------------------------------------------------------------- */
43 /** The vector of elements in this Composite.
44 */
45 protected ArrayList elements= new ArrayList(8);
46
47 /* ----------------------------------------------------------------- */
48 protected Composite nest=null;
49
50 /* ----------------------------------------------------------------- */
51 /** Default constructor.
52 */
53 public Composite()
54 {}
55
56 /* ----------------------------------------------------------------- */
57 /** Default constructor.
58 */
59 public Composite(String attributes)
60 {
61 super(attributes);
62 }
63
64 /* ----------------------------------------------------------------- */
65 /** Add an Object to the Composite by converting it to a Element or.
66 * String
67 * @param o The Object to add. If it is a String or Element, it is
68 * added directly, otherwise toString() is called.
69 * @return This Composite (for chained commands)
70 */
71 public Composite add(Object o)
72 {
73 if (nest!=null)
74 nest.add(o);
75 else
76 {
77 if (o!=null)
78 {
79 if (o instanceof Element)
80 {
81 if(o instanceof Page)
82 throw new IllegalArgumentException("Can't insert Page in Composite");
83 elements.add(o);
84 }
85 else if (o instanceof String)
86 elements.add(o);
87 else
88 elements.add(o.toString());
89 }
90 }
91 return this;
92 }
93
94 /* ----------------------------------------------------------------- */
95 /** Nest a Composite within a Composite.
96 * The passed Composite is added to this Composite. Adds to
97 * this composite are actually added to the nested Composite.
98 * Calls to nest are passed the nested Composite
99 * @return The Composite to unest on to return to the original
100 * state.
101 */
102 public Composite nest(Composite c)
103 {
104 if (nest!=null)
105 return nest.nest(c);
106 else
107 {
108 add(c);
109 nest=c;
110 }
111 return this;
112 }
113
114 /* ----------------------------------------------------------------- */
115 /** Explicit set of the Nested component.
116 * No add is performed. setNest() obeys any current nesting and
117 * sets the nesting of the nested component.
118 */
119 public Composite setNest(Composite c)
120 {
121 if (nest!=null)
122 nest.setNest(c);
123 else
124 nest=c;
125 return this;
126 }
127
128 /* ----------------------------------------------------------------- */
129 /** Recursively unnest the composites.
130 */
131 public Composite unnest()
132 {
133 if (nest!=null)
134 nest.unnest();
135 nest = null;
136 return this;
137 }
138
139
140 /* ----------------------------------------------------------------- */
141 /** The number of Elements in this Composite.
142 * @return The number of elements in this Composite
143 */
144 public int size()
145 {
146 return elements.size();
147 }
148
149 /* ----------------------------------------------------------------- */
150 /** Write the composite.
151 * The default implementation writes the elements sequentially. May
152 * be overridden for more specialized behaviour.
153 * @param out Writer to write the element to.
154 */
155 public void write(Writer out)
156 throws IOException
157 {
158 for (int i=0; i <elements.size() ; i++)
159 {
160 Object element = elements.get(i);
161
162 if (element instanceof Element)
163 ((Element)element).write(out);
164 else if (element==null)
165 out.write("null");
166 else
167 out.write(element.toString());
168 }
169 }
170
171 /* ----------------------------------------------------------------- */
172 /** Contents of the composite.
173 */
174 public String contents()
175 {
176 StringBuffer buf = new StringBuffer();
177 synchronized(buf)
178 {
179 for (int i=0; i <elements.size() ; i++)
180 {
181 Object element = elements.get(i);
182 if (element==null)
183 buf.append("null");
184 else
185 buf.append(element.toString());
186 }
187 }
188 return buf.toString();
189 }
190
191 /* ------------------------------------------------------------ */
192 /** Empty the contents of this Composite .
193 */
194 public Composite reset()
195 {
196 elements.clear();
197 return unnest();
198 }
199
200 /* ----------------------------------------------------------------- */
201 /* Flush is a package method used by Page.flush() to locate the
202 * most nested composite, write out and empty its contents.
203 */
204 void flush(Writer out)
205 throws IOException
206 {
207 if (nest!=null)
208 nest.flush(out);
209 else
210 {
211 write(out);
212 elements.clear();
213 }
214 }
215
216 /* ----------------------------------------------------------------- */
217 /* Flush is a package method used by Page.flush() to locate the
218 * most nested composite, write out and empty its contents.
219 */
220 void flush(OutputStream out)
221 throws IOException
222 {
223 flush(new OutputStreamWriter(out));
224 }
225
226 /* ----------------------------------------------------------------- */
227 /* Flush is a package method used by Page.flush() to locate the
228 * most nested composite, write out and empty its contents.
229 */
230 void flush(OutputStream out, String encoding)
231 throws IOException
232 {
233 flush(new OutputStreamWriter(out,encoding));
234 }
235
236 /* ------------------------------------------------------------ */
237 /** Replace an object within the composite.
238 */
239 public boolean replace(Object oldObj, Object newObj)
240 {
241 if (nest != null)
242 {
243 return nest.replace(oldObj, newObj);
244 }
245 else
246 {
247 int sz = elements.size();
248 for (int i = 0; i < sz; i++)
249 {
250 if (elements.get(i) == oldObj)
251 {
252 elements.set(i,newObj);
253 return true;
254 }
255 }
256 }
257
258 return false;
259 }
260
261 }