blob: 32997a3ed102a3e9e69fd160858c1f9d8d48eae9 [file] [log] [blame]
/*
* Copyright 2014-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.auth.profile.internal;
import java.util.AbstractMap;
import java.util.Map.Entry;
import java.util.Scanner;
/**
* An abstract template class for the generic operation that involves scanning
* through a profile configuration file. Subclass should implement the abstract
* methods to define the actions when different components of the profiles file
* are detected.
*/
public abstract class AbstractProfilesConfigFileScanner {
/**
* Action to be performed when an empty or comment line is detected
*/
protected abstract void onEmptyOrCommentLine(String profileName, String line);
/**
* Action to be performed when the starting line of a new profile is detected
*/
protected abstract void onProfileStartingLine(String newProfileName, String line);
/**
* Action to be performed when the scanner reaches the end of a profile
* section. This method is invoked either at the start of a new profile
* section, or at the end of the file.
*/
protected abstract void onProfileEndingLine(String prevProfileName);
/**
* Action to be performed when the scanner reaches the end of the
* credentials file.
*/
protected abstract void onEndOfFile();
/**
* Action to be performed when a property declaration is detected inside a
* profile section.
*
* @param profileName
* The name of the profile where this property is declared.
* @param propertyName
* The name of the property.
* @param propertyValue
* The value of the property.
* @param isSupportedProperty
* Whether this is a supported property according to the
* specification of credential profiles file.
* @param line
* The original line of text where the property is declared.
*/
protected abstract void onProfileProperty(String profileName,
String propertyName,
String propertyValue,
boolean isSupportedProperty,
String line);
/**
* Hook to allow subclasses to determine which properties are supported and which aren't.
*
* @return True if property is supported by scanner implementation, false otherwise.
*/
protected boolean isSupportedProperty(String propertyName) {
return true;
}
/**
* Scan through the given input, and perform the defined actions.
*
* @param scanner
* The scanner for the credentials file input.
*/
protected void run(Scanner scanner) {
String currentProfileName = null;
try {
while(scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
// Empty or comment lines
if (line.isEmpty() || line.startsWith("#")) {
onEmptyOrCommentLine(currentProfileName, line);
continue;
}
// parseGroupName returns null if this line does not
// indicate a new property group.
String newProfileName = parseProfileName(line);
boolean atNewProfileStartingLine = newProfileName != null;
if (atNewProfileStartingLine) {
if (currentProfileName != null) {
onProfileEndingLine(currentProfileName);
}
onProfileStartingLine(newProfileName, line);
// Start the new profile
currentProfileName = newProfileName;
} else {
// Parse the property line
Entry<String, String> property = parsePropertyLine(line);
if (currentProfileName == null) {
throw new IllegalArgumentException(
"Property is defined without a preceding profile name. "
+ "Current line: " + line);
}
onProfileProperty(currentProfileName,
property.getKey(),
property.getValue(),
isSupportedProperty(property.getKey()),
line);
}
}
// EOF
if (currentProfileName != null) {
onProfileEndingLine(currentProfileName);
}
onEndOfFile();
} finally {
scanner.close();
}
}
/**
* Returns the profile name if this line indicates the beginning of a new
* profile section. Otherwise, returns null.
*/
private static String parseProfileName(String trimmedLine) {
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
String profileName = trimmedLine.substring(1, trimmedLine.length() - 1);
return profileName.trim();
}
return null;
}
private static Entry<String, String> parsePropertyLine(String propertyLine) {
String[] pair = propertyLine.split("=", 2);
if (pair.length != 2) {
throw new IllegalArgumentException(
"Invalid property format: no '=' character is found in the line ["
+ propertyLine + "].");
}
String propertyKey = pair[0].trim();
String propertyValue = pair[1].trim();
return new AbstractMap.SimpleImmutableEntry<String, String>(propertyKey, propertyValue);
}
}