/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.management.internal.cli.converters;
import java.io.File;
import java.util.List;
import org.springframework.shell.core.Completion;
import org.springframework.shell.core.MethodTarget;
import org.springframework.shell.support.util.FileUtils;
import org.springframework.util.Assert;
import org.apache.geode.management.cli.ConverterHint;
import org.apache.geode.management.internal.cli.MultipleValueAdapter;
import org.apache.geode.management.internal.cli.shell.Gfsh;
/**
*
* @since GemFire 7.0
*
*
*/
public class DirConverter extends MultipleValueAdapter<String[]> {
private static final String HOME_DIRECTORY_SYMBOL = "~";
// Constants
private static final String home = System.getProperty("user.home");
@Override
public String[] convertFromText(String[] values, Class<?> targetType, String context) {
return values;
}
@Override
public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType,
String[] existingData, String context, MethodTarget target) {
String adjustedUserInput = convertUserInputIntoAFullyQualifiedPath(
(existingData != null) ? existingData[existingData.length - 1] : "");
String directoryData =
adjustedUserInput.substring(0, adjustedUserInput.lastIndexOf(File.separator) + 1);
adjustedUserInput =
adjustedUserInput.substring(adjustedUserInput.lastIndexOf(File.separator) + 1);
populate(completions, adjustedUserInput,
((existingData != null) ? existingData[existingData.length - 1] : ""), directoryData);
return true;
}
protected void populate(final List<Completion> completions, final String adjustedUserInput,
final String originalUserInput, final String directoryData) {
File directory = new File(directoryData);
if (!directory.isDirectory()) {
return;
}
for (File file : directory.listFiles()) {
if (adjustedUserInput == null || adjustedUserInput.length() == 0
|| file.getName().toLowerCase().startsWith(adjustedUserInput.toLowerCase())) {
String completion = "";
if (directoryData.length() > 0)
completion += directoryData;
completion += file.getName();
completion = convertCompletionBackIntoUserInputStyle(originalUserInput, completion);
if (file.isDirectory()) {
completions.add(new Completion(completion + File.separator));
}
}
}
}
private String convertCompletionBackIntoUserInputStyle(final String originalUserInput,
final String completion) {
if (FileUtils.denotesAbsolutePath(originalUserInput)) {
// Input was originally as a fully-qualified path, so we just keep the
// completion in that form
return completion;
}
if (originalUserInput.startsWith(HOME_DIRECTORY_SYMBOL)) {
// Input originally started with this symbol, so replace the user's home
// directory with it again
Assert.notNull(home, "Home directory could not be determined from system properties");
return HOME_DIRECTORY_SYMBOL + completion.substring(home.length());
}
// The path was working directory specific, so strip the working directory
// given the user never typed it
return completion.substring(getWorkingDirectoryAsString().length());
}
/**
* If the user input starts with a tilde character (~), replace the tilde character with the
* user's home directory. If the user input does not start with a tilde, simply return the
* original user input without any changes if the input specifies an absolute path, or return an
* absolute path based on the working directory if the input specifies a relative path.
*
* @param userInput the user input, which may commence with a tilde (required)
* @return a string that is guaranteed to no longer contain a tilde as the first character (never
* null)
*/
private String convertUserInputIntoAFullyQualifiedPath(final String userInput) {
if (FileUtils.denotesAbsolutePath(userInput)) {
// Input is already in a fully-qualified path form
return userInput;
}
if (userInput.startsWith(HOME_DIRECTORY_SYMBOL)) {
// Replace this symbol with the user's actual home directory
Assert.notNull(home, "Home directory could not be determined from system properties");
if (userInput.length() > 1) {
return home + userInput.substring(1);
}
}
// The path is working directory specific, so prepend the working directory
String fullPath = getWorkingDirectoryAsString() + userInput;
return fullPath;
}
private String getWorkingDirectoryAsString() {
try {
return getWorkingDirectory().getCanonicalPath() + File.separator;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
/**
* @return the "current working directory" this {@link DirConverter} should use if the user fails
* to provide an explicit directory in their input (required)
*/
private File getWorkingDirectory() {
return Gfsh.getCurrentInstance().getHome();
}
@Override
public boolean supports(Class<?> type, String optionContext) {
if (String[].class.isAssignableFrom(type) && optionContext.equals(ConverterHint.DIRS)) {
return true;
}
return false;
}
}