/* * gvNIX is an open source tool for rapid application development (RAD). * Copyright (C) 2010 Generalitat Valenciana * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.gvnix.service.roo.addon.addon.converters; import java.io.File; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.SortedSet; 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.file.monitor.event.FileDetails; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaType; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.Path; import org.springframework.roo.project.PathResolver; import org.springframework.roo.project.ProjectMetadata; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.shell.Completion; import org.springframework.roo.shell.Converter; import org.springframework.roo.shell.MethodTarget; /** * @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a * href="http://www.dgti.gva.es">General Directorate for Information * Technologies (DGTI)</a> */ @Component @Service public class JavaTypeListConverter implements Converter<JavaTypeList> { @Reference private MetadataService metadataService; @Reference private FileManager fileManager; @Reference private ProjectOperations projectOperations; /* * (non-Javadoc) * * @see * org.springframework.roo.shell.Converter#convertFromText(java.lang.String, * java.lang.Class, java.lang.String) */ public JavaTypeList convertFromText(String value, Class<?> requiredType, String optionContext) { JavaTypeList javaTypeList = new JavaTypeList(); List<JavaType> javaTypes = new ArrayList<JavaType>(); String[] javaTypeStringList; javaTypeStringList = StringUtils.split(value, ","); JavaType javaType; for (int i = 0; i <= javaTypeStringList.length - 1; i++) { javaType = new JavaType(javaTypeStringList[i]); javaTypes.add(javaType); } javaTypeList.setJavaTypes(javaTypes); return javaTypeList; } /* * (non-Javadoc) * * @see * org.springframework.roo.shell.Converter#getAllPossibleValues(java.util * .List, java.lang.Class, java.lang.String, java.lang.String, * org.springframework.roo.shell.MethodTarget) */ public boolean getAllPossibleValues(List<Completion> completions, Class<?> requiredType, String existingData, String optionContext, MethodTarget target) { if (existingData == null) { existingData = ""; } // Prepare the strings to compare with JavaTypes. String tmpExistingData = existingDataToComplete(existingData); String completeExistingDataList = convertInputIntoPrefixCompletion(existingData); if (optionContext != null && optionContext.contains("java")) { // Compare Java Basic Types. completeJavaSpecificPaths(completions, existingData, optionContext, completeExistingDataList, tmpExistingData); // Compare Project Java Types. completeProjectSpecificPaths(completions, existingData, completeExistingDataList, tmpExistingData); // } else if (optionContext != null // && optionContext.contains("exceptions")) { // // TODO: Nothing to do. } return false; } /* * (non-Javadoc) * * @see org.springframework.roo.shell.Converter#supports(java.lang.Class, * java.lang.String) */ public boolean supports(Class<?> requiredType, String optionContext) { return JavaTypeList.class.isAssignableFrom(requiredType); } /** * Adds common "java." types to the completions. For now we just provide * them statically. * * @param completions Completions to show in console for the Input String. * @param existingData String value from the command attribute. * @param optionContext Option context to evaluate. * @param completeExistingDataList String separated comma list of JavaType. * @param tmpExistingData The last JavaType from console Input to auto * complete. */ private void completeJavaSpecificPaths(List<Completion> completions, String existingData, String optionContext, String completeExistingDataList, String tmpExistingData) { List<String> types = new ArrayList<String>(); types.add(Boolean.class.getName()); types.add(String.class.getName()); // lang - numeric types.add(Number.class.getName()); types.add(Short.class.getName()); types.add(Byte.class.getName()); types.add(Integer.class.getName()); types.add(Long.class.getName()); types.add(Float.class.getName()); types.add(Double.class.getName()); // misc types.add(BigDecimal.class.getName()); types.add(BigInteger.class.getName()); // util types.add(List.class.getName()); // util types.add(Date.class.getName()); types.add(Calendar.class.getName()); for (String type : types) { if (type.startsWith(tmpExistingData) || tmpExistingData.startsWith(type)) { completions.add(new Completion(completeExistingDataList .concat(type))); } } } /** * Converts the input String from the shell to a Prefix to the completions. * * @param existingData String value from the command attribute. * @return {@link String} completePrefix to add for completions. */ private String convertInputIntoPrefixCompletion(String existingData) { String[] existingDataList; String completeExistingDataList = ""; existingDataList = StringUtils.split(existingData, ","); for (int i = 0; i < existingDataList.length - 1; i++) { if (completeExistingDataList.compareTo("") == 0) { completeExistingDataList = completeExistingDataList .concat(existingDataList[i]); } else { completeExistingDataList = completeExistingDataList.concat(",") .concat(existingDataList[i]); } } if (existingDataList.length > 1) { completeExistingDataList = completeExistingDataList.concat(","); } return completeExistingDataList; } /** * Return the last String member for auto completion. * <p> * The Input String is separated between commas. * </p> * * @param existingData Console Input String to compare. * @return {@link String} last member of the String to compare. */ private String existingDataToComplete(String existingData) { String[] existingDataList; String tmpExistingData; existingDataList = StringUtils.split(existingData, ","); if (existingDataList.length > 0) { tmpExistingData = StringUtils .trim(existingDataList[existingDataList.length - 1]); } else { tmpExistingData = existingData; } return tmpExistingData; } /** * Adds project "java." types to the completions. For now we just provide * them statically. * * @param completions * @param existingData * @param completeExistingDataList * @param tmpExistingData */ private void completeProjectSpecificPaths(List<Completion> completions, String existingData, String completeExistingDataList, String tmpExistingData) { String topLevelPath = ""; ProjectMetadata projectMetadata = (ProjectMetadata) metadataService .get(ProjectMetadata.getProjectIdentifier(projectOperations .getFocusedModuleName())); if (projectMetadata == null) { return; } topLevelPath = projectOperations.getTopLevelPackage( projectOperations.getFocusedModuleName()) .getFullyQualifiedPackageName(); String newValue = tmpExistingData; if (tmpExistingData.startsWith("~")) { if (tmpExistingData.length() > 1) { if (tmpExistingData.charAt(1) == '.') { newValue = topLevelPath + tmpExistingData.substring(1); } else { newValue = topLevelPath + "." + tmpExistingData.substring(1); } } else { newValue = topLevelPath + File.separator; } } PathResolver pathResolver = projectOperations.getPathResolver(); String antPath = pathResolver.getRoot(LogicalPath.getInstance( Path.SRC_MAIN_JAVA, "")) + File.separatorChar + newValue.replace(".", File.separator) + "*"; SortedSet<FileDetails> entries = fileManager .findMatchingAntPath(antPath); for (FileDetails fileIdentifier : entries) { String candidate = pathResolver.getRelativeSegment( fileIdentifier.getCanonicalPath()).substring(1); // drop the // leading // "/" boolean include = false; boolean directory = false; if (fileIdentifier.getFile().isDirectory()) { // Do not include directories that start with ., as this is used // for purposes like SVN (see ROO-125) if (!fileIdentifier.getFile().getName().startsWith(".")) { include = true; directory = true; } } else { // a file if (candidate.endsWith(".java")) { candidate = candidate.substring(0, candidate.length() - 5); // drop // .java include = true; } } if (include) { // Convert this path back into something the user would type if (tmpExistingData.startsWith("~")) { if (tmpExistingData.length() > 1) { if (tmpExistingData.charAt(1) == '.') { candidate = "~." + candidate .substring(topLevelPath.length() + 1); } else { candidate = "~" + candidate .substring(topLevelPath.length() + 1); } } else { candidate = "~" + candidate .substring(topLevelPath.length() + 1); } } candidate = candidate.replace(File.separator, "."); if (directory) { candidate = candidate + "."; } completions.add(new Completion(completeExistingDataList .concat(candidate))); } } } }