package org.springframework.roo.project;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.metadata.MetadataDependencyRegistry;
import org.springframework.roo.metadata.MetadataNotificationListener;
import org.springframework.roo.metadata.internal.MetadataDependencyRegistryTracker;
import org.springframework.roo.project.maven.Pom;
/**
* Automatically upgrades a Spring Roo annotation JAR to the current version of
* Roo. If the annotation JAR is equal to or newer than the version of Roo
* running, the upgrade service makes no changes.
*
* @author Ben Alex
* @author Enrique Ruiz at DISID Corporation S.L.
* @since 1.1
*/
@Component
public class AutomaticProjectUpgradeService implements MetadataNotificationListener {
private static class VersionInfo implements Comparable<VersionInfo> {
private Integer major = 0;
private Integer minor = 0;
private Integer patch = 0;
private String qualifier = "";
public int compareTo(final VersionInfo v) {
if (v == null) {
throw new NullPointerException("VersionInfo is null");
}
int result = major.compareTo(v.major);
if (result != 0) {
return result;
}
result = minor.compareTo(v.minor);
if (result != 0) {
return result;
}
result = patch.compareTo(v.patch);
if (result != 0) {
return result;
}
result = qualifier.compareTo(v.qualifier);
if (result != 0) {
return result;
}
return 0;
}
@Override
public String toString() {
return major + "." + minor + "." + patch + "." + qualifier;
}
}
private static final String MY_BUNDLE_SYMBOLIC_NAME = AutomaticProjectUpgradeService.class
.getPackage().getName();
private static final String SPRING_VERSION = "3.1.0.RELEASE";
private VersionInfo bundleVersionInfo;
@Reference
private ProjectOperations projectOperations;
protected MetadataDependencyRegistryTracker registryTracker = null;
/**
* This service is being activated so setup it:
* <ul>
* <li>Create and open the {@link MetadataDependencyRegistryTracker}.</li>
* </ul>
*/
protected void activate(final ComponentContext componentContext) {
this.registryTracker =
new MetadataDependencyRegistryTracker(componentContext.getBundleContext(), this);
this.registryTracker.open();
for (final Bundle b : componentContext.getBundleContext().getBundles()) {
if (!MY_BUNDLE_SYMBOLIC_NAME.equals(b.getSymbolicName())) {
continue;
}
final Object v = b.getHeaders().get("Bundle-Version");
if (v != null) {
final String version = v.toString();
bundleVersionInfo = extractVersionInfoFromString(version);
}
break;
}
}
/**
* This service is being deactivated so unregister upstream-downstream
* dependencies, triggers, matchers and listeners.
*
* @param context
*/
protected void deactivate(final ComponentContext componentContext) {
MetadataDependencyRegistry registry = this.registryTracker.getService();
registry.removeNotificationListener(this);
this.registryTracker.close();
}
/**
* Extracts the version information from the string. Never throws an
* exception.
*
* @param version to extract from (can be null or empty)
* @return the version information or null if it was not in a normal form
*/
private VersionInfo extractVersionInfoFromString(final String version) {
if (StringUtils.isBlank(version)) {
return null;
}
final String[] ver = version.split("\\.");
try {
if (ver.length == 4) {
final VersionInfo result = new VersionInfo();
result.major = new Integer(ver[0]);
result.minor = new Integer(ver[1]);
result.patch = new Integer(ver[2]);
result.qualifier = ver[3];
return result;
}
} catch (final RuntimeException e) {
return null;
}
return null;
}
public void notify(final String upstreamDependency, final String downstreamDependency) {
if (bundleVersionInfo != null && ProjectMetadata.isValid(upstreamDependency)) {
final String moduleName = ProjectMetadata.getModuleName(upstreamDependency);
// Project Metadata available.
if (!projectOperations.isProjectAvailable(moduleName)) {
return;
}
for (final Pom pom : projectOperations.getPoms()) {
final Set<Property> rooVersionResults =
pom.getPropertiesExcludingValue(new Property("roo.version"));
for (final Property existingProperty : rooVersionResults) {
final VersionInfo rooVersion = extractVersionInfoFromString(existingProperty.getValue());
if (rooVersion != null) {
if (rooVersion.compareTo(bundleVersionInfo) < 0) {
final Property newProperty =
new Property(existingProperty.getName(), bundleVersionInfo.toString());
projectOperations.addProperty(moduleName, newProperty);
break;
}
}
}
final Set<Property> springVersionResults =
pom.getPropertiesExcludingValue(new Property("spring.version"));
for (final Property existingProperty : springVersionResults) {
final VersionInfo springVersion =
extractVersionInfoFromString(existingProperty.getValue());
if (springVersion != null) {
final VersionInfo latestSpringVersion = extractVersionInfoFromString(SPRING_VERSION);
if (springVersion.compareTo(latestSpringVersion) < 0) {
final Property newProperty =
new Property(existingProperty.getName(), latestSpringVersion.toString());
projectOperations.addProperty(moduleName, newProperty);
break;
}
}
}
}
}
}
}