package org.springframework.roo.addon.layers.service;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
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.itd.AbstractItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.classpath.scanner.MemberDetails;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;
/**
* The metadata about a service interface within a user project
*
* @author Stefan Schmidt
* @author Andrew Swan
* @since 1.2.0
*/
public class ServiceInterfaceMetadata extends
AbstractItdTypeDetailsProvidingMetadataItem {
private static final InvocableMemberBodyBuilder BODY = new InvocableMemberBodyBuilder();
private static final String PROVIDES_TYPE_STRING = ServiceInterfaceMetadata.class
.getName();
private static final String PROVIDES_TYPE = MetadataIdentificationUtils
.create(PROVIDES_TYPE_STRING);
private static final int PUBLIC_ABSTRACT = Modifier.PUBLIC
| Modifier.ABSTRACT;
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 ServiceAnnotationValues annotationValues;
private final MemberDetails governorDetails;
/**
* Constructor
*
* @param identifier (required)
* @param aspectName (required)
* @param governorPhysicalTypeMetadata (required)
* @param governorDetails (required)
* @param domainTypeToIdTypeMap (required)
* @param annotationValues (required)
* @param domainTypePlurals
*/
public ServiceInterfaceMetadata(final String identifier,
final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata,
final MemberDetails governorDetails,
final Map<JavaType, JavaType> domainTypeToIdTypeMap,
final ServiceAnnotationValues annotationValues,
final Map<JavaType, String> domainTypePlurals) {
super(identifier, aspectName, governorPhysicalTypeMetadata);
Validate.notNull(annotationValues, "Annotation values required");
Validate.notNull(governorDetails, "Governor member details required");
Validate.notNull(domainTypeToIdTypeMap,
"Domain type to ID type map required required");
Validate.notNull(domainTypePlurals,
"Domain type plural values required");
this.annotationValues = annotationValues;
this.governorDetails = governorDetails;
for (final Entry<JavaType, JavaType> entry : domainTypeToIdTypeMap
.entrySet()) {
final JavaType domainType = entry.getKey();
final String plural = domainTypePlurals.get(domainType);
for (final ServiceLayerMethod method : ServiceLayerMethod.values()) {
builder.addMethod(getMethod(method, domainType,
entry.getValue(), plural));
}
}
// Create a representation of the desired output ITD
itdTypeDetails = builder.build();
}
/**
* Returns the metadata for declaring the given method in the service
* interface
*
* @param method the method to declare
* @param domainType the domain type being managed
* @param idType
* @param plural the domain type's plural
* @return <code>null</code> if the method isn't required or is already
* declared in the governor
*/
private MethodMetadataBuilder getMethod(final ServiceLayerMethod method,
final JavaType domainType, final JavaType idType,
final String plural) {
final JavaSymbolName methodName = method.getSymbolName(
annotationValues, domainType, plural);
if (methodName != null
&& governorDetails.isMethodDeclaredByAnother(methodName,
method.getParameterTypes(domainType, idType), getId())) {
// We don't want this method, or the governor already declares it
return null;
}
return new MethodMetadataBuilder(getId(), PUBLIC_ABSTRACT, methodName,
method.getReturnType(domainType),
AnnotatedJavaType.convertFromJavaTypes(method
.getParameterTypes(domainType, idType)),
method.getParameterNames(domainType, idType), BODY);
}
public ServiceAnnotationValues getServiceAnnotationValues() {
return annotationValues;
}
@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();
}
}