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 }