package org.springframework.roo.addon.jsf.converter;
import static org.springframework.roo.addon.jsf.converter.JsfConverterMetadata.ID_FIELD_NAME;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_METHOD;
import static org.springframework.roo.model.RooJavaType.ROO_JSF_CONVERTER;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.configurable.ConfigurableMetadataProvider;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.ItdTypeDetails;
import org.springframework.roo.classpath.details.MemberHoldingTypeDetails;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.itd.AbstractMemberDiscoveringItdMetadataProvider;
import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.layers.LayerService;
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.model.JavaType;
import org.springframework.roo.project.LogicalPath;
/**
* Implementation of {@link JsfConverterMetadataProvider}.
*
* @author Alan Stewart
* @since 1.2.0
*/
@Component(immediate = true)
@Service
public class JsfConverterMetadataProviderImpl extends
AbstractMemberDiscoveringItdMetadataProvider implements
JsfConverterMetadataProvider {
private static final int LAYER_POSITION = LayerType.HIGHEST.getPosition();
@Reference private ConfigurableMetadataProvider configurableMetadataProvider;
@Reference private LayerService layerService;
private final Map<String, JavaType> converterMidToEntityMap = new LinkedHashMap<String, JavaType>();
private final Map<JavaType, String> entityToConverterMidMap = new LinkedHashMap<JavaType, String>();
protected void activate(final ComponentContext context) {
metadataDependencyRegistry.addNotificationListener(this);
metadataDependencyRegistry.registerDependency(
PhysicalTypeIdentifier.getMetadataIdentiferType(),
getProvidesType());
addMetadataTrigger(ROO_JSF_CONVERTER);
configurableMetadataProvider.addMetadataTrigger(ROO_JSF_CONVERTER);
}
@Override
protected String createLocalIdentifier(final JavaType javaType,
final LogicalPath path) {
return JsfConverterMetadata.createIdentifier(javaType, path);
}
protected void deactivate(final ComponentContext context) {
metadataDependencyRegistry.removeNotificationListener(this);
metadataDependencyRegistry.deregisterDependency(
PhysicalTypeIdentifier.getMetadataIdentiferType(),
getProvidesType());
removeMetadataTrigger(ROO_JSF_CONVERTER);
configurableMetadataProvider.removeMetadataTrigger(ROO_JSF_CONVERTER);
}
private MemberTypeAdditions getFindMethod(final JavaType entity,
final String metadataIdentificationString) {
metadataDependencyRegistry.registerDependency(
typeLocationService.getPhysicalTypeIdentifier(entity),
metadataIdentificationString);
final List<FieldMetadata> idFields = persistenceMemberLocator
.getIdentifierFields(entity);
if (idFields.isEmpty()) {
return null;
}
final FieldMetadata idField = idFields.get(0);
final JavaType idType = persistenceMemberLocator
.getIdentifierType(entity);
if (idType == null) {
return null;
}
metadataDependencyRegistry
.registerDependency(idField.getDeclaredByMetadataId(),
metadataIdentificationString);
final MethodParameter idParameter = new MethodParameter(idType,
ID_FIELD_NAME);
return layerService.getMemberTypeAdditions(
metadataIdentificationString, FIND_METHOD.name(), entity,
idType, LAYER_POSITION, idParameter);
}
@Override
protected String getGovernorPhysicalTypeIdentifier(
final String metadataIdentificationString) {
final JavaType javaType = JsfConverterMetadata
.getJavaType(metadataIdentificationString);
final LogicalPath path = JsfConverterMetadata
.getPath(metadataIdentificationString);
return PhysicalTypeIdentifier.createIdentifier(javaType, path);
}
public String getItdUniquenessFilenameSuffix() {
return "Converter";
}
@Override
protected String getLocalMidToRequest(final ItdTypeDetails itdTypeDetails) {
// Determine the governor for this ITD, and whether any metadata is even
// hoping to hear about changes to that JavaType and its ITDs
final JavaType governor = itdTypeDetails.getName();
final String localMid = entityToConverterMidMap.get(governor);
if (localMid != null) {
return localMid;
}
final MemberHoldingTypeDetails memberHoldingTypeDetails = typeLocationService
.getTypeDetails(itdTypeDetails.getGovernor().getName());
if (memberHoldingTypeDetails != null) {
for (final JavaType type : memberHoldingTypeDetails
.getLayerEntities()) {
final String localMidType = entityToConverterMidMap.get(type);
if (localMidType != null) {
return localMidType;
}
}
}
return null;
}
@Override
protected ItdTypeDetailsProvidingMetadataItem getMetadata(
final String metadataIdentificationString,
final JavaType aspectName,
final PhysicalTypeMetadata governorPhysicalTypeMetadata,
final String itdFilename) {
// We need to parse the annotation, which we expect to be present
final JsfConverterAnnotationValues annotationValues = new JsfConverterAnnotationValues(
governorPhysicalTypeMetadata);
final JavaType entity = annotationValues.getEntity();
if (!annotationValues.isAnnotationFound() || entity == null) {
return null;
}
// Remember that this entity JavaType matches up with this metadata
// identification string
// Start by clearing any previous association
final JavaType oldEntity = converterMidToEntityMap
.get(metadataIdentificationString);
if (oldEntity != null) {
entityToConverterMidMap.remove(oldEntity);
}
entityToConverterMidMap.put(entity, metadataIdentificationString);
converterMidToEntityMap.put(metadataIdentificationString, entity);
final MemberTypeAdditions findMethod = getFindMethod(entity,
metadataIdentificationString);
final MethodMetadata identifierAccessor = persistenceMemberLocator
.getIdentifierAccessor(entity);
return new JsfConverterMetadata(metadataIdentificationString,
aspectName, governorPhysicalTypeMetadata, annotationValues,
findMethod, identifierAccessor);
}
public String getProvidesType() {
return JsfConverterMetadata.getMetadataIdentiferType();
}
}