http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/internal/resources/io/StringUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/StringUtils.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/StringUtils.java new file mode 100644 index 0000000..bfdb5f2 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/StringUtils.java @@ -0,0 +1,1173 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed 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.tamaya.core.internal.resources.io; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.TreeSet; + +/** +* Miscellaneous {@link String} utility methods. +* +* <p>Mainly for internal use within the framework; consider +* <a href="http://jakarta.apache.org/commons/lang/">Jakarta's Commons Lang</a> +* for a more comprehensive suite of String utilities. +* +* <p>This class delivers some simple functionality that should really +* be provided by the core Java {@code String} and {@link StringBuilder} +* classes, such as the ability to {@code replace} all occurrences of a given +* substring in a target string. It also provides easy-to-use methods to convert +* between delimited strings, such as CSV strings, and collections and arrays. +* +* @author Rod Johnson +* @author Juergen Hoeller +* @author Keith Donald +* @author Rob Harrop +* @author Rick Evans +* @author Arjen Poutsma +* @since 16 April 2001 +*/ +class StringUtils { + + private static final String FOLDER_SEPARATOR = "/"; + + private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; + + private static final String TOP_PATH = ".."; + + private static final String CURRENT_PATH = "."; + +// private static final char EXTENSION_SEPARATOR = '.'; +// + + private StringUtils(){} + +// //--------------------------------------------------------------------- +// // General convenience methods for working with Strings +// //--------------------------------------------------------------------- +// +// /** +// * Check whether the given String is empty. +// * <p>This method accepts any Object as an argument, comparing it to +// * {@code null} and the empty String. As a consequence, this method +// * will never return {@code true} for a non-null non-String object. +// * <p>The Object signature is useful for general attribute handling code +// * that commonly deals with Strings but generally has to iterate over +// * Objects since attributes may e.g. be primitive value objects as well. +// * @param str the candidate String +// * @since 3.2.1 +// */ +// public static boolean isEmpty(Object str) { +// return (str == null || "".equals(str)); +// } + + /** + * Check that the given CharSequence is neither {@code null} nor of length 0. + * Note: Will return {@code true} for a CharSequence that purely consists of whitespace. + * <p><pre class="code"> + * StringUtils.hasLength(null) = false + * StringUtils.hasLength("") = false + * StringUtils.hasLength(" ") = true + * StringUtils.hasLength("Hello") = true + * </pre> + * @param str the CharSequence to check (may be {@code null}) + * @return {@code true} if the CharSequence is not null and has length + */ + public static boolean hasLength(CharSequence str) { + return (str != null && str.length() > 0); + } + +// /** +// * Check that the given String is neither {@code null} nor of length 0. +// * Note: Will return {@code true} for a String that purely consists of whitespace. +// * @param str the String to check (may be {@code null}) +// * @return {@code true} if the String is not null and has length +// * @see #hasLength(CharSequence) +// */ +// public static boolean hasLength(String str) { +// return hasLength((CharSequence) str); +// } + + /** + * Check whether the given CharSequence has actual text. + * More specifically, returns {@code true} if the string not {@code null}, + * its length is greater than 0, and it contains at least one non-whitespace character. + * <p><pre class="code"> + * StringUtils.hasText(null) = false + * StringUtils.hasText("") = false + * StringUtils.hasText(" ") = false + * StringUtils.hasText("12345") = true + * StringUtils.hasText(" 12345 ") = true + * </pre> + * @param str the CharSequence to check (may be {@code null}) + * @return {@code true} if the CharSequence is not {@code null}, + * its length is greater than 0, and it does not contain whitespace only + * @see Character#isWhitespace + */ + public static boolean hasText(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String has actual text. + * More specifically, returns {@code true} if the string not {@code null}, + * its length is greater than 0, and it contains at least one non-whitespace character. + * @param str the String to check (may be {@code null}) + * @return {@code true} if the String is not {@code null}, its length is + * greater than 0, and it does not contain whitespace only + * @see #hasText(CharSequence) + */ + public static boolean hasText(String str) { + return hasText((CharSequence) str); + } + +// /** +// * Check whether the given CharSequence contains any whitespace characters. +// * @param str the CharSequence to check (may be {@code null}) +// * @return {@code true} if the CharSequence is not empty and +// * contains at least 1 whitespace character +// * @see Character#isWhitespace +// */ +// public static boolean containsWhitespace(CharSequence str) { +// if (!hasLength(str)) { +// return false; +// } +// int strLen = str.length(); +// for (int i = 0; i < strLen; i++) { +// if (Character.isWhitespace(str.charAt(i))) { +// return true; +// } +// } +// return false; +// } +// +// /** +// * Check whether the given String contains any whitespace characters. +// * @param str the String to check (may be {@code null}) +// * @return {@code true} if the String is not empty and +// * contains at least 1 whitespace character +// * @see #containsWhitespace(CharSequence) +// */ +// public static boolean containsWhitespace(String str) { +// return containsWhitespace((CharSequence) str); +// } +// +// /** +// * Trim leading and trailing whitespace from the given String. +// * @param str the String to check +// * @return the trimmed String +// * @see java.lang.Character#isWhitespace +// */ +// public static String trimWhitespace(String str) { +// if (!hasLength(str)) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str); +// while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { +// sb.deleteCharAt(0); +// } +// while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { +// sb.deleteCharAt(sb.length() - 1); +// } +// return sb.toString(); +// } +// +// /** +// * Trim <i>all</i> whitespace from the given String: +// * leading, trailing, and in between characters. +// * @param str the String to check +// * @return the trimmed String +// * @see java.lang.Character#isWhitespace +// */ +// public static String trimAllWhitespace(String str) { +// if (!hasLength(str)) { +// return str; +// } +// int len = str.length(); +// StringBuilder sb = new StringBuilder(str.length()); +// for (int i = 0; i < len; i++) { +// char c = str.charAt(i); +// if (!Character.isWhitespace(c)) { +// sb.append(c); +// } +// } +// return sb.toString(); +// } +// +// /** +// * Trim leading whitespace from the given String. +// * @param str the String to check +// * @return the trimmed String +// * @see java.lang.Character#isWhitespace +// */ +// public static String trimLeadingWhitespace(String str) { +// if (!hasLength(str)) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str); +// while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { +// sb.deleteCharAt(0); +// } +// return sb.toString(); +// } +// +// /** +// * Trim trailing whitespace from the given String. +// * @param str the String to check +// * @return the trimmed String +// * @see java.lang.Character#isWhitespace +// */ +// public static String trimTrailingWhitespace(String str) { +// if (!hasLength(str)) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str); +// while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { +// sb.deleteCharAt(sb.length() - 1); +// } +// return sb.toString(); +// } +// +// /** +// * Trim all occurrences of the supplied leading character from the given String. +// * @param str the String to check +// * @param leadingCharacter the leading character to be trimmed +// * @return the trimmed String +// */ +// public static String trimLeadingCharacter(String str, char leadingCharacter) { +// if (!hasLength(str)) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str); +// while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) { +// sb.deleteCharAt(0); +// } +// return sb.toString(); +// } +// +// /** +// * Trim all occurrences of the supplied trailing character from the given String. +// * @param str the String to check +// * @param trailingCharacter the trailing character to be trimmed +// * @return the trimmed String +// */ +// public static String trimTrailingCharacter(String str, char trailingCharacter) { +// if (!hasLength(str)) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str); +// while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) { +// sb.deleteCharAt(sb.length() - 1); +// } +// return sb.toString(); +// } +// +// +// /** +// * Test if the given String starts with the specified prefix, +// * ignoring upper/lower case. +// * @param str the String to check +// * @param prefix the prefix to look for +// * @see java.lang.String#startsWith +// */ +// public static boolean startsWithIgnoreCase(String str, String prefix) { +// if (str == null || prefix == null) { +// return false; +// } +// if (str.startsWith(prefix)) { +// return true; +// } +// if (str.length() < prefix.length()) { +// return false; +// } +// String lcStr = str.substring(0, prefix.length()).toLowerCase(); +// String lcPrefix = prefix.toLowerCase(); +// return lcStr.equals(lcPrefix); +// } +// +// /** +// * Test if the given String ends with the specified suffix, +// * ignoring upper/lower case. +// * @param str the String to check +// * @param suffix the suffix to look for +// * @see java.lang.String#endsWith +// */ +// public static boolean endsWithIgnoreCase(String str, String suffix) { +// if (str == null || suffix == null) { +// return false; +// } +// if (str.endsWith(suffix)) { +// return true; +// } +// if (str.length() < suffix.length()) { +// return false; +// } +// +// String lcStr = str.substring(str.length() - suffix.length()).toLowerCase(); +// String lcSuffix = suffix.toLowerCase(); +// return lcStr.equals(lcSuffix); +// } +// +// /** +// * Test whether the given string matches the given substring +// * at the given index. +// * @param str the original string (or StringBuilder) +// * @param index the index in the original string to start matching against +// * @param substring the substring to match at the given index +// */ +// public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { +// for (int j = 0; j < substring.length(); j++) { +// int i = index + j; +// if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { +// return false; +// } +// } +// return true; +// } +// +// /** +// * Count the occurrences of the substring in string s. +// * @param str string to search in. Return 0 if this is null. +// * @param sub string to search for. Return 0 if this is null. +// */ +// public static int countOccurrencesOf(String str, String sub) { +// if (str == null || sub == null || str.length() == 0 || sub.length() == 0) { +// return 0; +// } +// int count = 0; +// int pos = 0; +// int idx; +// while ((idx = str.indexOf(sub, pos)) != -1) { +// ++count; +// pos = idx + sub.length(); +// } +// return count; +// } +// + /** + * Replace all occurrences of a substring within a string with + * another string. + * @param inString String to examine + * @param oldPattern String to replace + * @param newPattern String to insert + * @return a String with the replacements + */ + public static String replace(String inString, String oldPattern, String newPattern) { + if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { + return inString; + } + StringBuilder sb = new StringBuilder(); + int pos = 0; // our position in the old string + int index = inString.indexOf(oldPattern); + // the index of an occurrence we've found, or -1 + int patLen = oldPattern.length(); + while (index >= 0) { + sb.append(inString.substring(pos, index)); + sb.append(newPattern); + pos = index + patLen; + index = inString.indexOf(oldPattern, pos); + } + sb.append(inString.substring(pos)); + // remember to append any characters to the right of a match + return sb.toString(); + } + +// /** +// * Delete all occurrences of the given substring. +// * @param inString the original String +// * @param pattern the pattern to delete all occurrences of +// * @return the resulting String +// */ +// public static String delete(String inString, String pattern) { +// return replace(inString, pattern, ""); +// } +// + /** + * Delete any character in a given String. + * @param inString the original String + * @param charsToDelete a set of characters to delete. + * E.g. "az\n" will delete 'a's, 'z's and new lines. + * @return the resulting String + */ + public static String deleteAny(String inString, String charsToDelete) { + if (!hasLength(inString) || !hasLength(charsToDelete)) { + return inString; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + if (charsToDelete.indexOf(c) == -1) { + sb.append(c); + } + } + return sb.toString(); + } + +// +// //--------------------------------------------------------------------- +// // Convenience methods for working with formatted Strings +// //--------------------------------------------------------------------- +// +// /** +// * Quote the given String with single quotes. +// * @param str the input String (e.g. "myString") +// * @return the quoted String (e.g. "'myString'"), +// * or {@code null} if the input was {@code null} +// */ +// public static String quote(String str) { +// return (str != null ? "'" + str + "'" : null); +// } +// +// /** +// * Turn the given Object into a String with single quotes +// * if it is a String; keeping the Object as-is else. +// * @param obj the input Object (e.g. "myString") +// * @return the quoted String (e.g. "'myString'"), +// * or the input object as-is if not a String +// */ +// public static Object quoteIfString(Object obj) { +// return (obj instanceof String ? quote((String) obj) : obj); +// } +// +// /** +// * Unqualify a string qualified by a '.' dot character. For example, +// * "this.name.is.qualified", returns "qualified". +// * @param qualifiedName the qualified name +// */ +// public static String unqualify(String qualifiedName) { +// return unqualify(qualifiedName, '.'); +// } +// +// /** +// * Unqualify a string qualified by a separator character. For example, +// * "this:name:is:qualified" returns "qualified" if using a ':' separator. +// * @param qualifiedName the qualified name +// * @param separator the separator +// */ +// public static String unqualify(String qualifiedName, char separator) { +// return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); +// } +// +// /** +// * Capitalize a {@code String}, changing the first letter to +// * upper case as per {@link Character#toUpperCase(char)}. +// * No other letters are changed. +// * @param str the String to capitalize, may be {@code null} +// * @return the capitalized String, {@code null} if null +// */ +// public static String capitalize(String str) { +// return changeFirstCharacterCase(str, true); +// } +// +// /** +// * Uncapitalize a {@code String}, changing the first letter to +// * lower case as per {@link Character#toLowerCase(char)}. +// * No other letters are changed. +// * @param str the String to uncapitalize, may be {@code null} +// * @return the uncapitalized String, {@code null} if null +// */ +// public static String uncapitalize(String str) { +// return changeFirstCharacterCase(str, false); +// } +// +// private static String changeFirstCharacterCase(String str, boolean capitalize) { +// if (str == null || str.length() == 0) { +// return str; +// } +// StringBuilder sb = new StringBuilder(str.length()); +// if (capitalize) { +// sb.append(Character.toUpperCase(str.charAt(0))); +// } +// else { +// sb.append(Character.toLowerCase(str.charAt(0))); +// } +// sb.append(str.substring(1)); +// return sb.toString(); +// } + + /** + * Extract the filename from the given path, + * e.g. "mypath/myfile.txt" -> "myfile.txt". + * @param path the file path (may be {@code null}) + * @return the extracted filename, or {@code null} if none + */ + public static String getFilename(String path) { + if (path == null) { + return null; + } + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); + } + +// /** +// * Extract the filename extension from the given path, +// * e.g. "mypath/myfile.txt" -> "txt". +// * @param path the file path (may be {@code null}) +// * @return the extracted filename extension, or {@code null} if none +// */ +// public static String getFilenameExtension(String path) { +// if (path == null) { +// return null; +// } +// int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); +// if (extIndex == -1) { +// return null; +// } +// int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); +// if (folderIndex > extIndex) { +// return null; +// } +// return path.substring(extIndex + 1); +// } +// +// /** +// * Strip the filename extension from the given path, +// * e.g. "mypath/myfile.txt" -> "mypath/myfile". +// * @param path the file path (may be {@code null}) +// * @return the path with stripped filename extension, +// * or {@code null} if none +// */ +// public static String stripFilenameExtension(String path) { +// if (path == null) { +// return null; +// } +// int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); +// if (extIndex == -1) { +// return path; +// } +// int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); +// if (folderIndex > extIndex) { +// return path; +// } +// return path.substring(0, extIndex); +// } + + /** + * Apply the given relative path to the given path, + * assuming standard Java folder separation (i.e. "/" separators). + * @param path the path to start from (usually a full file path) + * @param relativePath the relative path to apply + * (relative to the full file path above) + * @return the full file path that results from applying the relative path + */ + public static String applyRelativePath(String path, String relativePath) { + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (separatorIndex != -1) { + String newPath = path.substring(0, separatorIndex); + if (!relativePath.startsWith(FOLDER_SEPARATOR)) { + newPath += FOLDER_SEPARATOR; + } + return newPath + relativePath; + } + else { + return relativePath; + } + } + + /** + * Normalize the path by suppressing sequences like "path/.." and + * inner simple dots. + * <p>The result is convenient for path comparison. For other uses, + * notice that Windows separators ("\") are replaced by simple slashes. + * @param path the original path + * @return the normalized path + */ + public static String cleanPath(String path) { + if (path == null) { + return null; + } + String pathToUse = StringUtils.replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); + + // Strip prefix from path to analyze, to not treat it as part of the + // first path element. This is necessary to correctly parse paths like + // "file:core/../core/io/Resource.class", where the ".." should just + // strip the first "core" directory while keeping the "file:" prefix. + int prefixIndex = pathToUse.indexOf(":"); + String prefix = ""; + if (prefixIndex != -1) { + prefix = pathToUse.substring(0, prefixIndex + 1); + if (prefix.contains("/")) { + prefix = ""; + } + else { + pathToUse = pathToUse.substring(prefixIndex + 1); + } + } + if (pathToUse.startsWith(FOLDER_SEPARATOR)) { + prefix = prefix + FOLDER_SEPARATOR; + pathToUse = pathToUse.substring(1); + } + + String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); + List<String> pathElements = new LinkedList<String>(); + int tops = 0; + + for (int i = pathArray.length - 1; i >= 0; i--) { + String element = pathArray[i]; + if (CURRENT_PATH.equals(element)) { + // Points to current directory - drop it. + } + else if (TOP_PATH.equals(element)) { + // Registering top path found. + tops++; + } + else { + if (tops > 0) { + // Merging path element with element corresponding to top path. + tops--; + } + else { + // Normal path element found. + pathElements.add(0, element); + } + } + } + // Remaining top paths need to be retained. + for (int i = 0; i < tops; i++) { + pathElements.add(0, TOP_PATH); + } + return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); + } +// +// /** +// * Compare two paths after normalization of them. +// * @param path1 first path for comparison +// * @param path2 second path for comparison +// * @return whether the two paths are equivalent after normalization +// */ +// public static boolean pathEquals(String path1, String path2) { +// return cleanPath(path1).equals(cleanPath(path2)); +// } +// +// /** +// * Parse the given {@code localeString} value into a {@link Locale}. +// * <p>This is the inverse operation of {@link Locale#toString Locale's toString}. +// * @param localeString the locale String, following {@code Locale's} +// * {@code toString()} format ("en", "en_UK", etc); +// * also accepts spaces as separators, as an alternative to underscores +// * @return a corresponding {@code Locale} instance +// * @throws IllegalArgumentException in case of an invalid locale specification +// */ +// public static Locale parseLocaleString(String localeString) { +// String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); +// String language = (parts.length > 0 ? parts[0] : ""); +// String country = (parts.length > 1 ? parts[1] : ""); +// validateLocalePart(language); +// validateLocalePart(country); +// String variant = ""; +// if (parts.length > 2) { +// // There is definitely a variant, and it is everything after the country +// // code sans the separator between the country code and the variant. +// int endIndexOfCountryCode = localeString.indexOf(country, language.length()) + country.length(); +// // Strip off any leading '_' and whitespace, what's left is the variant. +// variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); +// if (variant.startsWith("_")) { +// variant = trimLeadingCharacter(variant, '_'); +// } +// } +// return (language.length() > 0 ? new Locale(language, country, variant) : null); +// } +// +// private static void validateLocalePart(String localePart) { +// for (int i = 0; i < localePart.length(); i++) { +// char ch = localePart.charAt(i); +// if (ch != '_' && ch != ' ' && !Character.isLetterOrDigit(ch)) { +// throw new IllegalArgumentException( +// "Locale part \"" + localePart + "\" contains invalid characters"); +// } +// } +// } +// +// /** +// * Determine the RFC 3066 compliant language tag, +// * as used for the HTTP "Accept-Language" header. +// * @param locale the Locale to transform to a language tag +// * @return the RFC 3066 compliant language tag as String +// */ +// public static String toLanguageTag(Locale locale) { +// return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); +// } +// +// /** +// * Parse the given {@code timeZoneString} value into a {@link TimeZone}. +// * @param timeZoneString the time zone String, following {@link TimeZone#getTimeZone(String)} +// * but throwing {@link IllegalArgumentException} in case of an invalid time zone specification +// * @return a corresponding {@link TimeZone} instance +// * @throws IllegalArgumentException in case of an invalid time zone specification +// */ +// public static TimeZone parseTimeZoneString(String timeZoneString) { +// TimeZone timeZone = TimeZone.getTimeZone(timeZoneString); +// if ("GMT".equals(timeZone.getID()) && !timeZoneString.startsWith("GMT")) { +// // We don't want that GMT fallback... +// throw new IllegalArgumentException("Invalid time zone specification '" + timeZoneString + "'"); +// } +// return timeZone; +// } +// +// +// //--------------------------------------------------------------------- +// // Convenience methods for working with String arrays +// //--------------------------------------------------------------------- +// +// /** +// * Append the given String to the given String array, returning a new array +// * consisting of the input array contents plus the given String. +// * @param array the array to append to (can be {@code null}) +// * @param str the String to append +// * @return the new array (never {@code null}) +// */ +// public static String[] addStringToArray(String[] array, String str) { +// if (ObjectUtils.isEmpty(array)) { +// return new String[] {str}; +// } +// String[] newArr = new String[array.length + 1]; +// System.arraycopy(array, 0, newArr, 0, array.length); +// newArr[array.length] = str; +// return newArr; +// } +// +// /** +// * Concatenate the given String arrays into one, +// * with overlapping array elements included twice. +// * <p>The order of elements in the original arrays is preserved. +// * @param array1 the first array (can be {@code null}) +// * @param array2 the second array (can be {@code null}) +// * @return the new array ({@code null} if both given arrays were {@code null}) +// */ +// public static String[] concatenateStringArrays(String[] array1, String[] array2) { +// if (ObjectUtils.isEmpty(array1)) { +// return array2; +// } +// if (ObjectUtils.isEmpty(array2)) { +// return array1; +// } +// String[] newArr = new String[array1.length + array2.length]; +// System.arraycopy(array1, 0, newArr, 0, array1.length); +// System.arraycopy(array2, 0, newArr, array1.length, array2.length); +// return newArr; +// } +// +// /** +// * Merge the given String arrays into one, with overlapping +// * array elements only included once. +// * <p>The order of elements in the original arrays is preserved +// * (with the exception of overlapping elements, which are only +// * included on their first occurrence). +// * @param array1 the first array (can be {@code null}) +// * @param array2 the second array (can be {@code null}) +// * @return the new array ({@code null} if both given arrays were {@code null}) +// */ +// public static String[] mergeStringArrays(String[] array1, String[] array2) { +// if (ObjectUtils.isEmpty(array1)) { +// return array2; +// } +// if (ObjectUtils.isEmpty(array2)) { +// return array1; +// } +// List<String> result = new ArrayList<String>(); +// result.addAll(Arrays.asList(array1)); +// for (String str : array2) { +// if (!result.contains(str)) { +// result.add(str); +// } +// } +// return toStringArray(result); +// } +// +// /** +// * Turn given source String array into sorted array. +// * @param array the source array +// * @return the sorted array (never {@code null}) +// */ +// public static String[] sortStringArray(String[] array) { +// if (ObjectUtils.isEmpty(array)) { +// return new String[0]; +// } +// Arrays.sort(array); +// return array; +// } +// + /** + * Copy the given Collection into a String array. + * The Collection must contain String elements only. + * @param collection the Collection to copy + * @return the String array ({@code null} if the passed-in + * Collection was {@code null}) + */ + public static String[] toStringArray(Collection<String> collection) { + if (collection == null) { + return null; + } + return collection.toArray(new String[collection.size()]); + } +// +// /** +// * Copy the given Enumeration into a String array. +// * The Enumeration must contain String elements only. +// * @param enumeration the Enumeration to copy +// * @return the String array ({@code null} if the passed-in +// * Enumeration was {@code null}) +// */ +// public static String[] toStringArray(Enumeration<String> enumeration) { +// if (enumeration == null) { +// return null; +// } +// List<String> list = Collections.list(enumeration); +// return list.toArray(new String[list.size()]); +// } +// +// /** +// * Trim the elements of the given String array, +// * calling {@code String.trim()} on each of them. +// * @param array the original String array +// * @return the resulting array (of the same size) with trimmed elements +// */ +// public static String[] trimArrayElements(String[] array) { +// if (ObjectUtils.isEmpty(array)) { +// return new String[0]; +// } +// String[] result = new String[array.length]; +// for (int i = 0; i < array.length; i++) { +// String element = array[i]; +// result[i] = (element != null ? element.trim() : null); +// } +// return result; +// } +// +// /** +// * Remove duplicate Strings from the given array. +// * Also sorts the array, as it uses a TreeSet. +// * @param array the String array +// * @return an array without duplicates, in natural sort order +// */ +// public static String[] removeDuplicateStrings(String[] array) { +// if (ObjectUtils.isEmpty(array)) { +// return array; +// } +// Set<String> set = new TreeSet<String>(); +// for (String element : array) { +// set.add(element); +// } +// return toStringArray(set); +// } +// + /** + * Split a String at the first occurrence of the delimiter. + * Does not include the delimiter in the result. + * @param toSplit the string to split + * @param delimiter to split the string up with + * @return a two element array with index 0 being before the delimiter, and + * index 1 being after the delimiter (neither element includes the delimiter); + * or {@code null} if the delimiter wasn't found in the given input String + */ + public static String[] split(String toSplit, String delimiter) { + if (!hasLength(toSplit) || !hasLength(delimiter)) { + return null; + } + int offset = toSplit.indexOf(delimiter); + if (offset < 0) { + return null; + } + String beforeDelimiter = toSplit.substring(0, offset); + String afterDelimiter = toSplit.substring(offset + delimiter.length()); + return new String[] {beforeDelimiter, afterDelimiter}; + } +// +// /** +// * Take an array Strings and split each element based on the given delimiter. +// * A {@code Properties} instance is then generated, with the left of the +// * delimiter providing the key, and the right of the delimiter providing the value. +// * <p>Will trim both the key and value before adding them to the +// * {@code Properties} instance. +// * @param array the array to process +// * @param delimiter to split each element using (typically the equals symbol) +// * @return a {@code Properties} instance representing the array contents, +// * or {@code null} if the array to process was null or empty +// */ +// public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { +// return splitArrayElementsIntoProperties(array, delimiter, null); +// } +// +// /** +// * Take an array Strings and split each element based on the given delimiter. +// * A {@code Properties} instance is then generated, with the left of the +// * delimiter providing the key, and the right of the delimiter providing the value. +// * <p>Will trim both the key and value before adding them to the +// * {@code Properties} instance. +// * @param array the array to process +// * @param delimiter to split each element using (typically the equals symbol) +// * @param charsToDelete one or more characters to remove from each element +// * prior to attempting the split operation (typically the quotation mark +// * symbol), or {@code null} if no removal should occur +// * @return a {@code Properties} instance representing the array contents, +// * or {@code null} if the array to process was {@code null} or empty +// */ +// public static Properties splitArrayElementsIntoProperties( +// String[] array, String delimiter, String charsToDelete) { +// +// if (ObjectUtils.isEmpty(array)) { +// return null; +// } +// Properties result = new Properties(); +// for (String element : array) { +// if (charsToDelete != null) { +// element = deleteAny(element, charsToDelete); +// } +// String[] splittedElement = split(element, delimiter); +// if (splittedElement == null) { +// continue; +// } +// result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); +// } +// return result; +// } +// + /** + * Tokenize the given String into a String array via a StringTokenizer. + * Trims tokens and omits empty tokens. + * <p>The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using {@code delimitedListToStringArray} + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter). + * @return an array of the tokens + * @see java.util.StringTokenizer + * @see String#trim() + */ + public static String[] tokenizeToStringArray(String str, String delimiters) { + return tokenizeToStringArray(str, delimiters, true, true); + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + * <p>The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using {@code delimitedListToStringArray} + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter) + * @param trimTokens trim the tokens via String's {@code trim} + * @param ignoreEmptyTokens omit empty tokens from the result array + * (only applies to tokens that are empty after trimming; StringTokenizer + * will not consider subsequent delimiters as token in the first place). + * @return an array of the tokens ({@code null} if the input String + * was {@code null}) + * @see java.util.StringTokenizer + * @see String#trim() + */ + public static String[] tokenizeToStringArray( + String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { + + if (str == null) { + return null; + } + StringTokenizer st = new StringTokenizer(str, delimiters); + List<String> tokens = new ArrayList<String>(); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (trimTokens) { + token = token.trim(); + } + if (!ignoreEmptyTokens || token.length() > 0) { + tokens.add(token); + } + } + return toStringArray(tokens); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + * <p>A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to {@code tokenizeToStringArray}. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter) { + return delimitedListToStringArray(str, delimiter, null); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + * <p>A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to {@code tokenizeToStringArray}. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @param charsToDelete a set of characters to delete. Useful for deleting unwanted + * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String. + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { + if (str == null) { + return new String[0]; + } + if (delimiter == null) { + return new String[] {str}; + } + List<String> result = new ArrayList<String>(); + if ("".equals(delimiter)) { + for (int i = 0; i < str.length(); i++) { + result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); + } + } + else { + int pos = 0; + int delPos; + while ((delPos = str.indexOf(delimiter, pos)) != -1) { + result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); + pos = delPos + delimiter.length(); + } + if (str.length() > 0 && pos <= str.length()) { + // Add rest of String, but not in case of empty input. + result.add(deleteAny(str.substring(pos), charsToDelete)); + } + } + return toStringArray(result); + } + +// /** +// * Convert a CSV list into an array of Strings. +// * @param str the input String +// * @return an array of Strings, or the empty array in case of empty input +// */ +// public static String[] commaDelimitedListToStringArray(String str) { +// return delimitedListToStringArray(str, ","); +// } +// +// /** +// * Convenience method to convert a CSV string list to a set. +// * Note that this will suppress duplicates. +// * @param str the input String +// * @return a Set of String entries in the list +// */ +// public static Set<String> commaDelimitedListToSet(String str) { +// Set<String> set = new TreeSet<String>(); +// String[] tokens = commaDelimitedListToStringArray(str); +// for (String token : tokens) { +// set.add(token); +// } +// return set; +// } +// + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for {@code toString()} implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @param prefix the String to start each element with + * @param suffix the String to end each element with + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection<?> coll, String delim, String prefix, String suffix) { + if (coll.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + Iterator<?> it = coll.iterator(); + while (it.hasNext()) { + sb.append(prefix).append(it.next()).append(suffix); + if (it.hasNext()) { + sb.append(delim); + } + } + return sb.toString(); + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for {@code toString()} implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection<?> coll, String delim) { + return collectionToDelimitedString(coll, delim, "", ""); + } + +// /** +// * Convenience method to return a Collection as a CSV String. +// * E.g. useful for {@code toString()} implementations. +// * @param coll the Collection to display +// * @return the delimited String +// */ +// public static String collectionToCommaDelimitedString(Collection<?> coll) { +// return collectionToDelimitedString(coll, ","); +// } + +// /** +// * Convenience method to return a String array as a delimited (e.g. CSV) +// * String. E.g. useful for {@code toString()} implementations. +// * @param arr the array to display +// * @param delim the delimiter to use (probably a ",") +// * @return the delimited String +// */ +// public static String arrayToDelimitedString(Object[] arr, String delim) { +// if (ObjectUtils.isEmpty(arr)) { +// return ""; +// } +// if (arr.length == 1) { +// return ObjectUtils.nullSafeToString(arr[0]); +// } +// StringBuilder sb = new StringBuilder(); +// for (int i = 0; i < arr.length; i++) { +// if (i > 0) { +// sb.append(delim); +// } +// sb.append(arr[i]); +// } +// return sb.toString(); +// } +// +// /** +// * Convenience method to return a String array as a CSV String. +// * E.g. useful for {@code toString()} implementations. +// * @param arr the array to display +// * @return the delimited String +// */ +// public static String arrayToCommaDelimitedString(Object[] arr) { +// return arrayToDelimitedString(arr, ","); +// } + +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/internal/resources/io/UrlResource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/UrlResource.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/UrlResource.java new file mode 100644 index 0000000..9764820 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/UrlResource.java @@ -0,0 +1,261 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed 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.tamaya.core.internal.resources.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Objects; + +/** + * {@link org.apache.tamaya.core.internal.resources.io.Resource} implementation for {@code java.net.URL} locators. + * Obviously supports resolution as URL, and also as File in case of + * the "file:" protocol. + * + * @author Juergen Hoeller + * @since 28.12.2003 + * @see java.net.URL + */ +public class UrlResource extends AbstractFileResolvingResource { + + /** + * Original URI, if available; used for URI and File access. + */ + private final URI uri; + + /** + * Original URL, used for actual access. + */ + private final URL url; + + /** + * Cleaned URL (with normalized path), used for comparisons. + */ + private final URL cleanedUrl; + + + /** + * Create a new UrlResource based on the given URI object. + * @param uri a URI + * @throws MalformedURLException if the given URL path is not valid + */ + public UrlResource(URI uri) throws MalformedURLException { + Objects.requireNonNull(uri, "URI must not be null"); + this.uri = uri; + this.url = uri.toURL(); + this.cleanedUrl = getCleanedUrl(this.url, uri.toString()); + } + + /** + * Create a new UrlResource based on the given URL object. + * @param url a URL + */ + public UrlResource(URL url) { + Objects.requireNonNull(url, "URL must not be null"); + this.url = url; + this.cleanedUrl = getCleanedUrl(this.url, url.toString()); + this.uri = null; + } + + /** + * Create a new UrlResource based on a URL path. + * <p>Note: The given path needs to be pre-encoded if necessary. + * @param path a URL path + * @throws MalformedURLException if the given URL path is not valid + * @see java.net.URL#URL(String) + */ + public UrlResource(String path) throws MalformedURLException { + Objects.requireNonNull(path, "Path must not be null"); + this.uri = null; + this.url = new URL(path); + this.cleanedUrl = getCleanedUrl(this.url, path); + } + + /** + * Create a new UrlResource based on a URI specification. + * <p>The given parts will automatically get encoded if necessary. + * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon); + * also known as "scheme" + * @param location the location (e.g. the file path within that protocol); + * also known as "scheme-specific part" + * @throws MalformedURLException if the given URL specification is not valid + * @see java.net.URI#URI(String, String, String) + */ + public UrlResource(String protocol, String location) throws MalformedURLException { + this(protocol, location, null); + } + + /** + * Create a new UrlResource based on a URI specification. + * <p>The given parts will automatically get encoded if necessary. + * @param protocol the URL protocol to use (e.g. "jar" or "file" - without colon); + * also known as "scheme" + * @param location the location (e.g. the file path within that protocol); + * also known as "scheme-specific part" + * @param fragment the fragment within that location (e.g. anchor on an HTML page, + * as following after a "#" separator) + * @throws MalformedURLException if the given URL specification is not valid + * @see java.net.URI#URI(String, String, String) + */ + public UrlResource(String protocol, String location, String fragment) throws MalformedURLException { + try { + this.uri = new URI(protocol, location, fragment); + this.url = this.uri.toURL(); + this.cleanedUrl = getCleanedUrl(this.url, this.uri.toString()); + } + catch (URISyntaxException ex) { + MalformedURLException exToThrow = new MalformedURLException(ex.getMessage()); + exToThrow.initCause(ex); + throw exToThrow; + } + } + + /** + * Determine a cleaned URL for the given original URL. + * @param originalUrl the original URL + * @param originalPath the original URL path + * @return the cleaned URL + */ + private URL getCleanedUrl(URL originalUrl, String originalPath) { + try { + return new URL(StringUtils.cleanPath(originalPath)); + } + catch (MalformedURLException ex) { + // Cleaned URL path cannot be converted to URL + // -> take original URL. + return originalUrl; + } + } + + + /** + * This implementation opens an InputStream for the given URL. + * It sets the "UseCaches" flag to {@code false}, + * mainly to avoid jar file locking on Windows. + * @see java.net.URL#openConnection() + * @see java.net.URLConnection#setUseCaches(boolean) + * @see java.net.URLConnection#getInputStream() + */ + @Override + public InputStream getInputStream()throws IOException { + URLConnection con = null; + try { + con = this.url.openConnection(); + ResourceUtils.useCachesIfNecessary(con); + return con.getInputStream(); + } + catch (IOException ex) { + // Close the HTTP connection (if applicable). + if (con instanceof HttpURLConnection) { + ((HttpURLConnection) con).disconnect(); + } + throw ex; + } + } + + /** + * This implementation returns the underlying URL reference. + */ + @Override + public URL getURL() throws IOException { + return this.url; + } + + /** + * This implementation returns the underlying URI directly, + * if possible. + */ + @Override + public URI getURI() throws IOException { + if (this.uri != null) { + return this.uri; + } + else { + return super.getURI(); + } + } + + /** + * This implementation returns a File reference for the underlying URL/URI, + * provided that it refers to a file in the file system. + */ + @Override + public File getFile() throws IOException { + if (this.uri != null) { + return super.getFile(this.uri); + } + else { + return super.getFile(); + } + } + + /** + * This implementation creates a UrlResource, applying the given path + * relative to the path of the underlying URL of this resource descriptor. + * @see java.net.URL#URL(java.net.URL, String) + */ + @Override + public Resource createRelative(String relativePath) throws MalformedURLException { + if (relativePath.startsWith("/")) { + relativePath = relativePath.substring(1); + } + return new UrlResource(new URL(this.url, relativePath)); + } + + /** + * This implementation returns the name of the file that this URL refers to. + * @see java.net.URL#getFile() + * @see java.io.File#getName() + */ + @Override + public String getFilename() { + return new File(this.url.getFile()).getName(); + } + + /** + * This implementation returns a description that includes the URL. + */ + @Override + public String getDescription() { + return "URL [" + this.url + "]"; + } + + + /** + * This implementation compares the underlying URL references. + */ + @Override + public boolean equals(Object obj) { + return (obj == this || + (obj instanceof UrlResource && this.cleanedUrl.equals(((UrlResource) obj).cleanedUrl))); + } + + /** + * This implementation returns the hash code of the underlying URL reference. + */ + @Override + public int hashCode() { + return this.cleanedUrl.hashCode(); + } + +} + http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsResource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsResource.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsResource.java new file mode 100644 index 0000000..06f509d --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsResource.java @@ -0,0 +1,132 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed 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.tamaya.core.internal.resources.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.Objects; + +/** + * JBoss VFS based {@link Resource} implementation. + * + * <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package + * {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and + * WildFly 8. + * + * @author Ales Justin + * @author Juergen Hoeller + * @author Costin Leau + * @since 3.0 + */ +public class VfsResource extends AbstractResource { + + private final Object resource; + + + public VfsResource(Object resource) { + Objects.requireNonNull(resource, "VirtualFile must not be null"); + this.resource = resource; + } + + + @Override + public InputStream getInputStream()throws IOException { + return VfsUtils.getInputStream(this.resource); + } + + @Override + public boolean exists() { + return VfsUtils.exists(this.resource); + } + + @Override + public boolean isReadable() { + return VfsUtils.isReadable(this.resource); + } + + @Override + public URL getURL() throws IOException { + try { + return VfsUtils.getURL(this.resource); + } + catch (Exception ex) { + throw new IllegalStateException("Failed to obtain URL for file " + this.resource, ex); + } + } + + @Override + public URI getURI() throws IOException { + try { + return VfsUtils.getURI(this.resource); + } + catch (Exception ex) { + throw new IllegalStateException("Failed to obtain URI for " + this.resource, ex); + } + } + + @Override + public File getFile() throws IOException { + return VfsUtils.getFile(this.resource); + } + + @Override + public long contentLength() throws IOException { + return VfsUtils.getSize(this.resource); + } + + @Override + public long lastModified() throws IOException { + return VfsUtils.getLastModified(this.resource); + } + + @Override + public Resource createRelative(String relativePath) throws IOException { + if (!relativePath.startsWith(".") && relativePath.contains("/")) { + try { + return new VfsResource(VfsUtils.getChild(this.resource, relativePath)); + } + catch (IOException ex) { + // fall back to getRelative + } + } + + return new VfsResource(VfsUtils.getRelative(new URL(getURL(), relativePath))); + } + + @Override + public String getFilename() { + return VfsUtils.getName(this.resource); + } + + @Override + public String getDescription() { + return this.resource.toString(); + } + + @Override + public boolean equals(Object obj) { + return (obj == this || (obj instanceof VfsResource && this.resource.equals(((VfsResource) obj).resource))); + } + + @Override + public int hashCode() { + return this.resource.hashCode(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsUtils.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsUtils.java new file mode 100644 index 0000000..ff2636f --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/VfsUtils.java @@ -0,0 +1,209 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed 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.tamaya.core.internal.resources.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.*; +import java.net.URI; +import java.net.URL; + +/** + * Utility for detecting and accessing JBoss VFS in the classpath. + * + * <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package + * {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and + * WildFly 8. + * + * <p>Thanks go to Marius Bogoevici for the initial patch. + * <b>Note:</b> This is an internal class and should not be used outside the framework. + * + * @author Costin Leau + * @author Juergen Hoeller + * @since 3.0.3 + */ +class VfsUtils { + + private static final String VFS3_PKG = "org.jboss.vfs."; + private static final String VFS_NAME = "VFS"; + + private static Method VFS_METHOD_GET_ROOT_URL = null; + private static Method VFS_METHOD_GET_ROOT_URI = null; + + private static Method VIRTUAL_FILE_METHOD_EXISTS = null; + private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; + private static Method VIRTUAL_FILE_METHOD_GET_SIZE; + private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; + private static Method VIRTUAL_FILE_METHOD_TO_URL; + private static Method VIRTUAL_FILE_METHOD_TO_URI; + private static Method VIRTUAL_FILE_METHOD_GET_NAME; + private static Method VIRTUAL_FILE_METHOD_GET_PATH_NAME; + private static Method VIRTUAL_FILE_METHOD_GET_CHILD; + + protected static Class<?> VIRTUAL_FILE_VISITOR_INTERFACE; + protected static Method VIRTUAL_FILE_METHOD_VISIT; + + private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE = null; + private static Method GET_PHYSICAL_FILE = null; + + static { + ClassLoader loader = VfsUtils.class.getClassLoader(); + try { + Class<?> vfsClass = loader.loadClass(VFS3_PKG + VFS_NAME); + VFS_METHOD_GET_ROOT_URL = ReflectionUtils.findMethod(vfsClass, "getChild", URL.class); + VFS_METHOD_GET_ROOT_URI = ReflectionUtils.findMethod(vfsClass, "getChild", URI.class); + + Class<?> virtualFile = loader.loadClass(VFS3_PKG + "VirtualFile"); + VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists"); + VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream"); + VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize"); + VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified"); + VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI"); + VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL"); + VIRTUAL_FILE_METHOD_GET_NAME = ReflectionUtils.findMethod(virtualFile, "getName"); + VIRTUAL_FILE_METHOD_GET_PATH_NAME = ReflectionUtils.findMethod(virtualFile, "getPathName"); + GET_PHYSICAL_FILE = ReflectionUtils.findMethod(virtualFile, "getPhysicalFile"); + VIRTUAL_FILE_METHOD_GET_CHILD = ReflectionUtils.findMethod(virtualFile, "getChild", String.class); + + VIRTUAL_FILE_VISITOR_INTERFACE = loader.loadClass(VFS3_PKG + "VirtualFileVisitor"); + VIRTUAL_FILE_METHOD_VISIT = ReflectionUtils.findMethod(virtualFile, "visit", VIRTUAL_FILE_VISITOR_INTERFACE); + + Class<?> visitorAttributesClass = loader.loadClass(VFS3_PKG + "VisitorAttributes"); + VISITOR_ATTRIBUTES_FIELD_RECURSE = ReflectionUtils.findField(visitorAttributesClass, "RECURSE"); + } + catch (ClassNotFoundException ex) { + throw new IllegalStateException("Could not detect JBoss VFS infrastructure", ex); + } + } + + private VfsUtils(){} + + static void visit(Object resource, InvocationHandler visitor) throws IOException { + Object visitorProxy = Proxy.newProxyInstance( + VIRTUAL_FILE_VISITOR_INTERFACE.getClassLoader(), + new Class<?>[]{VIRTUAL_FILE_VISITOR_INTERFACE}, visitor); + invokeVfsMethod(VIRTUAL_FILE_METHOD_VISIT, resource, visitorProxy); + } + + protected static Object invokeVfsMethod(Method method, Object target, Object... args) throws IOException { + try { + return method.invoke(target, args); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof IOException) { + throw (IOException) targetEx; + } + ReflectionUtils.handleInvocationTargetException(ex); + } + catch (Exception ex) { + ReflectionUtils.handleReflectionException(ex); + } + + throw new IllegalStateException("Invalid code path reached"); + } + + static boolean exists(Object vfsResource) { + try { + return (Boolean) invokeVfsMethod(VIRTUAL_FILE_METHOD_EXISTS, vfsResource); + } + catch (IOException ex) { + return false; + } + } + + static boolean isReadable(Object vfsResource) { + try { + return ((Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource) > 0); + } + catch (IOException ex) { + return false; + } + } + + static long getSize(Object vfsResource) throws IOException { + return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource); + } + + static long getLastModified(Object vfsResource) throws IOException { + return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED, vfsResource); + } + + static InputStream getInputStream(Object vfsResource) throws IOException { + return (InputStream) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_INPUT_STREAM, vfsResource); + } + + static URL getURL(Object vfsResource) throws IOException { + return (URL) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URL, vfsResource); + } + + static URI getURI(Object vfsResource) throws IOException { + return (URI) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URI, vfsResource); + } + + static String getName(Object vfsResource) { + try { + return (String) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_NAME, vfsResource); + } + catch (IOException ex) { + throw new IllegalStateException("Cannot get resource name", ex); + } + } + + static Object getRelative(URL url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); + } + + static Object getChild(Object vfsResource, String path) throws IOException { + return invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_CHILD, vfsResource, path); + } + + static File getFile(Object vfsResource) throws IOException { + return (File) invokeVfsMethod(GET_PHYSICAL_FILE, vfsResource); + } + + static Object getRoot(URI url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URI, null, url); + } + + // protected methods used by the support sub-package + + protected static Object getRoot(URL url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); + } + + protected static Object getVisitorAttribute() { + try{ + return VISITOR_ATTRIBUTES_FIELD_RECURSE.get(null); + } + catch(Exception e){ + ReflectionUtils.handleReflectionException(e); + return null; // never called + } + } + + protected static String getPath(Object resource) { + try{ + return (String) VIRTUAL_FILE_METHOD_GET_PATH_NAME.invoke(resource); + } + catch(Exception e){ + ReflectionUtils.handleReflectionException(e); + return null; // never called + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/internal/resources/io/WritableResource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/internal/resources/io/WritableResource.java b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/WritableResource.java new file mode 100644 index 0000000..26fe268 --- /dev/null +++ b/core/src/main/java/org/apache/tamaya/core/internal/resources/io/WritableResource.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed 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.tamaya.core.internal.resources.io; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Extended interface for a resource that supports writing to it. + * Provides an {@link #getOutputStream() OutputStream accessor}. + * + * @author Juergen Hoeller + * @since 3.1 + * @see java.io.OutputStream + */ +public interface WritableResource extends Resource { + + /** + * Return whether the contents of this resource can be modified, + * e.g. via {@link #getOutputStream()} or {@link #getFile()}. + * <p>Will be {@code true} for typical resource descriptors; + * note that actual content writing may still fail when attempted. + * However, a value of {@code false} is a definitive indication + * that the resource content cannot be modified. + * @see #getOutputStream() + * @see #isReadable() + */ + boolean isWritable(); + + /** + * Return an {@link OutputStream} for the underlying resource, + * allowing to (over-)write its content. + * @throws IOException if the stream could not be opened + * @see #getInputStream() + */ + OutputStream getOutputStream() throws IOException; + +} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertyProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertyProvider.java index 8134db8..bb1d3ce 100644 --- a/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertyProvider.java +++ b/core/src/main/java/org/apache/tamaya/core/properties/AbstractPropertyProvider.java @@ -27,7 +27,7 @@ import java.util.*; /** * Abstract base class for implementing a {@link org.apache.tamaya.PropertyProvider}. Also - * consider using {@link MapBasedPropertyProvider} instead of. + * consider using {@link org.apache.tamaya.core.internal.MapBasedPropertyProvider} instead of. */ @SuppressWarnings("NullableProblems") public abstract class AbstractPropertyProvider implements PropertyProvider, Serializable{ http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/AggregatedPropertyProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AggregatedPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/properties/AggregatedPropertyProvider.java deleted file mode 100644 index 91ddf2b..0000000 --- a/core/src/main/java/org/apache/tamaya/core/properties/AggregatedPropertyProvider.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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.tamaya.core.properties; - -import org.apache.tamaya.ConfigChangeSet; -import org.apache.tamaya.MetaInfoBuilder; -import org.apache.tamaya.PropertyProvider; -import java.util.*; - -/** - * Implementation for a {@link org.apache.tamaya.PropertyProvider} that is an aggregate of - * multiple child instances. Controlled by an {@link AggregationPolicy} the - * following aggregations are supported: - * <ul> - * <li><b>IGNORE: </b>Ignore all overrides.</li> - * <li><b>: </b></li> - * <li><b>: </b></li> - * <li><b>: </b></li> - * </ul> - */ -class AggregatedPropertyProvider extends AbstractPropertyProvider{ - - private static final long serialVersionUID = -1419376385695224799L; - private AggregationPolicy policy = AggregationPolicy.IGNORE; - private List<PropertyProvider> units = new ArrayList<PropertyProvider>(); - private PropertyProvider mutableProvider; - - /** - * Creates a new instance. - * @param mutableProvider the provider instance that would be used for delegating - * change requests. - * @param policy - * The aggregation policy to be used. - * @param propertyMaps - * The property sets to be included. - */ - public AggregatedPropertyProvider(PropertyProvider mutableProvider, AggregationPolicy policy, PropertyProvider... propertyMaps) { - super(MetaInfoBuilder.of().setType("aggregated").set("policy", policy.toString()).build()); - Objects.requireNonNull(policy); - this.policy = policy; - units.addAll(Arrays.asList(propertyMaps)); - this.mutableProvider = mutableProvider; - } - - /** - * Get the {@link AggregationPolicy} for this instance. - * - * @return the {@link AggregationPolicy}, never {@code null}. - */ - public AggregationPolicy getAggregationPolicy() { - return policy; - } - - /** - * Return the names of the {@link org.apache.tamaya.PropertyProvider} instances to be - * aggregated in this instance, in the order of precedence (the first are - * the weakest). - * - * @return the ordered list of aggregated scope identifiers, never - * {@code null}. - */ - public List<PropertyProvider> getConfigurationUnits() { - return Collections.unmodifiableList(units); - } - - /** - * Apply a config change to this item. Hereby the change must be related to the same instance. - * @param change the config change - * @throws org.apache.tamaya.ConfigException if an unrelated change was passed. - * @throws UnsupportedOperationException when the configuration is not writable. - */ - @Override - public void apply(ConfigChangeSet change){ - if(mutableProvider!=null) - mutableProvider.apply(change); - else - super.apply(change); - } - - @Override - public Map<String,String> toMap() { - Map<String, String> value = new HashMap<>(); - for (PropertyProvider unit : units) { - for (Map.Entry<String, String> entry : unit.toMap() - .entrySet()) { - switch (policy) { - case IGNORE: - if (!value.containsKey(entry.getKey())) { - value.put(entry.getKey(), entry.getValue()); - } - break; - case EXCEPTION: - if (value.containsKey(entry.getKey())) { - throw new IllegalStateException("Duplicate key: " - + entry.getKey() - + " in " + this); - } - else { - value.put(entry.getKey(), entry.getValue()); - } - break; - case OVERRIDE: - value.put(entry.getKey(), entry.getValue()); - break; - default: - break; - } - } - } - return value; - } - - @Override - public ConfigChangeSet load() { - for (PropertyProvider unit : units) { - unit.load(); - } - return super.load(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java b/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java deleted file mode 100644 index 576652f..0000000 --- a/core/src/main/java/org/apache/tamaya/core/properties/AggregationPolicy.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.tamaya.core.properties; - -/** - * Policy that defines how the different aggregates should be combined. - */ -public enum AggregationPolicy{ - /** Ignore overrides, only extend (additive). */ - IGNORE, - /** - * Interpret later keys as override (additive and override), replacing - * the key loaded earlier/from previous contained - * {@link javax.config.PropertyMap}. - */ - OVERRIDE, - /** - * Throw an exception, when keys are not disjunctive (strictly - * additive). - */ - EXCEPTION -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/ContextualPropertyProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/ContextualPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/properties/ContextualPropertyProvider.java deleted file mode 100644 index 1caa234..0000000 --- a/core/src/main/java/org/apache/tamaya/core/properties/ContextualPropertyProvider.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.tamaya.core.properties; - -import org.apache.tamaya.ConfigChangeSet; -import org.apache.tamaya.MetaInfo; -import org.apache.tamaya.MetaInfoBuilder; -import org.apache.tamaya.PropertyProvider; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; - -/** - * Created by Anatole on 12.04.2014. - */ -class ContextualPropertyProvider implements PropertyProvider{ - - private volatile Map<String,PropertyProvider> cachedMaps = new ConcurrentHashMap<>(); - - private Supplier<PropertyProvider> mapSupplier; - private Supplier<String> isolationKeySupplier; - private MetaInfo metaInfo; - - /** - * Creates a new contextual PropertyMap. Contextual maps delegate to different instances of PropertyMap depending - * on the keys returned from the isolationP - * - * @param mapSupplier - * @param isolationKeySupplier - */ - public ContextualPropertyProvider(Supplier<PropertyProvider> mapSupplier, Supplier<String> isolationKeySupplier){ - this.metaInfo = MetaInfoBuilder.of().setType("contextual").set("mapSupplier", mapSupplier.toString()) - .set("isolationKeySupplier", isolationKeySupplier.toString()).build(); - Objects.requireNonNull(mapSupplier); - Objects.requireNonNull(isolationKeySupplier); - this.mapSupplier = mapSupplier; - this.isolationKeySupplier = isolationKeySupplier; - } - - /** - * This method provides the contextual Map for the current environment. Hereby, ba default, for each different - * key returned by the #isolationKeySupplier a separate PropertyMap instance is acquired from the #mapSupplier. - * If the map supplier returns an instance it is cached in the local #cachedMaps. - * - * @return the current contextual PropertyMap. - */ - protected PropertyProvider getContextualMap(){ - String environmentKey = this.isolationKeySupplier.get(); - if(environmentKey == null){ - return PropertyProviders.empty(); - } - PropertyProvider map = this.cachedMaps.get(environmentKey); - if(map == null){ - synchronized(cachedMaps){ - map = this.cachedMaps.get(environmentKey); - if(map == null){ - map = this.mapSupplier.get(); - if(map == null){ - return PropertyProviders - .empty(MetaInfoBuilder.of().setInfo( - "No map provided by supplier " + mapSupplier + " for key " + environmentKey) - .build()); - } - this.cachedMaps.put(environmentKey, map); - } - } - } - return map; - } - - @Override - public ConfigChangeSet load(){ - return getContextualMap().load(); - } - - @Override - public boolean containsKey(String key){ - return getContextualMap().containsKey(key); - } - - @Override - public Map<String,String> toMap(){ - return getContextualMap().toMap(); - } - - @Override - public MetaInfo getMetaInfo(){ - return this.metaInfo; - } - - @Override - public Optional<String> get(String key){ - return getContextualMap().get(key); - } - - @Override - public Set<String> keySet(){ - return getContextualMap().keySet(); - } - - /** - * Apply a config change to this item. Hereby the change must be related to the same instance. - * @param change the config change - * @throws org.apache.tamaya.ConfigException if an unrelated change was passed. - * @throws UnsupportedOperationException when the configuration is not writable. - */ - @Override - public void apply(ConfigChangeSet change){ - getContextualMap().apply(change); - } - - /** - * Access a cached PropertyMap. - * - * @param key the target environment key as returned by the environment key supplier, not null. - * @return the corresponding PropertyMap, or null. - */ - public PropertyProvider getCachedMap(String key){ - return this.cachedMaps.get(key); - } - - /** - * Access the set of currently loaded/cached maps. - * - * @return the set of cached map keys, never null. - */ - public Set<String> getCachedMapKeys(){ - return this.cachedMaps.keySet(); - } - - /** - * Access the supplier for environment key, determining map isolation. - * - * @return the environment key supplier instance, not null. - */ - public Supplier<String> getIsolationKeySupplier(){ - return this.isolationKeySupplier; - } - - /** - * Access the supplier for new PropertyMap instances. - * - * @return the PropertyMap supplier instance, not null. - */ - public Supplier<PropertyProvider> getMapSupplier(){ - return this.mapSupplier; - } - - @Override - public String toString(){ - return "ContextualMap{" + - "cachedMaps(key)=" + cachedMaps.keySet() + - ", mapSupplier=" + mapSupplier + - ", isolationKeySupplier=" + isolationKeySupplier + - '}'; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/DelegatingPropertyProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/DelegatingPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/properties/DelegatingPropertyProvider.java deleted file mode 100644 index 69c4768..0000000 --- a/core/src/main/java/org/apache/tamaya/core/properties/DelegatingPropertyProvider.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.tamaya.core.properties; - -import org.apache.tamaya.ConfigChangeSet; -import org.apache.tamaya.MetaInfo; -import org.apache.tamaya.MetaInfoBuilder; -import org.apache.tamaya.PropertyProvider; - -import java.util.*; - -/** - * Implementation for a {@link org.apache.tamaya.PropertyProvider} that is an aggregate of - * multiple child instances. Controlled by an {@link org.apache.tamaya.core.properties.AggregationPolicy} the - * following aggregations are supported: - * <ul> - * <li><b>IGNORE: </b>Ignore all overrides.</li> - * <li><b>: </b></li> - * <li><b>: </b></li> - * <li><b>: </b></li> - * </ul> - */ -class DelegatingPropertyProvider implements PropertyProvider{ - - private static final long serialVersionUID = -1419376385695224799L; - private PropertyProvider mainMap; - private Map<String,String> parentMap; - private MetaInfo metaInfo; - - /** - * Creates a mew instance, with aggregation polilcy - * {@code AggregationPolicy.OVERRIDE}. - * - * @param mainMap The main ConfigMap. - * @param parentMap The delegated parent ConfigMap. - */ - public DelegatingPropertyProvider(PropertyProvider mainMap, Map<String,String> parentMap){ - this.metaInfo = - MetaInfoBuilder.of().setType("delegate").set("provider", mainMap.toString()).set("delegate", parentMap.toString()) - .build(); - Objects.requireNonNull(parentMap); - this.parentMap = parentMap; - Objects.requireNonNull(parentMap); - this.parentMap = parentMap; - } - - @Override - public ConfigChangeSet load(){ - return mainMap.load(); - } - - @Override - public boolean containsKey(String key){ - return keySet().contains(key); - } - - @Override - public Map<String,String> toMap(){ - return null; - } - - @Override - public MetaInfo getMetaInfo(){ - return this.metaInfo; - } - - @Override - public Optional<String> get(String key){ - Optional<String> val = mainMap.get(key); - if(!val.isPresent()){ - return Optional.ofNullable(parentMap.get(key)); - } - return val; - } - - @Override - public Set<String> keySet(){ - Set<String> keys = new HashSet<>(mainMap.keySet()); - keys.addAll(parentMap.keySet()); - return keys; - } - - @Override - public String toString(){ - return super.toString() + "(mainMap=" + mainMap + ", delegate=" + parentMap + ")"; - } -} http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/a55d1c97/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertyProvider.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertyProvider.java b/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertyProvider.java deleted file mode 100644 index 10927c6..0000000 --- a/core/src/main/java/org/apache/tamaya/core/properties/EnvironmentPropertyProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.tamaya.core.properties; - -import org.apache.tamaya.MetaInfoBuilder; -import java.util.Map; - -class EnvironmentPropertyProvider extends AbstractPropertyProvider{ - - private static final long serialVersionUID = 4753258482658331010L; - - public Map<String,String> toMap(){ - return System.getenv(); - } - - public EnvironmentPropertyProvider(){ - super(MetaInfoBuilder.of().setType("env-properties").build()); - } - - @Override - public String toString(){ - return "EnvironmentPropertyMap{" + - "props=" + super.toString() + - '}'; - } - -}