package org.springframework.roo.classpath.converters;
import static org.springframework.roo.shell.OptionContexts.UPDATE;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
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.TypeLocationService;
import org.springframework.roo.model.JavaPackage;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.project.maven.Pom;
import org.springframework.roo.shell.Completion;
import org.springframework.roo.shell.Converter;
import org.springframework.roo.shell.MethodTarget;
/**
* A {@link Converter} for {@link JavaPackage}s, with support for using
* {@value #TOP_LEVEL_PACKAGE_SYMBOL} to denote the user's top-level package.
*
* @author Ben Alex
* @since 1.0
*/
@Component
@Service
public class JavaPackageConverter implements Converter<JavaPackage> {
/**
* The shell character that represents the current project or module's top
* level Java package.
*/
public static final String TOP_LEVEL_PACKAGE_SYMBOL = "~";
@Reference FileManager fileManager;
@Reference LastUsed lastUsed;
@Reference ProjectOperations projectOperations;
@Reference TypeLocationService typeLocationService;
public JavaPackage convertFromText(final String value,
final Class<?> requiredType, final String optionContext) {
if (StringUtils.isBlank(value)) {
return null;
}
final JavaPackage result = new JavaPackage(
convertToFullyQualifiedPackageName(value));
if (optionContext != null && optionContext.contains(UPDATE)) {
lastUsed.setPackage(result);
}
return result;
}
private String convertToFullyQualifiedPackageName(final String text) {
final String normalisedText = StringUtils.removeEnd(text, ".")
.toLowerCase();
if (normalisedText.startsWith(TOP_LEVEL_PACKAGE_SYMBOL)) {
return replaceTopLevelPackageSymbol(normalisedText);
}
return normalisedText;
}
public boolean getAllPossibleValues(final List<Completion> completions,
final Class<?> requiredType, final String existingData,
final String optionContext, final MethodTarget target) {
if (projectOperations.isFocusedProjectAvailable()) {
completions.addAll(getCompletionsForAllKnownPackages());
}
return false;
}
private Collection<Completion> getCompletionsForAllKnownPackages() {
final Collection<Completion> completions = new LinkedHashSet<Completion>();
for (final Pom pom : projectOperations.getPoms()) {
for (final JavaType javaType : typeLocationService
.getTypesForModule(pom)) {
final String type = javaType.getFullyQualifiedTypeName();
completions.add(new Completion(type.substring(0,
type.lastIndexOf('.'))));
}
}
return completions;
}
private String getTopLevelPackage() {
if (projectOperations.isFocusedProjectAvailable()) {
return typeLocationService
.getTopLevelPackageForModule(projectOperations
.getFocusedModule());
}
// Shouldn't happen if there's a project, i.e. most of the time
return "";
}
/**
* Replaces the {@link #TOP_LEVEL_PACKAGE_SYMBOL} at the beginning of the
* given text with the current project/module's top-level package
*
* @param text
* @return a well-formed Java package name (might have a trailing dot)
*/
private String replaceTopLevelPackageSymbol(final String text) {
final String topLevelPackage = getTopLevelPackage();
if (TOP_LEVEL_PACKAGE_SYMBOL.equals(text)) {
return topLevelPackage;
}
final String textWithoutSymbol = StringUtils.removeStart(text,
TOP_LEVEL_PACKAGE_SYMBOL);
return topLevelPackage + "."
+ StringUtils.removeStart(textWithoutSymbol, ".");
}
public boolean supports(final Class<?> requiredType,
final String optionContext) {
return JavaPackage.class.isAssignableFrom(requiredType);
}
}