package org.springframework.roo.addon.dbre.addon;
import static org.springframework.roo.model.RooJavaType.ROO_DB_MANAGED;
import java.util.List;
import java.util.logging.Logger;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.dbre.addon.model.Database;
import org.springframework.roo.addon.dbre.addon.model.DbreModelService;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.customdata.CustomDataKeys;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.itd.AbstractItdMetadataProvider;
import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.metadata.MetadataDependencyRegistry;
import org.springframework.roo.metadata.internal.MetadataDependencyRegistryTracker;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.RooJavaType;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.support.logging.HandlerUtils;
/**
* Implementation of {@link DbreMetadataProvider}.
*
* @author Alan Stewart
* @author Enrique Ruiz at DISID Corporation S.L.
* @since 1.1
*/
@Component
@Service
public class DbreMetadataProviderImpl extends AbstractItdMetadataProvider implements
DbreMetadataProvider {
protected final static Logger LOGGER = HandlerUtils.getLogger(DbreMetadataProviderImpl.class);
private DbreModelService dbreModelService;
private TypeManagementService typeManagementService;
protected MetadataDependencyRegistryTracker registryTracker = null;
/**
* This service is being activated so setup it:
* <ul>
* <li>Create and open the {@link MetadataDependencyRegistryTracker}</li>
* <li>Registers {@link RooJavaType#ROO_DB_MANAGED} as additional JavaType
* that will trigger metadata registration.</li>
* </ul>
*/
@Override
protected void activate(final ComponentContext cContext) {
context = cContext.getBundleContext();
this.registryTracker =
new MetadataDependencyRegistryTracker(context, null,
PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType());
this.registryTracker.open();
addMetadataTrigger(ROO_DB_MANAGED);
}
/**
* This service is being deactivated so unregister upstream-downstream
* dependencies, triggers, matchers and listeners.
*
* @param context
*/
protected void deactivate(final ComponentContext context) {
MetadataDependencyRegistry registry = this.registryTracker.getService();
registry.deregisterDependency(PhysicalTypeIdentifier.getMetadataIdentiferType(),
getProvidesType());
this.registryTracker.close();
removeMetadataTrigger(ROO_DB_MANAGED);
}
@Override
protected String createLocalIdentifier(final JavaType javaType, final LogicalPath path) {
return DbreMetadata.createIdentifier(javaType, path);
}
@Override
protected String getGovernorPhysicalTypeIdentifier(final String metadataIdentificationString) {
final JavaType javaType = DbreMetadata.getJavaType(metadataIdentificationString);
final LogicalPath path = DbreMetadata.getPath(metadataIdentificationString);
return PhysicalTypeIdentifier.createIdentifier(javaType, path);
}
private IdentifierHolder getIdentifierHolder(final JavaType javaType) {
final List<FieldMetadata> identifierFields =
getPersistenceMemberLocator().getIdentifierFields(javaType);
if (identifierFields.isEmpty()) {
return null;
}
final FieldMetadata identifierField = identifierFields.get(0);
final boolean embeddedIdField =
identifierField.getCustomData().get(CustomDataKeys.EMBEDDED_ID_FIELD) != null;
final List<FieldMetadata> embeddedIdFields =
getPersistenceMemberLocator().getEmbeddedIdentifierFields(javaType);
return new IdentifierHolder(identifierField, embeddedIdField, embeddedIdFields);
}
public String getItdUniquenessFilenameSuffix() {
return "DbManaged";
}
@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 DbManagedAnnotationValues annotationValues =
new DbManagedAnnotationValues(governorPhysicalTypeMetadata);
if (!annotationValues.isAnnotationFound()) {
return null;
}
// Abort if the database couldn't be deserialized. This can occur if the
// DBRE XML file has been deleted or is empty.
final Database database = getDbreModelService().getDatabase(false);
if (database == null) {
return null;
}
// We know governor type details are non-null and can be safely cast
final JavaType javaType = governorPhysicalTypeMetadata.getMemberHoldingTypeDetails().getName();
final IdentifierHolder identifierHolder = getIdentifierHolder(javaType);
if (identifierHolder == null) {
return null;
}
final FieldMetadata versionField = getVersionField(javaType, metadataIdentificationString);
// Search for database-managed entities
final Iterable<ClassOrInterfaceTypeDetails> managedEntities =
getTypeLocationService().findClassesOrInterfaceDetailsWithAnnotation(ROO_DB_MANAGED);
boolean found = false;
for (final ClassOrInterfaceTypeDetails managedEntity : managedEntities) {
if (managedEntity.getName().equals(javaType)) {
found = true;
break;
}
}
if (!found) {
final String mid = getTypeLocationService().getPhysicalTypeIdentifier(javaType);
getMetadataDependencyRegistry().registerDependency(mid, metadataIdentificationString);
return null;
}
final DbreMetadata dbreMetadata =
new DbreMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata,
annotationValues, identifierHolder, versionField, managedEntities, database);
final ClassOrInterfaceTypeDetails updatedGovernor = dbreMetadata.getUpdatedGovernor();
if (updatedGovernor != null) {
getTypeManagementService().createOrUpdateTypeOnDisk(updatedGovernor);
}
return dbreMetadata;
}
public String getProvidesType() {
return DbreMetadata.getMetadataIdentiferType();
}
private FieldMetadata getVersionField(final JavaType domainType,
final String metadataIdentificationString) {
return getPersistenceMemberLocator().getVersionField(domainType);
}
public DbreModelService getDbreModelService() {
if (dbreModelService == null) {
// Get all Services implement DbreModelService interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(DbreModelService.class.getName(), null);
for (ServiceReference<?> ref : references) {
return (DbreModelService) context.getService(ref);
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load DbreModelService on DbreMetadataProviderImpl.");
return null;
}
} else {
return dbreModelService;
}
}
public TypeManagementService getTypeManagementService() {
if (typeManagementService == null) {
// Get all Services implement TypeManagementService interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(TypeManagementService.class.getName(), null);
for (ServiceReference<?> ref : references) {
return (TypeManagementService) context.getService(ref);
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load TypeManagementService on DbreMetadataProviderImpl.");
return null;
}
} else {
return typeManagementService;
}
}
}