package org.springframework.roo.classpath;
import java.io.File;
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.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.ProjectOperations;
/**
* Implementation of {@link TypeManagementService}.
*
* @author Alan Stewart
* @since 1.1.2
*/
@Component
@Service
public class TypeManagementServiceImpl implements TypeManagementService {
@Reference
private FileManager fileManager;
@Reference
private MetadataService metadataService;
@Reference
private ProjectOperations projectOperations;
@Reference
private TypeLocationService typeLocationService;
@Reference
private TypeParsingService typeParsingService;
public void addEnumConstant(final String physicalTypeIdentifier, final JavaSymbolName constantName) {
Validate.notBlank(physicalTypeIdentifier, "Type identifier not provided");
Validate.notNull(constantName, "Constant name required");
// Obtain the physical type and itd mutable details
final PhysicalTypeMetadata ptm =
(PhysicalTypeMetadata) metadataService.get(physicalTypeIdentifier);
Validate.notNull(ptm, "Java source code unavailable for type %s",
PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
final PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
Validate.notNull(ptd, "Java source code details unavailable for type %s",
PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
final ClassOrInterfaceTypeDetailsBuilder cidBuilder =
new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) ptd);
// Ensure it's an enum
Validate.isTrue(cidBuilder.getPhysicalTypeCategory() == PhysicalTypeCategory.ENUMERATION,
"%s is not an enum", PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
cidBuilder.addEnumConstant(constantName);
createOrUpdateTypeOnDisk(cidBuilder.build());
}
public void addField(final FieldMetadata field) {
this.addField(field, false);
}
public void addField(final FieldMetadata field, boolean evict) {
Validate.notNull(field, "Field metadata not provided");
// Obtain the physical type and ITD mutable details
PhysicalTypeMetadata ptm = null;
if (evict) {
ptm = (PhysicalTypeMetadata) metadataService.evictAndGet(field.getDeclaredByMetadataId());
} else {
ptm = (PhysicalTypeMetadata) metadataService.get(field.getDeclaredByMetadataId());
}
Validate.notNull(ptm, "Java source code unavailable for type %s",
PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
final PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
Validate.notNull(ptd, "Java source code details unavailable for type %s",
PhysicalTypeIdentifier.getFriendlyName(field.getDeclaredByMetadataId()));
final ClassOrInterfaceTypeDetailsBuilder cidBuilder =
new ClassOrInterfaceTypeDetailsBuilder((ClassOrInterfaceTypeDetails) ptd);
// Automatically add JSR 303 (Bean Validation API) support if there is
// no current JSR 303 support but a JSR 303 annotation is present
boolean jsr303Required = false;
for (final AnnotationMetadata annotation : field.getAnnotations()) {
if (annotation.getAnnotationType().getFullyQualifiedTypeName().startsWith("javax.validation")) {
jsr303Required = true;
break;
}
}
final LogicalPath path = PhysicalTypeIdentifier.getPath(cidBuilder.getDeclaredByMetadataId());
if (jsr303Required) {
// It's more likely the version below represents a later version
// than any specified in the user's own dependency list
projectOperations.addDependency(path.getModule(), new Dependency("javax.validation",
"validation-api", null));
}
cidBuilder.addField(field);
createOrUpdateTypeOnDisk(cidBuilder.build());
}
public void createOrUpdateTypeOnDisk(final ClassOrInterfaceTypeDetails cid) {
final String fileCanonicalPath =
typeLocationService.getPhysicalTypeCanonicalPath(cid.getDeclaredByMetadataId());
String newContents;
File file;
boolean existsFile = false;
if (fileCanonicalPath != null) {
file = new File(fileCanonicalPath);
existsFile = file.exists() && file.isFile();
}
if (existsFile) {
newContents = typeParsingService.updateAndGetCompilationUnitContents(fileCanonicalPath, cid);
} else {
newContents = typeParsingService.getCompilationUnitContents(cid);
}
fileManager.createOrUpdateTextFileIfRequired(fileCanonicalPath, newContents, true);
}
@Deprecated
public void generateClassFile(final ClassOrInterfaceTypeDetails cid) {
createOrUpdateTypeOnDisk(cid);
}
}