1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.compiler;
20
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Stack;
25
26 import javax.el.ELException;
27 import javax.faces.application.FacesMessage;
28 import javax.faces.view.facelets.CompositeFaceletHandler;
29 import javax.faces.view.facelets.FaceletHandler;
30 import javax.faces.view.facelets.Tag;
31 import javax.faces.view.facelets.TagAttribute;
32 import javax.faces.view.facelets.TagException;
33
34 import org.apache.myfaces.shared.renderkit.html.HTML;
35 import org.apache.myfaces.view.facelets.el.ELText;
36
37
38
39
40
41
42 final class TextUnit extends CompilationUnit
43 {
44
45 private final StringBuffer buffer;
46
47 private final StringBuffer textBuffer;
48
49 private final List<Instruction> instructionBuffer;
50
51 private final Stack<Tag> tags;
52
53 private final List<Object> children;
54
55 private boolean startTagOpen;
56
57 private final String alias;
58
59 private final String id;
60
61 private final List<Object> messages;
62
63 public TextUnit(String alias, String id)
64 {
65 this.alias = alias;
66 this.id = id;
67 this.buffer = new StringBuffer();
68 this.textBuffer = new StringBuffer();
69 this.instructionBuffer = new ArrayList<Instruction>();
70 this.tags = new Stack<Tag>();
71 this.children = new ArrayList<Object>();
72 this.startTagOpen = false;
73 this.messages = new ArrayList<Object>(4);
74 }
75
76 public FaceletHandler createFaceletHandler()
77 {
78 this.flushBufferToConfig(true);
79
80 if (this.children.size() == 0)
81 {
82 return LEAF;
83 }
84
85 FaceletHandler[] h = new FaceletHandler[this.children.size()];
86 Object obj;
87 for (int i = 0; i < h.length; i++)
88 {
89 obj = this.children.get(i);
90 if (obj instanceof FaceletHandler)
91 {
92 h[i] = (FaceletHandler) obj;
93 }
94 else
95 {
96 h[i] = ((CompilationUnit) obj).createFaceletHandler();
97 }
98 }
99 if (h.length == 1)
100 {
101 return h[0];
102 }
103 return new CompositeFaceletHandler(h);
104 }
105
106 private void addInstruction(Instruction instruction)
107 {
108 this.flushTextBuffer(false);
109 this.instructionBuffer.add(instruction);
110 }
111
112 private void flushTextBuffer(boolean child)
113 {
114 if (this.textBuffer.length() > 0)
115 {
116 String s = this.textBuffer.toString();
117
118 if (child)
119 {
120 s = trimRight(s);
121 }
122 if (s.length() > 0)
123 {
124 ELText txt = ELText.parse(s);
125 if (txt != null)
126 {
127 if (txt.isLiteral())
128 {
129 this.instructionBuffer.add(new LiteralTextInstruction(txt.toString()));
130 }
131 else
132 {
133 this.instructionBuffer.add(new TextInstruction(this.alias, txt));
134 }
135 }
136 }
137
138 }
139 this.textBuffer.setLength(0);
140 }
141
142 public void write(String text)
143 {
144 this.finishStartTag();
145 this.textBuffer.append(text);
146 this.buffer.append(text);
147 }
148
149 public void writeInstruction(String text)
150 {
151 this.finishStartTag();
152 ELText el = ELText.parse(text);
153 if (el.isLiteral())
154 {
155 this.addInstruction(new LiteralXMLInstruction(text));
156 }
157 else
158 {
159 this.addInstruction(new XMLInstruction(el));
160 }
161 this.buffer.append(text);
162 }
163
164 public void writeComment(String text)
165 {
166 this.finishStartTag();
167
168 ELText el = ELText.parse(text);
169 if (el.isLiteral())
170 {
171 this.addInstruction(new LiteralCommentInstruction(text));
172 }
173 else
174 {
175 this.addInstruction(new CommentInstruction(el));
176 }
177
178 this.buffer.append("<!--" + text + "-->");
179 }
180
181 public void startTag(Tag tag)
182 {
183
184
185 this.finishStartTag();
186
187
188 this.tags.push(tag);
189
190
191 this.buffer.append('<');
192 this.buffer.append(tag.getQName());
193
194 this.addInstruction(new StartElementInstruction(tag.getQName()));
195
196 TagAttribute[] attrs = tag.getAttributes().getAll();
197 if (attrs.length > 0)
198 {
199 for (int i = 0; i < attrs.length; i++)
200 {
201 String qname = attrs[i].getQName();
202 String value = attrs[i].getValue();
203 this.buffer.append(' ').append(qname).append("=\"").append(value).append("\"");
204
205 ELText txt = ELText.parse(value);
206 if (txt != null)
207 {
208 if (txt.isLiteral())
209 {
210 this.addInstruction(new LiteralAttributeInstruction(qname, txt.toString()));
211 }
212 else
213 {
214 this.addInstruction(new AttributeInstruction(this.alias, qname, txt));
215 }
216 }
217 }
218 }
219
220 if (!messages.isEmpty())
221 {
222 for (Iterator<Object> it = messages.iterator(); it.hasNext();)
223 {
224 Object[] message = (Object[])it.next();
225 this.addInstruction(new AddFacesMessageInstruction((FacesMessage.Severity) message[0], (String)message[1], (String)message[2]));
226 it.remove();
227 }
228 }
229
230
231 this.startTagOpen = true;
232 }
233
234 private void finishStartTag()
235 {
236 if (this.tags.size() > 0 && this.startTagOpen)
237 {
238 this.buffer.append(">");
239 this.startTagOpen = false;
240 }
241 }
242
243 public void endTag()
244 {
245 Tag tag = (Tag) this.tags.pop();
246
247 if (HTML.BODY_ELEM.equalsIgnoreCase(tag.getQName()))
248 {
249 this.addInstruction(new BodyEndElementInstruction(tag.getQName()));
250 }
251 else
252 {
253 this.addInstruction(new EndElementInstruction(tag.getQName()));
254 }
255
256 if (this.startTagOpen)
257 {
258 this.buffer.append("/>");
259 this.startTagOpen = false;
260 }
261 else
262 {
263 this.buffer.append("</").append(tag.getQName()).append('>');
264 }
265 }
266
267 public void addChild(CompilationUnit unit)
268 {
269
270
271 this.finishStartTag();
272 this.flushBufferToConfig(true);
273 this.children.add(unit);
274 }
275
276 protected void flushBufferToConfig(boolean child)
277 {
278
279
280 if (true)
281 {
282
283 this.flushTextBuffer(child);
284
285 int size = this.instructionBuffer.size();
286 if (size > 0)
287 {
288 try
289 {
290 String s = this.buffer.toString();
291 if (child)
292 s = trimRight(s);
293 ELText txt = ELText.parse(s);
294 if (txt != null)
295 {
296 Instruction[] instructions = (Instruction[]) this.instructionBuffer
297 .toArray(new Instruction[size]);
298 this.children.add(new UIInstructionHandler(this.alias, this.id, instructions, txt));
299 this.instructionBuffer.clear();
300 }
301
302 }
303 catch (ELException e)
304 {
305 if (this.tags.size() > 0)
306 {
307 throw new TagException((Tag) this.tags.peek(), e.getMessage());
308 }
309 else
310 {
311 throw new ELException(this.alias + ": " + e.getMessage(), e.getCause());
312 }
313 }
314 }
315
316
317 }
318 else if (this.buffer.length() > 0)
319 {
320 String s = this.buffer.toString();
321 if (s.trim().length() > 0)
322 {
323 if (child)
324 {
325 s = trimRight(s);
326 }
327 if (s.length() > 0)
328 {
329 try
330 {
331 ELText txt = ELText.parse(s);
332 if (txt != null)
333 {
334 if (txt.isLiteral())
335 {
336 this.children.add(new UILiteralTextHandler(txt.toString()));
337 }
338 else
339 {
340 this.children.add(new UITextHandler(this.alias, txt));
341 }
342 }
343 }
344 catch (ELException e)
345 {
346 if (this.tags.size() > 0)
347 {
348 throw new TagException((Tag) this.tags.peek(), e.getMessage());
349 }
350 else
351 {
352 throw new ELException(this.alias + ": " + e.getMessage(), e.getCause());
353 }
354 }
355 }
356 }
357 }
358
359
360 this.buffer.setLength(0);
361 }
362
363 public boolean isClosed()
364 {
365 return this.tags.empty();
366 }
367
368 private final static String trimRight(String s)
369 {
370 int i = s.length() - 1;
371 while (i >= 0 && Character.isWhitespace(s.charAt(i)))
372 {
373 i--;
374 }
375 if (i >= 0)
376 {
377 return s;
378 }
379 else
380 {
381 return "";
382 }
383
384
385
386
387
388
389
390
391
392 }
393
394 public String toString()
395 {
396 return "TextUnit[" + this.children.size() + "]";
397 }
398
399 public void addMessage(FacesMessage.Severity severity, String summary, String detail)
400 {
401 this.messages.add(new Object[]{severity, summary, detail});
402 }
403 }