package org.springframework.roo.addon.web.mvc.thymeleaf.addon;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.addon.web.mvc.thymeleaf.annotations.RooThymeleafMainController;
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.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.model.SpringletsJavaType;
import org.springframework.roo.project.LogicalPath;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
* Metadata for {@link RooThymeleafMainController}.
*
* @author Juan Carlos García
* @author Jose Manuel Vivó
* @since 2.0
*/
public class ThymeleafMainControllerMetadata extends AbstractItdTypeDetailsProvidingMetadataItem {
private static final String PROVIDES_TYPE_STRING = ThymeleafMainControllerMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
private static final JavaType CONTROLLER_ANNOTATION = new JavaType(
"org.springframework.stereotype.Controller");
private final MethodMetadata indexMethod;
private final MethodMetadata javasrcriptTemplatesMethod;
private final MethodMetadata accessibilityMethod;
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);
}
/**
* 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 ThymeleafMainControllerMetadata(final String identifier, final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata) {
super(identifier, aspectName, governorPhysicalTypeMetadata);
this.indexMethod = getIndexMethod();
this.accessibilityMethod = getAccessibilityMethod();
this.javasrcriptTemplatesMethod = getJavascriptTemplatesmethod();
// Add @Controller annotation
ensureGovernorIsAnnotated(new AnnotationMetadataBuilder(CONTROLLER_ANNOTATION));
// Add methods
ensureGovernorHasMethod(new MethodMetadataBuilder(indexMethod));
ensureGovernorHasMethod(new MethodMetadataBuilder(accessibilityMethod));
ensureGovernorHasMethod(new MethodMetadataBuilder(javasrcriptTemplatesMethod));
// Build the ITD
itdTypeDetails = builder.build();
}
/*
* =====================================================================================
*/
/**
* @return
*/
private MethodMetadata getJavascriptTemplatesmethod() {
// Define methodName
final JavaSymbolName methodName = new JavaSymbolName("javascriptTemplates");
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
// Create @PathVariable("templeate") String template parameter
AnnotationMetadataBuilder pathVarialbeAnnotation =
new AnnotationMetadataBuilder(SpringJavaType.PATH_VARIABLE);
pathVarialbeAnnotation.addStringAttribute("value", "template");
AnnotatedJavaType templateParameter =
new AnnotatedJavaType(JavaType.STRING, pathVarialbeAnnotation.build());
parameterTypes.add(templateParameter);
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
parameterNames.add(new JavaSymbolName("template"));
MethodMetadata existingMethod =
getGovernorMethod(methodName,
AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes));
if (existingMethod != null) {
return existingMethod;
}
// Adding annotations
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Adding @RequestMapping annotation
AnnotationMetadataBuilder requestMapping =
new AnnotationMetadataBuilder(SpringJavaType.REQUEST_MAPPING);
requestMapping.addStringAttribute("value", "/js/{template}.js");
getNameOfJavaType(SpringJavaType.REQUEST_METHOD);
requestMapping.addEnumAttribute("method", SpringJavaType.REQUEST_METHOD, "GET");
annotations.add(requestMapping);
// Generate body
InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
// if (StringUtils.hasLength(template)) {
// return template.concat(".js");
// }
bodyBuilder.appendFormalLine("if (%s.hasLength(template)) {",
getNameOfJavaType(SpringJavaType.STRING_UTILS));
bodyBuilder.indent();
bodyBuilder.appendFormalLine("return template.concat(\".js\");");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
// throw new NotFoundException("File not found")
bodyBuilder.appendFormalLine("throw new %s(\"File not found\");",
getNameOfJavaType(SpringletsJavaType.SPRINGLETS_NOT_FOUND_EXCEPTION));
MethodMetadataBuilder methodBuilder =
new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, JavaType.STRING,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
/**
* This method provides the "index" method that returns Thymeleaf view
*
* @return MethodMetadata
*/
private MethodMetadata getIndexMethod() {
// Define methodName
final JavaSymbolName methodName = new JavaSymbolName("index");
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
parameterTypes.add(AnnotatedJavaType.convertFromJavaType(SpringJavaType.MODEL));
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
parameterNames.add(new JavaSymbolName("model"));
MethodMetadata existingMethod =
getGovernorMethod(methodName,
AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes));
if (existingMethod != null) {
return existingMethod;
}
// Adding annotations
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Adding @GetMapping annotation
AnnotationMetadataBuilder getMapping =
new AnnotationMetadataBuilder(SpringJavaType.GET_MAPPING);
getMapping.addStringAttribute("value", "/");
annotations.add(getMapping);
// Generate body
InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
// Always save locale
bodyBuilder.appendFormalLine(
"model.addAttribute(\"application_locale\", %s.getLocale().getLanguage());",
getNameOfJavaType(SpringJavaType.LOCALE_CONTEXT_HOLDER));
// return "index";
bodyBuilder.appendFormalLine("return \"index\";");
MethodMetadataBuilder methodBuilder =
new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, JavaType.STRING,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
private MethodMetadata getAccessibilityMethod() {
// Define methodName
final JavaSymbolName methodName = new JavaSymbolName("accessibility");
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
parameterTypes.add(AnnotatedJavaType.convertFromJavaType(SpringJavaType.MODEL));
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
parameterNames.add(new JavaSymbolName("model"));
MethodMetadata existingMethod =
getGovernorMethod(methodName,
AnnotatedJavaType.convertFromAnnotatedJavaTypes(parameterTypes));
if (existingMethod != null) {
return existingMethod;
}
// Adding annotations
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Adding @GetMapping annotation
AnnotationMetadataBuilder getMapping =
new AnnotationMetadataBuilder(SpringJavaType.GET_MAPPING);
getMapping.addStringAttribute("value", "/accessibility");
annotations.add(getMapping);
// Generate body
InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
// Always save locale
bodyBuilder.appendFormalLine(
"model.addAttribute(\"application_locale\", %s.getLocale().getLanguage());",
getNameOfJavaType(SpringJavaType.LOCALE_CONTEXT_HOLDER));
// return "accessibility";
bodyBuilder.appendFormalLine("return \"accessibility\";");
MethodMetadataBuilder methodBuilder =
new MethodMetadataBuilder(getId(), Modifier.PUBLIC, methodName, JavaType.STRING,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder.build();
}
/**
* This method returns the index method of Thymeleaf
* main controller
*
* @return
*/
public MethodMetadata getCurrentIndexMethod() {
return this.indexMethod;
}
/**
* Returns the method which handles javascript templates request
* @return
*/
public MethodMetadata getJavasrcriptTemplates() {
return javasrcriptTemplatesMethod;
}
@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();
}
}