package org.richfaces.cdk.apt.processors;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import org.richfaces.cdk.CdkException;
import org.richfaces.cdk.Logger;
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.Signature;
import org.richfaces.cdk.apt.SourceUtils;
import org.richfaces.cdk.apt.SourceUtils.BeanProperty;
import org.richfaces.cdk.apt.SourceUtils.SuperTypeVisitor;
import org.richfaces.cdk.model.BeanModelBase;
import org.richfaces.cdk.model.ClassName;
import org.richfaces.cdk.model.MethodSignature;
import org.richfaces.cdk.model.PropertyBase;
import org.richfaces.cdk.util.JavaUtils;
import org.richfaces.cdk.xmlconfig.CdkEntityResolver;
import org.richfaces.cdk.xmlconfig.FragmentParser;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* <p class="changed_added_4_0">
* </p>
*
* @author asmirnov@exadel.com
*
*/
public class AttributesProcessorImpl implements AttributesProcessor {
private static final ClassName SIGNATURE_NONE_CLASS_NAME = ClassName.get(Signature.NONE.class);
private static final ClassName STRING_TYPE = ClassName.get(String.class);
@Inject
private Logger log;
private final DescriptionProcessor descriptionProcessor;
private final Provider<SourceUtils> utilsProvider;
private final FragmentParser parser;
/**
* <p class="changed_added_4_0">
* </p>
*
* @param descriptionProcessor
* @param utilsProvider
* @param parser
*/
@Inject
public AttributesProcessorImpl(DescriptionProcessor descriptionProcessor, Provider<SourceUtils> utilsProvider,
FragmentParser parser) {
this.descriptionProcessor = descriptionProcessor;
this.utilsProvider = utilsProvider;
this.parser = parser;
}
protected void processAttribute(SourceUtils.BeanProperty beanProperty, PropertyBase attribute) {
attribute.setType(beanProperty.getType());
AnnotationMirror attributeAnnotarion = beanProperty.getAnnotationMirror(Attribute.class);
if (attributeAnnotarion == null) {
attribute.setGenerate(!beanProperty.isExists());
attribute.setDescription(beanProperty.getDocComment());
attribute.setHidden(true);
if (attribute.getType().isPrimitive()) {
String value = getPimitiveDefaultValue(attribute.getType().getName());
if (value != null) {
attribute.setDefaultValue(value);
}
}
} else {
SourceUtils utils = utilsProvider.get();
utils.setModelProperty(attribute, attributeAnnotarion, "hidden");
utils.setModelProperty(attribute, attributeAnnotarion, "literal");
utils.setModelProperty(attribute, attributeAnnotarion, "passThrough");
utils.setModelProperty(attribute, attributeAnnotarion, "required");
utils.setModelProperty(attribute, attributeAnnotarion, "readOnly");
if (!utils.isDefaultValue(attributeAnnotarion, "generate")) {
attribute.setGenerate(utils.getAnnotationValue(attributeAnnotarion, "generate", boolean.class));
} else {
attribute.setGenerate(!beanProperty.isExists());
}
descriptionProcessor.processDescription(attribute,
utils.getAnnotationValue(attributeAnnotarion, "description", AnnotationMirror.class),
beanProperty.getDocComment());
setDefaultValue(attribute, attributeAnnotarion);
utils.setModelProperty(attribute, attributeAnnotarion, "suggestedValue");
// MethodExpression call signature.
attribute.setSignature(getSignature(attributeAnnotarion));
for (AnnotationMirror event : utils.getAnnotationValues(attributeAnnotarion, "events", AnnotationMirror.class)) {
setBehaviorEvent(attribute, event);
}
}
}
private void setDefaultValue(PropertyBase attribute, AnnotationMirror attributeAnnotarion) {
SourceUtils utils = utilsProvider.get();
String defaultValue;
// TODO - move to model validator.
if (utils.isDefaultValue(attributeAnnotarion, "defaultValue")) {
if (attribute.getType().isPrimitive()) {
String pimitiveDefaultValue = getPimitiveDefaultValue(attribute.getType().getName());
attribute.setDefaultValue(pimitiveDefaultValue);
}
} else {
defaultValue = utils.getAnnotationValue(attributeAnnotarion, "defaultValue", String.class);
if (STRING_TYPE.equals(attribute.getType())) {
defaultValue = JavaUtils.getEscapedString(defaultValue);
}
attribute.setDefaultValue(defaultValue);
}
}
private String getPimitiveDefaultValue(String typeName) {
if (isInstace(boolean.class, typeName)) {
return "false";
} else if (isInstace(int.class, typeName)) {
return "Integer.MIN_VALUE";
} else if (isInstace(long.class, typeName)) {
return "Long.MIN_VALUE";
} else if (isInstace(byte.class, typeName)) {
return "Byte.MIN_VALUE";
} else if (isInstace(short.class, typeName)) {
return "Short.MIN_VALUE";
} else if (isInstace(float.class, typeName)) {
return "Float.MIN_VALUE";
} else if (isInstace(double.class, typeName)) {
return "Double.MIN_VALUE";
} else if (isInstace(char.class, typeName)) {
return "Character.MIN_VALUE";
}
return null;
}
private boolean isInstace(Class<?> byteClass, String typeName) {
return byteClass.getSimpleName().equals(typeName);
}
private MethodSignature getSignature(AnnotationMirror attributeAnnotarion) {
SourceUtils utils = utilsProvider.get();
if (!utils.isDefaultValue(attributeAnnotarion, "signature")) {
AnnotationMirror signatureAnnotation = utils.getAnnotationValue(attributeAnnotarion, "signature",
AnnotationMirror.class);
ClassName returnType = utils.getAnnotationValue(signatureAnnotation, "returnType", ClassName.class);
if (!SIGNATURE_NONE_CLASS_NAME.equals(returnType)) {
MethodSignature methodSignature = new MethodSignature();
methodSignature.setParameters(Lists.newArrayList(utils.getAnnotationValues(signatureAnnotation, "parameters",
ClassName.class)));
methodSignature.setReturnType(returnType);
return methodSignature;
}
}
return null;
}
private void setBehaviorEvent(PropertyBase attribute, AnnotationMirror eventMirror) {
if (null != eventMirror) {
SourceUtils utils = utilsProvider.get();
org.richfaces.cdk.model.EventName event = new org.richfaces.cdk.model.EventName();
utils.setModelProperty(event, eventMirror, "name", "value");
utils.setModelProperty(event, eventMirror, "defaultEvent");
attribute.getEventNames().add(event);
}
}
@Override
public void processType(final BeanModelBase component, TypeElement element) throws CdkException {
log.debug("AttributesProcessorImpl.processType");
log.debug(" -> component = " + component);
log.debug(" -> typeElement = " + element);
log.debug(" -- Process XML files with standard attributes definitions.");
log.debug(" -> sourceUtils.visitSupertypes...");
SourceUtils sourceUtils = getSourceUtils();
sourceUtils.visitSupertypes(element, new SuperTypeVisitor() {
@Override
public void visit(TypeMirror type) {
String uri = type.toString() + ".xml";
try {
log.debug(" -> visit - " + type.toString());
component.getAttributes().addAll(parseProperties(uri));
} catch (CdkException e) {
log.error(e);
} catch (FileNotFoundException e) {
log.debug("No properties description found at " + uri);
}
}
});
log.debug(" -- Process Java files.");
Set<BeanProperty> properties = Sets.newHashSet();
properties.addAll(sourceUtils.getBeanPropertiesAnnotatedWith(Attribute.class, element));
// properties.addAll(sourceUtils.getAbstractBeanProperties(element));
for (BeanProperty beanProperty : properties) {
processAttribute(beanProperty, component.getOrCreateAttribute(beanProperty.getName()));
}
}
private Collection<? extends PropertyBase> parseProperties(String uri) throws FileNotFoundException {
return parser.parseProperties(CdkEntityResolver.URN_ATTRIBUTES + uri);
}
private SourceUtils getSourceUtils() {
return utilsProvider.get();
}
@Override
public void processXmlFragment(BeanModelBase component, String... attributesConfig) {
// Process all files from @Jsf.. attributes property.
for (String attributes : attributesConfig) {
try {
component.getAttributes().addAll(parseProperties(attributes));
} catch (CdkException e) {
log.error(e);
} catch (FileNotFoundException e) {
log.error("No properties description found at " + attributes);
}
}
}
}