/* * $Id$ * * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * This library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.richfaces.cdk.generate.freemarker; import java.util.NoSuchElementException; import java.util.Set; import org.richfaces.cdk.model.BehaviorModel; import org.richfaces.cdk.model.ClassName; import org.richfaces.cdk.model.ComponentModel; import org.richfaces.cdk.model.ConverterModel; import org.richfaces.cdk.model.EventModel; import org.richfaces.cdk.model.EventName; import org.richfaces.cdk.model.MethodSignature; import org.richfaces.cdk.model.ModelElementBase; import org.richfaces.cdk.model.PropertyBase; import org.richfaces.cdk.model.ValidatorModel; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.StringModel; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * <p class="changed_added_4_0"> * </p> * * @author asmirnov@exadel.com * */ public class ModelElementBaseTemplateModel extends StringModel implements TemplateModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new ModelElementBaseTemplateModel((ModelElementBase) object, (BeansWrapper) wrapper); } }; private final ModelElementBase model; private Set<EventName> eventNames; private final String name; /** * <p class="changed_added_4_0"> * </p> * * @param object * @param wrapper */ public ModelElementBaseTemplateModel(ModelElementBase object, BeansWrapper wrapper) { super(object, wrapper); model = object; if (model instanceof ComponentModel) { this.name = "Component"; } else if (model instanceof BehaviorModel) { this.name = "Behavior"; } else if (model instanceof ConverterModel) { this.name = "Converter"; } else if (model instanceof ValidatorModel) { this.name = "Validator"; } else { this.name = "UnknownModelElement"; } } @Override public String getAsString() { return name; } @Override public TemplateModel get(String key) throws TemplateModelException { if ("requiredAttributes".equals(key)) { return requiredAttributes(); } else if ("generatedAttributes".equals(key)) { return generatedAttributes(); } else if ("tagAttributes".equals(key)) { return tagAttributes(); } else if ("eventNames".equals(key)) { return eventNames(); } else if ("defaultEvent".equals(key)) { return defaultEvent(); } else if ("importClasses".equals(key)) { return getImportClasses(); } else if ("implemented".equals(key)) { return getImplementedInterfaces(); } else if ("tagImports".equals(key)) { return getTagImports(); } else if ("hasBindingAttribute".equals(key)) { return hasBindingAttribute(); } return super.get(key); } public TemplateModel getImportClasses() throws TemplateModelException { Set<ClassName> result = Sets.newTreeSet(); String targetPackage = model.getTargetClass().getPackage(); for (PropertyBase entry : model.getAttributes()) { if (entry.getGenerate()) { addIfNecessary(targetPackage, result, entry.getType()); } } // Import all interfaces implemented by the generated class. result.addAll(model.getInterfaces()); if (model instanceof ComponentModel) { ComponentModel component = (ComponentModel) model; for (EventModel event : component.getEvents()) { addIfNecessary(targetPackage, result, event.getSourceInterface()); addIfNecessary(targetPackage, result, event.getListenerInterface()); } } // Collection<String> list = new ArrayList<String>(result); return this.wrapper.wrap(result); } private void addIfNecessary(String pkg, Set<ClassName> classNames, ClassName toadd) { if (null != toadd && !isPredefined(toadd) && !pkg.equals(toadd.getPackage())) { classNames.add(toadd); } } public TemplateModel getTagImports() throws TemplateModelException { Set<ClassName> result = Sets.newTreeSet(); for (PropertyBase entry : model.getAttributes()) { if (!(entry.isHidden() || entry.isReadOnly() || null == entry.getSignature())) { MethodSignature methodSignature = entry.getSignature(); if (!isPredefined(methodSignature.getReturnType())) { result.add(methodSignature.getReturnType()); } for (ClassName className : methodSignature.getParameters()) { if (!isPredefined(className)) { result.add(className); } } } } return this.wrapper.wrap(result); } public TemplateModel hasBindingAttribute() throws TemplateModelException { return wrapper.wrap(Iterables.any(model.getAttributes(), new Predicate<PropertyBase>() { @Override public boolean apply(PropertyBase input) { return input.isBindingAttribute(); } })); } public TemplateModel getImplementedInterfaces() throws TemplateModelException { Set<ClassName> result = Sets.newTreeSet(); // Import all interfaces implemented by the generated class. result.addAll(model.getInterfaces()); if (model instanceof ComponentModel) { ComponentModel component = (ComponentModel) model; if (getEventNames().size() > 0) { result.add(ClassName.parseName("javax.faces.component.behavior.ClientBehaviorHolder")); } for (EventModel event : component.getEvents()) { ClassName sourceInterface = event.getSourceInterface(); if (null != sourceInterface) { result.add(sourceInterface); } } } // Collection<String> list = new ArrayList<String>(result); return this.wrapper.wrap(result); } public boolean isPredefined(PropertyBase property) { return isPredefined(property.getType()); } public boolean isPredefined(ClassName type) { return type.isPrimitive() || "java.lang".equals(type.getPackage()); } private TemplateModel eventNames() throws TemplateModelException { return wrapper.wrap(getEventNames()); } private TemplateModel defaultEvent() throws TemplateModelException { Set<EventName> names = getEventNames(); try { EventName defaultEvent = Iterables.find(names, new Predicate<EventName>() { @Override public boolean apply(EventName event) { return event.isDefaultEvent(); } }); return wrapper.wrap(defaultEvent); } catch (NoSuchElementException e) { return wrapper.wrap(null); } } private Set<EventName> getEventNames() { if (null == eventNames) { eventNames = Sets.newHashSet(); for (PropertyBase property : model.getAttributes()) { eventNames.addAll(property.getEventNames()); } } return eventNames; } private TemplateModel requiredAttributes() throws TemplateModelException { return wrapper.wrap(Collections2.filter(model.getAttributes(), new Predicate<PropertyBase>() { @Override public boolean apply(PropertyBase input) { return input.isRequired(); } })); } private TemplateModel generatedAttributes() throws TemplateModelException { return wrapper.wrap(Collections2.filter(model.getAttributes(), new Predicate<PropertyBase>() { @Override public boolean apply(PropertyBase input) { return input.getGenerate(); } })); } private TemplateModel tagAttributes() throws TemplateModelException { return wrapper.wrap(Collections2.filter(model.getAttributes(), new Predicate<PropertyBase>() { @Override public boolean apply(PropertyBase input) { return !(input.isHidden() || input.isReadOnly()); } })); } }