/* * JBoss, Home of Professional Open Source * Copyright , Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.richfaces.cdk.generate.taglib; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.richfaces.cdk.annotations.TagType; import org.richfaces.cdk.model.BeanModelBase; import org.richfaces.cdk.model.BehaviorModel; import org.richfaces.cdk.model.ComponentLibrary; import org.richfaces.cdk.model.ComponentModel; import org.richfaces.cdk.model.ConverterModel; import org.richfaces.cdk.model.DescriptionGroup; import org.richfaces.cdk.model.EventModel; import org.richfaces.cdk.model.FacesId; import org.richfaces.cdk.model.FunctionModel; import org.richfaces.cdk.model.PropertyBase; import org.richfaces.cdk.model.SimpleVisitor; import org.richfaces.cdk.model.TagModel; import org.richfaces.cdk.model.ValidatorModel; import org.richfaces.cdk.util.Strings; /** * @author akolonitsky * @since Feb 3, 2010 */ public class TaglibGeneratorVisitor extends SimpleVisitor<Boolean, ComponentLibrary> { private static final String COMPONENT = "component"; private static final String COMPONENT_TYPE = "component-type"; private static final String RENDERER_TYPE = "renderer-type"; private static final String HANDLER_CLASS = "handler-class"; /** * <p class="changed_added_4_0"> * Generated document. IDEA - set document as visitor patameter, to reuse this object instance. * </p> */ private Document document = DocumentHelper.createDocument(); /** * <p class="changed_added_4_0"> * faces-config element in document. * </p> */ private Element faceletTaglib; private boolean empty = true; public TaglibGeneratorVisitor() { } /** * <p class="changed_added_4_0"> * </p> * * @return the empty */ public boolean isEmpty() { return this.empty; } public Document getDocument() { return document; } public void setDocument(Document document) { this.document = document; } @Override public Boolean visitComponentLibrary(ComponentLibrary model, ComponentLibrary componentLibrary) { faceletTaglib = document.addElement("facelet-taglib", "http://java.sun.com/xml/ns/javaee"); faceletTaglib.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); faceletTaglib.addAttribute("xsi:schemaLocation", "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"); faceletTaglib.addAttribute("version", "2.0"); faceletTaglib.addAttribute("id", model.getTaglib().getShortName()); faceletTaglib.addElement("namespace").addText(model.getTaglib().getUri()); return null; } @Override public Boolean visitComponent(ComponentModel model, ComponentLibrary componentLibrary) { for (TagModel tagModel : model.getTags()) { if (isFaceletsTag(tagModel)) { Element tag = createTag(tagModel.getName()); // TODO - investigate proper usage of the <handler-class> element. // Most libraries use <handler-class> INSTEAD of <component> Element component = tag.addElement(COMPONENT); addDescription(tag, model); addDescription(component, model); component.addElement(COMPONENT_TYPE).addText(model.getId().getType()); FacesId rendererType = model.getRendererType(); // RendererModel renderer = componentLibrary.getRenderer(model.getFamily(), model.getId().getType()); if (null != rendererType) { component.addElement(RENDERER_TYPE).addText(rendererType.toString()); } addTagHandler(component, tagModel); appendAttributes(tag, model); empty = false; } } return null; } /** * <p class="changed_added_4_0"> * </p> * * @param parent DOM element for which <handler-class> element should be appended. * @param tag model. * @return true is explicit handler class definition was generated. */ private boolean addTagHandler(Element parent, TagModel tag) { if (tag != null && tag.getTargetClass() != null) { parent.addElement(HANDLER_CLASS).addText(tag.getTargetClass().getName()); return true; } else { return false; } } @Override public Boolean visitConverter(ConverterModel model, ComponentLibrary componentLibrary) { for (TagModel tagModel : model.getTags()) { if (isFaceletsTag(tagModel)) { Element tag = createTag(tagModel.getName()); Element converter = tag.addElement("converter"); addDescription(tag, model); addDescription(converter, model); converter.addElement("converter-id").addText(model.getId().toString()); addTagHandler(converter, tagModel); appendAttributes(tag, model); empty = false; } } return null; } /** * This method generates validator tag. * * <pre> * <tag> * <tag-name>formatValidator</tag-name> * <validator> * <validator-id></validator-id> * <handler-class></handler-class> * </validator> * * <attribute> * ... * </attribute> * </tag> * * <pre> * * */ public Boolean visitValidator(ValidatorModel model, ComponentLibrary componentLibrary) { for (TagModel tagModel : model.getTags()) { if (isFaceletsTag(tagModel)) { Element tag = createTag(tagModel.getName()); Element validator = tag.addElement("validator"); addDescription(tag, model); addDescription(validator, model); validator.addElement("validator-id").addText(model.getId().toString()); addTagHandler(validator, tagModel); appendAttributes(tag, model); empty = false; } } return null; } private void appendAttributes(Element tag, BeanModelBase model) { for (PropertyBase entry : model.getAttributes()) { if (!entry.isHidden() && !entry.isReadOnly()) { createAttributeElement(tag, entry.getName(), entry); } } } /** * <attribute> <description></description> <name>formatPatterns</name> <required>true</required> <type>String</type> * </attribute> * * @param tag * @param name * @param attribute * * @return * */ private Element createAttributeElement(Element tag, String name, PropertyBase attribute) { Element attr = tag.addElement("attribute"); addDescription(attr, attribute); attr.addElement("name").addText(name); if (attribute.isRequired()) { attr.addElement("required").addText("true"); } attr.addElement("type").addText(attribute.getType().getName()); return attr; } private Element createTag(String tagName) { Element tag = faceletTaglib.addElement("tag"); tag.addElement("tag-name").addText(tagName); empty = false; return tag; } @Override public Boolean visitBehavior(BehaviorModel model, ComponentLibrary componentLibrary) { for (TagModel tagModel : model.getTags()) { if (isFaceletsTag(tagModel)) { Element tag = createTag(tagModel.getName()); Element behavior = tag.addElement("behavior"); addDescription(tag, model); addDescription(behavior, model); behavior.addElement("behavior-id").addText(model.getId().toString()); addTagHandler(behavior, tagModel); appendAttributes(tag, model); empty = false; } } return null; } @Override public Boolean visitFunction(FunctionModel model, ComponentLibrary componentLibrary) { if (isFaceletsTag(model.getType())) { Element functionElement = faceletTaglib.addElement("function"); addDescription(functionElement, model); functionElement.addElement("function-name").addText(model.getName()); functionElement.addElement("function-class").addText(model.getFunctionClass().getName()); functionElement.addElement("function-signature").addText(model.getSignature()); empty = false; } return null; } @Override public Boolean visitEvent(EventModel model, ComponentLibrary param) { for (TagModel tagModel : model.getTags()) { if (isFaceletsTag(tagModel)) { Element tag = createTag(tagModel.getName()); addDescriptionForListener(tag, model); addTagHandler(tag, tagModel); appendAttributesForListener(tag, model); } } return null; } private void addDescriptionForListener(Element tag, EventModel model) { Element desc = tag.addElement("description"); String description = model.getDescription() == null ? "" : model.getDescription(); desc.setText(description); } private void appendAttributesForListener(Element tag, EventModel model) { for (ListenerAttribute attribute : ListenerAttribute.values()) { PropertyBase property = attribute.derivateProperty(model); createAttributeElement(tag, property.getName(), property); } } private boolean isFaceletsTag(TagType type) { return TagType.Facelets.equals(type) || TagType.All.equals(type); } private boolean isFaceletsTag(TagModel tagModel) { return isFaceletsTag(tagModel.getType()); } /** * <p class="changed_added_4_0"> * Add common description elements. * </p> * * @param parent * @param model */ private void addDescription(Element parent, DescriptionGroup model) { if (!Strings.isEmpty(model.getDescription())) { parent.addElement("description").addText(model.getDescription()); } if (!Strings.isEmpty(model.getDisplayName())) { parent.addElement("display-name").addText(model.getDisplayName()); } if (null != model.getIcon()) { Element iconElement = parent.addElement("icon"); if (!Strings.isEmpty(model.getIcon().getSmallIcon())) { iconElement.addElement("small-icon").addText(model.getIcon().getSmallIcon()); } if (!Strings.isEmpty(model.getIcon().getLargeIcon())) { iconElement.addElement("large-icon").addText(model.getIcon().getLargeIcon()); } } } }