package org.springframework.roo.addon.layers.repository.jpa;
import static org.springframework.roo.model.RooJavaType.ROO_REPOSITORY_JPA;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
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.PhysicalTypeCategory;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.ClassAttributeValue;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.process.manager.MutableFile;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.FeatureNames;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Element;
/**
* The {@link RepositoryJpaOperations} implementation.
*
* @author Stefan Schmidt
* @since 1.2.0
*/
@Component
@Service
public class RepositoryJpaOperationsImpl implements RepositoryJpaOperations {
@Reference private FileManager fileManager;
@Reference private PathResolver pathResolver;
@Reference private ProjectOperations projectOperations;
@Reference private TypeManagementService typeManagementService;
private void configureProject() {
final Element configuration = XmlUtils.getConfiguration(getClass());
final List<Dependency> dependencies = new ArrayList<Dependency>();
final List<Element> springDependencies = XmlUtils.findElements(
"/configuration/spring-data-jpa/dependencies/dependency",
configuration);
for (final Element dependencyElement : springDependencies) {
dependencies.add(new Dependency(dependencyElement));
}
projectOperations.addDependencies(
projectOperations.getFocusedModuleName(), dependencies);
final String appCtxId = pathResolver.getFocusedIdentifier(
Path.SPRING_CONFIG_ROOT, "applicationContext-jpa.xml");
if (fileManager.exists(appCtxId)) {
return;
}
else {
InputStream templateInputStream = null;
OutputStream outputStream = null;
try {
templateInputStream = getClass().getResourceAsStream(
"applicationContext-jpa.xml");
Validate.notNull(templateInputStream,
"Could not acquire 'applicationContext-jpa.xml' template");
String input = IOUtils.toString(templateInputStream);
input = input.replace("TO_BE_CHANGED_BY_ADDON",
projectOperations.getFocusedTopLevelPackage()
.getFullyQualifiedPackageName());
final MutableFile mutableFile = fileManager
.createFile(appCtxId);
outputStream = mutableFile.getOutputStream();
IOUtils.write(input, outputStream);
}
catch (final IOException e) {
throw new IllegalStateException("Unable to create '" + appCtxId
+ "'", e);
}
finally {
IOUtils.closeQuietly(templateInputStream);
IOUtils.closeQuietly(outputStream);
}
}
}
public String getName() {
return FeatureNames.JPA;
}
public boolean isInstalledInModule(final String moduleName) {
final LogicalPath resourcesPath = LogicalPath.getInstance(
Path.SRC_MAIN_RESOURCES, moduleName);
return projectOperations.isFocusedProjectAvailable()
&& fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(resourcesPath,
"META-INF/persistence.xml"));
}
public boolean isRepositoryInstallationPossible() {
return isInstalledInModule(projectOperations.getFocusedModuleName())
&& !projectOperations
.isFeatureInstalledInFocusedModule(FeatureNames.MONGO);
}
public void setupRepository(final JavaType interfaceType,
final JavaType domainType) {
Validate.notNull(interfaceType, "Interface type required");
Validate.notNull(domainType, "Domain type required");
final String interfaceIdentifier = pathResolver
.getFocusedCanonicalPath(Path.SRC_MAIN_JAVA, interfaceType);
if (fileManager.exists(interfaceIdentifier)) {
return; // Type exists already - nothing to do
}
// Build interface type
final AnnotationMetadataBuilder interfaceAnnotationMetadata = new AnnotationMetadataBuilder(
ROO_REPOSITORY_JPA);
interfaceAnnotationMetadata.addAttribute(new ClassAttributeValue(
new JavaSymbolName("domainType"), domainType));
final String interfaceMdId = PhysicalTypeIdentifier.createIdentifier(
interfaceType, pathResolver.getPath(interfaceIdentifier));
final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(
interfaceMdId, Modifier.PUBLIC, interfaceType,
PhysicalTypeCategory.INTERFACE);
cidBuilder.addAnnotation(interfaceAnnotationMetadata.build());
typeManagementService.createOrUpdateTypeOnDisk(cidBuilder.build());
// Take care of project configuration
configureProject();
}
}