package org.springframework.roo.addon.web.mvc.thymeleaf.addon;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooWebMvcThymeleafUIConfiguration;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.SpringJavaType;
import org.springframework.roo.project.LogicalPath;
/**
* Metadata for {@link RooWebMvcThymeleafUIConfiguration}.
*
* @author Jose Manuel Vivó
* @since 2.0
*/
public class ThymeleafUIConfigurationMetadata extends AbstractItdTypeDetailsProvidingMetadataItem {
private static final List<AnnotationMetadataBuilder> AUTOWIRED_LIST = Arrays
.asList(new AnnotationMetadataBuilder(SpringJavaType.AUTOWIRED));
private static final String PROVIDES_TYPE_STRING = ThymeleafUIConfigurationMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
private static final JavaType THYMELEAF_VIEW_RESOLVER = new JavaType(
"org.thymeleaf.spring4.view.ThymeleafViewResolver");
private static final JavaType SPRING_RESOURCE_TEMPLATE_RESOLVER = new JavaType(
"org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver");
private static final JavaType APPLICATION_CONTEXT_AWARE = new JavaType(
"org.springframework.context.ApplicationContextAware");
private static final JavaType TEMPLATE_ENGINE = new JavaType("org.thymeleaf.TemplateEngine");
private static final JavaType THYMELEAF_PROPERTIES = new JavaType(
"org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties");
private static final JavaType TEMPLATE_MODE = new JavaType(
"org.thymeleaf.templatemode.TemplateMode");
private static final JavaType APPLICATION_CONTEXT = new JavaType(
"org.springframework.context.ApplicationContext");
public static String createIdentifier(final JavaType javaType, final LogicalPath path) {
return PhysicalTypeIdentifierNamingUtils.createIdentifier(PROVIDES_TYPE_STRING, javaType, path);
}
public static JavaType getJavaType(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getJavaType(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
public static String getMetadataIdentiferType() {
return PROVIDES_TYPE;
}
public static LogicalPath getPath(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
public static boolean isValid(final String metadataIdentificationString) {
return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING,
metadataIdentificationString);
}
private final MethodMetadata javascriptThymeleafViewResolverMethod;
private final MethodMetadata javascriptTemplateResolverMethod;
private final FieldMetadata applicationContextAwareField;
private final MethodMetadata setApplicationContextMethod;
private final FieldMetadata thymeleafPropertiesField;
private final FieldMetadata templateEngineField;
/**
* Constructor
*
* @param identifier the identifier for this item of metadata (required)
* @param aspectName the Java type of the ITD (required)
* @param governorPhysicalTypeMetadata the governor, which is expected to
* contain a {@link ClassOrInterfaceTypeDetails} (required)
*/
public ThymeleafUIConfigurationMetadata(final String identifier, final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata) {
super(identifier, aspectName, governorPhysicalTypeMetadata);
ensureGovernorImplements(APPLICATION_CONTEXT_AWARE);
this.thymeleafPropertiesField = getThymeleafPropertiesField();
this.templateEngineField = getTemplateEngineField();
this.applicationContextAwareField = getApplicationContextField();
// Adding fields
ensureGovernorHasField(new FieldMetadataBuilder(this.thymeleafPropertiesField));
ensureGovernorHasField(new FieldMetadataBuilder(this.templateEngineField));
ensureGovernorHasField(new FieldMetadataBuilder(this.applicationContextAwareField));
this.setApplicationContextMethod = getMutatorMethod(this.applicationContextAwareField);
this.javascriptThymeleafViewResolverMethod = getJavascriptThymeleafViewResolverMethod();
this.javascriptTemplateResolverMethod = getJavascriptTemplateResolverMethod();
// Add index method
ensureGovernorHasMethod(new MethodMetadataBuilder(javascriptThymeleafViewResolverMethod));
ensureGovernorHasMethod(new MethodMetadataBuilder(javascriptTemplateResolverMethod));
// Build the ITD
itdTypeDetails = builder.build();
}
/*
* =====================================================================================
*/
private FieldMetadata getTemplateEngineField() {
return new FieldMetadataBuilder(getId(), Modifier.PRIVATE, AUTOWIRED_LIST, new JavaSymbolName(
"templateEngine"), TEMPLATE_ENGINE).build();
}
private FieldMetadata getThymeleafPropertiesField() {
return new FieldMetadataBuilder(getId(), Modifier.PRIVATE, AUTOWIRED_LIST, new JavaSymbolName(
"thymeleafProperties"), THYMELEAF_PROPERTIES).build();
}
/**
* Field for applicationContext
*
* @return
*/
private FieldMetadata getApplicationContextField() {
return new FieldMetadataBuilder(getId(), Modifier.PRIVATE,
new ArrayList<AnnotationMetadataBuilder>(), new JavaSymbolName("applicationContext"),
APPLICATION_CONTEXT).build();
}
/**
* Returns method which configure ThymeleafViewResolver
*
* @return
*/
private MethodMetadata getJavascriptThymeleafViewResolverMethod() {
// Define methodName
final JavaSymbolName methodName = new JavaSymbolName("javascriptThymeleafViewResolver");
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
MethodMetadata existingMethod =
getGovernorMethod(methodName,
AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes));
if (existingMethod != null) {
return existingMethod;
}
// Adding annotations
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// add @Bean
annotations.add(new AnnotationMetadataBuilder(SpringJavaType.BEAN));
// Generate body
InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
/*
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(UTF8);
resolver.setContentType("application/javascript");
resolver.setViewNames(new String[] {"*.js"});
resolver.setCache(this.properties.isCache());
return resolver;
*/
bodyBuilder.appendFormalLine("%1$s resolver = new %1$s();",
getNameOfJavaType(THYMELEAF_VIEW_RESOLVER));
bodyBuilder.appendFormalLine("resolver.setTemplateEngine(%s());",
getAccessorMethod(this.templateEngineField).getMethodName());
bodyBuilder.appendFormalLine("resolver.setCharacterEncoding(\"UTF-8\");");
bodyBuilder.appendFormalLine("resolver.setContentType(\"application/javascript\");");
bodyBuilder.appendFormalLine("resolver.setViewNames(new String[] {\"*.js\"});");
bodyBuilder.appendFormalLine("resolver.setCache(%s().isCache());",
getAccessorMethod(this.thymeleafPropertiesField).getMethodName());
bodyBuilder.appendFormalLine("return resolver;");
MethodMetadataBuilder methodBuilder =
new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, THYMELEAF_VIEW_RESOLVER,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
/**
* Returns method which configure SpringResourceTemplateResolve
*
* @return
*/
private MethodMetadata getJavascriptTemplateResolverMethod() {
// Define methodName
final JavaSymbolName methodName = new JavaSymbolName("javascriptTemplateResolver");
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
MethodMetadata existingMethod =
getGovernorMethod(methodName,
AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes));
if (existingMethod != null) {
return existingMethod;
}
// Adding annotations
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// add @Bean
annotations.add(new AnnotationMetadataBuilder(SpringJavaType.BEAN));
// Generate body
InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
/*
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(getApplicationContext());
resolver.setPrefix("classpath:/templates/fragments/js/");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
resolver.setCheckExistence(true);
resolver.setCacheable(this.properties.isCache());
return resolver;
*/
bodyBuilder.appendFormalLine("%1$s resolver = new %1$s();",
getNameOfJavaType(SPRING_RESOURCE_TEMPLATE_RESOLVER));
bodyBuilder.appendFormalLine("resolver.setApplicationContext(%s());",
getAccessorMethod(this.applicationContextAwareField).getMethodName());
bodyBuilder.appendFormalLine("resolver.setPrefix(\"classpath:/templates/fragments/js/\");");
bodyBuilder.appendFormalLine("resolver.setTemplateMode(%s.JAVASCRIPT);",
getNameOfJavaType(TEMPLATE_MODE));
bodyBuilder.appendFormalLine("resolver.setCharacterEncoding(\"UTF-8\");");
bodyBuilder.appendFormalLine("resolver.setCheckExistence(true);");
bodyBuilder.appendFormalLine("resolver.setCacheable(%s().isCache());",
getAccessorMethod(this.thymeleafPropertiesField).getMethodName());
bodyBuilder.appendFormalLine("return resolver;");
MethodMetadataBuilder methodBuilder =
new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName,
SPRING_RESOURCE_TEMPLATE_RESOLVER, parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
@Override
public String toString() {
final ToStringBuilder builder = new ToStringBuilder(this);
builder.append("identifier", getId());
builder.append("valid", valid);
builder.append("aspectName", aspectName);
builder.append("destinationType", destination);
builder.append("governor", governorPhysicalTypeMetadata.getId());
builder.append("itdTypeDetails", itdTypeDetails);
return builder.toString();
}
}