package org.springframework.roo.addon.cache;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.cache.providers.CacheProvider;
import org.springframework.roo.classpath.ModuleFeatureName;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.model.SpringJavaType;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.FeatureNames;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.project.maven.Pom;
import org.springframework.roo.support.logging.HandlerUtils;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
/**
* Operations for the 'push-in' add-on.
*
* @author Sergio Clares
* @since 2.0
*/
@Component
@Service
public class CacheOperationsImpl implements CacheOperations {
// ------------ OSGi component attributes ----------------
private BundleContext context;
private ProjectOperations projectOperations;
private TypeLocationService typeLocationService;
private TypeManagementService typeManagementService;
protected void activate(final ComponentContext cContext) {
this.context = cContext.getBundleContext();
}
private static final Logger LOGGER = HandlerUtils.getLogger(CacheOperationsImpl.class);
@Override
public boolean isCacheSetupAvailable() {
return getProjectOperations().isFocusedProjectAvailable()
&& getProjectOperations().isFeatureInstalled(FeatureNames.JPA);
}
@Override
public void setupCache(CacheProvider provider, String profile) {
// Add spring-boot-starter-cache dependency
List<Pom> modules =
(List<Pom>) getTypeLocationService().getModules(ModuleFeatureName.APPLICATION);
if (modules.size() == 0) {
throw new RuntimeException(String.format("ERROR: Not found a module with %s feature",
ModuleFeatureName.APPLICATION));
}
// Do the setup for each @SpringBootApplication module
for (Pom module : modules) {
addSpringCacheDependency(module);
}
// Add @EnableCache annotation to each application file
Set<ClassOrInterfaceTypeDetails> applicationClasses =
getTypeLocationService().findClassesOrInterfaceDetailsWithAnnotation(
SpringJavaType.SPRING_BOOT_APPLICATION);
for (ClassOrInterfaceTypeDetails applicationClass : applicationClasses) {
if (applicationClass.getAnnotation(SpringJavaType.ENABLE_CACHING) == null) {
ClassOrInterfaceTypeDetailsBuilder builder =
new ClassOrInterfaceTypeDetailsBuilder(applicationClass);
builder.addAnnotation(new AnnotationMetadataBuilder(SpringJavaType.ENABLE_CACHING));
getTypeManagementService().createOrUpdateTypeOnDisk(builder.build());
}
}
if (provider != null) {
// Do setup of cache provider
if (!provider.isInstalled()) {
provider.setup(profile);
}
}
}
/**
* Add Spring Cache starter to provided module.
*
* @param module the Pom where the starter should be installed.
*/
private void addSpringCacheDependency(Pom module) {
// Parse the configuration.xml file
final Element configuration = XmlUtils.getConfiguration(getClass());
final List<Dependency> dependencies = new ArrayList<Dependency>();
final List<Element> auditDependencies =
XmlUtils.findElements("/configuration/cache/dependencies/dependency", configuration);
for (final Element dependencyElement : auditDependencies) {
dependencies.add(new Dependency(dependencyElement));
}
getProjectOperations().addDependencies(module.getModuleName(), dependencies);
}
/**
* Method to obtain projectOperation service implementation
*
* @return
*/
public ProjectOperations getProjectOperations() {
if (projectOperations == null) {
// Get all Services implement ProjectOperations interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(ProjectOperations.class.getName(), null);
for (ServiceReference<?> ref : references) {
projectOperations = (ProjectOperations) context.getService(ref);
return projectOperations;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load ProjectOperations on PushInOperationsImpl.");
return null;
}
} else {
return projectOperations;
}
}
/**
* Method to obtain typeLocationService service implementation
*
* @return
*/
public TypeLocationService getTypeLocationService() {
if (typeLocationService == null) {
// Get all Services implement TypeLocationService interface
try {
ServiceReference<?>[] references =
context.getAllServiceReferences(TypeLocationService.class.getName(), null);
for (ServiceReference<?> ref : references) {
typeLocationService = (TypeLocationService) context.getService(ref);
return typeLocationService;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load TypeLocationService on PushInOperationsImpl.");
return null;
}
} else {
return typeLocationService;
}
}
/**
* Method to obtain typeManagementService service implementation
*
* @return
*/
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) {
typeManagementService = (TypeManagementService) context.getService(ref);
return typeManagementService;
}
return null;
} catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load TypeManagementService on PushInOperationsImpl.");
return null;
}
} else {
return typeManagementService;
}
}
}