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.List;
23 import java.util.Stack;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26
27 import javax.faces.application.FacesMessage;
28 import javax.faces.view.facelets.FaceletHandler;
29 import javax.faces.view.facelets.Tag;
30 import javax.faces.view.facelets.TagAttribute;
31 import javax.faces.view.facelets.TagAttributeException;
32 import javax.faces.view.facelets.TagDecorator;
33 import javax.faces.view.facelets.TagException;
34
35 import org.apache.myfaces.view.facelets.tag.TagAttributesImpl;
36 import org.apache.myfaces.view.facelets.tag.TagLibrary;
37 import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
38 import org.apache.myfaces.view.facelets.tag.composite.ImplementationHandler;
39 import org.apache.myfaces.view.facelets.tag.composite.InterfaceHandler;
40 import org.apache.myfaces.view.facelets.tag.ui.ComponentRefHandler;
41 import org.apache.myfaces.view.facelets.tag.ui.CompositionHandler;
42 import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
43
44
45
46
47
48
49
50
51
52 final class CompilationManager
53 {
54
55
56 private final static Logger log = Logger.getLogger(CompilationManager.class.getName());
57
58 private final Compiler compiler;
59
60 private final TagLibrary tagLibrary;
61
62 private final TagDecorator tagDecorator;
63
64 private final NamespaceManager namespaceManager;
65
66 private final Stack<CompilationUnit> units;
67
68 private int tagId;
69
70 private boolean finished;
71
72 private final String alias;
73
74 private CompilationUnit interfaceCompilationUnit;
75
76 private final FaceletsProcessingInstructions faceletsProcessingInstructions;
77
78 public CompilationManager(String alias, Compiler compiler, FaceletsProcessingInstructions instructions)
79 {
80
81
82 this.alias = alias;
83
84
85 this.compiler = compiler;
86 this.tagDecorator = compiler.createTagDecorator();
87 this.tagLibrary = compiler.createTagLibrary();
88
89
90 this.namespaceManager = new NamespaceManager();
91
92
93 this.tagId = 0;
94
95
96 this.finished = false;
97
98
99 this.units = new Stack<CompilationUnit>();
100 this.units.push(new CompilationUnit());
101
102 this.interfaceCompilationUnit = null;
103 this.faceletsProcessingInstructions = instructions;
104 }
105
106 public void writeInstruction(String value)
107 {
108 if (this.finished)
109 {
110 return;
111 }
112
113
114 if (value.length() == 0)
115 {
116 return;
117 }
118
119 TextUnit unit;
120 if (this.currentUnit() instanceof TextUnit)
121 {
122 unit = (TextUnit) this.currentUnit();
123 }
124 else
125 {
126 unit = new TextUnit(this.alias, this.nextTagId(),
127 faceletsProcessingInstructions.isEscapeInlineText(),
128 faceletsProcessingInstructions.isCompressSpaces());
129 this.startUnit(unit);
130 }
131 unit.writeInstruction(value);
132 }
133
134 public void writeDoctype(String name, String publicId, String systemId)
135 {
136 if (this.finished)
137 {
138 return;
139 }
140
141 DoctypeUnit unit = new DoctypeUnit(this.alias, this.nextTagId(),
142 name, publicId, systemId, faceletsProcessingInstructions.isHtml5Doctype());
143 this.startUnit(unit);
144 }
145
146 public void writeText(String value)
147 {
148
149 if (this.finished)
150 {
151 return;
152 }
153
154
155 if (value.length() == 0)
156 {
157 return;
158 }
159
160 TextUnit unit;
161 if (this.currentUnit() instanceof TextUnit)
162 {
163 unit = (TextUnit) this.currentUnit();
164 }
165 else
166 {
167 unit = new TextUnit(this.alias, this.nextTagId(),
168 faceletsProcessingInstructions.isEscapeInlineText(),
169 faceletsProcessingInstructions.isCompressSpaces());
170 this.startUnit(unit);
171 }
172 unit.write(value);
173 }
174
175 public void writeComment(String text)
176 {
177 if (this.compiler.isTrimmingComments())
178 {
179 return;
180 }
181
182 if (this.finished)
183 {
184 return;
185 }
186
187
188 if (text.length() == 0)
189 {
190 return;
191 }
192
193 TextUnit unit;
194 if (this.currentUnit() instanceof TextUnit)
195 {
196 unit = (TextUnit) this.currentUnit();
197 }
198 else
199 {
200 unit = new TextUnit(this.alias, this.nextTagId(),
201 faceletsProcessingInstructions.isEscapeInlineText(),
202 faceletsProcessingInstructions.isCompressSpaces());
203 this.startUnit(unit);
204 }
205
206 unit.writeComment(text);
207 }
208
209 public void writeWhitespace(String text)
210 {
211 if (!this.compiler.isTrimmingWhitespace())
212 {
213 this.writeText(text);
214 }
215 }
216
217 private String nextTagId()
218 {
219 return Integer.toHexString(Math.abs(this.alias.hashCode() ^ 13 * this.tagId++));
220 }
221
222 public void pushTag(Tag orig)
223 {
224
225 if (this.finished)
226 {
227 return;
228 }
229
230 if (log.isLoggable(Level.FINE))
231 {
232 log.fine("Tag Pushed: " + orig);
233 }
234
235 Tag t = this.tagDecorator.decorate(orig);
236 String[] qname = this.determineQName(t);
237 t = this.trimAttributes(t);
238
239 if (isTrimmed(qname[0], qname[1]))
240 {
241 log.fine("Composition Found, Popping Parent Tags");
242 this.units.clear();
243 NamespaceUnit nsUnit = this.namespaceManager.toNamespaceUnit(this.tagLibrary);
244 this.units.push(nsUnit);
245 this.startUnit(new TrimmedTagUnit(this.tagLibrary, qname[0], qname[1], t, this.nextTagId()));
246 log.fine("New Namespace and [Trimmed] TagUnit pushed");
247 }
248 else if (isRemove(qname[0], qname[1]))
249 {
250 this.units.push(new RemoveUnit());
251 }
252 else if (isCompositeComponentInterface(qname[0], qname[1]))
253 {
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 log.fine("Composite Component Interface Found, saving unit");
273 CompositeComponentUnit compositeRootCompilationUnit = new CompositeComponentUnit();
274 this.startUnit(compositeRootCompilationUnit);
275 interfaceCompilationUnit = new TagUnit(this.tagLibrary, qname[0], qname[1], t, this.nextTagId());
276 this.startUnit(interfaceCompilationUnit);
277 }
278 else if (isCompositeComponentImplementation(qname[0], qname[1]))
279 {
280 log.fine("Composite component Found, Popping Parent Tags");
281 this.units.clear();
282 NamespaceUnit nsUnit = this.namespaceManager.toNamespaceUnit(this.tagLibrary);
283 this.units.push(nsUnit);
284 CompositeComponentUnit compositeRootCompilationUnit = new CompositeComponentUnit();
285 this.startUnit(compositeRootCompilationUnit);
286 if (interfaceCompilationUnit != null)
287 {
288 this.currentUnit().addChild(interfaceCompilationUnit);
289 interfaceCompilationUnit = null;
290 }
291 this.startUnit(new TrimmedTagUnit(this.tagLibrary, qname[0], qname[1], t, this.nextTagId()));
292 log.fine("New Namespace and TagUnit pushed");
293 }
294 else if (this.tagLibrary.containsTagHandler(qname[0], qname[1]))
295 {
296 this.startUnit(new TagUnit(this.tagLibrary, qname[0], qname[1], t, this.nextTagId()));
297 }
298 else if (this.tagLibrary.containsNamespace(qname[0]))
299 {
300 throw new TagException(orig, "Tag Library supports namespace: " + qname[0]
301 + ", but no tag was defined for name: " + qname[1]);
302 }
303 else
304 {
305 TextUnit unit;
306 if (this.currentUnit() instanceof TextUnit)
307 {
308 unit = (TextUnit) this.currentUnit();
309 }
310 else
311 {
312 unit = new TextUnit(this.alias, this.nextTagId(),
313 faceletsProcessingInstructions.isEscapeInlineText(),
314 faceletsProcessingInstructions.isCompressSpaces());
315 this.startUnit(unit);
316 }
317
318 if (this.compiler.isDevelopmentProjectStage())
319 {
320 String qName = null;
321 boolean isPrefixed = false;
322 TagAttribute jsfc = t.getAttributes().get("jsfc");
323 if (jsfc != null)
324 {
325 qName = jsfc.getValue();
326 if (jsfc.getValue().indexOf(':') > 0)
327 {
328 isPrefixed = true;
329 }
330 }
331 else if (t.getQName().indexOf(':') > 0 )
332 {
333 qName = t.getQName();
334 isPrefixed = true;
335 }
336 if (isPrefixed)
337 {
338 unit.addMessage(FacesMessage.SEVERITY_WARN,
339 "Warning: The page "+alias+" declares namespace "+qname[0]+
340 " and uses the tag " + qName + " , but no TagLibrary associated to namespace.",
341 "Warning: The page "+alias+" declares namespace "+qname[0]+
342 " and uses the tag " + qName + " , but no TagLibrary associated to namespace. "+
343 "Please check the namespace name and if it is correct, it is probably that your " +
344 "library .taglib.xml cannot be found on the current classpath, or if you are " +
345 "referencing a composite component library check your library folder match with the " +
346 "namespace and can be located by the installed ResourceHandler.");
347 }
348 }
349
350 unit.startTag(t);
351 }
352 }
353
354 public void popTag()
355 {
356
357 if (this.finished)
358 {
359 return;
360 }
361
362 CompilationUnit unit = this.currentUnit();
363
364 if (unit instanceof TextUnit)
365 {
366 TextUnit t = (TextUnit) unit;
367 if (t.isClosed())
368 {
369 this.finishUnit();
370 }
371 else
372 {
373 t.endTag();
374 return;
375 }
376 }
377
378 unit = this.currentUnit();
379 if (unit instanceof TagUnit)
380 {
381 TagUnit t = (TagUnit) unit;
382 if (t instanceof TrimmedTagUnit)
383 {
384 this.finished = true;
385 return;
386 }
387 }
388 else if (unit instanceof CompositeComponentUnit)
389 {
390 this.finished = true;
391 return;
392 }
393
394 this.finishUnit();
395 }
396
397 public void popNamespace(String ns)
398 {
399 this.namespaceManager.popNamespace(ns);
400 if (this.currentUnit() instanceof NamespaceUnit)
401 {
402 this.finishUnit();
403 }
404 }
405
406 public void pushNamespace(String prefix, String uri)
407 {
408
409 if (log.isLoggable(Level.FINE))
410 {
411 log.fine("Namespace Pushed " + prefix + ": " + uri);
412 }
413
414 this.namespaceManager.pushNamespace(prefix, uri);
415 NamespaceUnit unit;
416 if (this.currentUnit() instanceof NamespaceUnit)
417 {
418 unit = (NamespaceUnit) this.currentUnit();
419 }
420 else
421 {
422 unit = new NamespaceUnit(this.tagLibrary);
423 this.startUnit(unit);
424 }
425 unit.setNamespace(prefix, uri);
426 }
427
428 public FaceletHandler createFaceletHandler()
429 {
430 return ((CompilationUnit) this.units.get(0)).createFaceletHandler();
431 }
432
433 private CompilationUnit currentUnit()
434 {
435 if (!this.units.isEmpty())
436 {
437 return (CompilationUnit) this.units.peek();
438 }
439 return null;
440 }
441
442 private void finishUnit()
443 {
444 Object obj = this.units.pop();
445
446 if (log.isLoggable(Level.FINE))
447 {
448 log.fine("Finished Unit: " + obj);
449 }
450 }
451
452 private void startUnit(CompilationUnit unit)
453 {
454
455 if (log.isLoggable(Level.FINE))
456 {
457 log.fine("Starting Unit: " + unit + " and adding it to parent: " + this.currentUnit());
458 }
459
460 this.currentUnit().addChild(unit);
461 this.units.push(unit);
462 }
463
464 private Tag trimAttributes(Tag tag)
465 {
466 Tag t = this.trimJSFCAttribute(tag);
467 t = this.trimNSAttributes(t);
468 return t;
469 }
470
471 protected static boolean isRemove(String ns, String name)
472 {
473 return (UILibrary.NAMESPACE.equals(ns) || UILibrary.ALIAS_NAMESPACE.equals(ns)) && "remove".equals(name);
474 }
475
476 protected static boolean isTrimmed(String ns, String name)
477 {
478 return (UILibrary.NAMESPACE.equals(ns) || UILibrary.ALIAS_NAMESPACE.equals(ns))
479 && (CompositionHandler.NAME.equals(name) || ComponentRefHandler.NAME.equals(name));
480 }
481
482 protected static boolean isCompositeComponentInterface(String ns, String name)
483 {
484 return (CompositeLibrary.NAMESPACE.equals(ns) || CompositeLibrary.ALIAS_NAMESPACE.equals(ns))
485 && InterfaceHandler.NAME.equals(name);
486 }
487
488 protected static boolean isCompositeComponentImplementation(String ns, String name)
489 {
490 return (CompositeLibrary.NAMESPACE.equals(ns) || CompositeLibrary.ALIAS_NAMESPACE.equals(ns))
491 && ImplementationHandler.NAME.equals(name);
492 }
493
494 private String[] determineQName(Tag tag)
495 {
496 TagAttribute attr = tag.getAttributes().get("jsfc");
497 if (attr != null)
498 {
499 if (log.isLoggable(Level.FINE))
500 {
501 log.fine(attr + " JSF Facelet Compile Directive Found");
502 }
503 String value = attr.getValue();
504 String namespace;
505 String localName;
506 int c = value.indexOf(':');
507 if (c == -1)
508 {
509 namespace = this.namespaceManager.getNamespace("");
510 localName = value;
511 }
512 else
513 {
514 String prefix = value.substring(0, c);
515 namespace = this.namespaceManager.getNamespace(prefix);
516 if (namespace == null)
517 {
518 throw new TagAttributeException(tag, attr, "No Namespace matched for: " + prefix);
519 }
520 localName = value.substring(c + 1);
521 }
522 return new String[] { namespace, localName };
523 }
524 else
525 {
526 return new String[] { tag.getNamespace(), tag.getLocalName() };
527 }
528 }
529
530 private Tag trimJSFCAttribute(Tag tag)
531 {
532 TagAttribute attr = tag.getAttributes().get("jsfc");
533 if (attr != null)
534 {
535 TagAttribute[] oa = tag.getAttributes().getAll();
536 TagAttribute[] na = new TagAttribute[oa.length - 1];
537 int p = 0;
538 for (int i = 0; i < oa.length; i++)
539 {
540 if (!"jsfc".equals(oa[i].getLocalName()))
541 {
542 na[p++] = oa[i];
543 }
544 }
545 return new Tag(tag, new TagAttributesImpl(na));
546 }
547 return tag;
548 }
549
550 private Tag trimNSAttributes(Tag tag)
551 {
552 TagAttribute[] attr = tag.getAttributes().getAll();
553 int remove = 0;
554 for (int i = 0; i < attr.length; i++)
555 {
556 if (attr[i].getQName().startsWith("xmlns") && this.tagLibrary.containsNamespace(attr[i].getValue()))
557 {
558 remove |= 1 << i;
559 if (log.isLoggable(Level.FINE))
560 {
561 log.fine(attr[i] + " Namespace Bound to TagLibrary");
562 }
563 }
564 }
565 if (remove == 0)
566 {
567 return tag;
568 }
569 else
570 {
571 List<TagAttribute> attrList = new ArrayList<TagAttribute>(attr.length);
572 int p = 0;
573 for (int i = 0; i < attr.length; i++)
574 {
575 p = 1 << i;
576 if ((p & remove) == p)
577 {
578 continue;
579 }
580 attrList.add(attr[i]);
581 }
582 attr = attrList.toArray(new TagAttribute[attrList.size()]);
583 return new Tag(tag.getLocation(), tag.getNamespace(), tag.getLocalName(), tag.getQName(),
584 new TagAttributesImpl(attr));
585 }
586 }
587
588
589
590
591
592
593 public FaceletsProcessingInstructions getFaceletsProcessingInstructions()
594 {
595 return faceletsProcessingInstructions;
596 }
597 }
598