/*
* $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());
}
}));
}
}