1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.apt;
21
22 import com.sun.mirror.apt.AnnotationProcessorEnvironment;
23 import com.sun.mirror.apt.Filer;
24 import com.sun.mirror.declaration.ClassDeclaration;
25 import com.sun.mirror.declaration.InterfaceDeclaration;
26 import com.sun.mirror.declaration.MethodDeclaration;
27 import com.sun.mirror.declaration.TypeDeclaration;
28 import com.sun.mirror.type.InterfaceType;
29 import org.apache.commons.io.IOUtils;
30 import org.apache.myfaces.tobago.apt.annotation.Converter;
31 import org.apache.myfaces.tobago.apt.annotation.Facet;
32 import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
33 import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
34 import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
35 import org.apache.myfaces.tobago.apt.annotation.Validator;
36 import org.codehaus.plexus.util.FileUtils;
37 import org.jdom.Attribute;
38 import org.jdom.Comment;
39 import org.jdom.DocType;
40 import org.jdom.Document;
41 import org.jdom.Element;
42 import org.jdom.JDOMException;
43 import org.jdom.Namespace;
44 import org.jdom.filter.ContentFilter;
45 import org.jdom.input.SAXBuilder;
46 import org.jdom.output.Format;
47 import org.jdom.output.XMLOutputter;
48 import org.xml.sax.EntityResolver;
49 import org.xml.sax.InputSource;
50 import org.xml.sax.SAXException;
51
52 import javax.xml.parsers.ParserConfigurationException;
53 import java.io.File;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.io.StringReader;
57 import java.io.StringWriter;
58 import java.io.Writer;
59 import java.lang.reflect.Field;
60 import java.util.ArrayList;
61 import java.util.Collection;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Locale;
65 import java.util.Map;
66
67
68
69
70
71 public class FacesConfigAnnotationVisitor extends AbstractAnnotationVisitor {
72 public static final String SOURCE_FACES_CONFIG_KEY = "sourceFacesConfig";
73 public static final String TARGET_FACES_CONFIG_KEY = "targetFacesConfig";
74
75 private String jsfVersion = "1.1";
76
77 private static final String SEPARATOR = System.getProperty("line.separator");
78 private static final String COMPONENT = "component";
79 private static final String COMPONENT_TYPE = "component-type";
80 private static final String COMPONENT_CLASS = "component-class";
81 private static final String COMPONENT_EXTENSION = "component-extension";
82 private static final String ALLOWED_CHILD_COMPONENTS = "allowed-child-components";
83 private static final String CATEGORY = "category";
84 private static final String DEPRECATED = "deprecated";
85 private static final String HIDDEN = "hidden";
86 private static final String FACET = "facet";
87 private static final String DISPLAY_NAME = "display-name";
88 private static final String DESCRIPTION = "description";
89 private static final String FACET_NAME = "facet-name";
90 private static final String FACET_EXTENSION = "facet-extension";
91 private static final String PROPERTY = "property";
92 private static final String PROPERTY_NAME = "property-name";
93 private static final String PROPERTY_CLASS = "property-class";
94 private static final String PROPERTY_EXTENSION = "property-extension";
95 private static final String VALUE_EXPRESSION = "value-expression";
96 private static final String PROPERTY_VALUES = "property-values";
97 private static final String READONLY = "read-only";
98 private static final String REQUIRED = "required";
99 private static final String DEFAULT_VALUE = "default-value";
100 private static final String ATTRIBUTE = "attribute";
101 private static final String ATTRIBUTE_NAME = "attribute-name";
102 private static final String ATTRIBUTE_CLASS = "attribute-class";
103 private static final String ATTRIBUTE_EXTENSION = "attribute-extension";
104 private static final String APPLICATION = "application";
105 private static final String FACTORY = "factory";
106 private static final String CONVERTER = "converter";
107 private static final String CONVERTER_ID = "converter-id";
108 private static final String CONVERTER_FOR_CLASS = "converter-for-class";
109 private static final String CONVERTER_CLASS = "converter-class";
110 private static final String VALIDATOR = "validator";
111 private static final String VALIDATOR_ID = "validator-id";
112 private static final String VALIDATOR_FOR_CLASS = "validator-for-class";
113 private static final String VALIDATOR_CLASS = "validator-class";
114 private static final String RENDERER = "renderer";
115 private static final String COMPONENT_FAMILY = "component-family";
116 private static final String RENDER_KIT = "render-kit";
117 private static final String RENDER_KIT_ID = "render-kit-id";
118 private static final String RENDER_KIT_CLASS = "render-kit-class";
119 private static final String RENDERER_TYPE = "renderer-type";
120 private static final String RENDERER_CLASS = "renderer-class";
121
122 public FacesConfigAnnotationVisitor(AnnotationProcessorEnvironment env) {
123 super(env);
124 }
125
126 public void process() throws ParserConfigurationException, IOException {
127 String sourceFacesConfigFile = null;
128 String targetFacesConfigFile = null;
129 for (Map.Entry<String, String> entry : getEnv().getOptions().entrySet()) {
130 if (entry.getKey().startsWith("-A" + SOURCE_FACES_CONFIG_KEY + "=")) {
131 sourceFacesConfigFile = entry.getKey().substring(SOURCE_FACES_CONFIG_KEY.length() + 3);
132 }
133 if (entry.getKey().startsWith("-A" + TARGET_FACES_CONFIG_KEY + "=")) {
134 targetFacesConfigFile = entry.getKey().substring(TARGET_FACES_CONFIG_KEY.length() + 3);
135 }
136 if (entry.getKey().startsWith("-Ajsf-version=")) {
137 String version = entry.getKey().substring("-Ajsf-version=".length());
138 if ("1.2".equals(version)) {
139 jsfVersion = "1.2";
140 }
141 if ("2.0".equals(version)) {
142 jsfVersion = "2.0";
143 }
144 }
145 }
146 Document document;
147 Writer writer = null;
148 try {
149 String content = FileUtils.fileRead(sourceFacesConfigFile);
150 SAXBuilder builder = new SAXBuilder();
151 builder.setEntityResolver(new EntityResolver() {
152 public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
153 if ("-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN".equals(publicId)) {
154 InputStream stream = FacesConfigAnnotationVisitor.class.getResourceAsStream(
155 "/org/apache/myfaces/tobago/dtd/web-facesconfig_1_1.dtd");
156 return new InputSource(stream);
157 }
158 return null;
159 }
160 });
161 document = builder.build(new StringReader(content));
162
163
164 normaliseLineEndings(document);
165
166
167
168 Element rootElement = document.getRootElement();
169 if (is12()) {
170 rootElement.setNamespace(Namespace.getNamespace("http://java.sun.com/xml/ns/javaee"));
171 Namespace xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
172 rootElement.addNamespaceDeclaration(Namespace.getNamespace("xi", "http://www.w3.org/2001/XInclude"));
173 rootElement.setAttribute(new Attribute("schemaLocation",
174 "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd", xsi));
175 rootElement.setAttribute("version", "1.2");
176 } else if (is20()) {
177 rootElement.setNamespace(Namespace.getNamespace("http://java.sun.com/xml/ns/javaee"));
178 Namespace xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
179 rootElement.addNamespaceDeclaration(Namespace.getNamespace("xi", "http://www.w3.org/2001/XInclude"));
180 rootElement.setAttribute(new Attribute("schemaLocation",
181 "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd", xsi));
182 rootElement.setAttribute("version", "2.0");
183 }
184 Namespace namespace = rootElement.getNamespace();
185 if (is12()||is20()) {
186 applyNamespace(rootElement, namespace);
187 }
188 List<Element> components = rootElement.getChildren(COMPONENT, namespace);
189
190 List<Element> newComponents = new ArrayList<Element>();
191 List<Element> newRenderer = new ArrayList<Element>();
192 List<Element> newConverters = new ArrayList<Element>();
193 List<Element> newValidators = new ArrayList<Element>();
194
195 for (ClassDeclaration decl : getCollectedClassDeclarations()) {
196 if (decl.getAnnotation(UIComponentTag.class) != null) {
197 addElement(decl, newComponents, newRenderer, namespace);
198 } else if (decl.getAnnotation(Converter.class) != null) {
199 addConverter(decl, newConverters, namespace);
200 } else if (decl.getAnnotation(Validator.class) != null) {
201 addValidator(decl, newValidators, namespace);
202 }
203 }
204
205 for (InterfaceDeclaration decl : getCollectedInterfaceDeclarations()) {
206 if (decl.getAnnotation(UIComponentTag.class) != null) {
207 addElement(decl, newComponents, newRenderer, namespace);
208 }
209 }
210 List<Element> elementsToAdd = new ArrayList<Element>();
211
212 for (Element newElement : newComponents) {
213 boolean found = containsElement(components, newElement);
214 if (!found) {
215 elementsToAdd.add(newElement);
216 }
217 }
218 if (!elementsToAdd.isEmpty()) {
219
220 int lastIndex = getIndexAfter(rootElement, COMPONENT, FACTORY, APPLICATION);
221 rootElement.addContent(lastIndex, elementsToAdd);
222 }
223 if (!newRenderer.isEmpty()) {
224 Element renderKit = new Element(RENDER_KIT, namespace);
225 Element renderKitId = new Element(RENDER_KIT_ID, namespace);
226 renderKitId.setText("tobago");
227 renderKit.addContent(renderKitId);
228 Element renderKitClass = new Element(RENDER_KIT_CLASS, namespace);
229 renderKitClass.setText("org.apache.myfaces.tobago.renderkit.TobagoRenderKit");
230 renderKit.addContent(renderKitClass);
231 renderKit.addContent(newRenderer);
232 int lastIndex = getIndexAfter(rootElement, CONVERTER, COMPONENT, FACTORY, APPLICATION);
233 rootElement.addContent(lastIndex, renderKit);
234 }
235 if (!newConverters.isEmpty()) {
236 int lastIndex = getIndexAfter(rootElement, RENDER_KIT, CONVERTER, COMPONENT, FACTORY, APPLICATION);
237 rootElement.addContent(lastIndex, newConverters);
238 }
239 if (!newValidators.isEmpty()) {
240 rootElement.addContent(newValidators);
241 }
242 if (is11()) {
243 document.setDocType(new DocType("faces-config",
244 "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN",
245 "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"));
246 }
247 writer =
248 getEnv().getFiler().createTextFile(Filer.Location.SOURCE_TREE, "", new File(targetFacesConfigFile), null);
249
250 StringWriter facesConfig = new StringWriter(1024);
251 Format format = Format.getPrettyFormat();
252 format.setLineSeparator(SEPARATOR);
253 XMLOutputter out = new XMLOutputter(format);
254 out.output(document, facesConfig);
255 if (is11()) {
256
257 String facesConfigStr =
258 facesConfig.toString().replaceFirst(" xmlns=\"http://java.sun.com/JSF/Configuration\"", "");
259
260 facesConfigStr = facesConfigStr.replaceFirst("\"http://java.sun.com/dtd/web-facesconfig_1_1.dtd\"",
261 "\"http://java.sun.com/dtd/web-facesconfig_1_1.dtd\"[\n"
262 + "<!ELEMENT allowed-child-components (#PCDATA)>\n"
263 + "<!ELEMENT category (#PCDATA)>\n"
264 + "<!ELEMENT deprecated (#PCDATA)>\n"
265 + "<!ELEMENT hidden (#PCDATA)>\n"
266 + "<!ELEMENT preferred (#PCDATA)>\n"
267 + "<!ELEMENT read-only (#PCDATA)>\n"
268 + "<!ELEMENT value-expression (#PCDATA)>\n"
269 + "<!ELEMENT property-values (#PCDATA)>\n"
270 + "<!ELEMENT required (#PCDATA)>\n"
271 + "]");
272 writer.append(facesConfigStr);
273 } else {
274 writer.append(facesConfig.toString());
275 }
276
277 } catch (JDOMException e) {
278 e.printStackTrace();
279 } catch (IOException e) {
280 e.printStackTrace();
281 } finally {
282 IOUtils.closeQuietly(writer);
283 }
284 }
285
286 private void applyNamespace(Element parent, Namespace namespace) {
287 for (Element element : (List<Element>) parent.getChildren()) {
288 element.setNamespace(namespace);
289 applyNamespace(element, namespace);
290 }
291 }
292
293 private void addConverter(ClassDeclaration decl, List<Element> newConverters, Namespace namespace) {
294 Converter converterAnn = decl.getAnnotation(Converter.class);
295 Element converter = new Element(CONVERTER, namespace);
296 if (converterAnn.id().length() > 0) {
297 Element converterId = new Element(CONVERTER_ID, namespace);
298 converterId.setText(converterAnn.id());
299 converter.addContent(converterId);
300 } else if (converterAnn.forClass().length() > 0) {
301 Element converterForClass = new Element(CONVERTER_FOR_CLASS, namespace);
302 converterForClass.setText(converterAnn.forClass());
303 converter.addContent(converterForClass);
304 }
305
306 Element converterClass = new Element(CONVERTER_CLASS, namespace);
307 converterClass.setText(decl.getQualifiedName());
308 converter.addContent(converterClass);
309 newConverters.add(converter);
310 }
311
312 private void addValidator(ClassDeclaration decl, List<Element> newValidators, Namespace namespace) {
313 Validator validatorAnn = decl.getAnnotation(Validator.class);
314 Element validator = new Element(VALIDATOR, namespace);
315 if (validatorAnn.id().length() > 0) {
316 Element validatorId = new Element(VALIDATOR_ID, namespace);
317 validatorId.setText(validatorAnn.id());
318 validator.addContent(validatorId);
319 } else if (validatorAnn.forClass().length() > 0) {
320 Element validatorForClass = new Element(VALIDATOR_FOR_CLASS, namespace);
321 validatorForClass.setText(validatorAnn.forClass());
322 validator.addContent(validatorForClass);
323 }
324
325 Element validatorClass = new Element(VALIDATOR_CLASS, namespace);
326 validatorClass.setText(decl.getQualifiedName());
327 validator.addContent(validatorClass);
328 newValidators.add(validator);
329 }
330
331 private boolean containsElement(List<Element> components, Element newElement) {
332 return getEqualElement(components, newElement) != null;
333 }
334
335 private Element getEqualElement(List<Element> components, Element newElement) {
336 for (Element element : components) {
337 if (equals(element, newElement)) {
338 return element;
339 }
340 }
341 return null;
342 }
343
344 private int getIndexAfter(Element rootElement, String... tagNames) {
345 for (String tagName : tagNames) {
346 int index = getIndexAfter(rootElement, tagName);
347 if (index != 0) {
348 return index;
349 }
350 }
351 return 0;
352 }
353
354 private int getIndexAfter(Element rootElement, String tagName) {
355 List<Element> components = rootElement.getChildren(tagName, rootElement.getNamespace());
356 if (!components.isEmpty()) {
357 return rootElement.indexOf(components.get(components.size() - 1)) + 1;
358 }
359 return 0;
360 }
361
362 public boolean equals(Element element1, Element element2) {
363 Namespace namespace = element1.getNamespace();
364 if (element1.getName().equals(element2.getName()) && element1.getNamespace().equals(element2.getNamespace())) {
365 if (element1.getChildText(COMPONENT_CLASS, namespace).equals(element2.getChildText(COMPONENT_CLASS, namespace))) {
366 if (element1.getChildText(COMPONENT_TYPE, namespace).equals(element2.getChildText(COMPONENT_TYPE, namespace))) {
367 return true;
368 }
369 }
370 }
371 return false;
372 }
373
374 protected Element createComponentElement(TypeDeclaration decl, UIComponentTag componentTag,
375 Class uiComponentClass, Namespace namespace) throws IOException, NoSuchFieldException, IllegalAccessException {
376 Field componentField = uiComponentClass.getField("COMPONENT_TYPE");
377 String componentType = (String) componentField.get(null);
378 Element element = new Element(COMPONENT, namespace);
379 String displayName = componentTag.displayName();
380 if (displayName.equals("")) {
381 displayName = uiComponentClass.getName().substring(uiComponentClass.getName().lastIndexOf(".") + 1);
382 }
383 Element elementDisplayName = new Element(DISPLAY_NAME, namespace);
384 elementDisplayName.setText(displayName);
385 element.addContent(elementDisplayName);
386 Element elementType = new Element(COMPONENT_TYPE, namespace);
387 elementType.setText(componentType);
388 element.addContent(elementType);
389 Element elementClass = new Element(COMPONENT_CLASS, namespace);
390 elementClass.setText(componentTag.uiComponent());
391 element.addContent(elementClass);
392
393 return element;
394 }
395
396 protected void addRendererElement(TypeDeclaration decl, UIComponentTag componentTag,
397 Class uiComponentClass, List<Element> renderer, Namespace namespace)
398 throws IOException, NoSuchFieldException, IllegalAccessException {
399 String rendererType = componentTag.rendererType();
400 if (rendererType != null && rendererType.length() > 0) {
401 Field componentField = uiComponentClass.getField("COMPONENT_FAMILY");
402 String componentFamily = (String) componentField.get(null);
403 Element element = new Element(RENDERER, namespace);
404 String displayName = componentTag.displayName();
405 if (displayName.equals("")) {
406 displayName = uiComponentClass.getName().substring(uiComponentClass.getName().lastIndexOf(".") + 1);
407 }
408 Element elementDisplayName = new Element(DISPLAY_NAME, namespace);
409 elementDisplayName.setText(displayName);
410 element.addContent(elementDisplayName);
411 Element elementComponentFamily = new Element(COMPONENT_FAMILY, namespace);
412 elementComponentFamily.addContent(componentFamily);
413 element.addContent(elementComponentFamily);
414 Element elementType = new Element(RENDERER_TYPE, namespace);
415 elementType.setText(rendererType);
416 element.addContent(elementType);
417 Element elementClass = new Element(RENDERER_CLASS, namespace);
418 String className = "org.apache.myfaces.tobago.renderkit." + rendererType + "Renderer";
419 elementClass.setText(className);
420 element.addContent(elementClass);
421 renderer.add(element);
422 }
423 }
424
425
426 private Element createElementExtension(TypeDeclaration decl, UIComponentTag uiComponentTag,
427 Namespace namespace) {
428 Element elementExtension = new Element(COMPONENT_EXTENSION, namespace);
429 Element elementAllowedChildComponents = new Element(ALLOWED_CHILD_COMPONENTS, namespace);
430 String[] allowedChildComponents = uiComponentTag.allowedChildComponenents();
431 String allowedComponentTypes = "";
432 for (String componentType : allowedChildComponents) {
433 allowedComponentTypes += componentType + " ";
434 }
435 elementAllowedChildComponents.setText(allowedComponentTypes);
436 elementExtension.addContent(elementAllowedChildComponents);
437 Element elementCategory = new Element(CATEGORY, namespace);
438 elementCategory.setText(uiComponentTag.category().toString());
439 elementExtension.addContent(elementCategory);
440 Deprecated deprecated = decl.getAnnotation(Deprecated.class);
441 if (deprecated != null) {
442 Element elementDeprecated = new Element(DEPRECATED, namespace);
443 elementDeprecated.setText("Warning: This component is deprecated!");
444 elementExtension.addContent(elementDeprecated);
445 }
446 Element elementHidden = new Element(HIDDEN, namespace);
447 elementHidden.setText(Boolean.toString(uiComponentTag.isHidden()));
448 elementExtension.addContent(elementHidden);
449
450 return elementExtension;
451 }
452
453 protected void addAttribute(MethodDeclaration d, Class uiComponentClass, List properties, List attributes,
454 Namespace namespace) {
455 UIComponentTagAttribute componentAttribute = d.getAnnotation(UIComponentTagAttribute.class);
456 if (componentAttribute != null) {
457 String simpleName = d.getSimpleName();
458 if (simpleName.startsWith("set")) {
459 String attributeStr = simpleName.substring(3, 4).toLowerCase(Locale.ENGLISH) + simpleName.substring(4);
460 String methodStr;
461 if (componentAttribute.type().length == 1
462 && (componentAttribute.type()[0].equals(Boolean.class.getName())
463 || componentAttribute.type()[0].equals("boolean"))) {
464 methodStr = "is" + simpleName.substring(3);
465 } else {
466 methodStr = "get" + simpleName.substring(3);
467 }
468 try {
469 uiComponentClass.getMethod(methodStr, new Class[0]);
470 Element property = new Element(PROPERTY, namespace);
471 Element propertyName = new Element(PROPERTY_NAME, namespace);
472 Element propertyClass = new Element(PROPERTY_CLASS, namespace);
473
474 propertyName.setText(attributeStr);
475 addClass(componentAttribute, propertyClass);
476
477 addDescription(d, property, namespace);
478
479 property.addContent(propertyName);
480 property.addContent(propertyClass);
481 if (componentAttribute.defaultValue().length() > 0) {
482 Element defaultValue = new Element(DEFAULT_VALUE, namespace);
483 defaultValue.setText(componentAttribute.defaultValue());
484 property.addContent(defaultValue);
485 }
486
487 property.addContent(createPropertyOrAttributeExtension(PROPERTY_EXTENSION, d, componentAttribute, namespace));
488 properties.add(property);
489 } catch (NoSuchMethodException e) {
490
491 Element attribute = new Element(ATTRIBUTE, namespace);
492 Element attributeName = new Element(ATTRIBUTE_NAME, namespace);
493 Element attributeClass = new Element(ATTRIBUTE_CLASS, namespace);
494
495 attributeName.setText(attributeStr);
496 addClass(componentAttribute, attributeClass);
497
498 addDescription(d, attribute, namespace);
499
500 attribute.addContent(attributeName);
501 attribute.addContent(attributeClass);
502 if (componentAttribute.defaultValue().length() > 0) {
503 Element defaultValue = new Element(DEFAULT_VALUE, namespace);
504 defaultValue.setText(componentAttribute.defaultValue());
505 attribute.addContent(defaultValue);
506 }
507
508 attribute.addContent(createPropertyOrAttributeExtension(ATTRIBUTE_EXTENSION, d,
509 componentAttribute, namespace));
510
511 attributes.add(attribute);
512 }
513 } else {
514 throw new IllegalArgumentException("Only setter allowed found: " + simpleName);
515 }
516 }
517 }
518
519 private void addClass(UIComponentTagAttribute componentAttribute, Element attributeClass) {
520 if (componentAttribute.type().length > 1) {
521 attributeClass.setText(Object.class.getName());
522 } else if (componentAttribute.type().length == 1) {
523 String className = componentAttribute.type()[0];
524 if (componentAttribute.expression().isMethodExpression() && isUnifiedEL()) {
525 className = "javax.el.MethodExpression";
526 }
527 attributeClass.setText((className.equals(Boolean.class.getName()) && !isUnifiedEL()) ? "boolean" : className);
528 } else {
529 if (componentAttribute.expression().isMethodExpression()) {
530 String className = "";
531 if (isUnifiedEL()) {
532 className = "javax.el.MethodExpression";
533 } else {
534 className = "javax.faces.el.MethodBinding";
535 }
536 attributeClass.setText(className);
537 }
538 }
539 }
540
541 private void addDescription(MethodDeclaration d, Element attribute, Namespace namespace) {
542 String comment = d.getDocComment();
543 if (comment != null) {
544 int index = comment.indexOf('@');
545 if (index != -1) {
546 comment = comment.substring(0, index);
547 }
548 comment = comment.trim();
549 if (comment.length() > 0) {
550 Element description = new Element(DESCRIPTION, namespace);
551 description.setText(comment);
552 attribute.addContent(description);
553 }
554 }
555 }
556
557 private Element createPropertyOrAttributeExtension(String extensionType, MethodDeclaration methodDeclaration,
558 UIComponentTagAttribute uiComponentTagAttribute, Namespace namespace) throws IllegalArgumentException {
559 Element extensionElement = new Element(extensionType, namespace);
560 Element valueExpression = new Element(VALUE_EXPRESSION, namespace);
561 valueExpression.setText(uiComponentTagAttribute.expression().toMetaDataString());
562 extensionElement.addContent(valueExpression);
563 String[] allowedValues = uiComponentTagAttribute.allowedValues();
564 if (allowedValues.length > 0) {
565 Element propertyValues = new Element(PROPERTY_VALUES, namespace);
566 String values = "";
567 for (String value : allowedValues) {
568 values += value + " ";
569 }
570 propertyValues.setText(values);
571 extensionElement.addContent(propertyValues);
572 }
573 Deprecated deprecated = methodDeclaration.getAnnotation(Deprecated.class);
574 if (deprecated != null) {
575 Element elementDeprecated = new Element(DEPRECATED, namespace);
576 elementDeprecated.setText("Warning: This property is deprecated!");
577 extensionElement.addContent(elementDeprecated);
578 }
579 Element hidden = new Element(HIDDEN, namespace);
580 hidden.setText(Boolean.toString(uiComponentTagAttribute.isHidden()));
581 extensionElement.addContent(hidden);
582 Element readOnly = new Element(READONLY, namespace);
583 readOnly.setText(Boolean.toString(uiComponentTagAttribute.isReadOnly()));
584 extensionElement.addContent(readOnly);
585 TagAttribute tagAttribute = methodDeclaration.getAnnotation(TagAttribute.class);
586 if (tagAttribute != null) {
587 Element required = new Element(REQUIRED, namespace);
588 required.setText(Boolean.toString(tagAttribute.required()));
589 extensionElement.addContent(required);
590 }
591
592 return extensionElement;
593 }
594
595 protected void addAttributes(InterfaceDeclaration type, Class uiComponentClass, List properties, List attributes,
596 Namespace namespace) {
597 addAttributes(type.getSuperinterfaces(), uiComponentClass, properties, attributes, namespace);
598 for (MethodDeclaration decl : getCollectedMethodDeclarations()) {
599 if (decl.getDeclaringType().equals(type)) {
600 addAttribute(decl, uiComponentClass, properties, attributes, namespace);
601 }
602 }
603 }
604
605 protected void addAttributes(Collection<InterfaceType> interfaces, Class uiComponentClass, List properties,
606 List attributes, Namespace namespace) {
607 for (InterfaceType type : interfaces) {
608 addAttributes(type.getDeclaration(), uiComponentClass, properties, attributes, namespace);
609 }
610 }
611
612 protected void addAttributes(ClassDeclaration d, Class uiComponentClass, List properties, List attributes,
613 Namespace namespace) {
614 for (MethodDeclaration decl : getCollectedMethodDeclarations()) {
615 if (d.getQualifiedName().
616 equals(decl.getDeclaringType().getQualifiedName())) {
617 addAttribute(decl, uiComponentClass, properties, attributes, namespace);
618 }
619 }
620 addAttributes(d.getSuperinterfaces(), uiComponentClass, properties, attributes, namespace);
621 if (d.getSuperclass() != null) {
622 addAttributes(d.getSuperclass().getDeclaration(), uiComponentClass, properties, attributes, namespace);
623 }
624 }
625
626
627 private void addFacets(UIComponentTag componentTag, Namespace namespace, Element element) {
628 Facet[] facets = componentTag.facets();
629 for (Facet facet : facets) {
630 Element facetElement = new Element(FACET, namespace);
631 String description = facet.description();
632 if (description != null && description.length() > 0) {
633 Element facetDescription = new Element(DESCRIPTION, namespace);
634 facetDescription.setText(description);
635 facetElement.addContent(facetDescription);
636 }
637 Element facetName = new Element(FACET_NAME, namespace);
638 facetName.setText(facet.name());
639 facetElement.addContent(facetName);
640 Element facetExtension = new Element(FACET_EXTENSION, namespace);
641 Element elementAllowedChildComponents = new Element(ALLOWED_CHILD_COMPONENTS, namespace);
642 String[] allowedChildComponents = facet.allowedChildComponenents();
643 String allowedComponentTypes = "";
644 for (String componentType : allowedChildComponents) {
645 allowedComponentTypes += componentType + " ";
646 }
647 elementAllowedChildComponents.setText(allowedComponentTypes);
648 facetExtension.addContent(elementAllowedChildComponents);
649 facetElement.addContent(facetExtension);
650 element.addContent(facetElement);
651 }
652 }
653
654 protected void addElement(ClassDeclaration decl, List<Element> components, List<Element> renderer,
655 Namespace namespace) throws IOException {
656 UIComponentTag componentTag = decl.getAnnotation(UIComponentTag.class);
657 if (componentTag != null) {
658 try {
659 Class<?> uiComponentClass = Class.forName(componentTag.uiComponent());
660 if (!componentTag.isComponentAlreadyDefined()) {
661 Element element = createComponentElement(decl, componentTag, uiComponentClass, namespace);
662 if (element != null) {
663 if (!containsElement(components, element)) {
664 addFacets(componentTag, namespace, element);
665 List attributes = new ArrayList();
666 List properties = new ArrayList();
667 addAttributes(decl, uiComponentClass, attributes, properties, namespace);
668 if (!attributes.isEmpty()) {
669 element.addContent(attributes);
670 }
671 if (!properties.isEmpty()) {
672 element.addContent(properties);
673 }
674 element.addContent(createElementExtension(decl, componentTag, namespace));
675 components.add(element);
676 } else {
677
678 }
679 }
680 }
681 addRendererElement(decl, componentTag, uiComponentClass, renderer, namespace);
682 } catch (Exception e) {
683 e.printStackTrace();
684 }
685 }
686 }
687
688 protected void addElement(InterfaceDeclaration decl, List<Element> components, List<Element> renderer,
689 Namespace namespace) throws IOException {
690 UIComponentTag componentTag = decl.getAnnotation(UIComponentTag.class);
691 if (componentTag != null) {
692 try {
693 Class<?> uiComponentClass = Class.forName(componentTag.uiComponent());
694 if (!componentTag.isComponentAlreadyDefined()) {
695 Element element = createComponentElement(decl, componentTag, uiComponentClass, namespace);
696 if (element != null) {
697 if (!containsElement(components, element)) {
698 addFacets(componentTag, namespace, element);
699 List attributes = new ArrayList();
700 List properties = new ArrayList();
701 addAttributes(decl, uiComponentClass, properties, attributes, namespace);
702 if (!attributes.isEmpty()) {
703 element.addContent(attributes);
704 }
705 if (!properties.isEmpty()) {
706 element.addContent(properties);
707 }
708 element.addContent(createElementExtension(decl, componentTag, namespace));
709 components.add(element);
710 } else {
711
712 }
713 }
714 }
715 addRendererElement(decl, componentTag, uiComponentClass, renderer, namespace);
716 } catch (Exception e) {
717 e.printStackTrace();
718 }
719 }
720 }
721
722 private void normaliseLineEndings(Document document) {
723 for (Iterator i = document.getDescendants(new ContentFilter(ContentFilter.COMMENT)); i.hasNext();) {
724 Comment c = (Comment) i.next();
725 c.setText(c.getText().replaceAll("\n", SEPARATOR));
726 }
727 }
728
729 private boolean is12() {
730 return "1.2".equals(jsfVersion);
731 }
732
733 private boolean is11() {
734 return "1.1".equals(jsfVersion);
735 }
736
737 private boolean is20() {
738 return "2.0".equals(jsfVersion);
739 }
740
741 private boolean isUnifiedEL() {
742 return !"1.1".equals(jsfVersion);
743 }
744 }