package org.springframework.roo.addon.solr;
import static org.springframework.roo.model.JavaType.INT_OBJECT;
import static org.springframework.roo.model.SpringJavaType.MODEL_MAP;
import static org.springframework.roo.model.SpringJavaType.REQUEST_MAPPING;
import static org.springframework.roo.model.SpringJavaType.REQUEST_PARAM;
import static org.springframework.roo.model.SpringJavaType.RESPONSE_BODY;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.roo.addon.web.mvc.controller.scaffold.WebScaffoldAnnotationValues;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.BooleanAttributeValue;
import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
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.project.LogicalPath;
/**
* Metadata for {@link RooSolrWebSearchable}.
*
* @author Stefan Schmidt
* @since 1.1
*/
public class SolrWebSearchMetadata extends
AbstractItdTypeDetailsProvidingMetadataItem {
private static final String PROVIDES_TYPE_STRING = SolrWebSearchMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
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);
}
public SolrWebSearchMetadata(final String identifier,
final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata,
final SolrWebSearchAnnotationValues annotationValues,
final WebScaffoldAnnotationValues webScaffoldAnnotationValues,
final SolrSearchAnnotationValues solrSearchAnnotationValues) {
super(identifier, aspectName, governorPhysicalTypeMetadata);
Validate.notNull(webScaffoldAnnotationValues,
"Web scaffold annotation values required");
Validate.notNull(annotationValues,
"Solr web searchable annotation values required");
Validate.notNull(solrSearchAnnotationValues,
"Solr search annotation values required");
Validate.isTrue(isValid(identifier), "Metadata identification string '"
+ identifier + "' does not appear to be a valid");
if (!isValid()) {
return;
}
if (annotationValues.getSearchMethod() != null
&& annotationValues.getSearchMethod().length() > 0) {
builder.addMethod(getSearchMethod(annotationValues,
solrSearchAnnotationValues, webScaffoldAnnotationValues));
}
if (annotationValues.getAutoCompleteMethod() != null
&& annotationValues.getAutoCompleteMethod().length() > 0) {
builder.addMethod(getAutocompleteMethod(annotationValues,
solrSearchAnnotationValues, webScaffoldAnnotationValues));
}
// Create a representation of the desired output ITD
itdTypeDetails = builder.build();
}
private MethodMetadataBuilder getAutocompleteMethod(
final SolrWebSearchAnnotationValues solrWebSearchAnnotationValues,
final SolrSearchAnnotationValues searchAnnotationValues,
final WebScaffoldAnnotationValues webScaffoldAnnotationValues) {
final JavaSymbolName methodName = new JavaSymbolName(
solrWebSearchAnnotationValues.getAutoCompleteMethod());
if (governorHasMethodWithSameName(methodName)) {
return null;
}
final List<AnnotationAttributeValue<?>> reqMapAttributes = new ArrayList<AnnotationAttributeValue<?>>();
reqMapAttributes.add(new StringAttributeValue(new JavaSymbolName(
"params"), "autocomplete"));
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
annotations.add(new AnnotationMetadataBuilder(REQUEST_MAPPING,
reqMapAttributes));
annotations.add(new AnnotationMetadataBuilder(RESPONSE_BODY));
final List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
parameterTypes.add(new AnnotatedJavaType(JavaType.STRING,
getRequestParamAnnotation("q", true)));
parameterNames.add(new JavaSymbolName("q"));
parameterTypes.add(new AnnotatedJavaType(JavaType.STRING,
getRequestParamAnnotation("facetFields", true)));
parameterNames.add(new JavaSymbolName("facetFields"));
parameterTypes.add(new AnnotatedJavaType(INT_OBJECT,
getRequestParamAnnotation("rows", false)));
parameterNames.add(new JavaSymbolName("rows"));
final String solrQuerySimpleName = new JavaType(
"org.apache.solr.client.solrj.SolrQuery")
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver());
final String facetFieldSimpleName = new JavaType(
"org.apache.solr.client.solrj.response.FacetField")
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver());
final String queryResponseSimpleName = new JavaType(
"org.apache.solr.client.solrj.response.QueryResponse")
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver());
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
bodyBuilder
.appendFormalLine("StringBuilder dojo = new StringBuilder(\"{identifier:'id',label:'label',items:[\");");
bodyBuilder.appendFormalLine(solrQuerySimpleName
+ " solrQuery = new SolrQuery(q.toLowerCase());");
bodyBuilder
.appendFormalLine("solrQuery.setRows(rows == null ? 10 : rows);");
bodyBuilder.appendFormalLine("solrQuery.setFacetMinCount(1);");
bodyBuilder
.appendFormalLine("solrQuery.addFacetField(facetFields.split(\",\"));");
bodyBuilder.appendFormalLine(queryResponseSimpleName
+ " response = "
+ webScaffoldAnnotationValues.getFormBackingObject()
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver()) + "."
+ searchAnnotationValues.getSearchMethod() + "(solrQuery);");
bodyBuilder.appendFormalLine("for (" + facetFieldSimpleName
+ " field: response.getFacetFields()) {");
bodyBuilder.indent();
bodyBuilder
.appendFormalLine("if (response.getResults().get(0) != null) {");
bodyBuilder.indent();
bodyBuilder
.appendFormalLine("Object fieldValue = response.getResults().get(0).getFieldValue(field.getName());");
bodyBuilder.appendFormalLine("if (fieldValue != null) {");
bodyBuilder.indent();
bodyBuilder
.appendFormalLine("dojo.append(\"{label:'\").append(fieldValue).append(\" (\").append(field.getValueCount()).append(\")\").append(\"',\").append(\"id:'\").append(field.getName()).append(\"'},\");");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
bodyBuilder.appendFormalLine("dojo.append(\"]}\");");
bodyBuilder.appendFormalLine("return dojo.toString();");
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC, methodName, JavaType.STRING,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder;
}
private AnnotationMetadata getRequestParamAnnotation(
final String paramName, final boolean required) {
final List<AnnotationAttributeValue<?>> attributeValue = new ArrayList<AnnotationAttributeValue<?>>();
if (!required) {
attributeValue.add(new BooleanAttributeValue(new JavaSymbolName(
"required"), false));
}
attributeValue.add(new StringAttributeValue(
new JavaSymbolName("value"), paramName));
return new AnnotationMetadataBuilder(REQUEST_PARAM, attributeValue)
.build();
}
private MethodMetadataBuilder getSearchMethod(
final SolrWebSearchAnnotationValues solrWebSearchAnnotationValues,
final SolrSearchAnnotationValues searchAnnotationValues,
final WebScaffoldAnnotationValues webScaffoldAnnotationValues) {
final JavaType targetObject = webScaffoldAnnotationValues
.getFormBackingObject();
Validate.notNull(targetObject,
"Could not aquire form backing object for the '"
+ webScaffoldAnnotationValues.getGovernorTypeDetails()
.getName().getFullyQualifiedTypeName()
+ "' controller");
final JavaSymbolName methodName = new JavaSymbolName(
solrWebSearchAnnotationValues.getSearchMethod());
if (governorHasMethodWithSameName(methodName)) {
return null;
}
final List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>();
final List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
parameterTypes.add(new AnnotatedJavaType(new JavaType("String"),
getRequestParamAnnotation("q", false)));
parameterNames.add(new JavaSymbolName("q"));
parameterTypes.add(new AnnotatedJavaType(new JavaType("String"),
getRequestParamAnnotation("fq", false)));
parameterNames.add(new JavaSymbolName("facetQuery"));
parameterTypes.add(new AnnotatedJavaType(new JavaType("Integer"),
getRequestParamAnnotation("page", false)));
parameterNames.add(new JavaSymbolName("page"));
parameterTypes.add(new AnnotatedJavaType(new JavaType("Integer"),
getRequestParamAnnotation("size", false)));
parameterNames.add(new JavaSymbolName("size"));
parameterTypes.add(new AnnotatedJavaType(MODEL_MAP));
parameterNames.add(new JavaSymbolName("modelMap"));
final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>();
requestMappingAttributes.add(new StringAttributeValue(
new JavaSymbolName("params"), "search"));
final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder(
REQUEST_MAPPING, requestMappingAttributes);
final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
annotations.add(requestMapping);
final String solrQuerySimpleName = new JavaType(
"org.apache.solr.client.solrj.SolrQuery")
.getNameIncludingTypeParameters(false,
builder.getImportRegistrationResolver());
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
bodyBuilder.appendFormalLine("if (q != null && q.length() != 0) {");
bodyBuilder.indent();
bodyBuilder.appendFormalLine(solrQuerySimpleName
+ " solrQuery = new "
+ solrQuerySimpleName
+ "(\""
+ webScaffoldAnnotationValues.getFormBackingObject()
.getSimpleTypeName().toLowerCase()
+ "_solrsummary_t:\" + q.toLowerCase());");
bodyBuilder
.appendFormalLine("if (page != null) solrQuery.setStart(page);");
bodyBuilder
.appendFormalLine("if (size != null) solrQuery.setRows(size);");
bodyBuilder
.appendFormalLine("modelMap.addAttribute(\"searchResults\", "
+ targetObject.getFullyQualifiedTypeName() + "."
+ searchAnnotationValues.getSearchMethod()
+ "(solrQuery).getResults());");
bodyBuilder.indentRemove();
bodyBuilder.appendFormalLine("}");
bodyBuilder.appendFormalLine("return \""
+ webScaffoldAnnotationValues.getPath() + "/search\";");
final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
getId(), Modifier.PUBLIC, methodName, JavaType.STRING,
parameterTypes, parameterNames, bodyBuilder);
methodBuilder.setAnnotations(annotations);
return methodBuilder;
}
@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();
}
}