package org.springframework.roo.addon.jpa.activerecord;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.addon.plural.PluralMetadata;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.ImportMetadataBuilder;
import org.springframework.roo.classpath.layers.CoreLayerProvider;
import org.springframework.roo.classpath.layers.LayerType;
import org.springframework.roo.classpath.layers.MemberTypeAdditions;
import org.springframework.roo.classpath.layers.MethodParameter;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.support.util.PairList;
/**
* The {@link org.springframework.roo.classpath.layers.LayerProvider} for the
* {@link LayerType#ACTIVE_RECORD} layer.
*
* @author Stefan Schmidt
* @author Andrew Swan
* @since 1.2.0
*/
@Component
@Service
public class EntityLayerProvider extends CoreLayerProvider {
@Reference private JpaActiveRecordMetadataProvider jpaActiveRecordMetadataProvider;
@Reference private MetadataService metadataService;
@Reference TypeLocationService typeLocationService;
public int getLayerPosition() {
return LayerType.ACTIVE_RECORD.getPosition();
}
public MemberTypeAdditions getMemberTypeAdditions(final String callerMID,
final String methodIdentifier, final JavaType targetEntity,
final JavaType idType, final MethodParameter... callerParameters) {
Validate.isTrue(StringUtils.isNotBlank(callerMID),
"Metadata identifier required");
Validate.notBlank(methodIdentifier, "Method identifier required");
Validate.notNull(targetEntity, "Target enitity type required");
// Get the CRUD-related values of this entity's @RooJpaActiveRecord
// annotation
final JpaCrudAnnotationValues annotationValues = jpaActiveRecordMetadataProvider
.getAnnotationValues(targetEntity);
if (annotationValues == null) {
return null;
}
// Check the entity has a plural form
final String plural = getPlural(targetEntity);
if (StringUtils.isBlank(plural)) {
return null;
}
// Look for an entity layer method with this ID and types of parameter
final List<JavaType> parameterTypes = new PairList<JavaType, JavaSymbolName>(
callerParameters).getKeys();
final EntityLayerMethod method = EntityLayerMethod.valueOf(
methodIdentifier, parameterTypes, targetEntity, idType);
if (method == null) {
return null;
}
// It's an entity layer method; see if it's specified by the annotation
final String methodName = method.getName(annotationValues,
targetEntity, plural);
if (StringUtils.isBlank(methodName)) {
return null;
}
// We have everything needed to generate a method call
final List<MethodParameter> callerParameterList = Arrays
.asList(callerParameters);
final String methodCall = method.getCall(annotationValues,
targetEntity, plural, callerParameterList);
final ClassOrInterfaceTypeDetailsBuilder additionsBuilder = new ClassOrInterfaceTypeDetailsBuilder(
callerMID);
if (method.isStatic()) {
additionsBuilder.add(ImportMetadataBuilder.getImport(callerMID,
targetEntity));
}
return new MemberTypeAdditions(additionsBuilder, methodName,
methodCall, method.isStatic(),
method.getParameters(callerParameterList));
}
/**
* Returns the plural form of the given entity
*
* @param javaType the entity for which to get the plural (required)
* @return <code>null</code> if it can't be found or is actually
* <code>null</code>
*/
private String getPlural(final JavaType javaType) {
final String key = PluralMetadata.createIdentifier(javaType,
typeLocationService.getTypePath(javaType));
final PluralMetadata pluralMetadata = (PluralMetadata) metadataService
.get(key);
if (pluralMetadata == null) {
// Can't acquire the plural
return null;
}
return pluralMetadata.getPlural();
}
/**
* For use by unit tests
*
* @param jpaActiveRecordMetadataProvider
*/
void setJpaActiveRecordMetadataProvider(
final JpaActiveRecordMetadataProvider jpaActiveRecordMetadataProvider) {
this.jpaActiveRecordMetadataProvider = jpaActiveRecordMetadataProvider;
}
/**
* For use by unit tests
*
* @param metadataService
*/
void setMetadataService(final MetadataService metadataService) {
this.metadataService = metadataService;
}
}