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.processor;
21
22 import org.apache.commons.io.IOUtils;
23 import org.apache.myfaces.tobago.apt.annotation.Converter;
24 import org.apache.myfaces.tobago.apt.annotation.Facet;
25 import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
26 import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
27 import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
28 import org.apache.myfaces.tobago.apt.annotation.Validator;
29 import org.apache.myfaces.tobago.apt.generate.ComponentInfo;
30 import org.jdom2.Attribute;
31 import org.jdom2.Comment;
32 import org.jdom2.Document;
33 import org.jdom2.Namespace;
34 import org.jdom2.filter.ContentFilter;
35 import org.jdom2.input.SAXBuilder;
36 import org.jdom2.output.Format;
37 import org.jdom2.output.XMLOutputter;
38
39 import javax.annotation.processing.SupportedAnnotationTypes;
40 import javax.annotation.processing.SupportedOptions;
41 import javax.annotation.processing.SupportedSourceVersion;
42 import javax.lang.model.SourceVersion;
43 import javax.lang.model.element.ExecutableElement;
44 import javax.lang.model.element.TypeElement;
45 import javax.tools.FileObject;
46 import javax.tools.StandardLocation;
47 import java.io.FileInputStream;
48 import java.io.IOException;
49 import java.io.StringReader;
50 import java.io.StringWriter;
51 import java.io.Writer;
52 import java.nio.charset.StandardCharsets;
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.Comparator;
56 import java.util.HashSet;
57 import java.util.Iterator;
58 import java.util.List;
59 import java.util.Locale;
60 import java.util.Map;
61 import java.util.Set;
62
63 @SupportedSourceVersion(SourceVersion.RELEASE_8)
64 @SupportedAnnotationTypes({
65 "org.apache.myfaces.tobago.apt.annotation.Tag",
66 "org.apache.myfaces.tobago.apt.annotation.TagAttribute",
67 "org.apache.myfaces.tobago.apt.annotation.Taglib",
68 "org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute",
69 "org.apache.myfaces.tobago.apt.annotation.UIComponentTag",
70 "org.apache.myfaces.tobago.apt.annotation.Facet",
71 "org.apache.myfaces.tobago.apt.annotation.Preliminary",
72 "org.apache.myfaces.tobago.apt.annotation.Converter",
73 "org.apache.myfaces.tobago.apt.annotation.Validator"})
74 @SupportedOptions({
75 FacesConfigGenerator.SOURCE_FACES_CONFIG,
76 FacesConfigGenerator.TARGET_FACES_CONFIG})
77 public class FacesConfigGenerator extends AbstractGenerator {
78
79 static final String SOURCE_FACES_CONFIG = "sourceFacesConfig";
80 static final String TARGET_FACES_CONFIG = "targetFacesConfig";
81
82 private static final String SEPARATOR = System.getProperty("line.separator");
83 private static final String COMPONENT = "component";
84 private static final String COMPONENT_TYPE = "component-type";
85 private static final String COMPONENT_CLASS = "component-class";
86 private static final String COMPONENT_EXTENSION = "component-extension";
87 private static final String ALLOWED_CHILD_COMPONENTS = "allowed-child-components";
88 private static final String CATEGORY = "category";
89 private static final String DEPRECATED = "deprecated";
90 private static final String HIDDEN = "hidden";
91 private static final String FACET = "facet";
92 private static final String DISPLAY_NAME = "display-name";
93 private static final String DESCRIPTION = "description";
94 private static final String FACET_NAME = "facet-name";
95 private static final String FACET_EXTENSION = "facet-extension";
96 private static final String PROPERTY = "property";
97 private static final String PROPERTY_NAME = "property-name";
98 private static final String PROPERTY_CLASS = "property-class";
99 private static final String PROPERTY_EXTENSION = "property-extension";
100 private static final String VALUE_EXPRESSION = "value-expression";
101 private static final String PROPERTY_VALUES = "property-values";
102 private static final String READONLY = "read-only";
103 private static final String REQUIRED = "required";
104 private static final String DEFAULT_VALUE = "default-value";
105 private static final String ATTRIBUTE = "attribute";
106 private static final String ATTRIBUTE_NAME = "attribute-name";
107 private static final String ATTRIBUTE_CLASS = "attribute-class";
108 private static final String ATTRIBUTE_EXTENSION = "attribute-extension";
109 private static final String APPLICATION = "application";
110 private static final String FACTORY = "factory";
111 private static final String CONVERTER = "converter";
112 private static final String CONVERTER_ID = "converter-id";
113 private static final String CONVERTER_FOR_CLASS = "converter-for-class";
114 private static final String CONVERTER_CLASS = "converter-class";
115 private static final String VALIDATOR = "validator";
116 private static final String VALIDATOR_ID = "validator-id";
117 private static final String VALIDATOR_FOR_CLASS = "validator-for-class";
118 private static final String VALIDATOR_CLASS = "validator-class";
119 private static final String RENDERER = "renderer";
120 private static final String COMPONENT_FAMILY = "component-family";
121 private static final String RENDER_KIT = "render-kit";
122 private static final String RENDER_KIT_ID = "render-kit-id";
123 private static final String RENDER_KIT_CLASS = "render-kit-class";
124 private static final String RENDERER_TYPE = "renderer-type";
125 private static final String RENDERER_CLASS = "renderer-class";
126 private static final String BEHAVIOR = "behavior";
127
128
129
130
131
132
133
134
135 private static final Set<String> IGNORED_PROPERTIES = new HashSet<>(Collections.singletonList("binding"));
136
137 private String sourceFacesConfigFile;
138 private String targetFacesConfigFile;
139
140 @Override
141 public void configure() {
142 final Map<String, String> options = processingEnv.getOptions();
143 sourceFacesConfigFile = options.get(SOURCE_FACES_CONFIG);
144 targetFacesConfigFile = options.get(TARGET_FACES_CONFIG);
145
146 info("Generating the faces-config.xml");
147 info("Options:");
148 info(SOURCE_FACES_CONFIG + ": " + sourceFacesConfigFile);
149 info(TARGET_FACES_CONFIG + ": " + targetFacesConfigFile);
150 }
151
152 @Override
153 protected void generate() throws Exception {
154 final Document document;
155 final String content = IOUtils.toString(new FileInputStream(sourceFacesConfigFile), StandardCharsets.UTF_8);
156 final SAXBuilder builder = new SAXBuilder();
157 document = builder.build(new StringReader(content));
158
159
160 normaliseLineEndings(document);
161
162
163
164 final org.jdom2.Element rootElement = document.getRootElement();
165
166 rootElement.setNamespace(Namespace.getNamespace("http://xmlns.jcp.org/xml/ns/javaee"));
167 final Namespace xsi = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
168
169 rootElement.setAttribute(new Attribute("schemaLocation",
170 "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd", xsi));
171 rootElement.setAttribute("version", "2.3");
172
173 final Namespace namespace = rootElement.getNamespace();
174 applyNamespace(rootElement, namespace);
175 final List<org.jdom2.Element> components = rootElement.getChildren(COMPONENT, namespace);
176
177 final List<org.jdom2.Element> newComponents = new ArrayList<>();
178 final List<org.jdom2.Element> newRenderer = new ArrayList<>();
179 final List<org.jdom2.Element> newConverters = new ArrayList<>();
180 final List<org.jdom2.Element> newValidators = new ArrayList<>();
181
182 for (final TypeElement element : getTypes()) {
183 if (element.getAnnotation(UIComponentTag.class) != null) {
184 addElement(element, newComponents, newRenderer, namespace);
185 } else if (element.getAnnotation(Converter.class) != null) {
186 addConverter(element, newConverters, namespace);
187 } else if (element.getAnnotation(Validator.class) != null) {
188 addValidator(element, newValidators, namespace);
189 }
190 }
191
192 final List<org.jdom2.Element> elementsToAdd = new ArrayList<>();
193
194 for (final org.jdom2.Element newElement : newComponents) {
195 final boolean found = containsElement(components, newElement);
196 if (!found) {
197 elementsToAdd.add(newElement);
198 }
199 }
200 if (!elementsToAdd.isEmpty()) {
201
202 final int lastIndex = getIndexAfter(rootElement, COMPONENT, FACTORY, APPLICATION);
203 rootElement.addContent(lastIndex, elementsToAdd);
204 }
205 if (!newRenderer.isEmpty()) {
206 org.jdom2.Element renderKit = getFirstElementByName(rootElement, RENDER_KIT);
207 if (renderKit == null) {
208 renderKit = new org.jdom2.Element(RENDER_KIT, namespace);
209 final int last = getIndexAfter(rootElement, CONVERTER, COMPONENT, FACTORY, APPLICATION, BEHAVIOR);
210 rootElement.addContent(last, renderKit);
211 }
212 final org.jdom2.Element renderKitId = new org.jdom2.Element(RENDER_KIT_ID, namespace);
213 renderKitId.setText("tobago");
214 renderKit.addContent(0, renderKitId);
215 final org.jdom2.Element renderKitClass = new org.jdom2.Element(RENDER_KIT_CLASS, namespace);
216 renderKitClass.setText("org.apache.myfaces.tobago.renderkit.TobagoRenderKit");
217 renderKit.addContent(1, renderKitClass);
218 renderKit.addContent(2, newRenderer);
219 }
220 if (!newConverters.isEmpty()) {
221 final int last = getIndexAfter(rootElement, RENDER_KIT, CONVERTER, COMPONENT, FACTORY, APPLICATION, BEHAVIOR);
222 rootElement.addContent(last, newConverters);
223 }
224 if (!newValidators.isEmpty()) {
225 rootElement.addContent(newValidators);
226 }
227 final FileObject resource = processingEnv.getFiler().createResource(
228 StandardLocation.SOURCE_OUTPUT, "", targetFacesConfigFile);
229 info("Writing to file: " + resource.toUri());
230
231 try (Writer writer = resource.openWriter()) {
232 final StringWriter facesConfig = new StringWriter(1024);
233 final Format format = Format.getPrettyFormat();
234 format.setLineSeparator(SEPARATOR);
235 final XMLOutputter out = new XMLOutputter(format);
236 out.output(document, facesConfig);
237 writer.append(facesConfig.toString());
238 }
239 }
240
241 private void applyNamespace(final org.jdom2.Element parent, final Namespace namespace) {
242 for (final org.jdom2.Element element : parent.getChildren()) {
243 element.setNamespace(namespace);
244 applyNamespace(element, namespace);
245 }
246 }
247
248 private void addConverter(
249 final TypeElement typeElement, final List<org.jdom2.Element> newConverters, final Namespace namespace) {
250 final Converter converterAnn = typeElement.getAnnotation(Converter.class);
251 final org.jdom2.Element converter = new org.jdom2.Element(CONVERTER, namespace);
252 if (converterAnn.id().length() > 0) {
253 final org.jdom2.Element converterId = new org.jdom2.Element(CONVERTER_ID, namespace);
254 converterId.setText(converterAnn.id());
255 converter.addContent(converterId);
256 } else if (converterAnn.forClass().length() > 0) {
257 final org.jdom2.Element converterForClass = new org.jdom2.Element(CONVERTER_FOR_CLASS, namespace);
258 converterForClass.setText(converterAnn.forClass());
259 converter.addContent(converterForClass);
260 }
261
262 final org.jdom2.Element converterClass = new org.jdom2.Element(CONVERTER_CLASS, namespace);
263 converterClass.setText(typeElement.getQualifiedName().toString());
264 converter.addContent(converterClass);
265 newConverters.add(converter);
266 }
267
268 private void addValidator(
269 final TypeElement typeElement, final List<org.jdom2.Element> newValidators, final Namespace namespace) {
270 final Validator validatorAnn = typeElement.getAnnotation(Validator.class);
271 final org.jdom2.Element validator = new org.jdom2.Element(VALIDATOR, namespace);
272 if (validatorAnn.id().length() > 0) {
273 final org.jdom2.Element validatorId = new org.jdom2.Element(VALIDATOR_ID, namespace);
274 validatorId.setText(validatorAnn.id());
275 validator.addContent(validatorId);
276 } else if (validatorAnn.forClass().length() > 0) {
277 final org.jdom2.Element validatorForClass = new org.jdom2.Element(VALIDATOR_FOR_CLASS, namespace);
278 validatorForClass.setText(validatorAnn.forClass());
279 validator.addContent(validatorForClass);
280 }
281
282 final org.jdom2.Element validatorClass = new org.jdom2.Element(VALIDATOR_CLASS, namespace);
283 validatorClass.setText(typeElement.getQualifiedName().toString());
284 validator.addContent(validatorClass);
285 newValidators.add(validator);
286 }
287
288 private boolean containsElement(final List<org.jdom2.Element> components, final org.jdom2.Element newElement) {
289 return getEqualElement(components, newElement) != null;
290 }
291
292 private org.jdom2.Element getEqualElement(
293 final List<org.jdom2.Element> components, final org.jdom2.Element newElement) {
294 for (final org.jdom2.Element element : components) {
295 if (equals(element, newElement)) {
296 return element;
297 }
298 }
299 return null;
300 }
301
302 private org.jdom2.Element getFirstElementByName(final org.jdom2.Element rootElement, final String tagName) {
303 final List<org.jdom2.Element> elements = rootElement.getChildren(tagName, rootElement.getNamespace());
304 if (elements.isEmpty()) {
305 return null;
306 } else {
307 return elements.get(0);
308 }
309 }
310
311 private int getIndexAfter(final org.jdom2.Element rootElement, final String... tagNames) {
312 for (final String tagName : tagNames) {
313 final int index = getIndexAfter(rootElement, tagName);
314 if (index != 0) {
315 return index;
316 }
317 }
318 return 0;
319 }
320
321 private int getIndexAfter(final org.jdom2.Element rootElement, final String tagName) {
322 final List<org.jdom2.Element> components = rootElement.getChildren(tagName, rootElement.getNamespace());
323 if (components.isEmpty()) {
324 return 0;
325 } else {
326 return rootElement.indexOf(components.get(components.size() - 1)) + 1;
327 }
328 }
329
330 public boolean equals(final org.jdom2.Element element1, final org.jdom2.Element element2) {
331 final Namespace namespace = element1.getNamespace();
332 if (element1.getName().equals(element2.getName()) && element1.getNamespace().equals(element2.getNamespace())) {
333 if (element1.getChildText(COMPONENT_CLASS, namespace).equals(element2.getChildText(COMPONENT_CLASS, namespace))) {
334 if (element1.getChildText(COMPONENT_TYPE, namespace).equals(element2.getChildText(COMPONENT_TYPE, namespace))) {
335 return true;
336 }
337 }
338 }
339 return false;
340 }
341
342 protected org.jdom2.Element createComponentElement(
343 final ComponentInfo componentInfo, final UIComponentTag componentTag, final Namespace namespace)
344 throws IOException, NoSuchFieldException, IllegalAccessException {
345 final org.jdom2.Element element = new org.jdom2.Element(COMPONENT, namespace);
346 final org.jdom2.Element elementDisplayName = new org.jdom2.Element(DISPLAY_NAME, namespace);
347 elementDisplayName.setText(componentInfo.getComponentClassName());
348 element.addContent(elementDisplayName);
349 final org.jdom2.Element elementType = new org.jdom2.Element(COMPONENT_TYPE, namespace);
350 elementType.setText(componentInfo.getComponentType());
351 element.addContent(elementType);
352 final org.jdom2.Element elementClass = new org.jdom2.Element(COMPONENT_CLASS, namespace);
353 elementClass.setText(componentTag.uiComponent());
354 element.addContent(elementClass);
355
356 return element;
357 }
358
359 protected void addRendererElement(
360 final ComponentInfo componentInfo, final UIComponentTag componentTag, final List<org.jdom2.Element> renderer,
361 final Namespace namespace)
362 throws IOException, NoSuchFieldException, IllegalAccessException {
363 for (final String rendererType : componentTag.rendererType()) {
364 final org.jdom2.Element element = new org.jdom2.Element(RENDERER, namespace);
365 String displayName = componentTag.displayName();
366 if (displayName.equals("")) {
367 displayName = componentInfo.getComponentClassName();
368 }
369 final org.jdom2.Element elementDisplayName = new org.jdom2.Element(DISPLAY_NAME, namespace);
370 elementDisplayName.setText(displayName);
371 element.addContent(elementDisplayName);
372 final org.jdom2.Element elementComponentFamily = new org.jdom2.Element(COMPONENT_FAMILY, namespace);
373 elementComponentFamily.addContent(componentInfo.getComponentFamily());
374 element.addContent(elementComponentFamily);
375 final org.jdom2.Element elementType = new org.jdom2.Element(RENDERER_TYPE, namespace);
376 elementType.setText(rendererType);
377 element.addContent(elementType);
378 final org.jdom2.Element elementClass = new org.jdom2.Element(RENDERER_CLASS, namespace);
379 final String className = "org.apache.myfaces.tobago.internal.renderkit.renderer." + rendererType + "Renderer";
380 elementClass.setText(className);
381 element.addContent(elementClass);
382 renderer.add(element);
383 }
384 }
385
386
387 private org.jdom2.Element createElementExtension(
388 final TypeElement typeElement, final UIComponentTag uiComponentTag,
389 final Namespace namespace) {
390 final org.jdom2.Element elementExtension = new org.jdom2.Element(COMPONENT_EXTENSION, namespace);
391 final org.jdom2.Element elementAllowedChildComponents = new org.jdom2.Element(ALLOWED_CHILD_COMPONENTS, namespace);
392 final String[] allowedChildComponents = uiComponentTag.allowedChildComponenents();
393 final StringBuilder allowedComponentTypes = new StringBuilder();
394 for (final String componentType : allowedChildComponents) {
395 allowedComponentTypes.append(componentType).append(" ");
396 }
397 elementAllowedChildComponents.setText(allowedComponentTypes.toString());
398 elementExtension.addContent(elementAllowedChildComponents);
399 final org.jdom2.Element elementCategory = new org.jdom2.Element(CATEGORY, namespace);
400 elementCategory.setText(uiComponentTag.category().toString());
401 elementExtension.addContent(elementCategory);
402 final Deprecated deprecated = typeElement.getAnnotation(Deprecated.class);
403 if (deprecated != null) {
404 final org.jdom2.Element elementDeprecated = new org.jdom2.Element(DEPRECATED, namespace);
405 elementDeprecated.setText("Warning: This component is deprecated!");
406 elementExtension.addContent(elementDeprecated);
407 }
408 final org.jdom2.Element elementHidden = new org.jdom2.Element(HIDDEN, namespace);
409 elementHidden.setText(Boolean.toString(uiComponentTag.isHidden()));
410 elementExtension.addContent(elementHidden);
411
412 return elementExtension;
413 }
414
415 protected void addAttribute(
416 final ExecutableElement executableElement, final List<org.jdom2.Element> attributes,
417 final List<org.jdom2.Element> properties,
418 final Namespace namespace) {
419 final UIComponentTagAttribute componentAttribute = executableElement.getAnnotation(UIComponentTagAttribute.class);
420 if (componentAttribute != null) {
421 final String simpleName = executableElement.getSimpleName().toString();
422 if (simpleName.startsWith("set")) {
423 final String name = simpleName.substring(3, 4).toLowerCase(Locale.ENGLISH) + simpleName.substring(4);
424 if (IGNORED_PROPERTIES.contains(name)) {
425 final org.jdom2.Element attribute = new org.jdom2.Element(ATTRIBUTE, namespace);
426 final org.jdom2.Element attributeName = new org.jdom2.Element(ATTRIBUTE_NAME, namespace);
427 final org.jdom2.Element attributeClass = new org.jdom2.Element(ATTRIBUTE_CLASS, namespace);
428
429 attributeName.setText(name);
430 addClass(componentAttribute, attributeClass);
431
432 addDescription(executableElement, attribute, namespace);
433
434 attribute.addContent(attributeName);
435 attribute.addContent(attributeClass);
436 if (componentAttribute.defaultValue().length() > 0) {
437 final org.jdom2.Element defaultValue = new org.jdom2.Element(DEFAULT_VALUE, namespace);
438 defaultValue.setText(componentAttribute.defaultValue());
439 attribute.addContent(defaultValue);
440 }
441
442 attribute.addContent(createPropertyOrAttributeExtension(ATTRIBUTE_EXTENSION, executableElement,
443 componentAttribute, namespace));
444
445 attributes.add(attribute);
446 } else {
447 final org.jdom2.Element property = new org.jdom2.Element(PROPERTY, namespace);
448 final org.jdom2.Element propertyName = new org.jdom2.Element(PROPERTY_NAME, namespace);
449 final org.jdom2.Element propertyClass = new org.jdom2.Element(PROPERTY_CLASS, namespace);
450
451 propertyName.setText(name);
452 addClass(componentAttribute, propertyClass);
453
454 addDescription(executableElement, property, namespace);
455
456 property.addContent(propertyName);
457 property.addContent(propertyClass);
458 if (componentAttribute.defaultValue().length() > 0) {
459 final org.jdom2.Element defaultValue = new org.jdom2.Element(DEFAULT_VALUE, namespace);
460 defaultValue.setText(componentAttribute.defaultValue());
461 property.addContent(defaultValue);
462 }
463
464 property.addContent(
465 createPropertyOrAttributeExtension(PROPERTY_EXTENSION, executableElement, componentAttribute, namespace));
466 properties.add(property);
467 }
468 } else {
469 throw new IllegalArgumentException("Only setter allowed found: " + simpleName);
470 }
471 }
472 }
473
474 private void addClass(final UIComponentTagAttribute componentAttribute, final org.jdom2.Element attributeClass) {
475 if (componentAttribute.type().length > 1) {
476 attributeClass.setText(Object.class.getName());
477 } else if (componentAttribute.type().length == 1) {
478 String className = componentAttribute.type()[0];
479 if (componentAttribute.expression().isMethodExpression()) {
480 className = "javax.el.MethodExpression";
481 }
482 attributeClass.setText(className);
483 } else {
484 if (componentAttribute.expression().isMethodExpression()) {
485 attributeClass.setText("javax.el.MethodExpression");
486 }
487 }
488 }
489
490 private void addDescription(
491 final ExecutableElement element, final org.jdom2.Element attribute, final Namespace namespace) {
492 String comment = processingEnv.getElementUtils().getDocComment(element);
493 if (comment != null) {
494 final int index = comment.indexOf('@');
495 if (index != -1) {
496 comment = comment.substring(0, index);
497 }
498 comment = comment.trim();
499 if (comment.length() > 0) {
500 final org.jdom2.Element description = new org.jdom2.Element(DESCRIPTION, namespace);
501 description.setText(comment);
502 attribute.addContent(description);
503 }
504 }
505 }
506
507 private org.jdom2.Element createPropertyOrAttributeExtension(
508 final String extensionType, final ExecutableElement executableElement,
509 final UIComponentTagAttribute uiComponentTagAttribute,
510 final Namespace namespace)
511 throws IllegalArgumentException {
512 final org.jdom2.Element extensionElement = new org.jdom2.Element(extensionType, namespace);
513 final org.jdom2.Element valueExpression = new org.jdom2.Element(VALUE_EXPRESSION, namespace);
514 valueExpression.setText(uiComponentTagAttribute.expression().toMetaDataString());
515 extensionElement.addContent(valueExpression);
516 final String[] allowedValues = uiComponentTagAttribute.allowedValues();
517 if (allowedValues.length > 0) {
518 final org.jdom2.Element propertyValues = new org.jdom2.Element(PROPERTY_VALUES, namespace);
519 final StringBuilder values = new StringBuilder();
520 for (final String value : allowedValues) {
521 values.append(value).append(" ");
522 }
523 propertyValues.setText(values.toString());
524 extensionElement.addContent(propertyValues);
525 }
526 final Deprecated deprecated = executableElement.getAnnotation(Deprecated.class);
527 if (deprecated != null) {
528 final org.jdom2.Element elementDeprecated = new org.jdom2.Element(DEPRECATED, namespace);
529 elementDeprecated.setText("Warning: This property is deprecated!");
530 extensionElement.addContent(elementDeprecated);
531 }
532 final org.jdom2.Element hidden = new org.jdom2.Element(HIDDEN, namespace);
533 hidden.setText(Boolean.toString(uiComponentTagAttribute.isHidden()));
534 extensionElement.addContent(hidden);
535 final org.jdom2.Element readOnly = new org.jdom2.Element(READONLY, namespace);
536 readOnly.setText(Boolean.toString(uiComponentTagAttribute.isReadOnly()));
537 extensionElement.addContent(readOnly);
538 final TagAttribute tagAttribute = executableElement.getAnnotation(TagAttribute.class);
539 if (tagAttribute != null) {
540 final org.jdom2.Element required = new org.jdom2.Element(REQUIRED, namespace);
541 required.setText(Boolean.toString(tagAttribute.required()));
542 extensionElement.addContent(required);
543 }
544
545 return extensionElement;
546 }
547
548 protected void addAttributes(
549 final TypeElement typeElement, final List<org.jdom2.Element> attributes, final List<org.jdom2.Element> properties,
550 final Namespace namespace) {
551
552 for (final javax.lang.model.element.Element element : processingEnv.getElementUtils().getAllMembers(typeElement)) {
553 final ExecutableElement executableElement = (ExecutableElement) element;
554 if (executableElement.getAnnotation(TagAttribute.class) == null
555 && executableElement.getAnnotation(UIComponentTagAttribute.class) == null) {
556 continue;
557 }
558
559 addAttribute(executableElement, attributes, properties, namespace);
560 }
561 }
562
563 private void addFacets(
564 final UIComponentTag componentTag, final Namespace namespace, final org.jdom2.Element element) {
565 final Facet[] facets = componentTag.facets();
566 for (final Facet facet : facets) {
567 final org.jdom2.Element facetElement = new org.jdom2.Element(FACET, namespace);
568 final String description = facet.description();
569 if (description.length() > 0) {
570 final org.jdom2.Element facetDescription = new org.jdom2.Element(DESCRIPTION, namespace);
571 facetDescription.setText(description);
572 facetElement.addContent(facetDescription);
573 }
574 final org.jdom2.Element facetName = new org.jdom2.Element(FACET_NAME, namespace);
575 facetName.setText(facet.name());
576 facetElement.addContent(facetName);
577 final org.jdom2.Element facetExtension = new org.jdom2.Element(FACET_EXTENSION, namespace);
578 final org.jdom2.Element elementAllowedChildComponents
579 = new org.jdom2.Element(ALLOWED_CHILD_COMPONENTS, namespace);
580 final String[] allowedChildComponents = facet.allowedChildComponenents();
581 final StringBuilder allowedComponentTypes = new StringBuilder();
582 for (final String componentType : allowedChildComponents) {
583 allowedComponentTypes.append(componentType).append(" ");
584 }
585 elementAllowedChildComponents.setText(allowedComponentTypes.toString());
586 facetExtension.addContent(elementAllowedChildComponents);
587 facetElement.addContent(facetExtension);
588 element.addContent(facetElement);
589 }
590 }
591
592 protected void addElement(
593 final TypeElement typeElement, final List<org.jdom2.Element> components, final List<org.jdom2.Element> renderer,
594 final Namespace namespace) throws Exception {
595 final UIComponentTag componentTag = typeElement.getAnnotation(UIComponentTag.class);
596 if (componentTag != null) {
597 final ComponentInfo componentInfo = new ComponentInfo(typeElement, componentTag);
598 if (!componentTag.isComponentAlreadyDefined()) {
599 final org.jdom2.Element element = createComponentElement(componentInfo, componentTag, namespace);
600 if (element != null) {
601 if (!containsElement(components, element)) {
602 addFacets(componentTag, namespace, element);
603 final List<org.jdom2.Element> attributes = new ArrayList<>();
604 final List<org.jdom2.Element> properties = new ArrayList<>();
605 addAttributes(typeElement, attributes, properties, namespace);
606 if (!attributes.isEmpty()) {
607 attributes.sort(Comparator.comparing(d -> d.getChildText(ATTRIBUTE_NAME, namespace)));
608 element.addContent(attributes);
609 }
610 if (!properties.isEmpty()) {
611 properties.sort(Comparator.comparing(d -> d.getChildText(PROPERTY_NAME, namespace)));
612 element.addContent(properties);
613 }
614 element.addContent(createElementExtension(typeElement, componentTag, namespace));
615 components.add(element);
616 } else {
617
618 }
619 }
620 }
621 addRendererElement(componentInfo, componentTag, renderer, namespace);
622 }
623 }
624
625 private void normaliseLineEndings(final Document document) {
626 final Iterator i = document.getDescendants(new ContentFilter(ContentFilter.COMMENT));
627 while (i.hasNext()) {
628 final Comment c = (Comment) i.next();
629 c.setText(c.getText().replaceAll("\n", SEPARATOR));
630 }
631 }
632 }