diff --git a/.asf.yaml b/.asf.yaml new file mode 100644 index 00000000..1e41914e --- /dev/null +++ b/.asf.yaml @@ -0,0 +1,36 @@ +# +# 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. +# +# see https://s.apache.org/asfyaml +github: + description: "Apache Maven Shared Utils" + homepage: https://maven.apache.org/shared/maven-shared-utils/ + labels: + - java + - build-management + - maven-shared + - maven + enabled_merge_buttons: + squash: true + merge: false + rebase: true + autolink_jira: + - MSHARED +notifications: + commits: commits@maven.apache.org + issues: issues@maven.apache.org + pullrequests: issues@maven.apache.org + jira_options: link label comment diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..778ea2af --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +# 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. + +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000..247b6e15 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,19 @@ +# 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. + +_extends: maven-gh-actions-shared +tag-template: maven-shared-utils-$NEXT_MINOR_VERSION diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml new file mode 100644 index 00000000..4d67fdcf --- /dev/null +++ b/.github/workflows/maven-verify.yml @@ -0,0 +1,27 @@ +# 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. + +name: Verify + +on: + push: + pull_request: + +jobs: + build: + name: Verify + uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v3 diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000..b44872cf --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,25 @@ +# 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. + +name: Release Drafter +on: + push: + branches: + - master +jobs: + update_release_draft: + uses: apache/maven-gh-actions-shared/.github/workflows/release-drafter.yml@v3 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e1b7e456 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +target/ +.project +.classpath +.settings/ +.svn/ +bin/ +# Intellij +*.ipr +*.iml +.idea +out/ +.DS_Store +/bootstrap +/dependencies.xml +.java-version +.checkstyle + diff --git a/src/main/java/org/apache/maven/shared/utils/package-info.java b/Jenkinsfile similarity index 58% rename from src/main/java/org/apache/maven/shared/utils/package-info.java rename to Jenkinsfile index ba04e238..09ac70f1 100644 --- a/src/main/java/org/apache/maven/shared/utils/package-info.java +++ b/Jenkinsfile @@ -1,6 +1,4 @@ -package org.apache.maven.shared.utils; - -/* +/** * 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 @@ -9,7 +7,7 @@ * "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 + * 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 @@ -19,18 +17,4 @@ * under the License. */ -/** - * - * The following classes have not been implemented because they are easy to get other where: - * - *
false
we will only overwrite if the local
- * file or directory is older than the one in the archive.
- *
- * @param overwrite
- */
- public void setOverwrite( boolean overwrite )
- {
- this.overwrite = overwrite;
- }
-
- /**
- * Actually perform the unpacking of the source archive
- * into the destination directory.
- *
- * @throws Exception
- */
- public void execute()
- throws Exception
- {
- expandFile( source, dest );
- }
-
- /**
- * It is intended to be overwritten when implementing an own unarchiver
- * - *Note: we kept this protected method for the sake of backward compatibility!
- * - * @param srcFile - * @param dest - * @throws Exception - */ - void expandFile( File srcFile, File dest ) - throws Exception - { - if ( source == null ) - { - throw new NullPointerException( "Source Archive must not be null!" ); - } - - File destDir = dest; - if ( destDir == null ) - { - destDir = new File( System.getProperty( "user.dir" ) ); - } - - FileInputStream fileInputStream = new FileInputStream( srcFile ); - try - { - ZipInputStream zipInputStream = new ZipInputStream( fileInputStream ); - - ZipEntry zipEntry; - - while ( ( zipEntry = zipInputStream.getNextEntry() ) != null ) - { - String zipEntryName = zipEntry.getName(); - Date zipEntryDate = new Date( zipEntry.getTime() ); - - extractFile( source, destDir, zipInputStream, zipEntryName, zipEntryDate, zipEntry.isDirectory() ); - } - } - finally - { - try - { - fileInputStream.close(); - } - catch ( IOException ioe ) - { - // no worries, all is ok ... - } - } - } - - /** - * Extract a single ZipEntry. - * - *Note: we kept this protected method for the sake of backward compatibility!
- * - * @param archive the archive to unpack - * @param destDir the destination dirctory - * @param compressedInputStream - * @param entryName - * @param entryDate - * @param isDirectory - * @throws Exception - */ - void extractFile( File archive, File destDir, InputStream compressedInputStream, String entryName, - Date entryDate, boolean isDirectory ) - throws Exception - { - File targetFile = new File( destDir, entryName ); - - // if overwrite is specified and the file type - // of the existing file does not match, then delete it - if ( overwrite && targetFile.exists() && targetFile.isDirectory() != isDirectory ) - { - deleteFileOrDir( targetFile ); - } - - if ( !targetFile.exists() || overwrite || targetFile.lastModified() <= entryDate.getTime() ) - { - if ( isDirectory ) - { - targetFile.mkdirs(); - } - else - { - byte[] buffer = new byte[BUFFER_SIZE]; - FileOutputStream fileOutputStream = new FileOutputStream( targetFile ); - try - { - int len; - while ( ( len = compressedInputStream.read( buffer ) ) > 0 ) - { - fileOutputStream.write( buffer, 0, len ); - } - } - finally - { - try - { - fileOutputStream.close(); - } - catch ( IOException ioe ) - { - // no worries, all is ok ... - } - } - targetFile.setLastModified( entryDate.getTime() ); - } - } - } - - /** - * small helper method who deletes the given directory or file. - * - * @param targetFile - * @throws IOException - */ - private void deleteFileOrDir( File targetFile ) - throws IOException - { - if ( targetFile.isDirectory() ) - { - FileUtils.deleteDirectory( targetFile ); - } - else - { - FileUtils.delete( targetFile ); - } - - } -} diff --git a/src/main/java/org/apache/maven/shared/utils/Os.java b/src/main/java/org/apache/maven/shared/utils/Os.java index f6514fc3..184b98aa 100644 --- a/src/main/java/org/apache/maven/shared/utils/Os.java +++ b/src/main/java/org/apache/maven/shared/utils/Os.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils; import java.util.Collections; import java.util.HashSet; @@ -26,12 +25,10 @@ /** *Condition that tests the OS type.
- * *This class got copied over from Apache ANT.
* Even the version from plexus-utils was
- * only an ANT fork!
+ * only an ANT fork!
* The last time it got copied was on 2011-08-12
When merging changes please take care of the special * OS_FAMILY handling in this version of Os.java!
* @@ -39,30 +36,42 @@ * @author Magesh Umasankar * @author Brian Fox * @author Mark Struberg - * @version $Revision$ - * + * */ -public class Os -{ - public static final String OS_NAME = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH ); +public class Os { + /** + * The OS Name. + */ + public static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); - public static final String OS_ARCH = System.getProperty( "os.arch" ).toLowerCase( Locale.ENGLISH ); + /** + * The OA architecture. + */ + public static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(Locale.ENGLISH); - public static final String OS_VERSION = System.getProperty( "os.version" ).toLowerCase( Locale.ENGLISH ); + /** + * The OS version. + */ + public static final String OS_VERSION = System.getProperty("os.version").toLowerCase(Locale.ENGLISH); - public static final String PATH_SEP = System.getProperty( "path.separator" ); + /** + * The path separator. + */ + public static final String PATH_SEP = System.getProperty("path.separator"); /** * system line separator , e.g. "\n" on unixoid systems and "\r\n" on Windows */ - public static final String LINE_SEP = System.getProperty( "line.separator" ); + public static final String LINE_SEP = System.getProperty("line.separator"); + /** + * OS Family + */ public static final String OS_FAMILY = getOsFamily(); // store the valid families private static final Settrue
if 'family' represents a valid OS-Family, false
otherwise.
*/
- public static boolean isValidFamily( String family )
- {
- return VALID_FAMILIES.contains( family );
+ public static boolean isValidFamily(String family) {
+ return VALID_FAMILIES.contains(family);
}
-
}
diff --git a/src/main/java/org/apache/maven/shared/utils/PathTool.java b/src/main/java/org/apache/maven/shared/utils/PathTool.java
index b6162110..bf0fd493 100644
--- a/src/main/java/org/apache/maven/shared/utils/PathTool.java
+++ b/src/main/java/org/apache/maven/shared/utils/PathTool.java
@@ -1,5 +1,3 @@
-package org.apache.maven.shared.utils;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -18,23 +16,33 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-import java.io.File;
-import java.util.StringTokenizer;
+package org.apache.maven.shared.utils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.io.File;
+import java.util.StringTokenizer;
+
/**
- * Path tool contains static methods to assist in determining path-related
- * information such as relative paths.
- *
+ * Path tool contains static methods to assist in determining path-related + * information such as relative paths.
+ ** This class originally got developed at Apache Anakia and later maintained * in maven-utils of Apache Maven-1. * Some external fixes by Apache Committers have been applied later. + *
*/ -public class PathTool -{ +public class PathTool { + + /** + * The constructor. + * + * @deprecated This is a utility class with only static methods. Don't create instances of it. + */ + @Deprecated + public PathTool() {} + /** * Determines the relative path of a filename from a base directory. * This method is useful in building relative links within pages of @@ -44,9 +52,9 @@ public class PathTool * file separators. The relative path returned is formed using * forward slashes as it is expected this path is to be used as a * link in a web page (again mimicking Anakia's behavior). - * + *
* This method is thread-safe.
- *
+ *
* PathTool.getRelativePath( null, null ) = "" * PathTool.getRelativePath( null, "/usr/local/java/bin" ) = "" @@ -65,18 +73,19 @@ public class PathTool * the base directory,basedir
is null or zero-length, * orfilename
is null or zero-length. */ - public static String getRelativePath( @Nullable String basedir, @Nullable String filename ) - { - basedir = uppercaseDrive( basedir ); - filename = uppercaseDrive( filename ); + public static String getRelativePath(@Nullable String basedir, @Nullable String filename) { + basedir = uppercaseDrive(basedir); + filename = uppercaseDrive(filename); /* * Verify the arguments and make sure the filename is relative * to the base directory. */ - if ( basedir == null || basedir.length() == 0 || filename == null || filename.length() == 0 - || !filename.startsWith( basedir ) ) - { + if (basedir == null + || basedir.length() == 0 + || filename == null + || filename.length() == 0 + || !filename.startsWith(basedir)) { return ""; } @@ -85,23 +94,22 @@ public static String getRelativePath( @Nullable String basedir, @Nullable String * that is being used, then strip that off the end of both the * base directory and filename. */ - String separator = determineSeparator( filename ); - basedir = StringUtils.chompLast( basedir, separator ); - filename = StringUtils.chompLast( filename, separator ); + String separator = determineSeparator(filename); + basedir = StringUtils.chompLast(basedir, separator); + filename = StringUtils.chompLast(filename, separator); /* * Remove the base directory from the filename to end up with a * relative filename (relative to the base directory). This * filename is then used to determine the relative path. */ - String relativeFilename = filename.substring( basedir.length() ); + String relativeFilename = filename.substring(basedir.length()); - return determineRelativePath( relativeFilename, separator ); + return determineRelativePath(relativeFilename, separator); } /** - * This method can calculate the relative path between two pathes on a file system. - *
+ *This method can calculate the relative path between two paths on a file system.
** PathTool.getRelativeFilePath( null, null ) = "" * PathTool.getRelativeFilePath( null, "/usr/local/java/bin" ) = "" @@ -120,59 +128,50 @@ public static String getRelativePath( @Nullable String basedir, @Nullable String * @param newPath new path * @return a relative file path fromoldPath
. */ - public static String getRelativeFilePath( final String oldPath, final String newPath ) - { - if ( StringUtils.isEmpty( oldPath ) || StringUtils.isEmpty( newPath ) ) - { + public static String getRelativeFilePath(final String oldPath, final String newPath) { + if (StringUtils.isEmpty(oldPath) || StringUtils.isEmpty(newPath)) { return ""; } // normalise the path delimiters - String fromPath = new File( oldPath ).getPath(); - String toPath = new File( newPath ).getPath(); + String fromPath = new File(oldPath).getPath(); + String toPath = new File(newPath).getPath(); // strip any leading slashes if its a windows path - if ( toPath.matches( "^\\[a-zA-Z]:" ) ) - { - toPath = toPath.substring( 1 ); + if (toPath.matches("^\\[a-zA-Z]:")) { + toPath = toPath.substring(1); } - if ( fromPath.matches( "^\\[a-zA-Z]:" ) ) - { - fromPath = fromPath.substring( 1 ); + if (fromPath.matches("^\\[a-zA-Z]:")) { + fromPath = fromPath.substring(1); } // lowercase windows drive letters. - if ( fromPath.startsWith( ":", 1 ) ) - { - fromPath = Character.toLowerCase( fromPath.charAt( 0 ) ) + fromPath.substring( 1 ); + if (fromPath.startsWith(":", 1)) { + fromPath = Character.toLowerCase(fromPath.charAt(0)) + fromPath.substring(1); } - if ( toPath.startsWith( ":", 1 ) ) - { - toPath = Character.toLowerCase( toPath.charAt( 0 ) ) + toPath.substring( 1 ); + if (toPath.startsWith(":", 1)) { + toPath = Character.toLowerCase(toPath.charAt(0)) + toPath.substring(1); } // check for the presence of windows drives. No relative way of // traversing from one to the other. - if ( ( toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) ) - && ( !toPath.substring( 0, 1 ).equals( fromPath.substring( 0, 1 ) ) ) ) - { + if ((toPath.startsWith(":", 1) && fromPath.startsWith(":", 1)) + && (!toPath.substring(0, 1).equals(fromPath.substring(0, 1)))) { // they both have drive path element but they dont match, no // relative path return null; } - if ( ( toPath.startsWith( ":", 1 ) && !fromPath.startsWith( ":", 1 ) ) - || ( !toPath.startsWith( ":", 1 ) && fromPath.startsWith( ":", 1 ) ) ) - { + if ((toPath.startsWith(":", 1) && !fromPath.startsWith(":", 1)) + || (!toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))) { // one has a drive path element and the other doesnt, no relative // path. return null; } - String resultPath = buildRelativePath( toPath, fromPath, File.separatorChar ); + String resultPath = buildRelativePath(toPath, fromPath, File.separatorChar); - if ( newPath.endsWith( File.separator ) && !resultPath.endsWith( File.separator ) ) - { + if (newPath.endsWith(File.separator) && !resultPath.endsWith(File.separator)) { return resultPath + File.separator; } @@ -194,21 +193,19 @@ public static String getRelativeFilePath( final String oldPath, final String new * terminated with a forward slash. A zero-length string is * returned if: the filename is zero-length. */ - @Nonnull private static String determineRelativePath( @Nonnull String filename, @Nonnull String separator ) - { - if ( filename.length() == 0 ) - { + @Nonnull + private static String determineRelativePath(@Nonnull String filename, @Nonnull String separator) { + if (filename.length() == 0) { return ""; } /* - * Count the slashes in the relative filename, but exclude the - * leading slash. If the path has no slashes, then the filename - * is relative to the current directory. - */ - int slashCount = StringUtils.countMatches( filename, separator ) - 1; - if ( slashCount <= 0 ) - { + * Count the slashes in the relative filename, but exclude the + * leading slash. If the path has no slashes, then the filename + * is relative to the current directory. + */ + int slashCount = StringUtils.countMatches(filename, separator) - 1; + if (slashCount <= 0) { return "."; } @@ -218,16 +215,15 @@ public static String getRelativeFilePath( final String oldPath, final String new * slash represents a "../" in the relative path. */ StringBuilder sb = new StringBuilder(); - for ( int i = 0; i < slashCount; i++ ) - { - sb.append( "../" ); + for (int i = 0; i < slashCount; i++) { + sb.append("../"); } /* * Finally, return the relative path but strip the trailing * slash to mimic Anakia's behavior. */ - return StringUtils.chop( sb.toString() ); + return StringUtils.chop(sb.toString()); } /** @@ -240,10 +236,9 @@ public static String getRelativeFilePath( final String oldPath, final String new * @return The file separator used withinfilename
. * This value is either a forward or backward slash. */ - private static String determineSeparator( String filename ) - { - int forwardCount = StringUtils.countMatches( filename, "/" ); - int backwardCount = StringUtils.countMatches( filename, "\\" ); + private static String determineSeparator(String filename) { + int forwardCount = StringUtils.countMatches(filename, "/"); + int backwardCount = StringUtils.countMatches(filename, "\\"); return forwardCount >= backwardCount ? "/" : "\\"; } @@ -254,42 +249,33 @@ private static String determineSeparator( String filename ) * @param path old path * @return String */ - static String uppercaseDrive( @Nullable String path ) - { - if ( path == null ) - { + static String uppercaseDrive(@Nullable String path) { + if (path == null) { return null; } - if ( path.length() >= 2 && path.charAt( 1 ) == ':' ) - { - path = Character.toUpperCase( path.charAt( 0 ) ) + path.substring( 1 ); + if (path.length() >= 2 && path.charAt(1) == ':') { + path = Character.toUpperCase(path.charAt(0)) + path.substring(1); } return path; } - @Nonnull private static String buildRelativePath( @Nonnull String toPath, @Nonnull String fromPath, - final char separatorChar ) - { + @Nonnull + private static String buildRelativePath( + @Nonnull String toPath, @Nonnull String fromPath, final char separatorChar) { // use tokeniser to traverse paths and for lazy checking - StringTokenizer toTokeniser = new StringTokenizer( toPath, String.valueOf( separatorChar ) ); - StringTokenizer fromTokeniser = new StringTokenizer( fromPath, String.valueOf( separatorChar ) ); + StringTokenizer toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar)); + StringTokenizer fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar)); int count = 0; // walk along the to path looking for divergence from the from path - while ( toTokeniser.hasMoreTokens() && fromTokeniser.hasMoreTokens() ) - { - if ( separatorChar == '\\' ) - { - if ( !fromTokeniser.nextToken().equalsIgnoreCase( toTokeniser.nextToken() ) ) - { + while (toTokeniser.hasMoreTokens() && fromTokeniser.hasMoreTokens()) { + if (separatorChar == '\\') { + if (!fromTokeniser.nextToken().equalsIgnoreCase(toTokeniser.nextToken())) { break; } - } - else - { - if ( !fromTokeniser.nextToken().equals( toTokeniser.nextToken() ) ) - { + } else { + if (!fromTokeniser.nextToken().equals(toTokeniser.nextToken())) { break; } } @@ -300,11 +286,10 @@ static String uppercaseDrive( @Nullable String path ) // reinitialise the tokenisers to count positions to retrieve the // gobbled token - toTokeniser = new StringTokenizer( toPath, String.valueOf( separatorChar ) ); - fromTokeniser = new StringTokenizer( fromPath, String.valueOf( separatorChar ) ); + toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar)); + fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar)); - while ( count-- > 0 ) - { + while (count-- > 0) { fromTokeniser.nextToken(); toTokeniser.nextToken(); } @@ -312,31 +297,26 @@ static String uppercaseDrive( @Nullable String path ) StringBuilder relativePath = new StringBuilder(); // add back refs for the rest of from location. - while ( fromTokeniser.hasMoreTokens() ) - { + while (fromTokeniser.hasMoreTokens()) { fromTokeniser.nextToken(); - relativePath.append( ".." ); + relativePath.append(".."); - if ( fromTokeniser.hasMoreTokens() ) - { - relativePath.append( separatorChar ); + if (fromTokeniser.hasMoreTokens()) { + relativePath.append(separatorChar); } } - if ( relativePath.length() != 0 && toTokeniser.hasMoreTokens() ) - { - relativePath.append( separatorChar ); + if (relativePath.length() != 0 && toTokeniser.hasMoreTokens()) { + relativePath.append(separatorChar); } // add fwd fills for whatevers left of newPath. - while ( toTokeniser.hasMoreTokens() ) - { - relativePath.append( toTokeniser.nextToken() ); + while (toTokeniser.hasMoreTokens()) { + relativePath.append(toTokeniser.nextToken()); - if ( toTokeniser.hasMoreTokens() ) - { - relativePath.append( separatorChar ); + if (toTokeniser.hasMoreTokens()) { + relativePath.append(separatorChar); } } return relativePath.toString(); diff --git a/src/main/java/org/apache/maven/shared/utils/PropertyUtils.java b/src/main/java/org/apache/maven/shared/utils/PropertyUtils.java index 6bdfdf3d..0730828c 100644 --- a/src/main/java/org/apache/maven/shared/utils/PropertyUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/PropertyUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,80 +16,166 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.Properties; -import org.apache.maven.shared.utils.io.IOUtil; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** - * + * Static utility methods for loading properties. */ -public class PropertyUtils -{ +public class PropertyUtils { - public PropertyUtils() - { - // should throw new IllegalAccessError( "Utility class" ); - } + /** + * The constructor. + * + * @deprecated This is a utility class with only static methods. Don't create instances of it. + */ + @Deprecated + public PropertyUtils() {} - public static java.util.Properties loadProperties( @Nonnull java.net.URL url ) - { - try - { - return loadProperties( url.openStream() ); - } - catch ( Exception e ) - { + /** + * @param url the URL which should be used to load the properties + * @return the loaded properties + * @deprecated use {@link #loadOptionalProperties(java.net.URL)} instead. This method should not + * be used as it suppresses exceptions silently when loading properties fails and returns {@code null} + * instead of an empty {@code Properties} instance when the given {@code URL} is {@code null}. + */ + @Deprecated + public static java.util.Properties loadProperties(@Nonnull URL url) { + try (InputStream in = url.openStream()) { + return loadProperties(in); + } catch (Exception e) { // ignore } return null; } - public static java.util.Properties loadProperties( @Nonnull java.io.File file ) - { - try - { - return loadProperties( new FileInputStream( file ) ); - } - catch ( Exception e ) - { + /** + * @param file the file from which the properties will be loaded + * @return the loaded properties + * @deprecated use {@link #loadOptionalProperties(java.io.File)} instead. This method should not + * be used as it suppresses exceptions silently when loading properties fails and returns {@code null} + * instead of an empty {@code Properties} instance when the given {@code File} is {@code null}. + */ + @Deprecated + public static Properties loadProperties(@Nonnull File file) { + try (InputStream in = new FileInputStream(file)) { + return loadProperties(in); + } catch (Exception e) { // ignore } return null; } - public static java.util.Properties loadProperties( @Nullable java.io.InputStream is ) - { - try - { - // to make this the same behaviour as the others we should really return null on any error + /** + * Loads {@code Properties} from an {@code InputStream} and closes the stream. + * In a future release, this will no longer close the stream, so callers + * should close the stream themselves. + * + * @param is {@link InputStream} + * @return the loaded properties + * @deprecated use {@link #loadOptionalProperties(java.io.InputStream)} instead. This method + * should not be used as it suppresses exceptions silently when loading properties fails. + */ + @Deprecated + public static Properties loadProperties(@Nullable InputStream is) { + try { Properties result = new Properties(); - if ( is != null ) - { - try - { - result.load( is ); - } - catch ( IOException e ) - { + if (is != null) { + try (InputStream in = is) { + result.load(in); + } catch (IOException e) { // ignore } } return result; - } - catch ( Exception e ) - { + } catch (Exception e) { // ignore } - finally - { - IOUtil.close( is ); - } return null; } + /** + * Loads {@code Properties} from a given {@code URL}. + *+ * If the given {@code URL} is {@code null} or the properties can't be read, an empty properties object is returned. + *
+ * + * @param url the {@code URL} of the properties resource to load or {@code null} + * @return the loaded properties or an empty {@code Properties} instance if properties fail to load + * @since 3.1.0 + */ + @Nonnull + public static Properties loadOptionalProperties(final @Nullable URL url) { + + Properties properties = new Properties(); + if (url != null) { + try (InputStream in = url.openStream()) { + properties.load(in); + } catch (IllegalArgumentException | IOException ex) { + // ignore and return empty properties + } + } + return properties; + } + + /** + * Loads {@code Properties} from a {@code File}. + *+ * If the given {@code File} is {@code null} or the properties file can't be read, an empty properties object is + * returned. + *
+ * + * @param file the {@code File} of the properties resource to load or {@code null} + * @return the loaded properties or an empty {@code Properties} instance if properties fail to load + * @since 3.1.0 + */ + @Nonnull + public static Properties loadOptionalProperties(final @Nullable File file) { + Properties properties = new Properties(); + if (file != null) { + try (InputStream in = new FileInputStream(file)) { + properties.load(in); + } catch (IllegalArgumentException | IOException ex) { + // ignore and return empty properties + } + } + + return properties; + } + + /** + * Loads {@code Properties} from an {@code InputStream} and closes the stream. + * If the given {@code InputStream} is {@code null} or the properties can't be read, an empty properties object is + * returned. In a future release, this will no longer close the stream, so callers + * should close the stream themselves. + * + * @param inputStream the properties resource to load or {@code null} + * @return the loaded properties or an empty {@code Properties} instance if properties fail to load + * @since 3.1.0 + */ + @Nonnull + public static Properties loadOptionalProperties(final @Nullable InputStream inputStream) { + + Properties properties = new Properties(); + + if (inputStream != null) { + try (InputStream in = inputStream) // reassign inputStream to autoclose + { + properties.load(in); + } catch (IllegalArgumentException | IOException ex) { + // ignore and return empty properties + } + } + + return properties; + } } diff --git a/src/main/java/org/apache/maven/shared/utils/ReaderFactory.java b/src/main/java/org/apache/maven/shared/utils/ReaderFactory.java index 5103219c..efdb8a24 100644 --- a/src/main/java/org/apache/maven/shared/utils/ReaderFactory.java +++ b/src/main/java/org/apache/maven/shared/utils/ReaderFactory.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils; + +import javax.annotation.Nonnull; import java.io.File; import java.io.FileInputStream; @@ -29,10 +30,8 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.URL; -import org.apache.commons.io.input.XmlStreamReader; - -import javax.annotation.Nonnull; +import org.apache.commons.io.input.XmlStreamReader; /** * Utility to create Readers from streams, with explicit encoding choice: platform default, @@ -40,24 +39,25 @@ * * @author Hervé Boutemy * @see java.nio.charset.Charset - * @see Supported encodings + * @see Supported encodings */ -public class ReaderFactory -{ +public class ReaderFactory { /** * ISO Latin Alphabet #1, also known as ISO-LATIN-1. * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.ISO_8859_1} */ + @Deprecated public static final String ISO_8859_1 = "ISO-8859-1"; /** * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.US_ASCII} */ + @Deprecated public static final String US_ASCII = "US-ASCII"; /** @@ -65,138 +65,138 @@ public class ReaderFactory * order accepted on input, big-endian used on output). * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16} */ + @Deprecated public static final String UTF_16 = "UTF-16"; /** * Sixteen-bit Unicode Transformation Format, big-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16BE} */ + @Deprecated public static final String UTF_16BE = "UTF-16BE"; /** * Sixteen-bit Unicode Transformation Format, little-endian byte order. * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16LE} */ + @Deprecated public static final String UTF_16LE = "UTF-16LE"; /** * Eight-bit Unicode Transformation Format. * Every implementation of the Java platform is required to support this character encoding. * - * @see java.nio.charset.Charset + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_8} */ + @Deprecated public static final String UTF_8 = "UTF-8"; /** * Thefile.encoding
System Property. */ - public static final String FILE_ENCODING = System.getProperty( "file.encoding" ); + public static final String FILE_ENCODING = System.getProperty("file.encoding"); /** * Create a new Reader with XML encoding detection rules. * - * @param in not null input stream. - * @return an XML reader instance for the input stream. - * @throws IOException if any. - * @see XmlStreamReader + * @param in not null input stream + * @return an XML reader instance for the input stream + * @throws IOException if any + * @deprecated use org.apache.commons.io.input.XmlStreamReader instead */ - public static Reader newXmlReader( @Nonnull InputStream in ) - throws IOException - { - return new XmlStreamReader( in ); + @Deprecated + public static Reader newXmlReader(@Nonnull InputStream in) throws IOException { + return new XmlStreamReader(in); } /** * Create a new Reader with XML encoding detection rules. * - * @param file not null file. - * @return an XML reader instance for the input file. - * @throws IOException if any. - * @see XmlStreamReader + * @param file not null file + * @return an XML reader instance for the input file + * @throws IOException if any + * @deprecated use org.apache.commons.io.input.XmlStreamReader instead */ - public static Reader newXmlReader( @Nonnull File file ) - throws IOException - { - return new XmlStreamReader( file ); + @Deprecated + public static Reader newXmlReader(@Nonnull File file) throws IOException { + return new XmlStreamReader(file); } /** * Create a new Reader with XML encoding detection rules. * - * @param url not null url. - * @return an XML reader instance for the input url. - * @throws IOException if any. - * @see XmlStreamReader + * @param url not null URL + * @return an XML reader instance for the input URL + * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.input.XmlStreamReader} instead */ - public static Reader newXmlReader( @Nonnull URL url ) - throws IOException - { - return new XmlStreamReader( url ); + @Deprecated + public static Reader newXmlReader(@Nonnull URL url) throws IOException { + return new XmlStreamReader(url); } /** - * Create a new Reader with default plaform encoding. + * Create a new Reader with default platform encoding. * * @param file not null file. - * @return a reader instance for the input file using the default platform charset. - * @throws FileNotFoundException if any. + * @return a reader instance for the input file using the default platform character set + * @throws FileNotFoundException if any * @see java.nio.charset.Charset#defaultCharset() + * @deprecated always specify an encoding. Do not depend on the default platform character set. */ - public static Reader newPlatformReader( @Nonnull File file ) - throws FileNotFoundException - { - return new FileReader( file ); + @Deprecated + public static Reader newPlatformReader(@Nonnull File file) throws FileNotFoundException { + return new FileReader(file); } /** * Create a new Reader with specified encoding. * - * @param in not null input stream. - * @param encoding not null supported encoding. - * @return a reader instance for the input stream using the given encoding. - * @throws UnsupportedEncodingException if any. - * @see Supported encodings + * @param in not null input stream + * @param encoding not null supported encoding + * @return a reader instance for the input stream using the given encoding + * @throws UnsupportedEncodingException if any + * @see Supported + * encodings */ - public static Reader newReader( @Nonnull InputStream in, @Nonnull String encoding ) - throws UnsupportedEncodingException - { - return new InputStreamReader( in, encoding ); + public static Reader newReader(@Nonnull InputStream in, @Nonnull String encoding) + throws UnsupportedEncodingException { + return new InputStreamReader(in, encoding); } /** * Create a new Reader with specified encoding. * - * @param file not null file. - * @param encoding not null supported encoding. - * @return a reader instance for the input file using the given encoding. - * @throws FileNotFoundException if any. - * @throws UnsupportedEncodingException if any. - * @see Supported encodings + * @param file not null file + * @param encoding not null supported encoding + * @return a reader instance for the input file using the given encoding + * @throws FileNotFoundException if any + * @throws UnsupportedEncodingException if any + * @see Supported + * encodings */ - public static Reader newReader( @Nonnull File file, @Nonnull String encoding ) - throws FileNotFoundException, UnsupportedEncodingException - { - return new InputStreamReader( new FileInputStream( file ), encoding ); + public static Reader newReader(@Nonnull File file, @Nonnull String encoding) + throws FileNotFoundException, UnsupportedEncodingException { + return new InputStreamReader(new FileInputStream(file), encoding); } /** * Create a new Reader with specified encoding. * - * @param url not null url. - * @param encoding not null supported encoding. - * @return a reader instance for the input url using the given encoding. - * @throws IOException if any. - * @see Supported encodings + * @param url not null URL + * @param encoding not null supported encoding + * @return a reader instance for the input URL using the given encoding + * @throws IOException if any + * @see Supported + * encodings */ - public static Reader newReader( @Nonnull URL url, @Nonnull String encoding ) - throws IOException - { - return new InputStreamReader( url.openStream(), encoding ); + public static Reader newReader(@Nonnull URL url, @Nonnull String encoding) throws IOException { + return new InputStreamReader(url.openStream(), encoding); } } diff --git a/src/main/java/org/apache/maven/shared/utils/StringUtils.java b/src/main/java/org/apache/maven/shared/utils/StringUtils.java index a88b47ca..dff90cbf 100644 --- a/src/main/java/org/apache/maven/shared/utils/StringUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/StringUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,7 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.Iterator; @@ -26,12 +27,9 @@ import java.util.Map; import java.util.StringTokenizer; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - /** *Common
- * + * *String
manipulation routines.Originally from * Turbine, the * GenerationJavaCore library and Velocity. @@ -49,29 +47,24 @@ * @author Fredrik Westermarck * @author Holger Krauth * @author Alexander Day Chaffee - * @version $Id$ - * + * */ -@SuppressWarnings( "JavaDoc" ) -public class StringUtils -{ +public class StringUtils { /** *
- * + * *
StringUtils
instances should NOT be constructed in * standard programming. Instead, the class should be used as *StringUtils.trim(" foo ");
.This constructor is public to permit tools that require a JavaBean * manager to operate.
*/ - public StringUtils() - { - } + public StringUtils() {} // Empty - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** - *Removes control characters, including whitespace, from both + *
Removes C0 control characters, including ASCII whitespace, from both * ends of this String, handling
* @@ -79,13 +72,13 @@ public StringUtils() * @return the trimmed text (nevernull
by returning * an empty String.null
) * @see java.lang.String#trim() */ - @Nonnull public static String clean( String str ) - { - return ( str == null ? "" : str.trim() ); + @Nonnull + public static String clean(String str) { + return (str == null ? "" : str.trim()); } /** - *Removes control characters, including whitespace, from both + *
Removes C0 control characters, including ASCII whitespace, from both * ends of this String, handling
* @@ -93,30 +86,26 @@ public StringUtils() * @return the trimmed text (ornull
by returning *null
.null
) * @see java.lang.String#trim() */ - public static String trim( String str ) - { - return ( str == null ? null : str.trim() ); + public static String trim(String str) { + return (str == null ? null : str.trim()); } /** - *Deletes all whitespaces from a String.
- * + *Deletes all whitespace from a String.
+ * *Whitespace is defined by * {@link Character#isWhitespace(char)}.
* * @param str String target to delete whitespace from - * @return the String without whitespaces - * @throws NullPointerException + * @return the String without whitespace */ - @Nonnull public static String deleteWhitespace( @Nonnull String str ) - { + @Nonnull + public static String deleteWhitespace(@Nonnull String str) { StringBuilder buffer = new StringBuilder(); int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( !Character.isWhitespace( str.charAt( i ) ) ) - { - buffer.append( str.charAt( i ) ); + for (int i = 0; i < sz; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + buffer.append(str.charAt(i)); } } return buffer.toString(); @@ -124,19 +113,18 @@ public static String trim( String str ) /** *Checks if a String is non
+ * not empty (null
and is - * not empty (length > 0
).length > 0
). * * @param str the String to check * @return true if the String is non-null, and not length zero */ - public static boolean isNotEmpty( @Nullable String str ) - { - return ( ( str != null ) && ( str.length() > 0 ) ); + public static boolean isNotEmpty(@Nullable String str) { + return ((str != null) && (str.length() > 0)); } /** *Checks if a (trimmed) String is
- * + * *null
or empty.Note: In future releases, this method will no longer trim the input string such that it works * complementary to {@link #isNotEmpty(String)}. Code that wants to test for whitespace-only strings should be * migrated to use {@link #isBlank(String)} instead.
@@ -145,16 +133,15 @@ public static boolean isNotEmpty( @Nullable String str ) * @returntrue
if the String isnull
, or * length zero once trimmed */ - public static boolean isEmpty( @Nullable String str ) - { - return ( ( str == null ) || ( str.trim().length() == 0 ) ); + public static boolean isEmpty(@Nullable String str) { + return ((str == null) || (str.trim().length() == 0)); } /** ** Checks if a String is whitespace, empty ("") or null. *
- * + * ** StringUtils.isBlank(null) = true * StringUtils.isBlank("") = true @@ -165,21 +152,18 @@ public static boolean isEmpty( @Nullable String str ) * * @param str the String to check, may be null * @returntrue
if the String is null, empty or whitespace - * + * */ - public static boolean isBlank( @Nullable String str ) - { + public static boolean isBlank(@Nullable String str) { int strLen; // CHECKSTYLE_OFF: InnerAssignment - if ( str == null || ( strLen = str.length() ) == 0 ) + if (str == null || (strLen = str.length()) == 0) // CHECKSTYLE_ON: InnerAssignment { return true; } - for ( int i = 0; i < strLen; i++ ) - { - if ( !Character.isWhitespace( str.charAt( i ) ) ) - { + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { return false; } } @@ -190,7 +174,7 @@ public static boolean isBlank( @Nullable String str ) ** Checks if a String is not empty (""), not null and not whitespace only. *
- * + * ** StringUtils.isNotBlank(null) = false * StringUtils.isNotBlank("") = false @@ -201,19 +185,18 @@ public static boolean isBlank( @Nullable String str ) * * @param str the String to check, may be null * @return* will become 'ThisIsIt'. * - * @param data - * @param replaceThis + * @param data The data. + * @param replaceThis The things which should be replaced. * @return humped String */ - @Nonnull public static String removeAndHump( @Nonnull String data, @Nonnull String replaceThis ) - { + @Nonnull + public static String removeAndHump(@Nonnull String data, @Nonnull String replaceThis) { String temp; StringBuilder out = new StringBuilder(); temp = data; - StringTokenizer st = new StringTokenizer( temp, replaceThis ); + StringTokenizer st = new StringTokenizer(temp, replaceThis); - while ( st.hasMoreTokens() ) - { + while (st.hasMoreTokens()) { String element = st.nextToken(); - out.append( capitalizeFirstLetter( element ) ); + out.append(capitalizeFirstLetter(element)); } return out.toString(); } /** - * Convert the first character of the given String to uppercase. - * This method will not trim of spaces! - * - *true
if the String is not empty and not null and not whitespace - * + * */ - public static boolean isNotBlank( @Nullable String str ) - { - return !isBlank( str ); + public static boolean isNotBlank(@Nullable String str) { + return !isBlank(str); } // Equals and IndexOf - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Compares two Strings, returning
- * + * *true
if they are equal.* @@ -222,16 +205,17 @@ public static boolean isNotBlank( @Nullable String str ) * @return
null
s are handled without exceptions. Twonull
* references are considered to be equal. The comparison is case sensitive.true
if the Strings are equal, case sensitive, or * bothnull
* @see java.lang.String#equals(Object) + * @deprecated use {@code java.lang.Objects.equals()} */ - public static boolean equals( @Nullable String str1, @Nullable String str2 ) - { - return ( str1 == null ? str2 == null : str1.equals( str2 ) ); + @Deprecated + public static boolean equals(@Nullable String str1, @Nullable String str2) { + return (str1 == null ? str2 == null : str1.equals(str2)); } /** *Compares two Strings, returning
- * + * *true
if they are equal ignoring * the case.* @@ -241,14 +225,13 @@ public static boolean equals( @Nullable String str1, @Nullable String str2 ) * both
Nulls
are handled without exceptions. Twonull
* references are considered equal. Comparison is case insensitive.null
* @see java.lang.String#equalsIgnoreCase(String) */ - public static boolean equalsIgnoreCase( String str1, String str2 ) - { - return ( str1 == null ? str2 == null : str1.equalsIgnoreCase( str2 ) ); + public static boolean equalsIgnoreCase(String str1, String str2) { + return (str1 == null ? str2 == null : str1.equalsIgnoreCase(str2)); } /** *Find the first index of any of a set of potential substrings.
- * + * ** * @param str the String to check @@ -256,36 +239,31 @@ public static boolean equalsIgnoreCase( String str1, String str2 ) * @return the first index of any of the searchStrs in str * @throws NullPointerException if any of searchStrs[i] is
null
String will return-1
.null
*/ - public static int indexOfAny( String str, String... searchStrs ) - { - if ( ( str == null ) || ( searchStrs == null ) ) - { + public static int indexOfAny(String str, String... searchStrs) { + if ((str == null) || (searchStrs == null)) { return -1; } // String's can't have a MAX_VALUEth index. int ret = Integer.MAX_VALUE; int tmp; - for ( String searchStr : searchStrs ) - { - tmp = str.indexOf( searchStr ); - if ( tmp == -1 ) - { + for (String searchStr : searchStrs) { + tmp = str.indexOf(searchStr); + if (tmp == -1) { continue; } - if ( tmp < ret ) - { + if (tmp < ret) { ret = tmp; } } - return ( ret == Integer.MAX_VALUE ) ? -1 : ret; + return (ret == Integer.MAX_VALUE) ? -1 : ret; } /** *Find the latest index of any of a set of potential substrings.
- * + * ** * @param str the String to check @@ -293,19 +271,15 @@ public static int indexOfAny( String str, String... searchStrs ) * @return the last index of any of the Strings * @throws NullPointerException if any of searchStrs[i] is
null
string will return-1
.null
*/ - public static int lastIndexOfAny( String str, String... searchStrs ) - { - if ( ( str == null ) || ( searchStrs == null ) ) - { + public static int lastIndexOfAny(String str, String... searchStrs) { + if ((str == null) || (searchStrs == null)) { return -1; } int ret = -1; int tmp; - for ( String searchStr : searchStrs ) - { - tmp = str.lastIndexOf( searchStr ); - if ( tmp > ret ) - { + for (String searchStr : searchStrs) { + tmp = str.lastIndexOf(searchStr); + if (tmp > ret) { ret = tmp; } } @@ -313,11 +287,11 @@ public static int lastIndexOfAny( String str, String... searchStrs ) } // Substring - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Gets a substring from the specified string avoiding exceptions.
- * + * *A negative start position can be used to start
* @@ -326,34 +300,29 @@ public static int lastIndexOfAny( String str, String... searchStrs ) * count back from the end of the String by this many characters * @return substring from start position */ - public static String substring( String str, int start ) - { - if ( str == null ) - { + public static String substring(String str, int start) { + if (str == null) { return null; } // handle negatives, which means last n characters - if ( start < 0 ) - { + if (start < 0) { start = str.length() + start; // remember start is negative } - if ( start < 0 ) - { + if (start < 0) { start = 0; } - if ( start > str.length() ) - { + if (start > str.length()) { return ""; } - return str.substring( start ); + return str.substring(start); } /** *n
* characters from the end of the String.Gets a substring from the specified String avoiding exceptions.
- * + * *A negative start position can be used to start/end
* @@ -362,53 +331,45 @@ public static String substring( String str, int start ) * count back from the end of the string by this many characters * @param end the position to end at (exclusive), negative means * count back from the end of the String by this many characters - * @return substring from start position to end positon + * @return substring from start position to end position */ - public static String substring( String str, int start, int end ) - { - if ( str == null ) - { + public static String substring(String str, int start, int end) { + if (str == null) { return null; } // handle negatives - if ( end < 0 ) - { + if (end < 0) { end = str.length() + end; // remember end is negative } - if ( start < 0 ) - { + if (start < 0) { start = str.length() + start; // remember start is negative } // check length next - if ( end > str.length() ) - { + if (end > str.length()) { // check this works. end = str.length(); } // if start is greater than end, return "" - if ( start > end ) - { + if (start > end) { return ""; } - if ( start < 0 ) - { + if (start < 0) { start = 0; } - if ( end < 0 ) - { + if (end < 0) { end = 0; } - return str.substring( start, end ); + return str.substring(start, end); } /** *n
* characters from the end of the String.Gets the leftmost
- * + * *n
characters of a String.If
@@ -418,25 +379,20 @@ public static String substring( String str, int start, int end ) * @return the leftmost characters * @throws IllegalArgumentException if len is less than zero */ - public static String left( String str, int len ) - { - if ( len < 0 ) - { - throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); + public static String left(String str, int len) { + if (len < 0) { + throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); } - if ( ( str == null ) || ( str.length() <= len ) ) - { + if ((str == null) || (str.length() <= len)) { return str; - } - else - { - return str.substring( 0, len ); + } else { + return str.substring(0, len); } } /** *n
characters are not available, or the * String isnull
, the String will be returned without * an exception.Gets the rightmost
- * + * *n
characters of a String.If
@@ -446,25 +402,20 @@ public static String left( String str, int len ) * @return the leftmost characters * @throws IllegalArgumentException if len is less than zero */ - public static String right( String str, int len ) - { - if ( len < 0 ) - { - throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); + public static String right(String str, int len) { + if (len < 0) { + throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); } - if ( ( str == null ) || ( str.length() <= len ) ) - { + if ((str == null) || (str.length() <= len)) { return str; - } - else - { - return str.substring( str.length() - len ); + } else { + return str.substring(str.length() - len); } } /** *n
characters are not available, or the String * isnull
, the String will be returned without an * exception.Gets
- * + * *n
characters from the middle of a String.If
@@ -476,90 +427,82 @@ public static String right( String str, int len ) * @throws IndexOutOfBoundsException if pos is out of bounds * @throws IllegalArgumentException if len is less than zero */ - public static String mid( String str, int pos, int len ) - { - if ( ( pos < 0 ) || ( ( str != null ) && ( pos > str.length() ) ) ) - { - throw new StringIndexOutOfBoundsException( "String index " + pos + " is out of bounds" ); + public static String mid(String str, int pos, int len) { + if ((pos < 0) || ((str != null) && (pos > str.length()))) { + throw new StringIndexOutOfBoundsException("String index " + pos + " is out of bounds"); } - if ( len < 0 ) - { - throw new IllegalArgumentException( "Requested String length " + len + " is less than zero" ); + if (len < 0) { + throw new IllegalArgumentException("Requested String length " + len + " is less than zero"); } - if ( str == null ) - { + if (str == null) { return null; } - if ( str.length() <= ( pos + len ) ) - { - return str.substring( pos ); - } - else - { - return str.substring( pos, pos + len ); + if (str.length() <= (pos + len)) { + return str.substring(pos); + } else { + return str.substring(pos, pos + len); } } // Splitting - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *n
characters are not available, the remainder * of the String will be returned without an exception. If the * String isnull
,null
will be returned.Splits the provided text into a array, using whitespace as the * separator.
- * + * *The separator is not included in the returned String array.
* * @param str the String to parse * @return an array of parsed Strings */ - @Nonnull public static String[] split( @Nonnull String str ) - { - return split( str, null, -1 ); + @Nonnull + public static String[] split(@Nonnull String str) { + return split(str, null, -1); } /** + * @param text the text to be split + * @param separator the separator at which the text will be split + * @return the resulting array * @see #split(String, String, int) */ - @Nonnull public static String[] split( @Nonnull String text, @Nullable String separator ) - { - return split( text, separator, -1 ); + @Nonnull + public static String[] split(@Nonnull String text, @Nullable String separator) { + return split(text, separator, -1); } /** *Splits the provided text into a array, based on a given separator.
- * + * *The separator is not included in the returned String array. The - * maximum number of splits to perfom can be controlled. A
- * - *null
- * separator will cause parsing to be on whitespace.This is useful for quickly splitting a String directly into + * maximum number of splits to perform can be controlled. A
+ * + *null
+ * separator causes splitting on whitespace.This is useful for quickly splitting a String into * an array of tokens, instead of an enumeration of tokens (as *
* - * @param str The string to parse. + * @param str the string to parse * @param separator Characters used as the delimiters. If *StringTokenizer
does).null
, splits on whitespace. - * @param max The maximum number of elements to include in the + * @param max the maximum number of elements to include in the * array. A zero or negative value implies no limit. * @return an array of parsed Strings */ - @Nonnull public static String[] split( @Nonnull String str, @Nullable String separator, int max ) - { + @Nonnull + public static String[] split(@Nonnull String str, @Nullable String separator, int max) { StringTokenizer tok; - if ( separator == null ) - { + if (separator == null) { // Null separator means we're using StringTokenizer's default // delimiter, which comprises all whitespace characters. - tok = new StringTokenizer( str ); - } - else - { - tok = new StringTokenizer( str, separator ); + tok = new StringTokenizer(str); + } else { + tok = new StringTokenizer(str, separator); } int listSize = tok.countTokens(); - if ( ( max > 0 ) && ( listSize > max ) ) - { + if ((max > 0) && (listSize > max)) { listSize = max; } @@ -567,22 +510,18 @@ public static String mid( String str, int pos, int len ) int i = 0; int lastTokenBegin; int lastTokenEnd = 0; - while ( tok.hasMoreTokens() ) - { - if ( ( max > 0 ) && ( i == listSize - 1 ) ) - { + while (tok.hasMoreTokens()) { + if ((max > 0) && (i == listSize - 1)) { // In the situation where we hit the max yet have // tokens left over in our input, the last list // element gets all remaining text. String endToken = tok.nextToken(); - lastTokenBegin = str.indexOf( endToken, lastTokenEnd ); - list[i] = str.substring( lastTokenBegin ); + lastTokenBegin = str.indexOf(endToken, lastTokenEnd); + list[i] = str.substring(lastTokenBegin); break; - } - else - { + } else { list[i] = tok.nextToken(); - lastTokenBegin = str.indexOf( list[i], lastTokenEnd ); + lastTokenBegin = str.indexOf(list[i], lastTokenEnd); lastTokenEnd = lastTokenBegin + list[i].length(); } i++; @@ -591,49 +530,48 @@ public static String mid( String str, int pos, int len ) } // Joining - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Concatenates elements of an array into a single String.
- * + * *The difference from join is that concatenate has no delimiter.
* * @param array the array of values to concatenate. * @return the concatenated string. */ - @Nonnull public static String concatenate( @Nonnull Object... array ) - { - return join( array, "" ); + @Nonnull + public static String concatenate(@Nonnull Object... array) { + return join(array, ""); } /** *Joins the elements of the provided array into a single String * containing the provided list of elements.
- * + * *No delimiter is added before or after the list. A *
* * @param array the array of values to join together * @param separator the separator character to use * @return the joined String + * @deprecated usenull
separator is the same as a blank String.java.lang.String.join(
) instead */ - @Nonnull public static String join( @Nonnull Object[] array, @Nullable String separator ) - { - if ( separator == null ) - { + @Deprecated + @Nonnull + public static String join(@Nonnull Object[] array, @Nullable String separator) { + if (separator == null) { separator = ""; } int arraySize = array.length; - int bufSize = ( arraySize == 0 ? 0 : ( array[0].toString().length() + separator.length() ) * arraySize ); - StringBuilder buf = new StringBuilder( bufSize ); + int bufSize = (arraySize == 0 ? 0 : (array[0].toString().length() + separator.length()) * arraySize); + StringBuilder buf = new StringBuilder(bufSize); - for ( int i = 0; i < arraySize; i++ ) - { - if ( i > 0 ) - { - buf.append( separator ); + for (int i = 0; i < arraySize; i++) { + if (i > 0) { + buf.append(separator); } - buf.append( array[i] ); + buf.append(array[i]); } return buf.toString(); } @@ -641,38 +579,37 @@ public static String mid( String str, int pos, int len ) /** *Joins the elements of the provided
- * + * *Iterator
into * a single String containing the provided elements.No delimiter is added before or after the list. A *
* * @param iterator thenull
separator is the same as a blank String.Iterator
of values to join together * @param separator the separator character to use * @return the joined String + * @deprecated usejava.lang.String.join(
) instead */ - @Nonnull public static String join( @Nonnull Iterator> iterator, String separator ) - { - if ( separator == null ) - { + @Deprecated + @Nonnull + public static String join(@Nonnull Iterator> iterator, String separator) { + if (separator == null) { separator = ""; } - StringBuilder buf = new StringBuilder( 256 ); // Java default is 16, probably too small - while ( iterator.hasNext() ) - { - buf.append( iterator.next() ); - if ( iterator.hasNext() ) - { - buf.append( separator ); + StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small + while (iterator.hasNext()) { + buf.append(iterator.next()); + if (iterator.hasNext()) { + buf.append(separator); } } return buf.toString(); } // Replacing - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Replace a char with another char inside a larger String, once.
- * + * *A
* * @param text text to search and replace in @@ -681,14 +618,13 @@ public static String mid( String str, int pos, int len ) * @return the text with any replacements processed * @see #replace(String text, char repl, char with, int max) */ - public static String replaceOnce( @Nullable String text, char repl, char with ) - { - return replace( text, repl, with, 1 ); + public static String replaceOnce(@Nullable String text, char repl, char with) { + return replace(text, repl, with, 1); } /** - *null
reference passed to this method is a no-op.Replace all occurances of a char within another char.
- * + *Replace all occurrences of a char within a string with another char.
+ * *A
* * @param text text to search and replace in @@ -697,15 +633,14 @@ public static String replaceOnce( @Nullable String text, char repl, char with ) * @return the text with any replacements processed * @see #replace(String text, char repl, char with, int max) */ - public static String replace( @Nullable String text, char repl, char with ) - { - return replace( text, repl, with, -1 ); + public static String replace(@Nullable String text, char repl, char with) { + return replace(text, repl, with, -1); } /** *null
reference passed to this method is a no-op.Replace a char with another char inside a larger String, * for the first
- * + * *max
values of the search char.A
* * @param text text to search and replace in @@ -714,14 +649,13 @@ public static String replace( @Nullable String text, char repl, char with ) * @param max maximum number of values to replace, ornull
reference passed to this method is a no-op.-1
if no maximum * @return the text with any replacements processed */ - public static String replace( @Nullable String text, char repl, char with, int max ) - { - return replace( text, String.valueOf( repl ), String.valueOf( with ), max ); + public static String replace(@Nullable String text, char repl, char with, int max) { + return replace(text, String.valueOf(repl), String.valueOf(with), max); } /** *Replace a String with another String inside a larger String, once.
- * + * *A
* * @param text text to search and replace in @@ -730,14 +664,13 @@ public static String replace( @Nullable String text, char repl, char with, int m * @return the text with any replacements processed * @see #replace(String text, String repl, String with, int max) */ - public static String replaceOnce( @Nullable String text, @Nullable String repl, @Nullable String with ) - { - return replace( text, repl, with, 1 ); + public static String replaceOnce(@Nullable String text, @Nullable String repl, @Nullable String with) { + return replace(text, repl, with, 1); } /** - *null
reference passed to this method is a no-op.Replace all occurances of a String within another String.
- * + *Replace all occurrences of a String within another String.
+ * *A
* * @param text text to search and replace in @@ -746,15 +679,14 @@ public static String replaceOnce( @Nullable String text, @Nullable String repl, * @return the text with any replacements processed * @see #replace(String text, String repl, String with, int max) */ - public static String replace( @Nullable String text, @Nullable String repl, @Nullable String with ) - { - return replace( text, repl, with, -1 ); + public static String replace(@Nullable String text, @Nullable String repl, @Nullable String with) { + return replace(text, repl, with, -1); } /** *null
reference passed to this method is a no-op.Replace a String with another String inside a larger String, * for the first
- * + * *max
values of the search String.A
* * @param text text to search and replace in @@ -763,26 +695,22 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nu * @param max maximum number of values to replace, ornull
reference passed to this method is a no-op.-1
if no maximum * @return the text with any replacements processed */ - public static String replace( @Nullable String text, @Nullable String repl, @Nullable String with, int max ) - { - if ( ( text == null ) || ( repl == null ) || ( with == null ) || ( repl.length() == 0 ) ) - { + public static String replace(@Nullable String text, @Nullable String repl, @Nullable String with, int max) { + if ((text == null) || (repl == null) || (with == null) || (repl.length() == 0)) { return text; } - StringBuilder buf = new StringBuilder( text.length() ); + StringBuilder buf = new StringBuilder(text.length()); int start = 0, end; - while ( ( end = text.indexOf( repl, start ) ) != -1 ) - { - buf.append( text, start, end ).append( with ); + while ((end = text.indexOf(repl, start)) != -1) { + buf.append(text, start, end).append(with); start = end + repl.length(); - if ( --max == 0 ) - { + if (--max == 0) { break; } } - buf.append( text, start, text.length() ); + buf.append(text, start, text.length()); return buf.toString(); } @@ -791,31 +719,29 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * * @param text String to do overlaying in * @param overlay String to overlay - * @param start int to start overlaying at - * @param end int to stop overlaying before - * @return String with overlayed text + * @param start position to start overlaying at + * @param end position to stop overlaying before + * @return String with overlaid text * @throws NullPointerException if text or overlay isnull
*/ - @SuppressWarnings( "ConstantConditions" ) - @Nonnull public static String overlayString( @Nonnull String text, @Nonnull String overlay, int start, int end ) - { - if ( overlay == null ) - { - throw new NullPointerException( "overlay is null" ); + @Nonnull + public static String overlayString(@Nonnull String text, @Nonnull String overlay, int start, int end) { + if (overlay == null) { + throw new NullPointerException("overlay is null"); } - return new StringBuilder( start + overlay.length() + text.length() - end + 1 ) - .append( text, 0, start ) - .append( overlay ) - .append( text, end, text.length() ) - .toString(); + return new StringBuilder(start + overlay.length() + text.length() - end + 1) + .append(text, 0, start) + .append(overlay) + .append(text, end, text.length()) + .toString(); } // Centering - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** - *Center a String in a larger String of size
n
.- *
+ *Center a String in a larger String of size
+ * *n
.Uses spaces as the value to buffer the String with. * Equivalent to
* @@ -824,14 +750,14 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String containing centered String * @throws NullPointerException if str iscenter(str, size, " ")
.null
*/ - @Nonnull public static String center( @Nonnull String str, int size ) - { - return center( str, size, " " ); + @Nonnull + public static String center(@Nonnull String str, int size) { + return center(str, size, " "); } /** *Center a String in a larger String of size
- * + * *n
.Uses a supplied String as the value to buffer the String with.
* * @param str String to center @@ -841,21 +767,20 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @throws NullPointerException if str or delim isnull
* @throws ArithmeticException if delim is the empty String */ - @Nonnull public static String center( @Nonnull String str, int size, @Nonnull String delim ) - { + @Nonnull + public static String center(@Nonnull String str, int size, @Nonnull String delim) { int sz = str.length(); int p = size - sz; - if ( p < 1 ) - { + if (p < 1) { return str; } - str = leftPad( str, sz + p / 2, delim ); - str = rightPad( str, size, delim ); + str = leftPad(str, sz + p / 2, delim); + str = rightPad(str, size, delim); return str; } // Chomping - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Remove the last newline, and everything after it from a String.
@@ -864,9 +789,9 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String without chomped newline * @throws NullPointerException if str isnull
*/ - @Nonnull public static String chomp( @Nonnull String str ) - { - return chomp( str, "\n" ); + @Nonnull + public static String chomp(@Nonnull String str) { + return chomp(str, "\n"); } /** @@ -878,15 +803,12 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String without chomped ending * @throws NullPointerException if str or sep isnull
*/ - @Nonnull public static String chomp( @Nonnull String str, @Nonnull String sep ) - { - int idx = str.lastIndexOf( sep ); - if ( idx != -1 ) - { - return str.substring( 0, idx ); - } - else - { + @Nonnull + public static String chomp(@Nonnull String str, @Nonnull String sep) { + int idx = str.lastIndexOf(sep); + if (idx != -1) { + return str.substring(0, idx); + } else { return str; } } @@ -899,9 +821,9 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String without chomped ending * @throws NullPointerException if str isnull
*/ - @Nonnull public static String chompLast( @Nonnull String str ) - { - return chompLast( str, "\n" ); + @Nonnull + public static String chompLast(@Nonnull String str) { + return chompLast(str, "\n"); } /** @@ -912,19 +834,15 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String without chomped ending * @throws NullPointerException if str or sep isnull
*/ - @Nonnull public static String chompLast( @Nonnull String str, @Nonnull String sep ) - { - if ( str.length() == 0 ) - { + @Nonnull + public static String chompLast(@Nonnull String str, @Nonnull String sep) { + if (str.length() == 0) { return str; } - String sub = str.substring( str.length() - sep.length() ); - if ( sep.equals( sub ) ) - { - return str.substring( 0, str.length() - sep.length() ); - } - else - { + String sub = str.substring(str.length() - sep.length()); + if (sep.equals(sub)) { + return str.substring(0, str.length() - sep.length()); + } else { return str; } } @@ -938,19 +856,14 @@ public static String replace( @Nullable String text, @Nullable String repl, @Nul * @return String chomped * @throws NullPointerException if str or sep isnull
*/ - @Nonnull public static String getChomp( @Nonnull String str, @Nonnull String sep ) - { - int idx = str.lastIndexOf( sep ); - if ( idx == str.length() - sep.length() ) - { + @Nonnull + public static String getChomp(@Nonnull String str, @Nonnull String sep) { + int idx = str.lastIndexOf(sep); + if (idx == str.length() - sep.length()) { return sep; - } - else if ( idx != -1 ) - { - return str.substring( idx ); - } - else - { + } else if (idx != -1) { + return str.substring(idx); + } else { return ""; } } @@ -964,15 +877,12 @@ else if ( idx != -1 ) * @return String without chomped beginning * @throws NullPointerException if str or sep isnull
*/ - @Nonnull public static String prechomp( @Nonnull String str, @Nonnull String sep ) - { - int idx = str.indexOf( sep ); - if ( idx != -1 ) - { - return str.substring( idx + sep.length() ); - } - else - { + @Nonnull + public static String prechomp(@Nonnull String str, @Nonnull String sep) { + int idx = str.indexOf(sep); + if (idx != -1) { + return str.substring(idx + sep.length()); + } else { return str; } } @@ -986,25 +896,22 @@ else if ( idx != -1 ) * @return String prechomped * @throws NullPointerException if str or sep isnull
*/ - @Nonnull public static String getPrechomp( @Nonnull String str, @Nonnull String sep ) - { - int idx = str.indexOf( sep ); - if ( idx != -1 ) - { - return str.substring( 0, idx + sep.length() ); - } - else - { + @Nonnull + public static String getPrechomp(@Nonnull String str, @Nonnull String sep) { + int idx = str.indexOf(sep); + if (idx != -1) { + return str.substring(0, idx + sep.length()); + } else { return ""; } } // Chopping - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Remove the last character from a String.
- * + * *If the String ends in
* @@ -1012,24 +919,20 @@ else if ( idx != -1 ) * @return String without last character * @throws NullPointerException if str is\r\n
, then remove both * of them.null
*/ - @Nonnull public static String chop( @Nonnull String str ) - { - if ( "".equals( str ) ) - { + @Nonnull + public static String chop(@Nonnull String str) { + if ("".equals(str)) { return ""; } - if ( str.length() == 1 ) - { + if (str.length() == 1) { return ""; } int lastIdx = str.length() - 1; - String ret = str.substring( 0, lastIdx ); - char last = str.charAt( lastIdx ); - if ( last == '\n' ) - { - if ( ret.charAt( lastIdx - 1 ) == '\r' ) - { - return ret.substring( 0, lastIdx - 1 ); + String ret = str.substring(0, lastIdx); + char last = str.charAt(lastIdx); + if (last == '\n') { + if (ret.charAt(lastIdx - 1) == '\r') { + return ret.substring(0, lastIdx - 1); } } return ret; @@ -1043,32 +946,28 @@ else if ( idx != -1 ) * @return String without newline * @throws NullPointerException if str isnull
*/ - @Nonnull public static String chopNewline( @Nonnull String str ) - { + @Nonnull + public static String chopNewline(@Nonnull String str) { int lastIdx = str.length() - 1; - char last = str.charAt( lastIdx ); - if ( last == '\n' ) - { - if ( str.charAt( lastIdx - 1 ) == '\r' ) - { + char last = str.charAt(lastIdx); + if (last == '\n') { + if (str.charAt(lastIdx - 1) == '\r') { lastIdx--; } - } - else - { + } else { lastIdx++; } - return str.substring( 0, lastIdx ); + return str.substring(0, lastIdx); } // Conversion - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- // spec 3.10.6 /** *Escapes any values it finds into their String form.
- * + * *So a tab becomes the characters
* @@ -1076,85 +975,71 @@ else if ( idx != -1 ) * @return String with escaped values * @throws NullPointerException if str is'\\'
and *'t'
.null
*/ - @Nonnull public static String escape( @Nonnull String str ) - { + @Nonnull + public static String escape(@Nonnull String str) { // improved with code from cybertiger@cyberiantiger.org // unicode from him, and defaul for < 32's. int sz = str.length(); - StringBuilder buffer = new StringBuilder( 2 * sz ); - for ( int i = 0; i < sz; i++ ) - { - char ch = str.charAt( i ); + StringBuilder buffer = new StringBuilder(2 * sz); + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); // handle unicode // CHECKSTYLE_OFF: MagicNumber - if ( ch > 0xfff ) - { - buffer.append( "\\u" ).append( Integer.toHexString( ch ) ); - } - else if ( ch > 0xff ) - { - buffer.append( "\\u0" ).append( Integer.toHexString( ch ) ); - } - else if ( ch > 0x7f ) - { - buffer.append( "\\u00" ).append( Integer.toHexString( ch ) ); + if (ch > 0xfff) { + buffer.append("\\u").append(Integer.toHexString(ch)); + } else if (ch > 0xff) { + buffer.append("\\u0").append(Integer.toHexString(ch)); + } else if (ch > 0x7f) { + buffer.append("\\u00").append(Integer.toHexString(ch)); } // CHECKSTYLE_ON: MagicNumber - else if ( ch < 32 ) - { - switch ( ch ) - { + else if (ch < 32) { + switch (ch) { case '\b': - buffer.append( '\\' ); - buffer.append( 'b' ); + buffer.append('\\'); + buffer.append('b'); break; case '\n': - buffer.append( '\\' ); - buffer.append( 'n' ); + buffer.append('\\'); + buffer.append('n'); break; case '\t': - buffer.append( '\\' ); - buffer.append( 't' ); + buffer.append('\\'); + buffer.append('t'); break; case '\f': - buffer.append( '\\' ); - buffer.append( 'f' ); + buffer.append('\\'); + buffer.append('f'); break; case '\r': - buffer.append( '\\' ); - buffer.append( 'r' ); + buffer.append('\\'); + buffer.append('r'); break; default: - if ( ch > 0xf ) - { - buffer.append( "\\u00" ).append( Integer.toHexString( ch ) ); - } - else - { - buffer.append( "\\u000" ).append( Integer.toHexString( ch ) ); + if (ch > 0xf) { + buffer.append("\\u00").append(Integer.toHexString(ch)); + } else { + buffer.append("\\u000").append(Integer.toHexString(ch)); } break; } - } - else - { - switch ( ch ) - { + } else { + switch (ch) { case '\'': - buffer.append( '\\' ); - buffer.append( '\'' ); + buffer.append('\\'); + buffer.append('\''); break; case '"': - buffer.append( '\\' ); - buffer.append( '"' ); + buffer.append('\\'); + buffer.append('"'); break; case '\\': - buffer.append( '\\' ); - buffer.append( '\\' ); + buffer.append('\\'); + buffer.append('\\'); break; default: - buffer.append( ch ); + buffer.append(ch); break; } } @@ -1163,7 +1048,7 @@ else if ( ch < 32 ) } // Padding - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Repeat a String
n
times to form a @@ -1172,22 +1057,21 @@ else if ( ch < 32 ) * @param str String to repeat * @param repeat number of times to repeat str * @return String with repeated String - * @throws NegativeArraySizeException ifrepeat < 0
+ * @throws NegativeArraySizeException ifrepeat < 0
* @throws NullPointerException if str isnull
*/ - @Nonnull public static String repeat( @Nonnull String str, int repeat ) - { - StringBuilder buffer = new StringBuilder( repeat * str.length() ); - for ( int i = 0; i < repeat; i++ ) - { - buffer.append( str ); + @Nonnull + public static String repeat(@Nonnull String str, int repeat) { + StringBuilder buffer = new StringBuilder(repeat * str.length()); + for (int i = 0; i < repeat; i++) { + buffer.append(str); } return buffer.toString(); } /** *Right pad a String with spaces.
- * + * *The String is padded to the size of
* * @param str String to repeat @@ -1195,14 +1079,14 @@ else if ( ch < 32 ) * @return right padded String * @throws NullPointerException if str isn
.null
*/ - @Nonnull public static String rightPad( @Nonnull String str, int size ) - { - return rightPad( str, size, " " ); + @Nonnull + public static String rightPad(@Nonnull String str, int size) { + return rightPad(str, size, " "); } /** *Right pad a String with a specified string.
- * + * *The String is padded to the size of
* * @param str String to pad out @@ -1212,19 +1096,18 @@ else if ( ch < 32 ) * @throws NullPointerException if str or delim isn
.null
* @throws ArithmeticException if delim is the empty String */ - @Nonnull public static String rightPad( @Nonnull String str, int size, @Nonnull String delim ) - { - size = ( size - str.length() ) / delim.length(); - if ( size > 0 ) - { - str += repeat( delim, size ); + @Nonnull + public static String rightPad(@Nonnull String str, int size, @Nonnull String delim) { + size = (size - str.length()) / delim.length(); + if (size > 0) { + str += repeat(delim, size); } return str; } /** *Left pad a String with spaces.
- * + * *The String is padded to the size of
* * @param str String to pad out @@ -1232,9 +1115,9 @@ else if ( ch < 32 ) * @return left padded String * @throws NullPointerException if str or delim isn
.null
*/ - @Nonnull public static String leftPad( @Nonnull String str, int size ) - { - return leftPad( str, size, " " ); + @Nonnull + public static String leftPad(@Nonnull String str, int size) { + return leftPad(str, size, " "); } /** @@ -1247,18 +1130,17 @@ else if ( ch < 32 ) * @throws NullPointerException if str or delim is null * @throws ArithmeticException if delim is the empty string */ - @Nonnull public static String leftPad( @Nonnull String str, int size, @Nonnull String delim ) - { - size = ( size - str.length() ) / delim.length(); - if ( size > 0 ) - { - str = repeat( delim, size ) + str; + @Nonnull + public static String leftPad(@Nonnull String str, int size, @Nonnull String delim) { + size = (size - str.length()) / delim.length(); + if (size > 0) { + str = repeat(delim, size) + str; } return str; } // Stripping - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Remove whitespace from the front and back of a String.
@@ -1266,15 +1148,14 @@ else if ( ch < 32 ) * @param str the String to remove whitespace from * @return the stripped String */ - public static String strip( String str ) - { - return strip( str, null ); + public static String strip(String str) { + return strip(str, null); } /** *Remove a specified String from the front and back of a * String.
- * + * *If whitespace is wanted to be removed, used the * {@link #strip(java.lang.String)} method.
* @@ -1282,10 +1163,9 @@ public static String strip( String str ) * @param delim the String to remove at start and end * @return the stripped String */ - public static String strip( String str, @Nullable String delim ) - { - str = stripStart( str, delim ); - return stripEnd( str, delim ); + public static String strip(String str, @Nullable String delim) { + str = stripStart(str, delim); + return stripEnd(str, delim); } /** @@ -1295,9 +1175,8 @@ public static String strip( String str, @Nullable String delim ) * @param strs the Strings to remove whitespace from * @return the stripped Strings */ - public static String[] stripAll( String... strs ) - { - return stripAll( strs, null ); + public static String[] stripAll(String... strs) { + return stripAll(strs, null); } /** @@ -1308,24 +1187,21 @@ public static String[] stripAll( String... strs ) * @param delimiter the String to remove at start and end * @return the stripped Strings */ - public static String[] stripAll( String[] strs, @Nullable String delimiter ) - { - if ( ( strs == null ) || ( strs.length == 0 ) ) - { + public static String[] stripAll(String[] strs, @Nullable String delimiter) { + if ((strs == null) || (strs.length == 0)) { return strs; } int sz = strs.length; String[] newArr = new String[sz]; - for ( int i = 0; i < sz; i++ ) - { - newArr[i] = strip( strs[i], delimiter ); + for (int i = 0; i < sz; i++) { + newArr[i] = strip(strs[i], delimiter); } return newArr; } /** *Strip any of a supplied String from the end of a String.
- * + * *If the strip String is
* @@ -1333,34 +1209,27 @@ public static String[] stripAll( String[] strs, @Nullable String delimiter ) * @param strip the String to remove * @return the stripped String */ - public static String stripEnd( String str, @Nullable String strip ) - { - if ( str == null ) - { + public static String stripEnd(String str, @Nullable String strip) { + if (str == null) { return null; } int end = str.length(); - if ( strip == null ) - { - while ( ( end != 0 ) && Character.isWhitespace( str.charAt( end - 1 ) ) ) - { + if (strip == null) { + while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) { end--; } - } - else - { - while ( ( end != 0 ) && ( strip.indexOf( str.charAt( end - 1 ) ) != -1 ) ) - { + } else { + while ((end != 0) && (strip.indexOf(str.charAt(end - 1)) != -1)) { end--; } } - return str.substring( 0, end ); + return str.substring(0, end); } /** *null
, whitespace is * stripped.Strip any of a supplied String from the start of a String.
- * + * *If the strip String is
* @@ -1368,10 +1237,8 @@ public static String stripEnd( String str, @Nullable String strip ) * @param strip the String to remove * @return the stripped String */ - public static String stripStart( String str, @Nullable String strip ) - { - if ( str == null ) - { + public static String stripStart(String str, @Nullable String strip) { + if (str == null) { return null; } @@ -1379,25 +1246,20 @@ public static String stripStart( String str, @Nullable String strip ) int sz = str.length(); - if ( strip == null ) - { - while ( ( start != sz ) && Character.isWhitespace( str.charAt( start ) ) ) - { + if (strip == null) { + while ((start != sz) && Character.isWhitespace(str.charAt(start))) { start++; } - } - else - { - while ( ( start != sz ) && ( strip.indexOf( str.charAt( start ) ) != -1 ) ) - { + } else { + while ((start != sz) && (strip.indexOf(str.charAt(start)) != -1)) { start++; } } - return str.substring( start ); + return str.substring(start); } // Case conversion - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *null
, whitespace is * stripped.Convert a String to upper case,
null
String @@ -1406,10 +1268,8 @@ public static String stripStart( String str, @Nullable String strip ) * @param str the String to uppercase * @return the upper cased String */ - public static String upperCase( String str ) - { - if ( str == null ) - { + public static String upperCase(String str) { + if (str == null) { return null; } return str.toUpperCase(); @@ -1422,10 +1282,8 @@ public static String upperCase( String str ) * @param str the string to lowercase * @return the lower cased String */ - public static String lowerCase( String str ) - { - if ( str == null ) - { + public static String lowerCase(String str) { + if (str == null) { return null; } return str.toLowerCase(); @@ -1433,161 +1291,125 @@ public static String lowerCase( String str ) /** *Uncapitalise a String.
- * + * *That is, convert the first character into lower-case. *
* * @param str the String to uncapitalise * @return uncapitalised String */ - public static String uncapitalise( String str ) - { - if ( str == null ) - { + public static String uncapitalise(String str) { + if (str == null) { return null; - } - else - { + } else { int length = str.length(); - if ( length == 0 ) - { + if (length == 0) { return ""; - } - else - { - return new StringBuffer( length ) - .append( Character.toLowerCase( str.charAt( 0 ) ) ) - .append( str, 1, length ) - .toString(); + } else { + return new StringBuffer(length) + .append(Character.toLowerCase(str.charAt(0))) + .append(str, 1, length) + .toString(); } } } /** *null
is returned asnull
.Capitalise a String.
- * + * *That is, convert the first character into title-case. *
* * @param str the String to capitalise * @return capitalised String */ - public static String capitalise( String str ) - { - if ( str == null ) - { + public static String capitalise(String str) { + if (str == null) { return null; - } - else - { + } else { int length = str.length(); - if ( length == 0 ) - { + if (length == 0) { return ""; - } - else - { - return new StringBuilder( length ) - .append( Character.toTitleCase( str.charAt( 0 ) ) ) - .append( str, 1, length ) - .toString(); + } else { + return new StringBuilder(length) + .append(Character.toTitleCase(str.charAt(0))) + .append(str, 1, length) + .toString(); } } } /** *null
is returned asnull
.Swaps the case of String.
- * + * *Properly looks after making sure the start of words * are Titlecase and not Uppercase.
- * + * ** * @param str the String to swap the case of * @return the modified String */ - public static String swapCase( String str ) - { - if ( str == null ) - { + public static String swapCase(String str) { + if (str == null) { return null; } int sz = str.length(); - StringBuilder buffer = new StringBuilder( sz ); + StringBuilder buffer = new StringBuilder(sz); boolean whitespace = false; char ch; char tmp; - for ( int i = 0; i < sz; i++ ) - { - ch = str.charAt( i ); - if ( Character.isUpperCase( ch ) ) - { - tmp = Character.toLowerCase( ch ); - } - else if ( Character.isTitleCase( ch ) ) - { - tmp = Character.toLowerCase( ch ); - } - else if ( Character.isLowerCase( ch ) ) - { - if ( whitespace ) - { - tmp = Character.toTitleCase( ch ); - } - else - { - tmp = Character.toUpperCase( ch ); + for (int i = 0; i < sz; i++) { + ch = str.charAt(i); + if (Character.isUpperCase(ch)) { + tmp = Character.toLowerCase(ch); + } else if (Character.isTitleCase(ch)) { + tmp = Character.toLowerCase(ch); + } else if (Character.isLowerCase(ch)) { + if (whitespace) { + tmp = Character.toTitleCase(ch); + } else { + tmp = Character.toUpperCase(ch); } - } - else - { + } else { tmp = ch; } - buffer.append( tmp ); - whitespace = Character.isWhitespace( ch ); + buffer.append(tmp); + whitespace = Character.isWhitespace(ch); } return buffer.toString(); } - /** *
null
is returned asnull
.Capitalise all the words in a String.
- * + * *Uses {@link Character#isWhitespace(char)} as a * separator between words.
- * + * ** * @param str the String to capitalise * @return capitalised String */ - public static String capitaliseAllWords( String str ) - { - if ( str == null ) - { + public static String capitaliseAllWords(String str) { + if (str == null) { return null; } int sz = str.length(); - StringBuilder buffer = new StringBuilder( sz ); + StringBuilder buffer = new StringBuilder(sz); boolean space = true; - for ( int i = 0; i < sz; i++ ) - { - char ch = str.charAt( i ); - if ( Character.isWhitespace( ch ) ) - { - buffer.append( ch ); + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + if (Character.isWhitespace(ch)) { + buffer.append(ch); space = true; - } - else if ( space ) - { - buffer.append( Character.toTitleCase( ch ) ); + } else if (space) { + buffer.append(Character.toTitleCase(ch)); space = false; - } - else - { - buffer.append( ch ); + } else { + buffer.append(ch); } } return buffer.toString(); @@ -1595,52 +1417,44 @@ else if ( space ) /** *
null
will returnnull
.Uncapitalise all the words in a string.
- * + * *Uses {@link Character#isWhitespace(char)} as a * separator between words.
- * + * ** * @param str the string to uncapitalise * @return uncapitalised string */ - public static String uncapitaliseAllWords( String str ) - { - if ( str == null ) - { + public static String uncapitaliseAllWords(String str) { + if (str == null) { return null; } int sz = str.length(); - StringBuilder buffer = new StringBuilder( sz ); + StringBuilder buffer = new StringBuilder(sz); boolean space = true; - for ( int i = 0; i < sz; i++ ) - { - char ch = str.charAt( i ); - if ( Character.isWhitespace( ch ) ) - { - buffer.append( ch ); + for (int i = 0; i < sz; i++) { + char ch = str.charAt(i); + if (Character.isWhitespace(ch)) { + buffer.append(ch); space = true; - } - else if ( space ) - { - buffer.append( Character.toLowerCase( ch ) ); + } else if (space) { + buffer.append(Character.toLowerCase(ch)); space = false; - } - else - { - buffer.append( ch ); + } else { + buffer.append(ch); } } return buffer.toString(); } // Nested extraction - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *
null
will returnnull
.Get the String that is nested in between two instances of the * same String.
- * + * *If
* @@ -1649,9 +1463,8 @@ else if ( space ) * @return the String that was nested, orstr
isnull
, will * returnnull
.null
* @throws NullPointerException if tag isnull
*/ - public static String getNestedString( String str, @Nonnull String tag ) - { - return getNestedString( str, tag, tag ); + public static String getNestedString(String str, @Nonnull String tag) { + return getNestedString(str, tag, tag); } /** @@ -1663,19 +1476,15 @@ public static String getNestedString( String str, @Nonnull String tag ) * @return the String that was nested, ornull
* @throws NullPointerException if open or close isnull
*/ - public static String getNestedString( String str, @Nonnull String open, @Nonnull String close ) - { - if ( str == null ) - { + public static String getNestedString(String str, @Nonnull String open, @Nonnull String close) { + if (str == null) { return null; } - int start = str.indexOf( open ); - if ( start != -1 ) - { - int end = str.indexOf( close, start + open.length() ); - if ( end != -1 ) - { - return str.substring( start + open.length(), end ); + int start = str.indexOf(open); + if (start != -1) { + int end = str.indexOf(close, start + open.length()); + if (end != -1) { + return str.substring(start + open.length(), end); } } return null; @@ -1683,28 +1492,24 @@ public static String getNestedString( String str, @Nonnull String open, @Nonnull /** *How many times is the substring in the larger String.
- * + * ** * @param str the String to check * @param sub the substring to count - * @return the number of occurances, 0 if the String is
null
returns0
.null
+ * @return the number of occurrences, 0 if the String isnull
* @throws NullPointerException if sub isnull
*/ - public static int countMatches( @Nullable String str, @Nonnull String sub ) - { - if ( sub.equals( "" ) ) - { + public static int countMatches(@Nullable String str, @Nonnull String sub) { + if (sub.equals("")) { return 0; } - if ( str == null ) - { + if (str == null) { return 0; } int count = 0; int idx = 0; - while ( ( idx = str.indexOf( sub, idx ) ) != -1 ) - { + while ((idx = str.indexOf(sub, idx)) != -1) { count++; idx += sub.length(); } @@ -1712,28 +1517,24 @@ public static int countMatches( @Nullable String str, @Nonnull String sub ) } // Character Tests - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** - *Checks if the String contains only unicode letters.
- * + *Checks if the String contains only Unicode letters.
+ * ** * @param str the String to check * @return
null
will returnfalse
. * An empty String will returntrue
.true
if only contains letters, and is non-null */ - public static boolean isAlpha( String str ) - { - if ( str == null ) - { + public static boolean isAlpha(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( !Character.isLetter( str.charAt( i ) ) ) - { + for (int i = 0; i < sz; i++) { + if (!Character.isLetter(str.charAt(i))) { return false; } } @@ -1742,24 +1543,20 @@ public static boolean isAlpha( String str ) /** *Checks if the String contains only whitespace.
- * + * ** * @param str the String to check * @return
null
will returnfalse
. An * empty String will returntrue
.true
if only contains whitespace, and is non-null */ - public static boolean isWhitespace( String str ) - { - if ( str == null ) - { + public static boolean isWhitespace(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( ( !Character.isWhitespace( str.charAt( i ) ) ) ) - { + for (int i = 0; i < sz; i++) { + if ((!Character.isWhitespace(str.charAt(i)))) { return false; } } @@ -1767,9 +1564,9 @@ public static boolean isWhitespace( String str ) } /** - *Checks if the String contains only unicode letters and + *
Checks if the String contains only Unicode letters and * space (
- * + * *' '
).* @@ -1777,17 +1574,13 @@ public static boolean isWhitespace( String str ) * @return
null
will returnfalse
. An * empty String will returntrue
.true
if only contains letters and space, * and is non-null */ - public static boolean isAlphaSpace( String str ) - { - if ( str == null ) - { + public static boolean isAlphaSpace(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( ( !Character.isLetter( str.charAt( i ) ) ) && ( str.charAt( i ) != ' ' ) ) - { + for (int i = 0; i < sz; i++) { + if ((!Character.isLetter(str.charAt(i))) && (str.charAt(i) != ' ')) { return false; } } @@ -1795,8 +1588,8 @@ public static boolean isAlphaSpace( String str ) } /** - *Checks if the String contains only unicode letters or digits.
- * + *Checks if the String contains only Unicode letters or digits.
+ * ** @@ -1804,17 +1597,13 @@ public static boolean isAlphaSpace( String str ) * @return
null
will returnfalse
. An empty * String will returntrue
.true
if only contains letters or digits, * and is non-null */ - public static boolean isAlphanumeric( String str ) - { - if ( str == null ) - { + public static boolean isAlphanumeric(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( !Character.isLetterOrDigit( str.charAt( i ) ) ) - { + for (int i = 0; i < sz; i++) { + if (!Character.isLetterOrDigit(str.charAt(i))) { return false; } } @@ -1822,9 +1611,9 @@ public static boolean isAlphanumeric( String str ) } /** - *Checks if the String contains only unicode letters, digits + *
Checks if the String contains only Unicode letters, digits * or space (
- * + * *' '
).* @@ -1832,17 +1621,13 @@ public static boolean isAlphanumeric( String str ) * @return
null
will returnfalse
. An empty * String will returntrue
.true
if only contains letters, digits or space, * and is non-null */ - public static boolean isAlphanumericSpace( String str ) - { - if ( str == null ) - { + public static boolean isAlphanumericSpace(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( ( !Character.isLetterOrDigit( str.charAt( i ) ) ) && ( str.charAt( i ) != ' ' ) ) - { + for (int i = 0; i < sz; i++) { + if ((!Character.isLetterOrDigit(str.charAt(i))) && (str.charAt(i) != ' ')) { return false; } } @@ -1850,25 +1635,21 @@ public static boolean isAlphanumericSpace( String str ) } /** - *Checks if the String contains only unicode digits.
- * + *Checks if the String contains only Unicode digits.
+ * ** * @param str the String to check * @return
null
will returnfalse
. * An empty String will returntrue
.true
if only contains digits, and is non-null */ - public static boolean isNumeric( String str ) - { - if ( str == null ) - { + public static boolean isNumeric(String str) { + if (str == null) { return false; } int sz = str.length(); - for ( int i = 0; i < sz; i++ ) - { - if ( !Character.isDigit( str.charAt( i ) ) ) - { + for (int i = 0; i < sz; i++) { + if (!Character.isDigit(str.charAt(i))) { return false; } } @@ -1876,7 +1657,7 @@ public static boolean isNumeric( String str ) } // Defaults - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Returns either the passed in
Object
as a String, @@ -1886,10 +1667,12 @@ public static boolean isNumeric( String str ) * @param obj the Object to check * @return the passed in Object's toString, or blank if it was *null
+ * @deprecated use {@code java.lang.Objects.toString()} */ - @Nonnull public static String defaultString( Object obj ) - { - return defaultString( obj, "" ); + @Deprecated + @Nonnull + public static String defaultString(Object obj) { + return defaultString(obj, ""); } /** @@ -1902,35 +1685,35 @@ public static boolean isNumeric( String str ) *null
* @return the passed in string, or the default if it was *null
+ * @deprecated use {@code java.lang.Objects.toString()} */ - @Nonnull public static String defaultString( Object obj, @Nonnull String defaultString ) - { - return ( obj == null ) ? defaultString : obj.toString(); + @Deprecated + @Nonnull + public static String defaultString(Object obj, @Nonnull String defaultString) { + return (obj == null) ? defaultString : obj.toString(); } // Reversing - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** *Reverse a String.
- * + * ** * @param str the String to reverse * @return the reversed String */ - public static String reverse( String str ) - { - if ( str == null ) - { + public static String reverse(String str) { + if (str == null) { return null; } - return new StringBuffer( str ).reverse().toString(); + return new StringBuffer(str).reverse().toString(); } /** *
null
String returnsnull
.Reverses a String that is delimited by a specific character.
- * + * *The Strings between the delimiters are not reversed. * Thus java.lang.String becomes String.lang.java (if the delimiter * is
@@ -1939,30 +1722,26 @@ public static String reverse( String str ) * @param delimiter the delimiter to use * @return the reversed String */ - @Nonnull public static String reverseDelimitedString( @Nonnull String str, String delimiter ) - { + @Nonnull + public static String reverseDelimitedString(@Nonnull String str, String delimiter) { // could implement manually, but simple way is to reuse other, // probably slower, methods. - String[] strs = split( str, delimiter ); - reverseArray( strs ); - return join( strs, delimiter ); + String[] strs = split(str, delimiter); + reverseArray(strs); + return join(strs, delimiter); } /** *'.'
).Reverses an array.
- * - *TAKEN FROM CollectionsUtils.
* * @param array the array to reverse */ - private static void reverseArray( @Nonnull String... array ) - { + private static void reverseArray(@Nonnull String... array) { int i = 0; int j = array.length - 1; String tmp; - while ( j > i ) - { + while (j > i) { tmp = array[j]; array[j] = array[i]; array[i] = tmp; @@ -1972,112 +1751,107 @@ private static void reverseArray( @Nonnull String... array ) } // Abbreviating - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** - * Turn "Now is the time for all good men" into "Now is the time for..." - * - * Specifically: - * - * If str is less than max characters long, return it. + *Turn "Now is the time for all good men" into "Now is the time for..."
+ *Specifically:
+ *If str is less than max characters long, return it. * Else abbreviate it to (substring(str, 0, max-3) + "..."). * If maxWidth is less than 3, throw an IllegalArgumentException. - * In no case will it return a string of length greater than maxWidth. + * In no case will it return a string of length greater than maxWidth.
* + * @param s The string to be abbreviated. * @param maxWidth maximum length of result string + * @return The abbreviated string. */ - @Nonnull public static String abbreviate( @Nonnull String s, int maxWidth ) - { - return abbreviate( s, 0, maxWidth ); + @Nonnull + public static String abbreviate(@Nonnull String s, int maxWidth) { + return abbreviate(s, 0, maxWidth); } /** * Turn "Now is the time for all good men" into "...is the time for..." - * + ** Works like abbreviate(String, int), but allows you to specify a "left edge" * offset. Note that this left edge is not necessarily going to be the leftmost * character in the result, or the first * character following the ellipses, but it will appear somewhere in the result. * In no case will it return a string of length greater than maxWidth. + *
* + * @param s String to abbreviate. * @param offset left edge of source string * @param maxWidth maximum length of result string + * @return The abbreviated string. */ - @Nonnull public static String abbreviate( @Nonnull String s, int offset, int maxWidth ) - { - if ( maxWidth < 4 ) - { - throw new IllegalArgumentException( "Minimum abbreviation width is 4" ); + @Nonnull + public static String abbreviate(@Nonnull String s, int offset, int maxWidth) { + if (maxWidth < 4) { + throw new IllegalArgumentException("Minimum abbreviation width is 4"); } - if ( s.length() <= maxWidth ) - { + if (s.length() <= maxWidth) { return s; } - if ( offset > s.length() ) - { + if (offset > s.length()) { offset = s.length(); } - if ( ( s.length() - offset ) < ( maxWidth - 3 ) ) - { - offset = s.length() - ( maxWidth - 3 ); + if ((s.length() - offset) < (maxWidth - 3)) { + offset = s.length() - (maxWidth - 3); } - if ( offset <= 4 ) - { - return s.substring( 0, maxWidth - 3 ) + "..."; + if (offset <= 4) { + return s.substring(0, maxWidth - 3) + "..."; } - if ( maxWidth < 7 ) - { - throw new IllegalArgumentException( "Minimum abbreviation width with offset is 7" ); + if (maxWidth < 7) { + throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); } - if ( ( offset + ( maxWidth - 3 ) ) < s.length() ) - { - return "..." + abbreviate( s.substring( offset ), maxWidth - 3 ); + if ((offset + (maxWidth - 3)) < s.length()) { + return "..." + abbreviate(s.substring(offset), maxWidth - 3); } - return "..." + s.substring( s.length() - ( maxWidth - 3 ) ); + return "..." + s.substring(s.length() - (maxWidth - 3)); } // Difference - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- /** * Compare two strings, and return the portion where they differ. * (More precisely, return the remainder of the second string, * starting from where it's different from the first.) - * - * E.g. strdiff("i am a machine", "i am a robot") -> "robot" + *+ * E.g. strdiff("i am a machine", "i am a robot") → "robot" + *
* + * @param s1 The first string. + * @param s2 The second string. * @return the portion of s2 where it differs from s1; returns the empty string ("") if they are equal */ - public static String difference( @Nonnull String s1, @Nonnull String s2 ) - { - int at = differenceAt( s1, s2 ); - if ( at == -1 ) - { + public static String difference(@Nonnull String s1, @Nonnull String s2) { + int at = differenceAt(s1, s2); + if (at == -1) { return ""; } - return s2.substring( at ); + return s2.substring(at); } /** * Compare two strings, and return the index at which the strings begin to differ. *- * E.g. strdiff("i am a machine", "i am a robot") -> 7 + * E.g. strdiff("i am a machine", "i am a robot") → 7 *
* + * @param s1 The first string. + * @param s2 The second string. * @return the index where s2 and s1 begin to differ; -1 if they are equal */ - public static int differenceAt( @Nonnull String s1, @Nonnull String s2 ) - { + public static int differenceAt(@Nonnull String s1, @Nonnull String s2) { int i; - for ( i = 0; ( i < s1.length() ) && ( i < s2.length() ); ++i ) - { - if ( s1.charAt( i ) != s2.charAt( i ) ) - { + for (i = 0; (i < s1.length()) && (i < s2.length()); ++i) { + if (s1.charAt(i) != s2.charAt(i)) { break; } } - if ( ( i < s2.length() ) || ( i < s1.length() ) ) - { + if ((i < s2.length()) || (i < s1.length())) { return i; } return -1; @@ -2088,30 +1862,26 @@ public static int differenceAt( @Nonnull String s1, @Nonnull String s2 ) * Any text looking like '${key}' will get replaced by the value stored * in the namespace map under the 'key'. * - * @param text - * @param namespace + * @param text The text where replacements will be searched for. + * @param namespace The namespace which contains the replacements. * @return the interpolated text. */ - public static String interpolate( String text, @Nonnull Map, ?> namespace ) - { - for ( Map.Entry, ?> entry : namespace.entrySet() ) - { + public static String interpolate(String text, @Nonnull Map, ?> namespace) { + for (Map.Entry, ?> entry : namespace.entrySet()) { String key = entry.getKey().toString(); Object obj = entry.getValue(); - if ( obj == null ) - { - throw new NullPointerException( "The value of the key '" + key + "' is null." ); + if (obj == null) { + throw new NullPointerException("The value of the key '" + key + "' is null."); } String value = obj.toString(); - text = replace( text, "${" + key + "}", value ); + text = replace(text, "${" + key + "}", value); - if ( !key.contains( " " ) ) - { - text = replace( text, "$" + key, value ); + if (!key.contains(" ")) { + text = replace(text, "$" + key, value); } } return text; @@ -2126,107 +1896,94 @@ public static String interpolate( String text, @Nonnull Map, ?> namespace ) *- * Attention: this method will currently throw a - *
+ * Converts the first character of the given String to uppercase. + * This method does not trim spaces! * * @param data the String to get capitalized * @return data string with the first character transformed to uppercase * @throws NullPointerException if data isIndexOutOfBoundsException
for empty strings! - *null
+ * @throws IndexOutOfBoundsException if data is empty */ - @Nonnull public static String capitalizeFirstLetter( @Nonnull String data ) - { - char firstChar = data.charAt( 0 ); - char titleCase = Character.toTitleCase( firstChar ); - if ( firstChar == titleCase ) - { + @Nonnull + public static String capitalizeFirstLetter(@Nonnull String data) { + char firstChar = data.charAt(0); + char titleCase = Character.toTitleCase(firstChar); + if (firstChar == titleCase) { return data; } - StringBuilder result = new StringBuilder( data.length() ); - result.append( titleCase ); - result.append( data, 1, data.length() ); + StringBuilder result = new StringBuilder(data.length()); + result.append(titleCase); + result.append(data, 1, data.length()); return result.toString(); } /** - * Convert the first character of the given String to lowercase. - * This method will not trim of spaces! - * - *- * Attention: this method will currently throw a - *
+ * Converts the first character of the given String to lowercase. + * This method does not trim spaces! * * @param data the String to get it's first character lower-cased. * @return data string with the first character transformed to lowercase * @throws NullPointerException if data isIndexOutOfBoundsException
for empty strings! - *null
+ * @throws IndexOutOfBoundsException if data is empty */ - @Nonnull public static String lowercaseFirstLetter( @Nonnull String data ) - { - char firstLetter = Character.toLowerCase( data.substring( 0, 1 ).charAt( 0 ) ); + @Nonnull + public static String lowercaseFirstLetter(@Nonnull String data) { + char firstLetter = Character.toLowerCase(data.substring(0, 1).charAt(0)); - String restLetters = data.substring( 1 ); + String restLetters = data.substring(1); return firstLetter + restLetters; } /** - * Take the input string and un-camel-case it. - * - * 'ThisIsIt' will become 'this-is-it'. + *Take the input string and un-camel-case it.
+ *'ThisIsIt' will become 'this-is-it'.
* - * @param view + * @param view the view * @return deHumped String */ - @Nonnull public static String addAndDeHump( @Nonnull String view ) - { + @Nonnull + public static String addAndDeHump(@Nonnull String view) { StringBuilder sb = new StringBuilder(); - for ( int i = 0; i < view.length(); i++ ) - { - if ( ( i != 0 ) && Character.isUpperCase( view.charAt( i ) ) ) - { - sb.append( '-' ); + for (int i = 0; i < view.length(); i++) { + if ((i != 0) && Character.isUpperCase(view.charAt(i))) { + sb.append('-'); } - sb.append( view.charAt( i ) ); + sb.append(view.charAt(i)); } - return sb.toString().trim().toLowerCase( Locale.ENGLISH ); + return sb.toString().trim().toLowerCase(Locale.ENGLISH); } /** *Quote and escape a String with the given character, handling
- * + * *null
.* StringUtils.quoteAndEscape(null, *) = null * StringUtils.quoteAndEscape("", *) = "" @@ -2235,98 +1992,93 @@ public static String interpolate( String text, @Nonnull Map, ?> namespace ) * StringUtils.quoteAndEscape("a\"bc", '\'') = 'a\"bc' ** - * @param source - * @param quoteChar + * @param source The source. + * @param quoteChar The quote character. * @return the String quoted and escaped * @see #quoteAndEscape(String, char, char[], char[], char, boolean) * @see #quoteAndEscape(String, char, char[], char[], char, boolean) - * + * */ - public static String quoteAndEscape( @Nullable String source, char quoteChar ) - { - return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, new char[]{ ' ' }, '\\', false ); + public static String quoteAndEscape(@Nullable String source, char quoteChar) { + return quoteAndEscape(source, quoteChar, new char[] {quoteChar}, new char[] {' '}, '\\', false); } /** *Quote and escape a String with the given character, handling
* - * @param source - * @param quoteChar - * @param quotingTriggers + * @param source the source + * @param quoteChar the quote character + * @param quotingTriggers the quoting trigger * @return the String quoted and escaped * @see #quoteAndEscape(String, char, char[], char[], char, boolean) - * + * */ - public static String quoteAndEscape( @Nullable String source, char quoteChar, @Nonnull char[] quotingTriggers ) - { - return quoteAndEscape( source, quoteChar, new char[]{ quoteChar }, quotingTriggers, '\\', false ); + public static String quoteAndEscape(@Nullable String source, char quoteChar, @Nonnull char[] quotingTriggers) { + return quoteAndEscape(source, quoteChar, new char[] {quoteChar}, quotingTriggers, '\\', false); } /** - * @param source - * @param quoteChar - * @param escapedChars - * @param escapeChar - * @param force + * @param source the source + * @param quoteChar the quote character + * @param escapedChars the escaped characters + * @param escapeChar the escape character + * @param force true/false * @return the String quoted and escaped * @see #quoteAndEscape(String, char, char[], char[], char, boolean) - * + * */ - public static String quoteAndEscape( @Nullable String source, char quoteChar, - @Nonnull final char[] escapedChars, char escapeChar, boolean force ) - { - return quoteAndEscape( source, quoteChar, escapedChars, new char[]{ ' ' }, escapeChar, force ); + public static String quoteAndEscape( + @Nullable String source, + char quoteChar, + @Nonnull final char[] escapedChars, + char escapeChar, + boolean force) { + return quoteAndEscape(source, quoteChar, escapedChars, new char[] {' '}, escapeChar, force); } /** - * @param source - * @param quoteChar - * @param escapedChars - * @param quotingTriggers - * @param escapeChar - * @param force + * @param source the source + * @param quoteChar the quote character + * @param escapedChars set of characters to escape + * @param quotingTriggers the quoting trigger + * @param escapeChar prefix for escaping a character + * @param force true/false * @return the String quoted and escaped - * */ - public static String quoteAndEscape( @Nullable String source, char quoteChar, @Nonnull final char[] escapedChars, - @Nonnull final char[] quotingTriggers, char escapeChar, boolean force ) - { - if ( source == null ) - { + public static String quoteAndEscape( + @Nullable String source, + char quoteChar, + @Nonnull final char[] escapedChars, + @Nonnull final char[] quotingTriggers, + char escapeChar, + boolean force) { + if (source == null) { return null; } - if ( !force && source.startsWith( Character.toString( quoteChar ) ) && source.endsWith( - Character.toString( quoteChar ) ) ) - { + if (!force + && source.startsWith(Character.toString(quoteChar)) + && source.endsWith(Character.toString(quoteChar))) { return source; } - String escaped = escape( source, escapedChars, escapeChar ); + String escaped = escape(source, escapedChars, escapeChar); boolean quote = false; - if ( force ) - { + if (force) { quote = true; - } - else if ( !escaped.equals( source ) ) - { + } else if (!escaped.equals(source)) { quote = true; - } - else - { - for ( char quotingTrigger : quotingTriggers ) - { - if ( escaped.indexOf( quotingTrigger ) > -1 ) - { + } else { + for (char quotingTrigger : quotingTriggers) { + if (escaped.indexOf(quotingTrigger) > -1) { quote = true; break; } } } - if ( quote ) - { + if (quote) { return quoteChar + escaped + quoteChar; } @@ -2334,60 +2086,52 @@ else if ( !escaped.equals( source ) ) } /** - * @param source - * @param escapedChars - * @param escapeChar + * @param source the source + * @param escapedChars set of characters to escape + * @param escapeChar prefix for escaping a character * @return the String escaped - * */ - public static String escape( @Nullable String source, @Nonnull final char[] escapedChars, char escapeChar ) - { - if ( source == null ) - { + public static String escape(@Nullable String source, @Nonnull final char[] escapedChars, char escapeChar) { + if (source == null) { return null; } char[] eqc = new char[escapedChars.length]; - System.arraycopy( escapedChars, 0, eqc, 0, escapedChars.length ); - Arrays.sort( eqc ); + System.arraycopy(escapedChars, 0, eqc, 0, escapedChars.length); + Arrays.sort(eqc); - StringBuilder buffer = new StringBuilder( source.length() ); + StringBuilder buffer = new StringBuilder(source.length()); - for ( int i = 0; i < source.length(); i++ ) - { - final char c = source.charAt( i ); - int result = Arrays.binarySearch( eqc, c ); + for (int i = 0; i < source.length(); i++) { + final char c = source.charAt(i); + int result = Arrays.binarySearch(eqc, c); - if ( result > -1 ) - { - buffer.append( escapeChar ); + if (result > -1) { + buffer.append(escapeChar); } - buffer.append( c ); + buffer.append(c); } return buffer.toString(); } /** - * Remove all duplicate whitespace characters and line terminators are replaced with a single - * space. + * Remove all duplicate whitespace characters and replace line terminators with a single space. * * @param s a not null String - * @return a string with unique whitespace. - * + * @return a string with unique whitespace + * */ - @Nonnull public static String removeDuplicateWhitespace( @Nonnull String s ) - { + @Nonnull + public static String removeDuplicateWhitespace(@Nonnull String s) { StringBuilder result = new StringBuilder(); int length = s.length(); boolean isPreviousWhiteSpace = false; - for ( int i = 0; i < length; i++ ) - { - char c = s.charAt( i ); - boolean thisCharWhiteSpace = Character.isWhitespace( c ); - if ( !( isPreviousWhiteSpace && thisCharWhiteSpace ) ) - { - result.append( c ); + for (int i = 0; i < length; i++) { + char c = s.charAt(i); + boolean thisCharWhiteSpace = Character.isWhitespace(c); + if (!(isPreviousWhiteSpace && thisCharWhiteSpace)) { + result.append(c); } isPreviousWhiteSpace = thisCharWhiteSpace; } @@ -2396,16 +2140,19 @@ public static String escape( @Nullable String source, @Nonnull final char[] esca /** * Parses the given String and replaces all occurrences of - * '\n', '\r' and '\r\n' with the system line separator. + * '\n', '\r', and "\r\n" with the system line separator. * * @param s a not null String - * @return a String that contains only System line separators. + * @return a String that contains only System line separators * @see #unifyLineSeparators(String, String) - * + * @deprecated this method produces platform dependent code and contributes to + * non-reproducible builds. In the context of Maven, this is almost never what's needed. + * Remove calls to this method and do not replace them. That is, change + * {@code Stringutils.unifyLineSeparators(s)} to simply {@code s}. */ - public static String unifyLineSeparators( @Nullable String s ) - { - return unifyLineSeparators( s, System.getProperty( "line.separator" ) ); + @Deprecated + public static String unifyLineSeparators(@Nullable String s) { + return unifyLineSeparators(s, System.getProperty("line.separator")); } /** @@ -2413,49 +2160,38 @@ public static String unifyLineSeparators( @Nullable String s ) * '\n', '\r' and '\r\n' with the system line separator. * * @param s a not null String - * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator. - * @return a String that contains only System line separators. - * @throws IllegalArgumentException if ls is not '\n', '\r' and '\r\n' characters. - * - */ - public static String unifyLineSeparators( @Nullable String s, @Nullable String ls ) - { - if ( s == null ) - { + * @param ls the wanted line separator ("\n" on UNIX), if null using the System line separator + * @return a String that contains only System line separators + * @throws IllegalArgumentException if ls is not '\n', '\r', or "\r\n" + * + */ + public static String unifyLineSeparators(@Nullable String s, @Nullable String ls) { + if (s == null) { return null; } - if ( ls == null ) - { - ls = System.getProperty( "line.separator" ); + if (ls == null) { + ls = System.getProperty("line.separator"); } - if ( !( ls.equals( "\n" ) || ls.equals( "\r" ) || ls.equals( "\r\n" ) ) ) - { - throw new IllegalArgumentException( "Requested line separator is invalid." ); + if (!(ls.equals("\n") || ls.equals("\r") || ls.equals("\r\n"))) { + throw new IllegalArgumentException("Requested line separator is invalid."); } int length = s.length(); - StringBuilder buffer = new StringBuilder( length ); - for ( int i = 0; i < length; i++ ) - { - if ( s.charAt( i ) == '\r' ) - { - if ( ( i + 1 ) < length && s.charAt( i + 1 ) == '\n' ) - { + StringBuilder buffer = new StringBuilder(length); + for (int i = 0; i < length; i++) { + if (s.charAt(i) == '\r') { + if ((i + 1) < length && s.charAt(i + 1) == '\n') { i++; } - buffer.append( ls ); - } - else if ( s.charAt( i ) == '\n' ) - { - buffer.append( ls ); - } - else - { - buffer.append( s.charAt( i ) ); + buffer.append(ls); + } else if (s.charAt(i) == '\n') { + buffer.append(ls); + } else { + buffer.append(s.charAt(i)); } } @@ -2465,9 +2201,9 @@ else if ( s.charAt( i ) == '\n' ) /** *null
.Checks if String contains a search character, handling
- * + * *null
. * This method uses {@link String#indexOf(int)}.A
- * + * *null
or empty ("") String will returnfalse
.* StringUtils.contains(null, *) = false * StringUtils.contains("", *) = false @@ -2479,20 +2215,18 @@ else if ( s.charAt( i ) == '\n' ) * @param searchChar the character to find * @return true if the String contains the search character, * false if not ornull
string input - * + * */ - @SuppressWarnings( "ConstantConditions" ) - public static boolean contains( @Nullable String str, char searchChar ) - { - return !isEmpty( str ) && str.indexOf( searchChar ) >= 0; + public static boolean contains(@Nullable String str, char searchChar) { + return !isEmpty(str) && str.indexOf(searchChar) >= 0; } /** *Checks if String contains a search String, handling
- * + * *null
. * This method uses {@link String#indexOf(int)}.A
- * + * *null
String will returnfalse
.* StringUtils.contains(null, *) = false * StringUtils.contains(*, null) = false @@ -2507,16 +2241,14 @@ public static boolean contains( @Nullable String str, char searchChar ) * @return true if the String contains the search String, * false if not ornull
string input */ - public static boolean contains( @Nullable String str, @Nullable String searchStr ) - { - return !( str == null || searchStr == null ) && str.contains( searchStr ); + public static boolean contains(@Nullable String str, @Nullable String searchStr) { + return !(str == null || searchStr == null) && str.contains(searchStr); } /** *Checks if String ends with a search String, handling
- * *null
.A
- * + * *null
String will returnfalse
.* StringUtils.endsWithIgnoreCase(null, *) = false * StringUtils.endsWithIgnoreCase(*, null) = false @@ -2530,21 +2262,18 @@ public static boolean contains( @Nullable String str, @Nullable String searchStr * @param searchStr the String to find at end, may be null * @return true if the String ends with the search String, * false if not ornull
string input - * + * */ - public static boolean endsWithIgnoreCase( @Nullable String str, @Nullable String searchStr ) - { - if ( str == null || searchStr == null ) - { + public static boolean endsWithIgnoreCase(@Nullable String str, @Nullable String searchStr) { + if (str == null || searchStr == null) { // for consistency with contains return false; } - if ( str.length() < searchStr.length() ) - { + if (str.length() < searchStr.length()) { return false; } - return str.regionMatches( true, str.length() - searchStr.length(), searchStr, 0, searchStr.length() ); + return str.regionMatches(true, str.length() - searchStr.length(), searchStr, 0, searchStr.length()); } } diff --git a/src/main/java/org/apache/maven/shared/utils/WriterFactory.java b/src/main/java/org/apache/maven/shared/utils/WriterFactory.java index 7e33c8f9..1679d884 100644 --- a/src/main/java/org/apache/maven/shared/utils/WriterFactory.java +++ b/src/main/java/org/apache/maven/shared/utils/WriterFactory.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils; + +import javax.annotation.Nonnull; import java.io.File; import java.io.FileNotFoundException; @@ -28,10 +29,8 @@ import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; -import org.apache.maven.shared.utils.xml.XmlStreamWriter; - -import javax.annotation.Nonnull; +import org.apache.maven.shared.utils.xml.XmlStreamWriter; /** * Utility to create Writers, with explicit encoding choice: platform default, @@ -39,141 +38,150 @@ * * @author Hervé Boutemy * @see java.nio.charset.Charset - * @see Supported encodings - * @version $Id$ + * @see Supported encodings */ -public class WriterFactory -{ +public class WriterFactory { /** * ISO Latin Alphabet #1, also known as ISO-LATIN-1. * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.ISO_8859_1} */ + @Deprecated public static final String ISO_8859_1 = "ISO-8859-1"; /** * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.US_ASCII} */ + @Deprecated public static final String US_ASCII = "US-ASCII"; /** * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either * order accepted on input, big-endian used on output). * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16} */ + @Deprecated public static final String UTF_16 = "UTF-16"; /** * Sixteen-bit Unicode Transformation Format, big-endian byte order. * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16BE} */ + @Deprecated public static final String UTF_16BE = "UTF-16BE"; /** * Sixteen-bit Unicode Transformation Format, little-endian byte order. * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_16LE} */ + @Deprecated public static final String UTF_16LE = "UTF-16LE"; /** * Eight-bit Unicode Transformation Format. * Every implementation of the Java platform is required to support this character encoding. - * @see java.nio.charset.Charset + * + * @deprecated use {@code java.nio.charset.StandardCharset.UTF_8} */ + @Deprecated public static final String UTF_8 = "UTF-8"; /** * Thefile.encoding
System Property. */ - public static final String FILE_ENCODING = System.getProperty( "file.encoding" ); + public static final String FILE_ENCODING = System.getProperty("file.encoding"); /** * Create a new Writer with XML encoding detection rules. * - * @param out not null output stream. - * @return an XML writer instance for the output stream. - * @throws IOException if any. + * @param out not null output stream + * @return an XML writer instance for the output stream + * @throws IOException if any * @see XmlStreamWriter + * @deprecated use org.apache.commons.io.input.XmlStreamWriter instead */ - public static XmlStreamWriter newXmlWriter( @Nonnull OutputStream out ) - throws IOException - { - return new XmlStreamWriter( out ); + @Deprecated + public static XmlStreamWriter newXmlWriter(@Nonnull OutputStream out) throws IOException { + return new XmlStreamWriter(out); } /** * Create a new Writer with XML encoding detection rules. * - * @param file not null file. - * @return an XML writer instance for the output file. - * @throws IOException if any. + * @param file not null file + * @return an XML writer instance for the output file + * @throws IOException if any * @see XmlStreamWriter + * @deprecated use org.apache.commons.io.input.XmlStreamWriter instead */ - public static XmlStreamWriter newXmlWriter( @Nonnull File file ) - throws IOException - { - return new XmlStreamWriter( file ); + @Deprecated + public static XmlStreamWriter newXmlWriter(@Nonnull File file) throws IOException { + return new XmlStreamWriter(file); } /** * Create a new Writer with default platform encoding. * - * @param out not null output stream. - * @return a writer instance for the output stream using the default platform charset. - * @see java.nio.charset.Charset#defaultCharset() + * @param out not null output stream + * @return a writer instance for the output stream using the default platform charset + * @deprecated always specify an encoding. Do not depend on the default platform character set. */ - public static Writer newPlatformWriter( @Nonnull OutputStream out ) - { - return new OutputStreamWriter( out ); + @Deprecated + public static Writer newPlatformWriter(@Nonnull OutputStream out) { + return new OutputStreamWriter(out); } /** * Create a new Writer with default platform encoding. * - * @param file not null file. - * @return a writer instance for the output file using the default platform charset. - * @throws IOException if any. - * @see java.nio.charset.Charset#defaultCharset() + * @param file not null file + * @return a writer instance for the output file using the default platform charset + * @throws IOException if any + * @deprecated always specify an encoding. Do not depend on the default platform character set. */ - public static Writer newPlatformWriter( @Nonnull File file ) - throws IOException - { - return new FileWriter( file ); + @Deprecated + public static Writer newPlatformWriter(@Nonnull File file) throws IOException { + return new FileWriter(file); } /** * Create a new Writer with specified encoding. * - * @param out not null output stream. - * @param encoding not null supported encoding. - * @return a writer instance for the output stream using the given encoding. - * @throws UnsupportedEncodingException if any. - * @see Supported encodings + * @param out not null output stream + * @param encoding not null supported encoding + * @return a writer instance for the output stream using the given encoding + * @throws UnsupportedEncodingException if any + * @see Supported + * encodings */ - public static Writer newWriter( @Nonnull OutputStream out, @Nonnull String encoding ) - throws UnsupportedEncodingException - { - return new OutputStreamWriter( out, encoding ); + public static Writer newWriter(@Nonnull OutputStream out, @Nonnull String encoding) + throws UnsupportedEncodingException { + return new OutputStreamWriter(out, encoding); } /** * Create a new Writer with specified encoding. * - * @param file not null file. - * @param encoding not null supported encoding. - * @return a writer instance for the output file using the given encoding. - * @throws UnsupportedEncodingException if any. - * @throws FileNotFoundException if any. - * @see Supported encodings + * @param file not null file + * @param encoding not null supported encoding + * @return a writer instance for the output file using the given encoding + * @throws UnsupportedEncodingException if any + * @throws FileNotFoundException if any + * @see Supported + * encodings */ - public static Writer newWriter( @Nonnull File file, @Nonnull String encoding ) - throws UnsupportedEncodingException, FileNotFoundException - { - return newWriter( new FileOutputStream( file ), encoding ); + public static Writer newWriter(@Nonnull File file, @Nonnull String encoding) + throws UnsupportedEncodingException, FileNotFoundException { + return newWriter(new FileOutputStream(file), encoding); } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java b/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java index 979e8615..97ffb479 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,45 +16,35 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; /** * @author Kristian Rosenvold */ -class AbstractStreamHandler - extends Thread -{ +class AbstractStreamHandler extends Thread { private volatile boolean done; private volatile boolean disabled; - boolean isDone() - { + boolean isDone() { return done; } - public synchronized void waitUntilDone() - throws InterruptedException - { - while ( !isDone() ) - { + public synchronized void waitUntilDone() throws InterruptedException { + while (!isDone()) { wait(); } } - - boolean isDisabled() - { + boolean isDisabled() { return disabled; } - public void disable() - { + public void disable() { disabled = true; } - protected void setDone() - { + protected void setDone() { done = true; } - } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/Arg.java b/src/main/java/org/apache/maven/shared/utils/cli/Arg.java index 4e6041d8..df7be1ff 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/Arg.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/Arg.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,26 +16,35 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; import java.io.File; /** - * + * */ -public interface Arg -{ - void setValue( String value ); +public interface Arg { + /** + * @param value the value to be set + */ + void setValue(String value); - void setLine( String line ); + /** + * @param line the line of arguments + * @throws CommandLineException in case of unbalanced quotes. + */ + void setLine(String line) throws CommandLineException; - void setFile( File value ); + /** + * @param file the file to be set + */ + void setFile(File file); /** - * To mask the argument value when a command line ask to print his arguments. + * Whether to hide the argument value when a command line prints the arguments. * - * @param mask new state of the {@code maks} property + * @param mask new state of the {@code mask} property * @since 0.6 */ - void setMask( boolean mask ); - + void setMask(boolean mask); } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineCallable.java b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineCallable.java index 1b338e5c..ae806f07 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineCallable.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineCallable.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; import java.util.concurrent.Callable; @@ -26,9 +25,9 @@ * * @author Kristian Rosenvold */ -public interface CommandLineCallable - extends Callable-{ - Integer call() - throws CommandLineException; +public interface CommandLineCallable extends Callable { + /** + * {@inheritDoc} + */ + Integer call() throws CommandLineException; } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineException.java b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineException.java index f51c2c9e..cb326782 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineException.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineException.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,21 +16,29 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; /** * @author Trygve Laugstøl - * @version $Id$ */ -public class CommandLineException - extends Exception -{ - public CommandLineException( String message ) - { - super( message ); +public class CommandLineException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1344773066470228441L; + + /** + * @param message The message of the exception. + */ + public CommandLineException(String message) { + super(message); } - public CommandLineException( String message, Throwable cause ) - { - super( message, cause ); + /** + * @param message The message of the exception. + * @param cause The problem which caused the exception. + */ + public CommandLineException(String message, Throwable cause) { + super(message, cause); } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineTimeOutException.java b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineTimeOutException.java index 0cd9777a..88edb652 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineTimeOutException.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineTimeOutException.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,23 +16,30 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; /** + * Report a timeout for executing process. + * * @author Olivier Lamy - * @version $Id$ - * + * */ -public class CommandLineTimeOutException - extends CommandLineException -{ +public class CommandLineTimeOutException extends CommandLineException { + + private static final long serialVersionUID = 7322428741683224481L; /** - * @param message - * @param cause + * @param message The message of the exception. + * @param cause The cause of the exception. */ - public CommandLineTimeOutException( String message, Throwable cause ) - { - super( message, cause ); + public CommandLineTimeOutException(String message, Throwable cause) { + super(message, cause); } + /** + * @param message The message of the exception. + */ + public CommandLineTimeOutException(String message) { + super(message); + } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java index ac5a108f..96714b4e 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.InputStream; import java.nio.charset.Charset; @@ -27,82 +29,81 @@ import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.concurrent.TimeUnit; import org.apache.maven.shared.utils.Os; import org.apache.maven.shared.utils.StringUtils; /** * @author Trygve Laugstøl - * @version $Id$ */ -public abstract class CommandLineUtils -{ +public abstract class CommandLineUtils { /** - * + * A {@code StreamConsumer} providing consumed lines as a {@code String}. + * + * @see #getOutput() */ - @SuppressWarnings( "UnusedDeclaration" ) - public static class StringStreamConsumer - implements StreamConsumer - { - private final StringBuffer string = new StringBuffer(); + public static class StringStreamConsumer implements StreamConsumer { - private static final String LS = System.getProperty( "line.separator" ); + private final StringBuilder string = new StringBuilder(); - public void consumeLine( String line ) - { - string.append( line ).append( LS ); - } + private static final String LS = System.getProperty("line.separator", "\n"); - public String getOutput() - { - return string.toString(); + /** + * {@inheritDoc} + */ + @Override + public void consumeLine(String line) { + string.append(line).append(LS); } - } - - private static class ProcessHook - extends Thread - { - private final Process process; - private ProcessHook( Process process ) - { - super( "CommandlineUtils process shutdown hook" ); - this.process = process; - this.setContextClassLoader( null ); - } - - public void run() - { - process.destroy(); + /** + * @return The output. + */ + public String getOutput() { + return string.toString(); } } - - @SuppressWarnings( "UnusedDeclaration" ) - public static int executeCommandLine( @Nonnull Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr ) - throws CommandLineException - { - return executeCommandLine( cl, null, systemOut, systemErr, 0 ); + /** + * @param cl The command line {@link Commandline} + * @param systemOut {@link StreamConsumer} + * @param systemErr {@link StreamConsumer} + * @return return code. + * @throws CommandLineException in case of a problem. + */ + public static int executeCommandLine(@Nonnull Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr) + throws CommandLineException { + return executeCommandLine(cl, null, systemOut, systemErr, 0); } - @SuppressWarnings( "UnusedDeclaration" ) - public static int executeCommandLine( @Nonnull Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr, - int timeoutInSeconds ) - throws CommandLineException - { - return executeCommandLine( cl, null, systemOut, systemErr, timeoutInSeconds ); + /** + * @param cl The command line {@link Commandline} + * @param systemOut {@link StreamConsumer} + * @param systemErr {@link StreamConsumer} + * @param timeoutInSeconds The timeout. + * @return return code. + * @throws CommandLineException in case of a problem. + */ + public static int executeCommandLine( + @Nonnull Commandline cl, StreamConsumer systemOut, StreamConsumer systemErr, int timeoutInSeconds) + throws CommandLineException { + return executeCommandLine(cl, null, systemOut, systemErr, timeoutInSeconds); } - @SuppressWarnings( "UnusedDeclaration" ) - public static int executeCommandLine( @Nonnull Commandline cl, InputStream systemIn, StreamConsumer systemOut, - StreamConsumer systemErr ) - throws CommandLineException - { - return executeCommandLine( cl, systemIn, systemOut, systemErr, 0 ); + /** + * @param cl The command line {@link Commandline} + * @param systemIn {@link StreamConsumer} + * @param systemOut {@link StreamConsumer} + * @param systemErr {@link StreamConsumer} + * @return return code. + * @throws CommandLineException in case of a problem. + */ + public static int executeCommandLine( + @Nonnull Commandline cl, InputStream systemIn, StreamConsumer systemOut, StreamConsumer systemErr) + throws CommandLineException { + return executeCommandLine(cl, systemIn, systemOut, systemErr, 0); } /** @@ -113,13 +114,15 @@ public static int executeCommandLine( @Nonnull Commandline cl, InputStream syste * @param timeoutInSeconds Positive integer to specify timeout, zero and negative integers for no timeout. * @return A return value, see {@link Process#exitValue()} * @throws CommandLineException or CommandLineTimeOutException if time out occurs - * @noinspection ThrowableResultOfMethodCallIgnored */ - public static int executeCommandLine( @Nonnull Commandline cl, InputStream systemIn, StreamConsumer systemOut, - StreamConsumer systemErr, int timeoutInSeconds ) - throws CommandLineException - { - return executeCommandLine( cl, systemIn, systemOut, systemErr, timeoutInSeconds, null ); + public static int executeCommandLine( + @Nonnull Commandline cl, + InputStream systemIn, + StreamConsumer systemOut, + StreamConsumer systemErr, + int timeoutInSeconds) + throws CommandLineException { + return executeCommandLine(cl, systemIn, systemOut, systemErr, timeoutInSeconds, null); } /** @@ -132,15 +135,17 @@ public static int executeCommandLine( @Nonnull Commandline cl, InputStream syste * exceeded, but before waiting on the stream feeder and pumpers to finish. * @return A return value, see {@link Process#exitValue()} * @throws CommandLineException or CommandLineTimeOutException if time out occurs - * @noinspection ThrowableResultOfMethodCallIgnored */ - public static int executeCommandLine( @Nonnull Commandline cl, InputStream systemIn, StreamConsumer systemOut, - StreamConsumer systemErr, int timeoutInSeconds, - @Nullable Runnable runAfterProcessTermination ) - throws CommandLineException - { - return executeCommandLine( cl, systemIn, systemOut, systemErr, timeoutInSeconds, runAfterProcessTermination, - null ); + public static int executeCommandLine( + @Nonnull Commandline cl, + InputStream systemIn, + StreamConsumer systemOut, + StreamConsumer systemErr, + int timeoutInSeconds, + @Nullable Runnable runAfterProcessTermination) + throws CommandLineException { + return executeCommandLine( + cl, systemIn, systemOut, systemErr, timeoutInSeconds, runAfterProcessTermination, null); } /** @@ -154,17 +159,18 @@ public static int executeCommandLine( @Nonnull Commandline cl, InputStream syste * @param streamCharset Charset to use for reading streams * @return A return value, see {@link Process#exitValue()} * @throws CommandLineException or CommandLineTimeOutException if time out occurs - * @noinspection ThrowableResultOfMethodCallIgnored */ - public static int executeCommandLine( @Nonnull Commandline cl, InputStream systemIn, StreamConsumer systemOut, - StreamConsumer systemErr, int timeoutInSeconds, - @Nullable Runnable runAfterProcessTermination, - @Nullable final Charset streamCharset ) - throws CommandLineException - { - final CommandLineCallable future = - executeCommandLineAsCallable( cl, systemIn, systemOut, systemErr, timeoutInSeconds, - runAfterProcessTermination, streamCharset ); + public static int executeCommandLine( + @Nonnull Commandline cl, + InputStream systemIn, + StreamConsumer systemOut, + StreamConsumer systemErr, + int timeoutInSeconds, + @Nullable Runnable runAfterProcessTermination, + @Nullable final Charset streamCharset) + throws CommandLineException { + final CommandLineCallable future = executeCommandLineAsCallable( + cl, systemIn, systemOut, systemErr, timeoutInSeconds, runAfterProcessTermination, streamCharset); return future.call(); } @@ -181,18 +187,17 @@ public static int executeCommandLine( @Nonnull Commandline cl, InputStream syste * must be called on this to be sure the forked process has terminated, no guarantees is made about * any internal state before after the completion of the call statements * @throws CommandLineException or CommandLineTimeOutException if time out occurs - * @noinspection ThrowableResultOfMethodCallIgnored */ - public static CommandLineCallable executeCommandLineAsCallable( @Nonnull final Commandline cl, - @Nullable final InputStream systemIn, - final StreamConsumer systemOut, - final StreamConsumer systemErr, - final int timeoutInSeconds, - @Nullable final Runnable runAfterProcessTermination ) - throws CommandLineException - { - return executeCommandLineAsCallable( cl, systemIn, systemOut, systemErr, timeoutInSeconds, - runAfterProcessTermination, null ); + public static CommandLineCallable executeCommandLineAsCallable( + @Nonnull final Commandline cl, + @Nullable final InputStream systemIn, + final StreamConsumer systemOut, + final StreamConsumer systemErr, + final int timeoutInSeconds, + @Nullable final Runnable runAfterProcessTermination) + throws CommandLineException { + return executeCommandLineAsCallable( + cl, systemIn, systemOut, systemErr, timeoutInSeconds, runAfterProcessTermination, null); } /** @@ -209,137 +214,133 @@ public static CommandLineCallable executeCommandLineAsCallable( @Nonnull final C * must be called on this to be sure the forked process has terminated, no guarantees is made about * any internal state before after the completion of the call statements * @throws CommandLineException or CommandLineTimeOutException if time out occurs - * @noinspection ThrowableResultOfMethodCallIgnored */ - public static CommandLineCallable executeCommandLineAsCallable( @Nonnull final Commandline cl, - @Nullable final InputStream systemIn, - final StreamConsumer systemOut, - final StreamConsumer systemErr, - final int timeoutInSeconds, - @Nullable final Runnable runAfterProcessTermination, - @Nullable final Charset streamCharset ) - throws CommandLineException - { + public static CommandLineCallable executeCommandLineAsCallable( + @Nonnull final Commandline cl, + @Nullable final InputStream systemIn, + final StreamConsumer systemOut, + final StreamConsumer systemErr, + final int timeoutInSeconds, + @Nullable final Runnable runAfterProcessTermination, + @Nullable final Charset streamCharset) + throws CommandLineException { //noinspection ConstantConditions - if ( cl == null ) - { - throw new IllegalArgumentException( "cl cannot be null." ); + if (cl == null) { + throw new IllegalArgumentException("cl cannot be null."); } final Process p = cl.execute(); - final StreamFeeder inputFeeder = systemIn != null ? new StreamFeeder( systemIn, p.getOutputStream() ) : null; + final Thread processHook = new Thread() { - final StreamPumper outputPumper = new StreamPumper( p.getInputStream(), systemOut ); + { + this.setName("CommandLineUtils process shutdown hook"); + this.setContextClassLoader(null); + } - final StreamPumper errorPumper = new StreamPumper( p.getErrorStream(), systemErr ); + @Override + public void run() { + p.destroy(); + } + }; - if ( inputFeeder != null ) - { - inputFeeder.start(); - } + ShutdownHookUtils.addShutDownHook(processHook); - outputPumper.start(); + return new CommandLineCallable() { - errorPumper.start(); + @Override + public Integer call() throws CommandLineException { + StreamPollFeeder inputFeeder = null; + StreamPumper outputPumper = null; + StreamPumper errorPumper = null; + try { + if (systemIn != null) { + inputFeeder = new StreamPollFeeder(systemIn, p.getOutputStream()); + inputFeeder.setName("StreamPollFeeder-systemIn"); + inputFeeder.start(); + } - final ProcessHook processHook = new ProcessHook( p ); + outputPumper = new StreamPumper(p.getInputStream(), systemOut); + outputPumper.setName("StreamPumper-systemOut"); + outputPumper.start(); - ShutdownHookUtils.addShutDownHook( processHook ); + errorPumper = new StreamPumper(p.getErrorStream(), systemErr); + errorPumper.setName("StreamPumper-systemErr"); + errorPumper.start(); - return new CommandLineCallable() - { - public Integer call() - throws CommandLineException - { - try - { - int returnValue; - if ( timeoutInSeconds <= 0 ) - { - returnValue = p.waitFor(); + if (timeoutInSeconds > 0 && !p.waitFor(timeoutInSeconds, TimeUnit.SECONDS)) { + throw new CommandLineTimeOutException( + String.format("Process timed out after %d seconds.", timeoutInSeconds)); } - else - { - long now = System.currentTimeMillis(); - long timeoutInMillis = 1000L * timeoutInSeconds; - long finish = now + timeoutInMillis; - while ( isAlive( p ) && ( System.currentTimeMillis() < finish ) ) - { - Thread.sleep( 10 ); - } - if ( isAlive( p ) ) - { - throw new InterruptedException( - "Process timeout out after " + timeoutInSeconds + " seconds" ); - } - returnValue = p.exitValue(); + int returnValue = p.waitFor(); + + // TODO Find out if waitUntilDone needs to be called using a try-finally construct. The method may + // throw an + // InterruptedException so that calls to waitUntilDone may be skipped. + // try + // { + // if ( inputFeeder != null ) + // { + // inputFeeder.waitUntilDone(); + // } + // } + // finally + // { + // try + // { + // outputPumper.waitUntilDone(); + // } + // finally + // { + // errorPumper.waitUntilDone(); + // } + // } + if (inputFeeder != null) { + inputFeeder.waitUntilDone(); } - if ( runAfterProcessTermination != null ) - { - runAfterProcessTermination.run(); - } + outputPumper.waitUntilDone(); + errorPumper.waitUntilDone(); - waitForAllPumpers( inputFeeder, outputPumper, errorPumper ); + if (inputFeeder != null && inputFeeder.getException() != null) { + throw new CommandLineException("Failure processing stdin.", inputFeeder.getException()); + } - if ( outputPumper.getException() != null ) - { - throw new CommandLineException( "Error inside systemOut parser", outputPumper.getException() ); + if (outputPumper.getException() != null) { + throw new CommandLineException("Failure processing stdout.", outputPumper.getException()); } - if ( errorPumper.getException() != null ) - { - throw new CommandLineException( "Error inside systemErr parser", errorPumper.getException() ); + if (errorPumper.getException() != null) { + throw new CommandLineException("Failure processing stderr.", errorPumper.getException()); } return returnValue; - } - catch ( InterruptedException ex ) - { - if ( inputFeeder != null ) - { - inputFeeder.disable(); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new CommandLineTimeOutException( + "Error while executing external command, process killed.", ex); + } finally { + if (outputPumper != null) { + outputPumper.disable(); } - - outputPumper.disable(); - errorPumper.disable(); - throw new CommandLineTimeOutException( "Error while executing external command, process killed.", - ex ); - } - finally - { - ShutdownHookUtils.removeShutdownHook( processHook ); - - processHook.run(); - - if ( inputFeeder != null ) - { - inputFeeder.close(); + if (errorPumper != null) { + errorPumper.disable(); } - outputPumper.close(); - - errorPumper.close(); + try { + if (runAfterProcessTermination != null) { + runAfterProcessTermination.run(); + } + } finally { + ShutdownHookUtils.removeShutdownHook(processHook); + processHook.run(); + } } } }; } - private static void waitForAllPumpers( @Nullable StreamFeeder inputFeeder, StreamPumper outputPumper, - StreamPumper errorPumper ) - throws InterruptedException - { - if ( inputFeeder != null ) - { - inputFeeder.waitUntilDone(); - } - - outputPumper.waitUntilDone(); - errorPumper.waitUntilDone(); - } - /** * Gets the shell environment variables for this process. Note that the returned mapping from variable names to * values will always be case-sensitive regardless of the platform, i.e. getSystemEnvVars().get("path")
@@ -347,12 +348,11 @@ private static void waitForAllPumpers( @Nullable StreamFeeder inputFeeder, Strea * with case-insensitive environment variables like Windows, all variable names will be normalized to upper case. * * @return The shell environment variables, can be empty but nevernull
. - * @see System#getenv() System.getenv() API, new in JDK 5.0, to get the same result - * since 2.0.2 System#getenv() will be used if available in the current running jvm. + * @deprecated use System#getenv() */ - public static Properties getSystemEnvVars() - { - return getSystemEnvVars( !Os.isFamily( Os.FAMILY_WINDOWS ) ); + @Deprecated + public static Properties getSystemEnvVars() { + return getSystemEnvVars(!Os.isFamily(Os.FAMILY_WINDOWS)); } /** @@ -361,38 +361,21 @@ public static Properties getSystemEnvVars() * * @param caseSensitive Whether environment variable keys should be treated case-sensitively. * @return Properties object of (possibly modified) envar keys mapped to their values. - * @see System#getenv() System.getenv() API, new in JDK 5.0, to get the same result - * since 2.0.2 System#getenv() will be used if available in the current running jvm. + * @deprecated use System#getenv() */ - public static Properties getSystemEnvVars( boolean caseSensitive ) - { + @Deprecated + public static Properties getSystemEnvVars(boolean caseSensitive) { Mapenvs = System.getenv(); - return ensureCaseSensitivity( envs, caseSensitive ); + return ensureCaseSensitivity(envs, caseSensitive); } - private static boolean isAlive( Process p ) - { - if ( p == null ) - { - return false; - } - - try - { - p.exitValue(); - return false; - } - catch ( IllegalThreadStateException e ) - { - return true; - } - } - - public static String[] translateCommandline( String toProcess ) - throws Exception - { - if ( ( toProcess == null ) || ( toProcess.length() == 0 ) ) - { + /** + * @param toProcess The command line to translate. + * @return The array of translated parts. + * @throws CommandLineException in case of unbalanced quotes. + */ + public static String[] translateCommandline(String toProcess) throws CommandLineException { + if ((toProcess == null) || (toProcess.length() == 0)) { return new String[0]; } @@ -401,109 +384,105 @@ public static String[] translateCommandline( String toProcess ) final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; + boolean inEscape = false; int state = normal; - StringTokenizer tok = new StringTokenizer( toProcess, "\"\' ", true ); - List tokens = new ArrayList (); + final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' \\", true); + List tokens = new ArrayList<>(); StringBuilder current = new StringBuilder(); - while ( tok.hasMoreTokens() ) - { + while (tok.hasMoreTokens()) { String nextTok = tok.nextToken(); - switch ( state ) - { + switch (state) { case inQuote: - if ( "\'".equals( nextTok ) ) - { - state = normal; - } - else - { - current.append( nextTok ); + if ("\'".equals(nextTok)) { + if (inEscape) { + current.append(nextTok); + inEscape = false; + } else { + state = normal; + } + } else { + current.append(nextTok); + inEscape = "\\".equals(nextTok); } break; case inDoubleQuote: - if ( "\"".equals( nextTok ) ) - { - state = normal; - } - else - { - current.append( nextTok ); + if ("\"".equals(nextTok)) { + if (inEscape) { + current.append(nextTok); + inEscape = false; + } else { + state = normal; + } + } else { + current.append(nextTok); + inEscape = "\\".equals(nextTok); } break; default: - if ( "\'".equals( nextTok ) ) - { - state = inQuote; - } - else if ( "\"".equals( nextTok ) ) - { - state = inDoubleQuote; - } - else if ( " ".equals( nextTok ) ) - { - if ( current.length() != 0 ) - { - tokens.add( current.toString() ); - current.setLength( 0 ); + if ("\'".equals(nextTok)) { + if (inEscape) { + inEscape = false; + current.append(nextTok); + } else { + state = inQuote; } - } - else - { - current.append( nextTok ); + } else if ("\"".equals(nextTok)) { + if (inEscape) { + inEscape = false; + current.append(nextTok); + } else { + state = inDoubleQuote; + } + } else if (" ".equals(nextTok)) { + if (current.length() != 0) { + tokens.add(current.toString()); + current.setLength(0); + } + } else { + current.append(nextTok); + inEscape = "\\".equals(nextTok); } break; } } - if ( current.length() != 0 ) - { - tokens.add( current.toString() ); + if (current.length() != 0) { + tokens.add(current.toString()); } - if ( ( state == inQuote ) || ( state == inDoubleQuote ) ) - { - throw new CommandLineException( "unbalanced quotes in " + toProcess ); + if ((state == inQuote) || (state == inDoubleQuote)) { + throw new CommandLineException("unbalanced quotes in " + toProcess); } - return tokens.toArray( new String[tokens.size()] ); + return tokens.toArray(new String[tokens.size()]); } - public static String toString( String... line ) - { + /** + * @param line the lines + * @return the concatenated lines, quoted and escaped, separated by spaces + */ + public static String toString(String... line) { // empty path return empty string - if ( ( line == null ) || ( line.length == 0 ) ) - { + if ((line == null) || (line.length == 0)) { return ""; } - // path containing one or more elements final StringBuilder result = new StringBuilder(); - for ( int i = 0; i < line.length; i++ ) - { - if ( i > 0 ) - { - result.append( ' ' ); - } - try - { - result.append( StringUtils.quoteAndEscape( line[i], '\"' ) ); - } - catch ( Exception e ) - { - System.err.println( "Error quoting argument: " + e.getMessage() ); + for (int i = 0; i < line.length; i++) { + if (i > 0) { + result.append(' '); } + result.append(StringUtils.quoteAndEscape(line[i], '\"')); } return result.toString(); } - static Properties ensureCaseSensitivity( Map envs, boolean preserveKeyCase ) - { + static Properties ensureCaseSensitivity(Map envs, boolean preserveKeyCase) { Properties envVars = new Properties(); - for ( Map.Entry entry : envs.entrySet() ) - { - envVars.put( !preserveKeyCase ? entry.getKey().toUpperCase( Locale.ENGLISH ) : entry.getKey(), - entry.getValue() ); + for (Map.Entry entry : envs.entrySet()) { + envVars.put( + !preserveKeyCase ? entry.getKey().toUpperCase(Locale.ENGLISH) : entry.getKey(), entry.getValue()); } return envVars; } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/Commandline.java b/src/main/java/org/apache/maven/shared/utils/cli/Commandline.java index 043a3691..619f5a10 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/Commandline.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/Commandline.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; import java.io.File; import java.io.IOException; @@ -34,19 +33,17 @@ import org.apache.maven.shared.utils.StringUtils; import org.apache.maven.shared.utils.cli.shell.BourneShell; import org.apache.maven.shared.utils.cli.shell.CmdShell; -import org.apache.maven.shared.utils.cli.shell.CommandShell; import org.apache.maven.shared.utils.cli.shell.Shell; /** - * + * * Commandline objects help handling command lines specifying processes to * execute. *
- * + ** The class can be used to define a command line as nested elements or as a * helper to define a command line by an application. *
- * ** <someelement>
- * - * + *
* <acommandline executable="/executable/to/run">
@@ -56,8 +53,7 @@ * </acommandline>
* </someelement>
** The element
@@ -65,380 +61,363 @@ * @author thomas.haas@softwired-inc.com * @author Stefan Bodewig */ -public class Commandline - implements Cloneable -{ - private final Listsomeelement
must provide a method *createAcommandline
which returns an instance of this class. *arguments = new Vector (); +public class Commandline implements Cloneable { + private final List arguments = new Vector<>(); - //protected Vector envVars = new Vector(); - // synchronized added to preserve synchronize of Vector class - private final Map envVars = Collections.synchronizedMap( new LinkedHashMap () ); + private final Map envVars = Collections.synchronizedMap(new LinkedHashMap ()); private Shell shell; + private boolean shellEnvironmentInherited = true; + /** * Create a new command line object. - * Shell is autodetected from operating system + * Shell is autodetected from operating system. + * + * @param shell the shell instance */ - public Commandline( Shell shell ) - { + public Commandline(Shell shell) { this.shell = shell; } /** * Create a new command line object. - * Shell is autodetected from operating system + * Shell is autodetected from operating system. * - * @param toProcess The command to process + * @param toProcess the command to process + * @throws CommandLineException in case of unbalanced quotes. */ - public Commandline( String toProcess ) - { + public Commandline(String toProcess) throws CommandLineException { setDefaultShell(); - String[] tmp = new String[0]; - try - { - tmp = CommandLineUtils.translateCommandline( toProcess ); - } - catch ( Exception e ) - { - System.err.println( "Error translating Commandline." ); - } - if ( ( tmp != null ) && ( tmp.length > 0 ) ) - { - setExecutable( tmp[0] ); - for ( int i = 1; i < tmp.length; i++ ) - { - createArg().setValue( tmp[i] ); + String[] tmp = CommandLineUtils.translateCommandline(toProcess); + if ((tmp.length > 0)) { + setExecutable(tmp[0]); + for (int i = 1; i < tmp.length; i++) { + createArg().setValue(tmp[i]); } } } /** * Create a new command line object. - * Shell is autodetected from operating system + * Shell is autodetected from operating system. */ - public Commandline() - { + public Commandline() { setDefaultShell(); } /** - * Sets the shell or command-line interpretor for the detected operating system, + *
Sets the shell or command-line interpreter for the detected operating system, * and the shell arguments.
*/ - private void setDefaultShell() - { - //If this is windows set the shell to command.com or cmd.exe with correct arguments. - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) - { - if ( Os.isFamily( Os.FAMILY_WIN9X ) ) - { - setShell( new CommandShell() ); - } - else - { - setShell( new CmdShell() ); - } - } - else - { - setShell( new BourneShell() ); + private void setDefaultShell() { + // If this is windows set the shell to command.com or cmd.exe with correct arguments. + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + setShell(new CmdShell()); + } else { + setShell(new BourneShell()); } } /** - * Creates an argument object. - * - *Each commandline object has at most one instance of the - * argument class. This method calls - *
+ * Creates an empty argument object and inserts it at the end of the argument list. * - * @return the argument object. + * @return the argument object */ - public Arg createArg() - { - return this.createArg( false ); + public Arg createArg() { + return this.createArg(false); } /** - * Creates an argument object and adds it to our list of args. - * - *this.createArgument(false)
.Each commandline object has at most one instance of the - * argument class.
+ * Creates an argument object and adds it to the list of args. * * @param insertAtStart if true, the argument is inserted at the - * beginning of the list of args, otherwise it is appended. + * beginning of the list of args. Otherwise it is appended. + * @return the argument */ - public Arg createArg( boolean insertAtStart ) - { + public Arg createArg(boolean insertAtStart) { Arg argument = new Argument(); - if ( insertAtStart ) - { - arguments.add( 0, argument ); - } - else - { - arguments.add( argument ); + if (insertAtStart) { + arguments.add(0, argument); + } else { + arguments.add(argument); } return argument; } /** * Sets the executable to run. + * + * @param executable the executable */ - public void setExecutable( String executable ) - { - shell.setExecutable( executable ); + public void setExecutable(String executable) { + shell.setExecutable(executable); } - public String getExecutable() - { + /** + * @return the executable + */ + public String getExecutable() { return shell.getExecutable(); } - public void addArguments( String... line ) - { - for ( String aLine : line ) - { - createArg().setValue( aLine ); + /** + * @param line the arguments + */ + public void addArguments(String... line) { + for (String aLine : line) { + createArg().setValue(aLine); } } /** - * Add an environment variable + * Add an environment variable. + * + * @param name the name of the environment variable + * @param value the appropriate value */ - public void addEnvironment( String name, String value ) - { - //envVars.add( name + "=" + value ); - envVars.put( name, value ); + public void addEnvironment(String name, String value) { + envVars.put(name, value); } /** - * Add system environment variables + * Add system environment variables. + * + * @deprecated please use {@link #setShellEnvironmentInherited(boolean)} */ - public void addSystemEnvironment() - { + @Deprecated + public void addSystemEnvironment() {} + + private void copySystemEnvironment() { Properties systemEnvVars = CommandLineUtils.getSystemEnvVars(); - for ( Object o : systemEnvVars.keySet() ) - { + for (Object o : systemEnvVars.keySet()) { String key = (String) o; - if ( !envVars.containsKey( key ) ) - { - addEnvironment( key, systemEnvVars.getProperty( key ) ); + if (!envVars.containsKey(key)) { + addEnvironment(key, systemEnvVars.getProperty(key)); } } } /** - * Return the list of environment variables + * Return the list of environment variables. + * + * @return an array of all environment variables */ - public String[] getEnvironmentVariables() - { - addSystemEnvironment(); - String[] environmentVars = new String[envVars.size()]; - int i = 0; - for ( String name : envVars.keySet() ) - { - String value = envVars.get( name ); - environmentVars[i] = name + "=" + value; - i++; + public String[] getEnvironmentVariables() { + if (isShellEnvironmentInherited()) { + copySystemEnvironment(); } - return environmentVars; + + ListenvironmentVars = new ArrayList<>(); + for (String name : envVars.keySet()) { + String value = envVars.get(name); + if (value != null) { + environmentVars.add(name + "=" + value); + } + } + return environmentVars.toArray(new String[0]); } /** * Returns the executable and all defined arguments. + * + * @return an array of all arguments including the executable */ - public String[] getCommandline() - { + public String[] getCommandline() { final String[] args = getArguments(); String executable = getExecutable(); - if ( executable == null ) - { + if (executable == null) { return args; } final String[] result = new String[args.length + 1]; result[0] = executable; - System.arraycopy( args, 0, result, 1, args.length ); + System.arraycopy(args, 0, result, 1, args.length); return result; } /** - * @return the shell, executable and all defined arguments without masking any arguments. + * @return the shell, executable and all defined arguments without masking any arguments */ - private String[] getShellCommandline() - { - return getShellCommandline( false ) ; + private String[] getShellCommandline() { + return getShellCommandline(false); } /** - * @param mask flag to mask any arguments (having his {@code mask} field to {@code true}). + * @param mask flag to mask any arguments (having his {@code mask} field to {@code true}) * @return the shell, executable and all defined arguments with masking some arguments if * {@code mask} parameter is on */ - private String[] getShellCommandline( boolean mask ) - { - List shellCommandLine = getShell().getShellCommandLine( getArguments( mask ) ); - return shellCommandLine.toArray( new String[shellCommandLine.size()] ); + private String[] getShellCommandline(boolean mask) { + List shellCommandLine = getShell().getShellCommandLine(getArguments(mask)); + return shellCommandLine.toArray(new String[shellCommandLine.size()]); } /** * Returns all arguments defined by addLine
, *addValue
or the argument object. + * @return an array of arguments. */ - public String[] getArguments() - { - return getArguments( false ); + public String[] getArguments() { + return getArguments(false); } /** * Returns all arguments defined byaddLine
, - *addValue
or the argument object. + *addValue
, or the argument object. * - * @param mask flag to mask any arguments (having his {@code mask} field to {@code true}). + * @param mask flag to mask any arguments (having his {@code mask} field to {@code true}) + * @return an array of arguments */ - public String[] getArguments( boolean mask ) - { - Listresult = new ArrayList ( arguments.size() * 2 ); - for ( Arg argument : arguments ) - { + public String[] getArguments(boolean mask) { + List result = new ArrayList<>(arguments.size() * 2); + for (Arg argument : arguments) { Argument arg = (Argument) argument; String[] s = arg.getParts(); - if ( s != null ) - { - if ( mask && ( arg.isMask() ) ) - { + if (s != null) { + if (mask && (arg.isMask())) { // should be a key-pair argument - if ( s.length > 0 ) - { + if (s.length > 0) { // use a masked copy String[] copy = new String[s.length]; - Arrays.fill( copy, "*****" ); + Arrays.fill(copy, "*****"); s = copy; } } - Collections.addAll( result, s ); + Collections.addAll(result, s); } } - return result.toArray( new String[result.size()] ); + return result.toArray(new String[result.size()]); } - public String toString() - { - return StringUtils.join( getShellCommandline( true ), " " ); + /** {@inheritDoc} + */ + public String toString() { + return StringUtils.join(getShellCommandline(true), " "); } - - public Object clone() - { - throw new RuntimeException( "Do we ever clone a commandline?" ); -/* Commandline c = new Commandline( (Shell) shell.clone() ); - c.addArguments( getArguments() ); - return c;*/ + /** {@inheritDoc} + */ + public Object clone() { + throw new RuntimeException("Do we ever clone a commandline?"); + /* Commandline c = new Commandline( (Shell) shell.clone() ); + c.addArguments( getArguments() ); + return c;*/ } /** - * Sets execution directory. + * Sets working directory. + * + * @param path the working directory */ - public void setWorkingDirectory( String path ) - { - shell.setWorkingDirectory( path ); + public void setWorkingDirectory(String path) { + shell.setWorkingDirectory(path); } /** - * Sets execution directory. + * Sets working directory. + * + * @param workingDirectory the working directory */ - public void setWorkingDirectory( File workingDirectory ) - { - shell.setWorkingDirectory( workingDirectory ); + public void setWorkingDirectory(File workingDirectory) { + shell.setWorkingDirectory(workingDirectory); } - public File getWorkingDirectory() - { + /** + * @return the working directory + */ + public File getWorkingDirectory() { return shell.getWorkingDirectory(); } /** * Clear out the arguments but leave the executable in place for another operation. */ - public void clearArgs() - { + public void clearArgs() { arguments.clear(); } /** - * Executes the command. + * Indicates whether the environment variables of the current process + * should are propagated to the executing Command. + * By default, the current environment variables are inherited by the new Command line execution. + * + * @return true
if the environment variables should be propagated,false
otherwise. */ - public Process execute() - throws CommandLineException - { - Process process; + public boolean isShellEnvironmentInherited() { + return shellEnvironmentInherited; + } - //addEnvironment( "MAVEN_TEST_ENVAR", "MAVEN_TEST_ENVAR_VALUE" ); + /** + * Specifies whether the environment variables of the current process should be propagated to the executing Command. + * + * @param shellEnvironmentInheritedtrue
if the environment variables should be propagated, + *false
otherwise. + */ + public void setShellEnvironmentInherited(boolean shellEnvironmentInherited) { + this.shellEnvironmentInherited = shellEnvironmentInherited; + } + + /** + * Execute the command. + * + * @return the process + * @throws CommandLineException in case of errors + */ + public Process execute() throws CommandLineException { + Process process; String[] environment = getEnvironmentVariables(); File workingDir = shell.getWorkingDirectory(); - try - { - if ( workingDir == null ) - { - process = Runtime.getRuntime().exec( getShellCommandline(), environment ); - } - else - { - if ( !workingDir.exists() ) - { + try { + if (workingDir == null) { + process = Runtime.getRuntime().exec(getShellCommandline(), environment); + } else { + if (!workingDir.exists()) { throw new CommandLineException( - "Working directory \"" + workingDir.getPath() + "\" does not exist!" ); - } - else if ( !workingDir.isDirectory() ) - { + "Working directory \"" + workingDir.getPath() + "\" does not exist!"); + } else if (!workingDir.isDirectory()) { throw new CommandLineException( - "Path \"" + workingDir.getPath() + "\" does not specify a directory." ); + "Path \"" + workingDir.getPath() + "\" does not specify a directory."); } - process = Runtime.getRuntime().exec( getShellCommandline(), environment, workingDir ); + process = Runtime.getRuntime().exec(getShellCommandline(), environment, workingDir); } - } - catch ( IOException ex ) - { - throw new CommandLineException( "Error while executing process.", ex ); + } catch (IOException ex) { + throw new CommandLineException("Error while executing process.", ex); } return process; } /** - * Allows to set the shell to be used in this command line. + * Set the shell to be used for this command line. * * @param shell the shell */ - void setShell( Shell shell ) - { + void setShell(Shell shell) { this.shell = shell; } /** * Get the shell to be used in this command line. + * + * @return the shell */ - public Shell getShell() - { + public Shell getShell() { return shell; } /** - * + * A single command line argument */ - public static class Argument - implements Arg - { + public static class Argument implements Arg { private String[] parts; private boolean mask; @@ -446,56 +425,47 @@ public static class Argument /** * {@inheritDoc} */ - public void setValue( String value ) - { - if ( value != null ) - { - parts = new String[]{ value }; + public void setValue(String value) { + if (value != null) { + parts = new String[] {value}; } } /** * {@inheritDoc} */ - public void setLine( String line ) - { - if ( line == null ) - { + public void setLine(String line) throws CommandLineException { + if (line == null) { return; } - try - { - parts = CommandLineUtils.translateCommandline( line ); - } - catch ( Exception e ) - { - System.err.println( "Error translating Commandline." ); - } + parts = CommandLineUtils.translateCommandline(line); } /** * {@inheritDoc} */ - public void setFile( File value ) - { - parts = new String[]{ value.getAbsolutePath() }; + public void setFile(File value) { + parts = new String[] {value.getAbsolutePath()}; } /** * {@inheritDoc} */ - public void setMask( boolean mask ) - { + public void setMask(boolean mask) { this.mask = mask; } - private String[] getParts() - { + /** + * @return the parts + */ + private String[] getParts() { return parts; } - public boolean isMask() - { + /** + * @return true/false + */ + public boolean isMask() { return mask; } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/DefaultConsumer.java b/src/main/java/org/apache/maven/shared/utils/cli/DefaultConsumer.java index db75f534..f2640462 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/DefaultConsumer.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/DefaultConsumer.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,16 +16,23 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; + +import java.io.IOException; /** * @author Emmanuel Venisse - * @version $Id$ */ -public class DefaultConsumer - implements StreamConsumer -{ - public void consumeLine( String line ) - { - System.out.println( line ); +public class DefaultConsumer implements StreamConsumer { + + /** + * {@inheritDoc} + */ + @Override + public void consumeLine(String line) throws IOException { + System.out.println(line); + if (System.out.checkError()) { + throw new IOException(String.format("Failure writing line '%s' to stdout.", line)); + } } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/ShutdownHookUtils.java b/src/main/java/org/apache/maven/shared/utils/cli/ShutdownHookUtils.java index 9ce64657..5ec3bbc6 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/ShutdownHookUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/ShutdownHookUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; import java.security.AccessControlException; @@ -29,39 +28,31 @@ * * @author Kristian Rosenvold */ -public class ShutdownHookUtils -{ +public class ShutdownHookUtils { - public static void addShutDownHook( Thread hook ) - { - try - { - Runtime.getRuntime().addShutdownHook( hook ); - } - catch ( IllegalStateException ignore ) - { + /** + * @param hook The thread hook. + */ + public static void addShutDownHook(Thread hook) { + try { + Runtime.getRuntime().addShutdownHook(hook); + } catch (IllegalStateException ignore) { // ignore - } - catch ( AccessControlException ignore ) - { + } catch (AccessControlException ignore) { // ignore } } - public static void removeShutdownHook( Thread hook ) - { - try - { - Runtime.getRuntime().removeShutdownHook( hook ); - } - catch ( IllegalStateException ignore ) - { + /** + * @param hook The hook which should be removed. + */ + public static void removeShutdownHook(Thread hook) { + try { + Runtime.getRuntime().removeShutdownHook(hook); + } catch (IllegalStateException ignore) { // ignore - } - catch ( AccessControlException ignore ) - { + } catch (AccessControlException ignore) { // ignore } } - } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/StreamConsumer.java b/src/main/java/org/apache/maven/shared/utils/cli/StreamConsumer.java index c460ad9f..9279acaa 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/StreamConsumer.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/StreamConsumer.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,22 +16,25 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; + +import java.io.IOException; /** - * Works in concert with the StreamPumper class to + *Works in concert with the StreamPumper class to * allow implementations to gain access to the lines being - * "Pumped". - *
- * Please note that implementations of this interface can be expected to be - * called from arbitrary threads and must therefore be threadsafe. + * "Pumped". + *Please note that implementations of this interface can be expected to be + * called from arbitrary threads and must therefore be threadsafe.
* * @author Florin Vancea * @author Paul Julius */ -public interface StreamConsumer -{ +public interface StreamConsumer { /** * Called when the StreamPumper pumps a line from the Stream. + * @param line The line to be consumed. + * @throws IOException if consuming {@code line} fails. */ - void consumeLine( String line ); + void consumeLine(String line) throws IOException; } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/StreamFeeder.java b/src/main/java/org/apache/maven/shared/utils/cli/StreamFeeder.java deleted file mode 100644 index 8409eebb..00000000 --- a/src/main/java/org/apache/maven/shared/utils/cli/StreamFeeder.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.apache.maven.shared.utils.cli; - -/* - * 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. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Read from an InputStream and write the output to an OutputStream. - * - * @author Trygve Laugstøl - * @version $Id$ - */ -class StreamFeeder - extends AbstractStreamHandler -{ - private final AtomicReferenceinput; - private final AtomicReference output; - - /** - * Create a new StreamFeeder - * - * @param input Stream to read from - * @param output Stream to write to - */ - public StreamFeeder( InputStream input, OutputStream output ) - { - this.input = new AtomicReference ( input ); - this.output = new AtomicReference ( output ); - } - - // ---------------------------------------------------------------------- - // Runnable implementation - // ---------------------------------------------------------------------- - - @Override - public void run() - { - try - { - feed(); - } - catch ( Throwable e ) - { - // Catch everything so the streams will be closed and flagged as done. - } - finally - { - close(); - - synchronized ( this ) - { - notifyAll(); - } - } - } - - // ---------------------------------------------------------------------- - // - // ---------------------------------------------------------------------- - - public void close() - { - setDone(); - final InputStream is = input.getAndSet( null ); - if ( is != null ) - { - try - { - is.close(); - } - catch ( IOException ex ) - { - // ignore - } - } - - final OutputStream os = output.getAndSet( null ); - if ( os != null ) - { - try - { - os.close(); - } - catch ( IOException ex ) - { - // ignore - } - } - } - - // ---------------------------------------------------------------------- - // - // ---------------------------------------------------------------------- - - @SuppressWarnings( "checkstyle:innerassignment" ) - private void feed() - throws IOException - { - InputStream is = input.get(); - OutputStream os = output.get(); - if ( is != null && os != null ) - { - for ( int data; !isDone() && ( data = is.read() ) != -1; ) - { - if ( !isDisabled() ) - { - os.write( data ); - } - } - } - } - -} diff --git a/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java b/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java new file mode 100644 index 00000000..27d75bb1 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/cli/StreamPollFeeder.java @@ -0,0 +1,117 @@ +/* + * 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.maven.shared.utils.cli; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Objects; + +/** + * Poll InputStream for available data and write the output to an OutputStream. + * + * @author Trygve Laugstøl + */ +class StreamPollFeeder extends Thread { + + public static final int BUF_LEN = 80; + + private final InputStream input; + private final OutputStream output; + + private Throwable exception; + + private boolean done; + private final Object lock = new Object(); + + /** + * Create a new StreamPollFeeder + * + * @param input Stream to read from + * @param output Stream to write to + */ + StreamPollFeeder(InputStream input, OutputStream output) { + this.input = Objects.requireNonNull(input); + this.output = Objects.requireNonNull(output); + this.done = false; + } + + @Override + public void run() { + + byte[] buf = new byte[BUF_LEN]; + + try { + while (!done) { + if (input.available() > 0) { + int i = input.read(buf); + if (i > 0) { + output.write(buf, 0, i); + output.flush(); + } else { + done = true; + } + } else { + synchronized (lock) { + if (!done) { + lock.wait(100); + } + } + } + } + } catch (IOException e) { + exception = e; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + close(); + } + } + + private void close() { + try { + output.close(); + } catch (IOException e) { + if (exception == null) { + exception = e; + } + } + } + + /** + * @since 3.2.0 + */ + public Throwable getException() { + return this.exception; + } + + public void waitUntilDone() { + + synchronized (lock) { + done = true; + lock.notifyAll(); + } + + try { + join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/src/main/java/org/apache/maven/shared/utils/cli/StreamPumper.java b/src/main/java/org/apache/maven/shared/utils/cli/StreamPumper.java index 3118a642..03a79ca1 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/StreamPumper.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/StreamPumper.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,94 +16,83 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; + +import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.PrintWriter; import java.io.Reader; import java.nio.charset.Charset; -import javax.annotation.Nullable; - -import org.apache.maven.shared.utils.io.IOUtil; - /** - * Class to pump the error stream during Process's runtime. Copied from the Ant - * built-in task. + * Class to pump the error stream during Process's runtime. Copied from the Ant built-in task. * * @author Florin Vancea * @author Paul Julius - * */ -public class StreamPumper - extends AbstractStreamHandler -{ +public class StreamPumper extends AbstractStreamHandler { private final BufferedReader in; private final StreamConsumer consumer; - private final PrintWriter out; - private volatile Exception exception = null; private static final int SIZE = 1024; - public StreamPumper( InputStream in, StreamConsumer consumer ) - { - this( new InputStreamReader( in ), null, consumer ); + /** + * @param in {@link InputStream} + * @param consumer {@link StreamConsumer} + */ + public StreamPumper(InputStream in, StreamConsumer consumer) { + this(new InputStreamReader(in), consumer); } - public StreamPumper( InputStream in, StreamConsumer consumer, @Nullable Charset charset ) - { - this( null == charset ? new InputStreamReader( in ) : new InputStreamReader( in, charset ), null, consumer ); + /** + * @param in {@link InputStream} + * @param consumer {@link StreamConsumer} + * @param charset {@link Charset} + */ + public StreamPumper(InputStream in, StreamConsumer consumer, @Nullable Charset charset) { + this(null == charset ? new InputStreamReader(in) : new InputStreamReader(in, charset), consumer); } - private StreamPumper( Reader in, PrintWriter writer, StreamConsumer consumer ) - { - this.in = new BufferedReader( in, SIZE ); - this.out = writer; + /** + * @param in {@link Reader} + * @param consumer {@link StreamConsumer} + */ + private StreamPumper(Reader in, StreamConsumer consumer) { + super(); + this.in = new BufferedReader(in, SIZE); this.consumer = consumer; } - public void run() - { - try - { - for ( String line = in.readLine(); line != null; line = in.readLine() ) - { - try - { - if ( exception == null ) - { - consumeLine( line ); + /** run it. */ + public void run() { + try { + for (String line = in.readLine(); line != null; line = in.readLine()) { + try { + if (exception == null) { + consumeLine(line); } - } - catch ( Exception t ) - { + } catch (Exception t) { exception = t; } - - if ( out != null ) - { - out.println( line ); - - out.flush(); - } - } - } - catch ( IOException e ) - { + } catch (IOException e) { exception = e; - } - finally - { - IOUtil.close( in ); + } finally { + try { + in.close(); + } catch (final IOException e2) { + if (this.exception == null) { + this.exception = e2; + } + } - synchronized ( this ) - { + synchronized (this) { setDone(); this.notifyAll(); @@ -113,29 +100,36 @@ public void run() } } - public void flush() - { - if ( out != null ) - { - out.flush(); - } + /** + * flush. + * + * @deprecated As of 3.2.0, removed without replacement. + */ + @Deprecated + public void flush() { + // Nothing to flush. } - public void close() - { - IOUtil.close( out ); + /** + * Close it. + * + * @deprecated As of 3.2.0, removed without replacement. + */ + @Deprecated + public void close() { + // Nothing to close. } - public Exception getException() - { + /** + * @return {@link Exception} + */ + public Exception getException() { return exception; } - private void consumeLine( String line ) - { - if ( consumer != null && !isDisabled() ) - { - consumer.consumeLine( line ); + private void consumeLine(String line) throws IOException { + if (consumer != null && !isDisabled()) { + consumer.consumeLine(line); } } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/WriterStreamConsumer.java b/src/main/java/org/apache/maven/shared/utils/cli/WriterStreamConsumer.java index d8a48531..d3dbbbe4 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/WriterStreamConsumer.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/WriterStreamConsumer.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,29 +16,35 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli; -import java.io.PrintWriter; +import java.io.BufferedWriter; +import java.io.IOException; import java.io.Writer; /** * @author Jason van Zyl - * @version $Id$ + * */ -public class WriterStreamConsumer - implements StreamConsumer -{ +public class WriterStreamConsumer implements StreamConsumer { - private final PrintWriter writer; + private final BufferedWriter writer; - public WriterStreamConsumer( Writer writer ) - { - this.writer = new PrintWriter( writer ); + /** + * @param writer {@link Writer} + */ + public WriterStreamConsumer(Writer writer) { + super(); + this.writer = new BufferedWriter(writer); } - public void consumeLine( String line ) - { - writer.println( line ); - - writer.flush(); + /** + * {@inheritDoc} + */ + @Override + public void consumeLine(String line) throws IOException { + this.writer.append(line); + this.writer.newLine(); + this.writer.flush(); } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaTool.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaTool.java index bdfdf5d6..813ccc02 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaTool.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaTool.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,13 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.javatool; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; import org.apache.maven.shared.utils.Os; import org.apache.maven.shared.utils.StringUtils; @@ -25,24 +30,18 @@ import org.apache.maven.shared.utils.cli.CommandLineUtils; import org.apache.maven.shared.utils.cli.Commandline; import org.apache.maven.shared.utils.cli.StreamConsumer; -import org.apache.maven.toolchain.Toolchain; -import org.codehaus.plexus.logging.AbstractLogEnabled; - -import java.io.File; -import java.io.InputStream; -import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Abstract implementation of a {@link JavaTool}. * - * @author Tony Chemit + * @author Tony Chemit * @since 0.5 - * @param + * @param Tool-specific request type */ -public abstract class AbstractJavaTool - extends AbstractLogEnabled - implements JavaTool -{ +public abstract class AbstractJavaTool implements JavaTool { + private final Logger logger = LoggerFactory.getLogger(getClass()); /** * The java tool name to find out in the jdk. @@ -57,212 +56,233 @@ public abstract class AbstractJavaTool /** * Optional toolChain used to find java tool executable file. */ - private Toolchain toolchain; + private Object toolchain; - protected AbstractJavaTool( String javaToolName ) - { + /** + * @param javaToolName The name of the java tool. + */ + protected AbstractJavaTool(String javaToolName) { this.javaToolName = javaToolName; } /** - * Create the commandline object given the request. + * Create the command line object given the request. * * @param request User request on the java tool - * @param javaToolFile Location of the java tool file to use - * @return the commandline + * @param javaToolFileLocation Location of the java tool file to use + * @return the command line * @throws JavaToolException if could not create the command line from the request */ - protected abstract Commandline createCommandLine( Request request, String javaToolFile ) - throws JavaToolException; + protected abstract Commandline createCommandLine(Request request, String javaToolFileLocation) + throws JavaToolException; + + protected Logger getLogger() { + return logger; + } /** * {@inheritDoc} */ - public String getJavaToolName() - { + public String getJavaToolName() { return javaToolName; } /** * {@inheritDoc} */ - public void setToolchain( Toolchain toolchain ) - { + public void setToolchain(Object toolchain) { this.toolchain = toolchain; } /** * {@inheritDoc} */ - public JavaToolResult execute( Request request ) - throws JavaToolException - { + public JavaToolResult execute(Request request) throws JavaToolException { - if ( javaToolFile == null ) - { + if (javaToolFile == null) { // find the java tool file to use - try - { + try { javaToolFile = findJavaToolExecutable(); - } - catch ( Exception e ) - { - throw new JavaToolException( "Error finding " + javaToolName + " executable. Reason: " + e.getMessage(), - e ); + } catch (Exception e) { + throw new JavaToolException( + "Error finding " + javaToolName + " executable. Reason: " + e.getMessage(), e); } } // creates the command line from the given request - Commandline cli = createCommandLine( request, javaToolFile ); + Commandline cli = createCommandLine(request, javaToolFile); // execute it - JavaToolResult result = executeCommandLine( cli, request ); + JavaToolResult result = executeCommandLine(cli, request); // return result return result; } - protected InputStream createSystemInputStream() - { - InputStream systemIn = new InputStream() - { + /** + * @return {@link InputStream} + */ + protected InputStream createSystemInputStream() { + InputStream systemIn = new InputStream() { /** * {@inheritDoc} */ - public int read() - { + public int read() { return -1; } - }; return systemIn; } - protected JavaToolResult executeCommandLine( Commandline cli, Request request ) - { - if ( getLogger().isDebugEnabled() ) - { - getLogger().debug( "Executing: " + cli ); + /** + * @param cli {@link Commandline} + * @param request The request. + * @return {@link JavaToolRequest} + */ + protected JavaToolResult executeCommandLine(Commandline cli, Request request) { + if (getLogger().isDebugEnabled()) { + getLogger().debug("Executing: " + cli); } JavaToolResult result = createResult(); - result.setCommandline( cli ); + result.setCommandline(cli); InputStream systemIn = createSystemInputStream(); - StreamConsumer systemOut = createSystemOutStreamConsumer( request ); + StreamConsumer systemOut = createSystemOutStreamConsumer(request); - StreamConsumer systemErr = createSystemErrorStreamConsumer( request ); + StreamConsumer systemErr = createSystemErrorStreamConsumer(request); - try - { - int resultCode = CommandLineUtils.executeCommandLine( cli, systemIn, systemOut, systemErr ); + try { + int resultCode = CommandLineUtils.executeCommandLine(cli, systemIn, systemOut, systemErr); - result.setExitCode( resultCode ); - } - catch ( CommandLineException e ) - { - result.setExecutionException( e ); + result.setExitCode(resultCode); + } catch (CommandLineException e) { + result.setExecutionException(e); } return result; } - protected StreamConsumer createSystemErrorStreamConsumer( Request request ) - { + /** + * @param request The request. + * @return {@link StreamConsumer} + */ + protected StreamConsumer createSystemErrorStreamConsumer(Request request) { StreamConsumer systemErr = request.getSystemErrorStreamConsumer(); - if ( systemErr == null ) - { - systemErr = new StreamConsumer() - { + if (systemErr == null) { + systemErr = new StreamConsumer() { /** * {@inheritDoc} */ - public void consumeLine( final String line ) - { - getLogger().warn( line ); + @Override + public void consumeLine(final String line) { + getLogger().warn(line); } - }; } return systemErr; } - protected StreamConsumer createSystemOutStreamConsumer( Request request ) - { + /** + * @param request The request. + * @return {@link StreamConsumer} + */ + protected StreamConsumer createSystemOutStreamConsumer(Request request) { StreamConsumer systemOut = request.getSystemOutStreamConsumer(); - if ( systemOut == null ) - { + if (systemOut == null) { - systemOut = new StreamConsumer() - { + systemOut = new StreamConsumer() { /** * {@inheritDoc} */ - public void consumeLine( final String line ) - { - getLogger().info( line ); - + @Override + public void consumeLine(final String line) { + getLogger().info(line); } - }; } return systemOut; } - protected JavaToolResult createResult() - { + /** + * @return The JavaToolResult. + */ + protected JavaToolResult createResult() { return new JavaToolResult(); } - protected String findJavaToolExecutable() - { - String command = javaToolName + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" ); - + /** + * @return The location of the java tool executable. + */ + protected String findJavaToolExecutable() { String executable = null; - if ( toolchain != null ) - { - executable = toolchain.findTool( javaToolName ); + if (toolchain != null) { + executable = findToolchainExecutable(); } - if ( executable == null ) - { - executable = findExecutable( command, System.getProperty( "java.home" ), "../bin", "bin", "../sh" ); + String command = javaToolName + (Os.isFamily(Os.FAMILY_WINDOWS) ? ".exe" : ""); + + if (executable == null) { + executable = findExecutable(command, System.getProperty("java.home"), "../bin", "bin", "../sh"); } - if ( executable == null ) - { + if (executable == null) { Map env = System.getenv(); - String[] variables = { "JDK_HOME", "JAVA_HOME" }; + String[] variables = {"JDK_HOME", "JAVA_HOME"}; - for ( String variable : variables ) - { - executable = findExecutable( command, env.get( variable ), "bin", "sh" ); - if ( executable != null ) - { + for (String variable : variables) { + executable = findExecutable(command, env.get(variable), "bin", "sh"); + if (executable != null) { break; } } } - if ( executable == null ) - { + if (executable == null) { executable = command; } return executable; } + /** + * Run toolchain.findTool( javaToolName ); through reflection to avoid compile dependency on + * Maven core. + */ + private String findToolchainExecutable() { + try { + Method m = toolchain.getClass().getMethod("findTool", String.class); + return (String) m.invoke(toolchain, javaToolName); + } catch (NoSuchMethodException e) { + // should not happen if toolchain is really a Toolchain object + getLogger().warn("unexpected NoSuchMethodException", e); + } catch (SecurityException e) { + // should not happen + getLogger().warn("unexpected SecurityException", e); + } catch (IllegalAccessException e) { + // should not happen + getLogger().warn("unexpected IllegalAccessException", e); + } catch (IllegalArgumentException e) { + // should not happen: parameter is the right type + getLogger().warn("unexpected IllegalArgumentException", e); + } catch (InvocationTargetException e) { + // not expected... + getLogger().warn("unexpected InvocationTargetException", e); + } + return null; + } + /** * Finds the specified command in any of the given sub directories of the specified JDK/JRE home directory. * @@ -271,17 +291,13 @@ protected String findJavaToolExecutable() * @param subDirs The sub directories of the home directory to search in, must not be null
. * @return The (absolute) path to the command if found,null
otherwise. */ - private String findExecutable( String command, String homeDir, String... subDirs ) - { + private String findExecutable(String command, String homeDir, String... subDirs) { String result = null; - if ( StringUtils.isNotEmpty( homeDir ) ) - { - for ( String subDir : subDirs ) - { - File file = new File( new File( homeDir, subDir ), command ); - - if ( file.isFile() ) - { + if (StringUtils.isNotEmpty(homeDir)) { + for (String subDir : subDirs) { + File file = new File(new File(homeDir, subDir), command); + + if (file.isFile()) { result = file.getAbsolutePath(); break; } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaToolRequest.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaToolRequest.java index 6e18178a..e2bcce36 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaToolRequest.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/AbstractJavaToolRequest.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,18 +16,17 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.javatool; import org.apache.maven.shared.utils.cli.StreamConsumer; /** * Abstract implementation of a {@link JavaToolRequest}. * - * @author Tony Chemit+ * @author Tony Chemit * @since 0.5 */ -public class AbstractJavaToolRequest - implements JavaToolRequest -{ +public class AbstractJavaToolRequest implements JavaToolRequest { /** * Optional system out stream consumer used by the commandline execution. @@ -44,32 +41,28 @@ public class AbstractJavaToolRequest /** * {@inheritDoc} */ - public StreamConsumer getSystemOutStreamConsumer() - { + public StreamConsumer getSystemOutStreamConsumer() { return systemOutStreamConsumer; } /** * {@inheritDoc} */ - public StreamConsumer getSystemErrorStreamConsumer() - { + public StreamConsumer getSystemErrorStreamConsumer() { return systemErrorStreamConsumer; } /** * {@inheritDoc} */ - public void setSystemOutStreamConsumer( StreamConsumer systemOutStreamConsumer ) - { + public void setSystemOutStreamConsumer(StreamConsumer systemOutStreamConsumer) { this.systemOutStreamConsumer = systemOutStreamConsumer; } /** * {@inheritDoc} */ - public void setSystemErrorStreamConsumer( StreamConsumer systemErrorStreamConsumer ) - { + public void setSystemErrorStreamConsumer(StreamConsumer systemErrorStreamConsumer) { this.systemErrorStreamConsumer = systemErrorStreamConsumer; } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaTool.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaTool.java index fe226f64..dd3ba021 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaTool.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaTool.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,30 +16,25 @@ * specific language governing permissions and limitations * under the License. */ - -import org.apache.maven.toolchain.Toolchain; +package org.apache.maven.shared.utils.cli.javatool; /** - * Describes a java tool, means a executable available in the jdk. - * - * The name of the tool ({@link #getJavaToolName()}) reflects the name of the executable that should exists as an - * executable in the jdk, like {@code jarsigner, keytool, javadoc, ...}. - * - * An abstract implementation of the {@link JavaTool} named {@link AbstractJavaTool} use the command line API to execute - * any user requests of this tool. + * Describes a java tool, means a executable available in the jdk.
+ *The name of the tool ({@link #getJavaToolName()}) reflects the name of the executable that should exists as an + * executable in the jdk, like {@code jarsigner, keytool, javadoc, ...}.
+ *An abstract implementation of the {@link JavaTool} named {@link AbstractJavaTool} use the command line API to + * execute any user requests of this tool.
* - * @author Tony Chemit+ * @author Tony Chemit * @since 0.5 - * @param + * @param Tool-specific request type */ -public interface JavaTool -{ +public interface JavaTool { /** - * Return the name of the java tool. This is exactly the name (without his extension) of the executable to - * find in the {@code jdk/bin} directory. - * - * For example: {@code jarsigner, keytool, javadoc, ...} + * Return the name of the java tool. This is exactly the name (without his extension) of the executable to + * find in the {@code jdk/bin} directory.
+ *For example: {@code jarsigner, keytool, javadoc, ...}
* * @return the name of the java tool. */ @@ -51,22 +44,21 @@ public interface JavaTool* Set an optional tool chain to find out the java tool executable location. * * @param toolchain optional tool chain to find out the java tool executable location. + * To avoid direct dependency on Maven core, this parameter is an Object that will be + * used as Toolchain through reflection */ - void setToolchain( Toolchain toolchain ); + void setToolchain(Object toolchain); /** - * Execute the input request and then returns the result of the execution. - * - * If could not create the java tool invocation, a {@link JavaToolException} will be thrown. - * - * If execution fails, then the result will have a none-zero {@link JavaToolResult#getExitCode()} and his + * Execute the input request and then returns the result of the execution.
+ *If could not create the java tool invocation, a {@link JavaToolException} will be thrown.
+ *If execution fails, then the result will have a none-zero {@link JavaToolResult#getExitCode()} and his * {@link JavaToolResult#getExecutionException()} will be filled with the error, otherwise the exist code will be - * zero. + * zero.
* * @param request the request to perform * @return the result of the tool execution * @throws JavaToolException if could not create the java tool invocation */ - JavaToolResult execute( Request request ) - throws JavaToolException; + JavaToolResult execute(Request request) throws JavaToolException; } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolException.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolException.java index 410dd011..ee3465d7 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolException.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolException.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,31 +16,34 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.javatool; /** - * Signals an error during the construction of the command line used to invoke java tool, e.g. illegal invocation - * arguments. - * - * This should not be confused with a failure of the invoked java tool build itself which will be reported by means of a - * non-zero exit code. + *Signals an error during the construction of the command line used to invoke java tool, e.g. illegal invocation + * arguments.
+ *This should not be confused with a failure of the invoked java tool build itself which will be reported by means + * of a non-zero exit code.
+ * + * @author Tony Chemit * - * @author Tony Chemit- * @version $Id$ * @see JavaToolResult#getExitCode() * @since 0.5 */ -public class JavaToolException - extends Exception -{ +public class JavaToolException extends Exception { private static final long serialVersionUID = 1L; - public JavaToolException( String message ) - { - super( message ); + /** + * @param message The message of the exception. + */ + public JavaToolException(String message) { + super(message); } - public JavaToolException( String message, Throwable cause ) - { - super( message, cause ); + /** + * @param message The message of the exception. + * @param cause The cause of the exception. + */ + public JavaToolException(String message, Throwable cause) { + super(message, cause); } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolRequest.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolRequest.java index 7227774c..4dc77874 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolRequest.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolRequest.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,33 +16,31 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.javatool; import org.apache.maven.shared.utils.cli.StreamConsumer; /** * Specifies the minimum parameters used to control a {@link JavaTool} invocation. * - * @author Tony Chemit + * @author Tony Chemit * @since 0.5 */ -public interface JavaToolRequest -{ +public interface JavaToolRequest { /** - * Gets the value of the {@code systemOutStreamConsumer} field. - * - * This option field if filled is used by the commandline tool to consume system ouput stream of the jarsigner - * command. + * Gets the value of the {@code systemOutStreamConsumer} field.
+ *This option field if filled is used by the commandline tool to consume system ouput stream of the jarsigner + * command.
* * @return the value of the {@code systemOutStreamConsumer} field. */ StreamConsumer getSystemOutStreamConsumer(); /** - * Gets the value of the {@code systemErrorStreamConsumer} field. - * - * This option field if filled is used by the commandline tool to consume system error stream of the jarsigner - * command. + *Gets the value of the {@code systemErrorStreamConsumer} field.
+ *This option field if filled is used by the commandline tool to consume system error stream of the jarsigner + * command.
* * @return the value of the {@code systemErrorStreamConsumer} field. */ @@ -55,12 +51,12 @@ public interface JavaToolRequest * * @param systemOutStreamConsumer the new value of the field {@code systemOutStreamConsumer}. */ - void setSystemOutStreamConsumer( StreamConsumer systemOutStreamConsumer ); + void setSystemOutStreamConsumer(StreamConsumer systemOutStreamConsumer); /** * Sets the new given value to the field {@code systemErrorStreamConsumer} of the request. * * @param systemErrorStreamConsumer the new value of the field {@code systemErrorStreamConsumer}. */ - void setSystemErrorStreamConsumer( StreamConsumer systemErrorStreamConsumer ); + void setSystemErrorStreamConsumer(StreamConsumer systemErrorStreamConsumer); } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolResult.java b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolResult.java index f3a6a77e..49ccd034 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolResult.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/javatool/JavaToolResult.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.javatool; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.javatool; import org.apache.maven.shared.utils.cli.CommandLineException; import org.apache.maven.shared.utils.cli.Commandline; @@ -25,11 +24,10 @@ /** * Describes the result of a {@link JavaTool} invocation. * - * @author Tony Chemit+ * @author Tony Chemit * @since 0.5 */ -public class JavaToolResult -{ +public class JavaToolResult { /** * The exception that prevented to execute the command line, will be null
if jarSigner could be * successfully started. @@ -52,8 +50,7 @@ public class JavaToolResult * * @return The exit code from the tool invocation. */ - public int getExitCode() - { + public int getExitCode() { return exitCode; } @@ -62,8 +59,7 @@ public int getExitCode() * * @return The command line used */ - public Commandline getCommandline() - { + public Commandline getCommandline() { return commandline; } @@ -73,8 +69,7 @@ public Commandline getCommandline() * @return The exception that prevented to invoke tool ornull
if the command line was successfully * processed by the operating system. */ - public CommandLineException getExecutionException() - { + public CommandLineException getExecutionException() { return executionException; } @@ -83,8 +78,7 @@ public CommandLineException getExecutionException() * * @param exitCode The exit code reported by the tool invocation. */ - public void setExitCode( int exitCode ) - { + public void setExitCode(int exitCode) { this.exitCode = exitCode; } @@ -93,8 +87,7 @@ public void setExitCode( int exitCode ) * * @param executionException The exception that prevented to execute the command line, may benull
. */ - public void setExecutionException( CommandLineException executionException ) - { + public void setExecutionException(CommandLineException executionException) { this.executionException = executionException; } @@ -103,8 +96,7 @@ public void setExecutionException( CommandLineException executionException ) * * @param commandline the commandline used to obtain this result */ - public void setCommandline( Commandline commandline ) - { + public void setCommandline(Commandline commandline) { this.commandline = commandline; } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java index 845e4a4d..0825bb45 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/BourneShell.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.shell; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,73 +16,67 @@ * specific language governing permissions and limitations * under the License. */ - +package org.apache.maven.shared.utils.cli.shell; import java.util.ArrayList; import java.util.List; + import org.apache.maven.shared.utils.Os; -import org.apache.maven.shared.utils.StringUtils; /** * @author Jason van Zyl */ -public class BourneShell - extends Shell -{ - private static final char[] BASH_QUOTING_TRIGGER_CHARS = - { ' ', '$', ';', '&', '|', '<', '>', '*', '?', '(', ')', '[', ']', '{', '}', '`' }; - - public BourneShell() - { - setShellCommand( "/bin/sh" ); - setArgumentQuoteDelimiter( '\'' ); - setExecutableQuoteDelimiter( '\"' ); - setSingleQuotedArgumentEscaped( true ); - setSingleQuotedExecutableEscaped( false ); - setQuotedExecutableEnabled( true ); +public class BourneShell extends Shell { + + /** + * Create instance of BourneShell. + */ + public BourneShell() { + setUnconditionalQuoting(true); + setShellCommand("/bin/sh"); + setArgumentQuoteDelimiter('\''); + setExecutableQuoteDelimiter('\''); + setSingleQuotedArgumentEscaped(true); + setSingleQuotedExecutableEscaped(false); + setQuotedExecutableEnabled(true); } /** * {@inheritDoc} */ - public String getExecutable() - { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) - { + public String getExecutable() { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { return super.getExecutable(); } - return unifyQuotes( super.getExecutable() ); + return quoteOneItem(super.getExecutable(), true); } - public ListgetShellArgsList() - { + /** {@inheritDoc} */ + public List getShellArgsList() { List shellArgs = new ArrayList (); List existingShellArgs = super.getShellArgsList(); - if ( ( existingShellArgs != null ) && !existingShellArgs.isEmpty() ) - { - shellArgs.addAll( existingShellArgs ); + if ((existingShellArgs != null) && !existingShellArgs.isEmpty()) { + shellArgs.addAll(existingShellArgs); } - shellArgs.add( "-c" ); + shellArgs.add("-c"); return shellArgs; } - public String[] getShellArgs() - { + /** {@inheritDoc} */ + public String[] getShellArgs() { String[] shellArgs = super.getShellArgs(); - if ( shellArgs == null ) - { + if (shellArgs == null) { shellArgs = new String[0]; } - if ( ( shellArgs.length > 0 ) && !shellArgs[shellArgs.length - 1].equals( "-c" ) ) - { + if ((shellArgs.length > 0) && !shellArgs[shellArgs.length - 1].equals("-c")) { String[] newArgs = new String[shellArgs.length + 1]; - System.arraycopy( shellArgs, 0, newArgs, 0, shellArgs.length ); + System.arraycopy(shellArgs, 0, newArgs, 0, shellArgs.length); newArgs[shellArgs.length] = "-c"; shellArgs = newArgs; @@ -93,57 +85,38 @@ public String[] getShellArgs() return shellArgs; } - protected String getExecutionPreamble() - { - if ( getWorkingDirectoryAsString() == null ) - { + /** {@inheritDoc} */ + protected String getExecutionPreamble() { + if (getWorkingDirectoryAsString() == null) { return null; } String dir = getWorkingDirectoryAsString(); - StringBuilder sb = new StringBuilder(); - sb.append( "cd " ); - - sb.append( unifyQuotes( dir ) ); - sb.append( " && " ); - - return sb.toString(); - } - protected char[] getQuotingTriggerChars() - { - return BASH_QUOTING_TRIGGER_CHARS; + return "cd " + quoteOneItem(dir, false) + " && "; } /** * Unify quotes in a path for the Bourne Shell.
- * *- * BourneShell.unifyQuotes(null) = null - * BourneShell.unifyQuotes("") = (empty) - * BourneShell.unifyQuotes("/test/quotedpath'abc") = /test/quotedpath\'abc - * BourneShell.unifyQuotes("/test/quoted path'abc") = "/test/quoted path'abc" - * BourneShell.unifyQuotes("/test/quotedpath\"abc") = "/test/quotedpath\"abc" - * BourneShell.unifyQuotes("/test/quoted path\"abc") = "/test/quoted path\"abc" - * BourneShell.unifyQuotes("/test/quotedpath\"'abc") = "/test/quotedpath\"'abc" - * BourneShell.unifyQuotes("/test/quoted path\"'abc") = "/test/quoted path\"'abc" + * BourneShell.quoteOneItem(null) = null + * BourneShell.quoteOneItem("") = '' + * BourneShell.quoteOneItem("/test/quotedpath'abc") = '/test/quotedpath'"'"'abc' + * BourneShell.quoteOneItem("/test/quoted path'abc") = '/test/quoted pat'"'"'habc' + * BourneShell.quoteOneItem("/test/quotedpath\"abc") = '/test/quotedpath"abc' + * BourneShell.quoteOneItem("/test/quoted path\"abc") = '/test/quoted path"abc' + * BourneShell.quoteOneItem("/test/quotedpath\"'abc") = '/test/quotedpath"'"'"'abc' + * BourneShell.quoteOneItem("/test/quoted path\"'abc") = '/test/quoted path"'"'"'abc' ** * @param path not null path. * @return the path unified correctly for the Bourne shell. */ - private static String unifyQuotes( String path ) - { - if ( path == null ) - { + protected String quoteOneItem(String path, boolean isExecutable) { + if (path == null) { return null; } - if ( path.indexOf( ' ' ) == -1 && path.indexOf( '\'' ) != -1 && path.indexOf( '"' ) == -1 ) - { - return StringUtils.escape( path ); - } - - return StringUtils.quoteAndEscape( path, '\"', BASH_QUOTING_TRIGGER_CHARS ); + return "'" + path.replace("'", "'\"'\"'") + "'"; } } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/CmdShell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/CmdShell.java index aeb1efd6..3d72e324 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/shell/CmdShell.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/CmdShell.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.shell; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,26 +16,25 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.cli.shell; import java.util.Arrays; import java.util.List; /** - *- * Implementation to call the CMD Shell present on Windows NT, 2000 and XP - *
+ * Implementation to call the CMD Shell present on Windows NT, 2000, XP, 7, 8, and 10. * * @author Carlos Sanchez - * + * */ -public class CmdShell - extends Shell -{ - public CmdShell() - { - setShellCommand( "cmd.exe" ); - setQuotedExecutableEnabled( true ); - setShellArgs( new String[]{ "/X", "/C" } ); +public class CmdShell extends Shell { + /** + * Create an instance of CmdShell. + */ + public CmdShell() { + setShellCommand("cmd.exe"); + setQuotedExecutableEnabled(true); + setShellArgs(new String[] {"/X", "/C"}); } /** @@ -50,7 +47,6 @@ public CmdShell() ** From cmd.exe /? output: *
- * ** If /C or /K is specified, then the remainder of the command line after * the switch is processed as a command line, where the following logic is @@ -73,20 +69,21 @@ public CmdShell() * remove the last quote character on the command line, preserving * any text after the last quote character. *- * ** Always quoting the entire command line, regardless of these conditions * appears to make Windows processes invoke successfully. *
+ * + * @param executable The executable. + * @param arguments The arguments for the executable. + * @return The resulting command line. */ - public ListgetCommandLine( String executable, String... arguments ) - { + public List getCommandLine(String executable, String... arguments) { StringBuilder sb = new StringBuilder(); - sb.append( '"' ); - sb.append( super.getCommandLine( executable, arguments ).get( 0 ) ); - sb.append( '"' ); + sb.append('"'); + sb.append(super.getCommandLine(executable, arguments).get(0)); + sb.append('"'); - return Arrays.asList( sb.toString() ); + return Arrays.asList(sb.toString()); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/CommandShell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/CommandShell.java index a26e7dae..f1b5cd42 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/shell/CommandShell.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/CommandShell.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.shell; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,23 +16,21 @@ * specific language governing permissions and limitations * under the License. */ - +package org.apache.maven.shared.utils.cli.shell; /** - * * Implementation to call the Command.com Shell present on Windows 95, 98 and Me - *
* * @author Carlos Sanchez - * + * @deprecated Windows ME is long dead. Update to Windows 10 and use {@link CmdShell}. */ -public class CommandShell - extends Shell -{ - public CommandShell() - { - setShellCommand( "command.com" ); - setShellArgs( new String[]{ "/C" } ); +@Deprecated +public class CommandShell extends Shell { + /** + * Create an instance. + */ + public CommandShell() { + setShellCommand("command.com"); + setShellArgs(new String[] {"/C"}); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java b/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java index 70dddd0d..c8208af3 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/shell/Shell.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.cli.shell; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,31 +16,29 @@ * specific language governing permissions and limitations * under the License. */ - +package org.apache.maven.shared.utils.cli.shell; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; + import org.apache.maven.shared.utils.StringUtils; /** - ** Class that abstracts the Shell functionality, - * with subclases for shells that behave particularly, like + * with subclasses for shells that behave particularly, like + * *
*
- * * * @author Carlos Sanchez - * + * */ -public class Shell - implements Cloneable -{ - private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = { ' ' }; +public class Shell implements Cloneable { + private static final char[] DEFAULT_QUOTING_TRIGGER_CHARS = {' '}; private String shellCommand; @@ -50,6 +46,8 @@ public class Shell private boolean quotedArgumentsEnabled = true; + private boolean unconditionalQuoting = false; + private String executable; private String workingDir; @@ -65,183 +63,172 @@ public class Shell private char exeQuoteDelimiter = '\"'; /** - * Set the command to execute the shell (eg. COMMAND.COM, /bin/bash,...) + * Set the command to execute the shell (e.g. COMMAND.COM, /bin/bash,...). * - * @param shellCommand The command + * @param shellCommand the command */ - void setShellCommand( String shellCommand ) - { + void setShellCommand(String shellCommand) { this.shellCommand = shellCommand; } /** - * Get the command to execute the shell + * Get the command to execute the shell. * - * @return The command + * @return the command */ - String getShellCommand() - { + String getShellCommand() { return shellCommand; } /** * Set the shell arguments when calling a command line (not the executable arguments) - * (eg. /X /C for CMD.EXE) + * (e.g. /X /C for CMD.EXE). * * @param shellArgs the arguments to the shell */ - void setShellArgs( String[] shellArgs ) - { + void setShellArgs(String[] shellArgs) { this.shellArgs.clear(); - this.shellArgs.addAll( Arrays.asList( shellArgs ) ); + this.shellArgs.addAll(Arrays.asList(shellArgs)); } /** * Get the shell arguments * - * @return The arguments + * @return the arguments */ - String[] getShellArgs() - { - if ( ( shellArgs == null ) || shellArgs.isEmpty() ) - { + String[] getShellArgs() { + if (shellArgs.isEmpty()) { return null; - } - else - { - return shellArgs.toArray( new String[shellArgs.size()] ); + } else { + return shellArgs.toArray(new String[0]); } } + protected String quoteOneItem(String inputString, boolean isExecutable) { + char[] escapeChars = getEscapeChars(isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped()); + return StringUtils.quoteAndEscape( + inputString, + isExecutable ? getExecutableQuoteDelimiter() : getArgumentQuoteDelimiter(), + escapeChars, + getQuotingTriggerChars(), + '\\', + unconditionalQuoting); + } + /** * Get the command line for the provided executable and arguments in this shell * - * @param executable executable that the shell has to call - * @param arguments arguments for the executable, not the shell - * @return List with one String object with executable and arguments quoted as needed + * @param executableParameter executable that the shell has to call + * @param argumentsParameter arguments for the executable, not the shell + * @return list with one String object with executable and arguments quoted as needed */ - List- *
command.com
- *
cmd.exe
getCommandLine( String executable, String... arguments ) - { - return getRawCommandLine( executable, arguments ); + List getCommandLine(String executableParameter, String... argumentsParameter) { + return getRawCommandLine(executableParameter, argumentsParameter); } - List getRawCommandLine( String executable, String... arguments ) - { - List commandLine = new ArrayList (); + /** + * @param executableParameter Executable + * @param argumentsParameter the arguments for the executable + * @return the list on command line + */ + List getRawCommandLine(String executableParameter, String... argumentsParameter) { + List commandLine = new ArrayList<>(); StringBuilder sb = new StringBuilder(); - if ( executable != null ) - { + if (executableParameter != null) { String preamble = getExecutionPreamble(); - if ( preamble != null ) - { - sb.append( preamble ); + if (preamble != null) { + sb.append(preamble); } - if ( isQuotedExecutableEnabled() ) - { - char[] escapeChars = - getEscapeChars( isSingleQuotedExecutableEscaped(), isDoubleQuotedExecutableEscaped() ); - - sb.append( StringUtils.quoteAndEscape( getExecutable(), getExecutableQuoteDelimiter(), escapeChars, - getQuotingTriggerChars(), '\\', false ) ); - } - else - { - sb.append( getExecutable() ); + if (isQuotedExecutableEnabled()) { + sb.append(quoteOneItem(executableParameter, true)); + } else { + sb.append(executableParameter); } } - for ( String argument : arguments ) - { - if ( sb.length() > 0 ) - { - sb.append( ' ' ); + for (String argument : argumentsParameter) { + if (sb.length() > 0) { + sb.append(' '); } - if ( isQuotedArgumentsEnabled() ) - { - char[] escapeChars = getEscapeChars( isSingleQuotedArgumentEscaped(), isDoubleQuotedArgumentEscaped() ); - - sb.append( StringUtils.quoteAndEscape( argument, getArgumentQuoteDelimiter(), escapeChars, - getQuotingTriggerChars(), '\\', false ) ); - } - else - { - sb.append( argument ); + if (isQuotedArgumentsEnabled()) { + sb.append(quoteOneItem(argument, false)); + } else { + sb.append(argument); } } - commandLine.add( sb.toString() ); + commandLine.add(sb.toString()); return commandLine; } - char[] getQuotingTriggerChars() - { + char[] getQuotingTriggerChars() { return DEFAULT_QUOTING_TRIGGER_CHARS; } - String getExecutionPreamble() - { + String getExecutionPreamble() { return null; } - char[] getEscapeChars( boolean includeSingleQuote, boolean includeDoubleQuote ) - { - StringBuilder buf = new StringBuilder( 2 ); - if ( includeSingleQuote ) - { - buf.append( '\'' ); + char[] getEscapeChars(boolean includeSingleQuote, boolean includeDoubleQuote) { + StringBuilder buf = new StringBuilder(2); + if (includeSingleQuote) { + buf.append('\''); } - if ( includeDoubleQuote ) - { - buf.append( '\"' ); + if (includeDoubleQuote) { + buf.append('\"'); } char[] result = new char[buf.length()]; - buf.getChars( 0, buf.length(), result, 0 ); + buf.getChars(0, buf.length(), result, 0); return result; } - protected boolean isDoubleQuotedArgumentEscaped() - { + /** + * @return false in all cases + */ + protected boolean isDoubleQuotedArgumentEscaped() { return false; } - protected boolean isSingleQuotedArgumentEscaped() - { + /** + * @return {@link #singleQuotedArgumentEscaped} + */ + protected boolean isSingleQuotedArgumentEscaped() { return singleQuotedArgumentEscaped; } - boolean isDoubleQuotedExecutableEscaped() - { + boolean isDoubleQuotedExecutableEscaped() { return false; } - boolean isSingleQuotedExecutableEscaped() - { + boolean isSingleQuotedExecutableEscaped() { return singleQuotedExecutableEscaped; } - void setArgumentQuoteDelimiter( char argQuoteDelimiter ) - { - this.argQuoteDelimiter = argQuoteDelimiter; + /** + * @param argQuoteDelimiterParameter {@link #argQuoteDelimiter} + */ + void setArgumentQuoteDelimiter(char argQuoteDelimiterParameter) { + this.argQuoteDelimiter = argQuoteDelimiterParameter; } - char getArgumentQuoteDelimiter() - { + char getArgumentQuoteDelimiter() { return argQuoteDelimiter; } - void setExecutableQuoteDelimiter( char exeQuoteDelimiter ) - { - this.exeQuoteDelimiter = exeQuoteDelimiter; + /** + * @param exeQuoteDelimiterParameter {@link #exeQuoteDelimiter} + */ + void setExecutableQuoteDelimiter(char exeQuoteDelimiterParameter) { + this.exeQuoteDelimiter = exeQuoteDelimiterParameter; } - char getExecutableQuoteDelimiter() - { + char getExecutableQuoteDelimiter() { return exeQuoteDelimiter; } @@ -253,119 +240,119 @@ char getExecutableQuoteDelimiter() * @return List of String objects, whose array version is suitable to be used as argument * of Runtime.getRuntime().exec() */ - public List getShellCommandLine( String... arguments ) - { + public List getShellCommandLine(String... arguments) { - List commandLine = new ArrayList (); + List commandLine = new ArrayList<>(); - if ( getShellCommand() != null ) - { - commandLine.add( getShellCommand() ); + if (getShellCommand() != null) { + commandLine.add(getShellCommand()); } - if ( getShellArgs() != null ) - { - commandLine.addAll( getShellArgsList() ); + if (getShellArgs() != null) { + commandLine.addAll(getShellArgsList()); } - commandLine.addAll( getCommandLine( getExecutable(), arguments ) ); + commandLine.addAll(getCommandLine(executable, arguments)); return commandLine; - } - List getShellArgsList() - { + List getShellArgsList() { return shellArgs; } - public void setQuotedArgumentsEnabled( boolean quotedArgumentsEnabled ) - { + /** + * @param quotedArgumentsEnabled {@link #quotedArgumentsEnabled} + */ + public void setQuotedArgumentsEnabled(boolean quotedArgumentsEnabled) { this.quotedArgumentsEnabled = quotedArgumentsEnabled; } - boolean isQuotedArgumentsEnabled() - { + boolean isQuotedArgumentsEnabled() { return quotedArgumentsEnabled; } - void setQuotedExecutableEnabled( boolean quotedExecutableEnabled ) - { + void setQuotedExecutableEnabled(boolean quotedExecutableEnabled) { this.quotedExecutableEnabled = quotedExecutableEnabled; } - boolean isQuotedExecutableEnabled() - { + boolean isQuotedExecutableEnabled() { return quotedExecutableEnabled; } /** * Sets the executable to run. + * @param executable The executable. */ - public void setExecutable( String executable ) - { - if ( ( executable == null ) || ( executable.length() == 0 ) ) - { + public void setExecutable(String executable) { + if ((executable == null) || (executable.length() == 0)) { return; } - this.executable = executable.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); + this.executable = executable.replace('/', File.separatorChar).replace('\\', File.separatorChar); } - public String getExecutable() - { + /** + * @return The executable. + */ + public String getExecutable() { return executable; } /** * Sets execution directory. + * @param path The path which should be used as working directory. */ - public void setWorkingDirectory( String path ) - { - if ( path != null ) - { - workingDir = path; + public void setWorkingDirectory(String path) { + if (path != null) { + this.workingDir = path; } } /** * Sets execution directory. + * + * @param workingDirectory the working directory */ - public void setWorkingDirectory( File workingDir ) - { - if ( workingDir != null ) - { - this.workingDir = workingDir.getAbsolutePath(); + public void setWorkingDirectory(File workingDirectory) { + if (workingDirectory != null) { + this.workingDir = workingDirectory.getAbsolutePath(); } } - public File getWorkingDirectory() - { - return workingDir == null ? null : new File( workingDir ); + /** + * @return the working directory + */ + public File getWorkingDirectory() { + return workingDir == null ? null : new File(workingDir); } - String getWorkingDirectoryAsString() - { + String getWorkingDirectoryAsString() { return workingDir; } - public Object clone() - { - throw new RuntimeException( "Do we ever clone this?" ); -/* Shell shell = new Shell(); + /** {@inheritDoc} */ + public Object clone() { + throw new RuntimeException("Do we ever clone this?"); + /* Shell shell = new Shell(); shell.setExecutable( getExecutable() ); shell.setWorkingDirectory( getWorkingDirectory() ); shell.setShellArgs( getShellArgs() ); return shell;*/ } - void setSingleQuotedArgumentEscaped( boolean singleQuotedArgumentEscaped ) - { + void setSingleQuotedArgumentEscaped(boolean singleQuotedArgumentEscaped) { this.singleQuotedArgumentEscaped = singleQuotedArgumentEscaped; } - void setSingleQuotedExecutableEscaped( boolean singleQuotedExecutableEscaped ) - { + void setSingleQuotedExecutableEscaped(boolean singleQuotedExecutableEscaped) { this.singleQuotedExecutableEscaped = singleQuotedExecutableEscaped; } + public boolean isUnconditionalQuoting() { + return unconditionalQuoting; + } + + public void setUnconditionalQuoting(boolean unconditionalQuoting) { + this.unconditionalQuoting = unconditionalQuoting; + } } diff --git a/src/main/java/org/apache/maven/shared/utils/introspection/ClassMap.java b/src/main/java/org/apache/maven/shared/utils/introspection/ClassMap.java index 252da22d..17f2593f 100644 --- a/src/main/java/org/apache/maven/shared/utils/introspection/ClassMap.java +++ b/src/main/java/org/apache/maven/shared/utils/introspection/ClassMap.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.introspection; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.introspection; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -33,13 +32,10 @@ * @author Bob McWhirter * @author Attila Szegedi * @author Geir Magnusson Jr. - * @version $Id$ + * */ -public class ClassMap -{ - private static final class CacheMiss - { - } +public class ClassMap { + private static final class CacheMiss {} private static final CacheMiss CACHE_MISS = new CacheMiss(); @@ -49,7 +45,6 @@ private static final class CacheMiss * Class passed into the constructor used to as * the basis for the Method map. */ - private final Class> clazz; /** @@ -62,9 +57,9 @@ private static final class CacheMiss /** * Standard constructor + * @param clazz The class. */ - public ClassMap( Class> clazz ) - { + public ClassMap(Class> clazz) { this.clazz = clazz; populateMethodCache(); } @@ -72,58 +67,48 @@ public ClassMap( Class> clazz ) /** * @return the class object whose methods are cached by this map. */ - Class> getCachedClass() - { + Class> getCachedClass() { return clazz; } /** - * Find a Method using the methodKey - * provided. - * - * Look in the methodMap for an entry. If found, + * Find a Method using the methodKey provided.
+ *Look in the methodMap for an entry. If found, * it'll either be a CACHE_MISS, in which case we * simply give up, or it'll be a Method, in which - * case, we return it. - *
- * If nothing is found, then we must actually go - * and introspect the method from the MethodMap. + * case, we return it. + *If nothing is found, then we must actually go + * and introspect the method from the MethodMap.
+ * @param name Method name. + * @param params Method parameters. + * @return The found method. + * @throws MethodMap.AmbiguousException in case of duplicate methods. */ - public Method findMethod( String name, Object... params ) - throws MethodMap.AmbiguousException - { - String methodKey = makeMethodKey( name, params ); - Object cacheEntry = methodCache.get( methodKey ); - - if ( cacheEntry == CACHE_MISS ) - { + public Method findMethod(String name, Object... params) throws MethodMap.AmbiguousException { + String methodKey = makeMethodKey(name, params); + Object cacheEntry = methodCache.get(methodKey); + + if (cacheEntry == CACHE_MISS) { return null; } - if ( cacheEntry == null ) - { - try - { - cacheEntry = methodMap.find( name, params ); - } - catch ( MethodMap.AmbiguousException ae ) - { + if (cacheEntry == null) { + try { + cacheEntry = methodMap.find(name, params); + } catch (MethodMap.AmbiguousException ae) { /* * that's a miss :) */ - methodCache.put( methodKey, CACHE_MISS ); + methodCache.put(methodKey, CACHE_MISS); throw ae; } - if ( cacheEntry == null ) - { - methodCache.put( methodKey, CACHE_MISS ); - } - else - { - methodCache.put( methodKey, cacheEntry ); + if (cacheEntry == null) { + methodCache.put(methodKey, CACHE_MISS); + } else { + methodCache.put(methodKey, cacheEntry); } } @@ -137,28 +122,26 @@ public Method findMethod( String name, Object... params ) * are taken from all the public methods * that our class provides. */ - private void populateMethodCache() - { + private void populateMethodCache() { /* * get all publicly accessible methods */ - Method[] methods = getAccessibleMethods( clazz ); + Method[] methods = getAccessibleMethods(clazz); /* * map and cache them */ - for ( Method method : methods ) - { + for (Method method : methods) { /* * now get the 'public method', the method declared by a * public interface or class. (because the actual implementing * class may be a facade... */ - Method publicMethod = getPublicMethod( method ); + Method publicMethod = getPublicMethod(method); /* * it is entirely possible that there is no public method for @@ -167,10 +150,9 @@ private void populateMethodCache() * in which case, ignore it. Otherwise, map and cache */ - if ( publicMethod != null ) - { - methodMap.add( publicMethod ); - methodCache.put( makeMethodKey( publicMethod ), publicMethod ); + if (publicMethod != null) { + methodMap.add(publicMethod); + methodCache.put(makeMethodKey(publicMethod), publicMethod); } } } @@ -180,78 +162,55 @@ private void populateMethodCache() * the concatenation of the name and the * types of the method parameters. */ - private String makeMethodKey( Method method ) - { + private String makeMethodKey(Method method) { Class>[] parameterTypes = method.getParameterTypes(); - StringBuilder methodKey = new StringBuilder( method.getName() ); + StringBuilder methodKey = new StringBuilder(method.getName()); - for ( Class> parameterType : parameterTypes ) - { + for (Class> parameterType : parameterTypes) { /* * If the argument type is primitive then we want * to convert our primitive type signature to the * corresponding Object type so introspection for * methods with primitive types will work correctly. */ - if ( parameterType.isPrimitive() ) - { - if ( parameterType.equals( Boolean.TYPE ) ) - { - methodKey.append( "java.lang.Boolean" ); - } - else if ( parameterType.equals( Byte.TYPE ) ) - { - methodKey.append( "java.lang.Byte" ); + if (parameterType.isPrimitive()) { + if (parameterType.equals(Boolean.TYPE)) { + methodKey.append("java.lang.Boolean"); + } else if (parameterType.equals(Byte.TYPE)) { + methodKey.append("java.lang.Byte"); + } else if (parameterType.equals(Character.TYPE)) { + methodKey.append("java.lang.Character"); + } else if (parameterType.equals(Double.TYPE)) { + methodKey.append("java.lang.Double"); + } else if (parameterType.equals(Float.TYPE)) { + methodKey.append("java.lang.Float"); + } else if (parameterType.equals(Integer.TYPE)) { + methodKey.append("java.lang.Integer"); + } else if (parameterType.equals(Long.TYPE)) { + methodKey.append("java.lang.Long"); + } else if (parameterType.equals(Short.TYPE)) { + methodKey.append("java.lang.Short"); } - else if ( parameterType.equals( Character.TYPE ) ) - { - methodKey.append( "java.lang.Character" ); - } - else if ( parameterType.equals( Double.TYPE ) ) - { - methodKey.append( "java.lang.Double" ); - } - else if ( parameterType.equals( Float.TYPE ) ) - { - methodKey.append( "java.lang.Float" ); - } - else if ( parameterType.equals( Integer.TYPE ) ) - { - methodKey.append( "java.lang.Integer" ); - } - else if ( parameterType.equals( Long.TYPE ) ) - { - methodKey.append( "java.lang.Long" ); - } - else if ( parameterType.equals( Short.TYPE ) ) - { - methodKey.append( "java.lang.Short" ); - } - } - else - { - methodKey.append( parameterType.getName() ); + } else { + methodKey.append(parameterType.getName()); } } return methodKey.toString(); } - private static String makeMethodKey( String method, Object... params ) - { - StringBuilder methodKey = new StringBuilder().append( method ); + private static String makeMethodKey(String method, Object... params) { + StringBuilder methodKey = new StringBuilder().append(method); - for ( Object param : params ) - { + for (Object param : params) { Object arg = param; - if ( arg == null ) - { + if (arg == null) { arg = OBJECT; } - methodKey.append( arg.getClass().getName() ); + methodKey.append(arg.getClass().getName()); } return methodKey.toString(); @@ -263,8 +222,7 @@ private static String makeMethodKey( String method, Object... params ) * from public superclasses and interfaces (if they exist). Basically * upcasts every method to the nearest acccessible method. */ - private static Method[] getAccessibleMethods( Class> clazz ) - { + private static Method[] getAccessibleMethods(Class> clazz) { Method[] methods = clazz.getMethods(); /* @@ -272,8 +230,7 @@ private static Method[] getAccessibleMethods( Class> clazz ) * clazz is public */ - if ( Modifier.isPublic( clazz.getModifiers() ) ) - { + if (Modifier.isPublic(clazz.getModifiers())) { return methods; } @@ -283,27 +240,23 @@ private static Method[] getAccessibleMethods( Class> clazz ) MethodInfo[] methodInfos = new MethodInfo[methods.length]; - for ( int i = methods.length; i-- > 0; ) - { - methodInfos[i] = new MethodInfo( methods[i] ); + for (int i = methods.length; i-- > 0; ) { + methodInfos[i] = new MethodInfo(methods[i]); } - int upcastCount = getAccessibleMethods( clazz, methodInfos, 0 ); + int upcastCount = getAccessibleMethods(clazz, methodInfos, 0); /* * Reallocate array in case some method had no accessible counterpart. */ - if ( upcastCount < methods.length ) - { + if (upcastCount < methods.length) { methods = new Method[upcastCount]; } int j = 0; - for ( MethodInfo methodInfo : methodInfos ) - { - if ( methodInfo.upcast ) - { + for (MethodInfo methodInfo : methodInfos) { + if (methodInfo.upcast) { methods[j++] = methodInfo.method; } } @@ -319,8 +272,7 @@ private static Method[] getAccessibleMethods( Class> clazz ) * @param upcastCount current number of methods we have matched * @return count of matched methods */ - private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfos, int upcastCount ) - { + private static int getAccessibleMethods(Class> clazz, MethodInfo[] methodInfos, int upcastCount) { int l = methodInfos.length; /* @@ -328,22 +280,16 @@ private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfo * 'non-upcasted' methods to see if we have a match */ - if ( Modifier.isPublic( clazz.getModifiers() ) ) - { - for ( int i = 0; i < l && upcastCount < l; ++i ) - { - try - { + if (Modifier.isPublic(clazz.getModifiers())) { + for (int i = 0; i < l && upcastCount < l; ++i) { + try { MethodInfo methodInfo = methodInfos[i]; - if ( !methodInfo.upcast ) - { - methodInfo.tryUpcasting( clazz ); + if (!methodInfo.upcast) { + methodInfo.tryUpcasting(clazz); upcastCount++; } - } - catch ( NoSuchMethodException e ) - { + } catch (NoSuchMethodException e) { /* * Intentionally ignored - it means * it wasn't found in the current class @@ -355,8 +301,7 @@ private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfo * Short circuit if all methods were upcast */ - if ( upcastCount == l ) - { + if (upcastCount == l) { return upcastCount; } } @@ -367,16 +312,14 @@ private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfo Class> superclazz = clazz.getSuperclass(); - if ( superclazz != null ) - { - upcastCount = getAccessibleMethods( superclazz, methodInfos, upcastCount ); + if (superclazz != null) { + upcastCount = getAccessibleMethods(superclazz, methodInfos, upcastCount); /* * Short circuit if all methods were upcast */ - if ( upcastCount == l ) - { + if (upcastCount == l) { return upcastCount; } } @@ -389,16 +332,14 @@ private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfo Class>[] interfaces = clazz.getInterfaces(); - for ( int i = interfaces.length; i-- > 0; ) - { - upcastCount = getAccessibleMethods( interfaces[i], methodInfos, upcastCount ); + for (int i = interfaces.length; i-- > 0; ) { + upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount); /* * Short circuit if all methods were upcast */ - if ( upcastCount == l ) - { + if (upcastCount == l) { return upcastCount; } } @@ -417,8 +358,7 @@ private static int getAccessibleMethods( Class> clazz, MethodInfo[] methodInfo * method is itself declared by a public class, this method is an identity * function. */ - private static Method getPublicMethod( Method method ) - { + private static Method getPublicMethod(Method method) { Class> clazz = method.getDeclaringClass(); /* @@ -426,12 +366,11 @@ private static Method getPublicMethod( Method method ) * class is public. */ - if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 ) - { + if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) { return method; } - return getPublicMethod( clazz, method.getName(), method.getParameterTypes() ); + return getPublicMethod(clazz, method.getName(), method.getParameterTypes()); } /** @@ -442,20 +381,15 @@ private static Method getPublicMethod( Method method ) * @param name the name of the method * @param paramTypes the classes of method parameters */ - private static Method getPublicMethod( Class> clazz, String name, Class>... paramTypes ) - { + private static Method getPublicMethod(Class> clazz, String name, Class>... paramTypes) { /* * if this class is public, then try to get it */ - if ( ( clazz.getModifiers() & Modifier.PUBLIC ) != 0 ) - { - try - { - return clazz.getMethod( name, paramTypes ); - } - catch ( NoSuchMethodException e ) - { + if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) { + try { + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { /* * If the class does not have the method, then neither its * superclass nor any of its interfaces has it so quickly return @@ -471,12 +405,10 @@ private static Method getPublicMethod( Class> clazz, String name, Class>... Class> superclazz = clazz.getSuperclass(); - if ( superclazz != null ) - { - Method superclazzMethod = getPublicMethod( superclazz, name, paramTypes ); + if (superclazz != null) { + Method superclazzMethod = getPublicMethod(superclazz, name, paramTypes); - if ( superclazzMethod != null ) - { + if (superclazzMethod != null) { return superclazzMethod; } } @@ -487,12 +419,10 @@ private static Method getPublicMethod( Class> clazz, String name, Class>... Class>[] interfaces = clazz.getInterfaces(); - for ( Class> anInterface : interfaces ) - { - Method interfaceMethod = getPublicMethod( anInterface, name, paramTypes ); + for (Class> anInterface : interfaces) { + Method interfaceMethod = getPublicMethod(anInterface, name, paramTypes); - if ( interfaceMethod != null ) - { + if (interfaceMethod != null) { return interfaceMethod; } } @@ -503,8 +433,7 @@ private static Method getPublicMethod( Class> clazz, String name, Class>... /** * Used for the iterative discovery process for public methods. */ - private static final class MethodInfo - { + private static final class MethodInfo { Method method; String name; @@ -513,18 +442,15 @@ private static final class MethodInfo boolean upcast; - MethodInfo( Method method ) - { + MethodInfo(Method method) { this.method = null; name = method.getName(); parameterTypes = method.getParameterTypes(); upcast = false; } - void tryUpcasting( Class> clazz ) - throws NoSuchMethodException - { - method = clazz.getMethod( name, parameterTypes ); + void tryUpcasting(Class> clazz) throws NoSuchMethodException { + method = clazz.getMethod(name, parameterTypes); name = null; parameterTypes = null; upcast = true; diff --git a/src/main/java/org/apache/maven/shared/utils/introspection/IntrospectionException.java b/src/main/java/org/apache/maven/shared/utils/introspection/IntrospectionException.java index 18ffe383..bf751cc9 100644 --- a/src/main/java/org/apache/maven/shared/utils/introspection/IntrospectionException.java +++ b/src/main/java/org/apache/maven/shared/utils/introspection/IntrospectionException.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.introspection; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,19 +16,20 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.introspection; + +class IntrospectionException extends Exception { -class IntrospectionException - extends Exception -{ + /** + * + */ + private static final long serialVersionUID = -6090771282553728784L; - public IntrospectionException( String message ) - { - super( message ); + IntrospectionException(String message) { + super(message); } - public IntrospectionException( Throwable cause ) - { - super( cause ); + IntrospectionException(Throwable cause) { + super(cause); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/introspection/MethodMap.java b/src/main/java/org/apache/maven/shared/utils/introspection/MethodMap.java index 4d2521a9..edafdfb1 100644 --- a/src/main/java/org/apache/maven/shared/utils/introspection/MethodMap.java +++ b/src/main/java/org/apache/maven/shared/utils/introspection/MethodMap.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.introspection; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.introspection; import java.lang.reflect.Method; import java.util.ArrayList; @@ -33,10 +32,9 @@ * @author Christoph Reck * @author Geir Magnusson Jr. * @author Attila Szegedi - * @version $Id$ + * */ -class MethodMap -{ +class MethodMap { private static final int MORE_SPECIFIC = 0; private static final int LESS_SPECIFIC = 1; @@ -55,19 +53,17 @@ class MethodMap * * @param method The method */ - void add( Method method ) - { + void add(Method method) { String methodName = method.getName(); - Listl = get( methodName ); + List l = get(methodName); - if ( l == null ) - { + if (l == null) { l = new ArrayList (); - methodByNameMap.put( methodName, l ); + methodByNameMap.put(methodName, l); } - l.add( method ); + l.add(method); } /** @@ -76,9 +72,8 @@ void add( Method method ) * @param key The name of the method. * @return List list of methods */ - List get( String key ) - { - return methodByNameMap.get( key ); + List get(String key) { + return methodByNameMap.get(key); } /** @@ -109,21 +104,17 @@ List get( String key ) * @throws AmbiguousException if there is more than one maximally * specific applicable method */ - Method find( String methodName, Object... args ) - throws AmbiguousException - { - List methodList = get( methodName ); + Method find(String methodName, Object... args) throws AmbiguousException { + List methodList = get(methodName); - if ( methodList == null ) - { + if (methodList == null) { return null; } int l = args.length; Class>[] classes = new Class[l]; - for ( int i = 0; i < l; ++i ) - { + for (int i = 0; i < l; ++i) { Object arg = args[i]; /* @@ -133,31 +124,26 @@ Method find( String methodName, Object... args ) classes[i] = arg == null ? null : arg.getClass(); } - return getMostSpecific( methodList, classes ); + return getMostSpecific(methodList, classes); } /** * simple distinguishable exception, used when * we run across ambiguous overloading */ - static class AmbiguousException - extends Exception - { - } + static class AmbiguousException extends Exception { + private static final long serialVersionUID = 751688436639650618L; + } - private static Method getMostSpecific( List methods, Class>... classes ) - throws AmbiguousException - { - LinkedList applicables = getApplicables( methods, classes ); + private static Method getMostSpecific(List methods, Class>... classes) throws AmbiguousException { + LinkedList applicables = getApplicables(methods, classes); - if ( applicables.isEmpty() ) - { + if (applicables.isEmpty()) { return null; } - if ( applicables.size() == 1 ) - { + if (applicables.size() == 1) { return applicables.getFirst(); } @@ -169,17 +155,14 @@ private static Method getMostSpecific( List methods, Class>... classes LinkedList maximals = new LinkedList (); - for ( Method app : applicables ) - { + for (Method app : applicables) { Class>[] appArgs = app.getParameterTypes(); boolean lessSpecific = false; - for ( Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); ) - { + for (Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); ) { Method max = maximal.next(); - switch ( moreSpecific( appArgs, max.getParameterTypes() ) ) - { + switch (moreSpecific(appArgs, max.getParameterTypes())) { case MORE_SPECIFIC: /* * This method is more specific than the previously @@ -204,14 +187,12 @@ private static Method getMostSpecific( List methods, Class>... classes } } - if ( !lessSpecific ) - { - maximals.addLast( app ); + if (!lessSpecific) { + maximals.addLast(app); } } - if ( maximals.size() > 1 ) - { + if (maximals.size() > 1) { // We have more than one maximally specific method throw new AmbiguousException(); } @@ -228,24 +209,19 @@ private static Method getMostSpecific( List methods, Class>... classes * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if * c1 is less specific than c2, INCOMPARABLE if they are incomparable. */ - private static int moreSpecific( Class>[] c1, Class>[] c2 ) - { + private static int moreSpecific(Class>[] c1, Class>[] c2) { boolean c1MoreSpecific = false; boolean c2MoreSpecific = false; - for ( int i = 0; i < c1.length; ++i ) - { - if ( c1[i] != c2[i] ) - { - c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible( c2[i], c1[i] ); - c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible( c1[i], c2[i] ); + for (int i = 0; i < c1.length; ++i) { + if (c1[i] != c2[i]) { + c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible(c2[i], c1[i]); + c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible(c1[i], c2[i]); } } - if ( c1MoreSpecific ) - { - if ( c2MoreSpecific ) - { + if (c1MoreSpecific) { + if (c2MoreSpecific) { /* * Incomparable due to cross-assignable arguments (i.e. * foo(String, Object) vs. foo(Object, String)) @@ -257,8 +233,7 @@ private static int moreSpecific( Class>[] c1, Class>[] c2 ) return MORE_SPECIFIC; } - if ( c2MoreSpecific ) - { + if (c2MoreSpecific) { return LESS_SPECIFIC; } @@ -279,15 +254,12 @@ private static int moreSpecific( Class>[] c1, Class>[] c2 ) * formal and actual arguments matches, and argument types are assignable * to formal types through a method invocation conversion). */ - private static LinkedList getApplicables( List methods, Class>... classes ) - { + private static LinkedList getApplicables(List methods, Class>... classes) { LinkedList list = new LinkedList (); - for ( Method method : methods ) - { - if ( isApplicable( method, classes ) ) - { - list.add( method ); + for (Method method : methods) { + if (isApplicable(method, classes)) { + list.add(method); } } return list; @@ -301,19 +273,15 @@ private static LinkedList getApplicables( List methods, Class> * @param classes The arguments * @return true if the method applies to the parameter types */ - private static boolean isApplicable( Method method, Class>... classes ) - { + private static boolean isApplicable(Method method, Class>... classes) { Class>[] methodArgs = method.getParameterTypes(); - if ( methodArgs.length != classes.length ) - { + if (methodArgs.length != classes.length) { return false; } - for ( int i = 0; i < classes.length; ++i ) - { - if ( !isMethodInvocationConvertible( methodArgs[i], classes[i] ) ) - { + for (int i = 0; i < classes.length; ++i) { + if (!isMethodInvocationConvertible(methodArgs[i], classes[i])) { return false; } } @@ -339,13 +307,11 @@ private static boolean isApplicable( Method method, Class>... classes ) * type or an object type of a primitive type that can be converted to * the formal type. */ - private static boolean isMethodInvocationConvertible( Class> formal, Class> actual ) - { + private static boolean isMethodInvocationConvertible(Class> formal, Class> actual) { /* * if it's a null, it means the arg was null */ - if ( actual == null && !formal.isPrimitive() ) - { + if (actual == null && !formal.isPrimitive()) { return true; } @@ -353,8 +319,7 @@ private static boolean isMethodInvocationConvertible( Class> formal, Class> * Check for identity or widening reference conversion */ - if ( actual != null && formal.isAssignableFrom( actual ) ) - { + if (actual != null && formal.isAssignableFrom(actual)) { return true; } @@ -363,45 +328,44 @@ private static boolean isMethodInvocationConvertible( Class> formal, Class> * actual parameters are never primitives. */ - if ( formal.isPrimitive() ) - { - if ( formal == Boolean.TYPE && actual == Boolean.class ) - { + if (formal.isPrimitive()) { + if (formal == Boolean.TYPE && actual == Boolean.class) { return true; } - if ( formal == Character.TYPE && actual == Character.class ) - { + if (formal == Character.TYPE && actual == Character.class) { return true; } - if ( formal == Byte.TYPE && actual == Byte.class ) - { + if (formal == Byte.TYPE && actual == Byte.class) { return true; } - if ( formal == Short.TYPE && ( actual == Short.class || actual == Byte.class ) ) - { + if (formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) { return true; } - if ( formal == Integer.TYPE - && ( actual == Integer.class || actual == Short.class || actual == Byte.class ) ) - { + if (formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) { return true; } - if ( formal == Long.TYPE - && ( actual == Long.class || actual == Integer.class || actual == Short.class - || actual == Byte.class ) ) - { + if (formal == Long.TYPE + && (actual == Long.class + || actual == Integer.class + || actual == Short.class + || actual == Byte.class)) { return true; } - if ( formal == Float.TYPE - && ( actual == Float.class || actual == Long.class || actual == Integer.class - || actual == Short.class || actual == Byte.class ) ) - { + if (formal == Float.TYPE + && (actual == Float.class + || actual == Long.class + || actual == Integer.class + || actual == Short.class + || actual == Byte.class)) { return true; } - if ( formal == Double.TYPE - && ( actual == Double.class || actual == Float.class || actual == Long.class || actual == Integer.class - || actual == Short.class || actual == Byte.class ) ) - { + if (formal == Double.TYPE + && (actual == Double.class + || actual == Float.class + || actual == Long.class + || actual == Integer.class + || actual == Short.class + || actual == Byte.class)) { return true; } } @@ -423,13 +387,11 @@ private static boolean isMethodInvocationConvertible( Class> formal, Class> * or formal and actual are both primitive types and actual can be * subject to widening conversion to formal. */ - private static boolean isStrictMethodInvocationConvertible( Class> formal, Class> actual ) - { + private static boolean isStrictMethodInvocationConvertible(Class> formal, Class> actual) { /* * we shouldn't get a null into, but if so */ - if ( actual == null && !formal.isPrimitive() ) - { + if (actual == null && !formal.isPrimitive()) { return true; } @@ -437,8 +399,7 @@ private static boolean isStrictMethodInvocationConvertible( Class> formal, Cla * Check for identity or widening reference conversion */ - if ( formal.isAssignableFrom( actual ) ) - { + if (formal.isAssignableFrom(actual)) { return true; } @@ -446,29 +407,26 @@ private static boolean isStrictMethodInvocationConvertible( Class> formal, Cla * Check for widening primitive conversion. */ - if ( formal.isPrimitive() ) - { - if ( formal == Short.TYPE && ( actual == Byte.TYPE ) ) - { + if (formal.isPrimitive()) { + if (formal == Short.TYPE && (actual == Byte.TYPE)) { return true; } - if ( formal == Integer.TYPE && ( actual == Short.TYPE || actual == Byte.TYPE ) ) - { + if (formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) { return true; } - if ( formal == Long.TYPE && ( actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE ) ) - { + if (formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { return true; } - if ( formal == Float.TYPE - && ( actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE ) ) - { + if (formal == Float.TYPE + && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { return true; } - if ( formal == Double.TYPE - && ( actual == Float.TYPE || actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE - || actual == Byte.TYPE ) ) - { + if (formal == Double.TYPE + && (actual == Float.TYPE + || actual == Long.TYPE + || actual == Integer.TYPE + || actual == Short.TYPE + || actual == Byte.TYPE)) { return true; } } diff --git a/src/main/java/org/apache/maven/shared/utils/introspection/ReflectionValueExtractor.java b/src/main/java/org/apache/maven/shared/utils/introspection/ReflectionValueExtractor.java index 555c81dd..7e212778 100644 --- a/src/main/java/org/apache/maven/shared/utils/introspection/ReflectionValueExtractor.java +++ b/src/main/java/org/apache/maven/shared/utils/introspection/ReflectionValueExtractor.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.introspection; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,10 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.introspection; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; @@ -29,24 +31,18 @@ import org.apache.maven.shared.utils.StringUtils; import org.apache.maven.shared.utils.introspection.MethodMap.AmbiguousException; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - - /** * Using simple dotted expressions to extract the values from an Object instance, * For example we might want to extract a value like:
- * *project.build.sourceDirectory
The implementation supports indexed, nested and mapped properties similar to the JSP way.
* * @author Jason van Zyl * @author Vincent Siveton - * @version $Id$ + * * @see * http://struts.apache.org/1.x/struts-taglib/indexedprops.html */ -public class ReflectionValueExtractor -{ +public class ReflectionValueExtractor { private static final Class>[] CLASS_ARGS = new Class[0]; private static final Object[] OBJECT_ARGS = new Object[0]; @@ -70,123 +66,105 @@ public class ReflectionValueExtractor static final char MAPPED_END = ')'; - static class Tokenizer - { + static class Tokenizer { final String expression; int idx; - public Tokenizer( String expression ) - { + Tokenizer(String expression) { this.expression = expression; } - public int peekChar() - { - return idx < expression.length() ? expression.charAt( idx ) : EOF; + public int peekChar() { + return idx < expression.length() ? expression.charAt(idx) : EOF; } - public int skipChar() - { - return idx < expression.length() ? expression.charAt( idx++ ) : EOF; + public int skipChar() { + return idx < expression.length() ? expression.charAt(idx++) : EOF; } - public String nextToken( char delimiter ) - { + public String nextToken(char delimiter) { int start = idx; - while ( idx < expression.length() && delimiter != expression.charAt( idx ) ) - { + while (idx < expression.length() && delimiter != expression.charAt(idx)) { idx++; } // delimiter MUST be present - if ( idx <= start || idx >= expression.length() ) - { + if (idx <= start || idx >= expression.length()) { return null; } - return expression.substring( start, idx++ ); + return expression.substring(start, idx++); } - public String nextPropertyName() - { + public String nextPropertyName() { final int start = idx; - while ( idx < expression.length() && Character.isJavaIdentifierPart( expression.charAt( idx ) ) ) - { + while (idx < expression.length() && Character.isJavaIdentifierPart(expression.charAt(idx))) { idx++; } // property name does not require delimiter - if ( idx <= start || idx > expression.length() ) - { + if (idx <= start || idx > expression.length()) { return null; } - return expression.substring( start, idx ); + return expression.substring(start, idx); } - public int getPosition() - { + public int getPosition() { return idx < expression.length() ? idx : EOF; } // to make tokenizer look pretty in debugger @Override - public String toString() - { - return idx < expression.length() ? expression.substring( idx ) : ""; + public String toString() { + return idx < expression.length() ? expression.substring(idx) : " "; } } - private ReflectionValueExtractor() - { - } + private ReflectionValueExtractor() {} /** * The implementation supports indexed, nested and mapped properties.
- * **
- nested properties should be defined by a dot, i.e. "user.address.street"
*- indexed properties (java.util.List or array instance) should be contains
*(\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"- mapped properties should be contains
- *(\\w+)\\((.+)\\)
pattern, * i.e. "user.addresses(myAddress).street"+ *
* * @param expression not null expression * @param root not null object * @return the object defined by the expression * @throws IntrospectionException if any */ - public static Object evaluate( @Nonnull String expression, @Nullable Object root ) - throws IntrospectionException - { - return evaluate( expression, root, true ); + public static Object evaluate(@Nonnull String expression, @Nullable Object root) throws IntrospectionException { + return evaluate(expression, root, true); } /** ** The implementation supports indexed, nested and mapped properties. *
- * **
- nested properties should be defined by a dot, i.e. "user.address.street"
*- indexed properties (java.util.List or array instance) should be contains
*(\\w+)\\[(\\d+)\\]
* pattern, i.e. "user.addresses[1].street"- mapped properties should be contains
- *(\\w+)\\((.+)\\)
pattern, i.e. * "user.addresses(myAddress).street"+ *
* * @param expression not null expression * @param root not null object + * @param trimRootToken trim root token yes/no. * @return the object defined by the expression * @throws IntrospectionException if any */ - public static Object evaluate( @Nonnull String expression, @Nullable Object root, boolean trimRootToken ) - throws IntrospectionException - { + public static Object evaluate(@Nonnull String expression, @Nullable Object root, boolean trimRootToken) + throws IntrospectionException { Object value = root; // ---------------------------------------------------------------------- @@ -194,46 +172,45 @@ public static Object evaluate( @Nonnull String expression, @Nullable Object root // MavenProject instance. // ---------------------------------------------------------------------- - if ( StringUtils.isEmpty( expression ) || !Character.isJavaIdentifierStart( expression.charAt( 0 ) ) ) - { + if (StringUtils.isEmpty(expression) || !Character.isJavaIdentifierStart(expression.charAt(0))) { return null; } - boolean hasDots = expression.indexOf( PROPERTY_START ) >= 0; + boolean hasDots = expression.indexOf(PROPERTY_START) >= 0; final Tokenizer tokenizer; - if ( trimRootToken && hasDots ) - { - tokenizer = new Tokenizer( expression ); + if (trimRootToken && hasDots) { + tokenizer = new Tokenizer(expression); tokenizer.nextPropertyName(); - if ( tokenizer.getPosition() == EOF ) - { + if (tokenizer.getPosition() == EOF) { return null; } - } - else - { - tokenizer = new Tokenizer( "." + expression ); + } else { + tokenizer = new Tokenizer("." + expression); } int propertyPosition = tokenizer.getPosition(); - while ( value != null && tokenizer.peekChar() != EOF ) - { - switch ( tokenizer.skipChar() ) - { + while (value != null && tokenizer.peekChar() != EOF) { + switch (tokenizer.skipChar()) { case INDEXED_START: - value = - getIndexedValue( expression, propertyPosition, tokenizer.getPosition(), value, - tokenizer.nextToken( INDEXED_END ) ); + value = getIndexedValue( + expression, + propertyPosition, + tokenizer.getPosition(), + value, + tokenizer.nextToken(INDEXED_END)); break; case MAPPED_START: - value = - getMappedValue( expression, propertyPosition, tokenizer.getPosition(), value, - tokenizer.nextToken( MAPPED_END ) ); + value = getMappedValue( + expression, + propertyPosition, + tokenizer.getPosition(), + value, + tokenizer.nextToken(MAPPED_END)); break; case PROPERTY_START: propertyPosition = tokenizer.getPosition(); - value = getPropertyValue( value, tokenizer.nextPropertyName() ); + value = getPropertyValue(value, tokenizer.nextPropertyName()); break; default: // could not parse expression @@ -244,155 +221,118 @@ public static Object evaluate( @Nonnull String expression, @Nullable Object root return value; } - private static Object getMappedValue( final String expression, final int from, final int to, final Object value, - final String key ) - throws IntrospectionException - { - if ( value == null || key == null ) - { + private static Object getMappedValue( + final String expression, final int from, final int to, final Object value, final String key) + throws IntrospectionException { + if (value == null || key == null) { return null; } - if ( value instanceof Map ) - { - Object[] localParams = new Object[] { key }; - ClassMap classMap = getClassMap( value.getClass() ); - try - { - Method method = classMap.findMethod( "get", localParams ); - return method.invoke( value, localParams ); - } - catch ( AmbiguousException e ) - { - throw new IntrospectionException( e ); - } - catch ( IllegalAccessException e ) - { - throw new IntrospectionException( e ); - } - catch ( InvocationTargetException e ) - { - throw new IntrospectionException( e.getTargetException() ); + if (value instanceof Map) { + Object[] localParams = new Object[] {key}; + ClassMap classMap = getClassMap(value.getClass()); + try { + Method method = classMap.findMethod("get", localParams); + return method.invoke(value, localParams); + } catch (AmbiguousException e) { + throw new IntrospectionException(e); + } catch (IllegalAccessException e) { + throw new IntrospectionException(e); + } catch (InvocationTargetException e) { + throw new IntrospectionException(e.getTargetException()); } - } - final String message = - String.format( "The token '%s' at position '%d' refers to a java.util.Map, but the value " - + "seems is an instance of '%s'", expression.subSequence( from, to ), from, value.getClass() ); + final String message = String.format( + "The token '%s' at position '%d' refers to a java.util.Map, but the value " + + "seems is an instance of '%s'", + expression.subSequence(from, to), from, value.getClass()); - throw new IntrospectionException( message ); + throw new IntrospectionException(message); } - private static Object getIndexedValue( final String expression, final int from, final int to, final Object value, - final String indexStr ) - throws IntrospectionException - { - try - { - int index = Integer.parseInt( indexStr ); - - if ( value.getClass().isArray() ) - { - return Array.get( value, index ); + private static Object getIndexedValue( + final String expression, final int from, final int to, final Object value, final String indexStr) + throws IntrospectionException { + try { + int index = Integer.parseInt(indexStr); + + if (value.getClass().isArray()) { + return Array.get(value, index); } - if ( value instanceof List ) - { - ClassMap classMap = getClassMap( value.getClass() ); + if (value instanceof List) { + ClassMap classMap = getClassMap(value.getClass()); // use get method on List interface - Object[] localParams = new Object[] { index }; + Object[] localParams = new Object[] {index}; Method method = null; - try - { - method = classMap.findMethod( "get", localParams ); - return method.invoke( value, localParams ); - } - catch ( AmbiguousException e ) - { - throw new IntrospectionException( e ); - } - catch ( IllegalAccessException e ) - { - throw new IntrospectionException( e ); + try { + method = classMap.findMethod("get", localParams); + return method.invoke(value, localParams); + } catch (AmbiguousException e) { + throw new IntrospectionException(e); + } catch (IllegalAccessException e) { + throw new IntrospectionException(e); } } - } - catch ( NumberFormatException e ) - { + } catch (NumberFormatException e) { return null; - } - catch ( InvocationTargetException e ) - { + } catch (InvocationTargetException e) { // catch array index issues gracefully, otherwise release - if ( e.getCause() instanceof IndexOutOfBoundsException ) - { + if (e.getCause() instanceof IndexOutOfBoundsException) { return null; } - throw new IntrospectionException( e.getTargetException() ); + throw new IntrospectionException(e.getTargetException()); } - final String message = - String.format( "The token '%s' at position '%d' refers to a java.util.List or an array, but the value " - + "seems is an instance of '%s'", expression.subSequence( from, to ), from, value.getClass() ); + final String message = String.format( + "The token '%s' at position '%d' refers to a java.util.List or an array, but the value " + + "seems is an instance of '%s'", + expression.subSequence(from, to), from, value.getClass()); - throw new IntrospectionException( message ); + throw new IntrospectionException(message); } - private static Object getPropertyValue( Object value, String property ) - throws IntrospectionException - { - if ( value == null || property == null ) - { + private static Object getPropertyValue(Object value, String property) throws IntrospectionException { + if (value == null || property == null) { return null; } - ClassMap classMap = getClassMap( value.getClass() ); - String methodBase = StringUtils.capitalizeFirstLetter( property ); + ClassMap classMap = getClassMap(value.getClass()); + String methodBase = StringUtils.capitalizeFirstLetter(property); String methodName = "get" + methodBase; - try - { - Method method = classMap.findMethod( methodName, CLASS_ARGS ); + try { + Method method = classMap.findMethod(methodName, CLASS_ARGS); - if ( method == null ) - { + if (method == null) { // perhaps this is a boolean property?? methodName = "is" + methodBase; - method = classMap.findMethod( methodName, CLASS_ARGS ); + method = classMap.findMethod(methodName, CLASS_ARGS); } - if ( method == null ) - { + if (method == null) { return null; } - return method.invoke( value, OBJECT_ARGS ); - } - catch ( InvocationTargetException e ) - { - throw new IntrospectionException( e.getTargetException() ); - } - catch ( AmbiguousException e ) - { - throw new IntrospectionException( e ); - } - catch ( IllegalAccessException e ) - { - throw new IntrospectionException( e ); + return method.invoke(value, OBJECT_ARGS); + } catch (InvocationTargetException e) { + throw new IntrospectionException(e.getTargetException()); + } catch (AmbiguousException e) { + throw new IntrospectionException(e); + } catch (IllegalAccessException e) { + throw new IntrospectionException(e); } } - private static ClassMap getClassMap( Class> clazz ) - { - ClassMap classMap = CLASS_MAPS.get( clazz ); + private static ClassMap getClassMap(Class> clazz) { + ClassMap classMap = CLASS_MAPS.get(clazz); - if ( classMap == null ) - { - classMap = new ClassMap( clazz ); + if (classMap == null) { + classMap = new ClassMap(clazz); - CLASS_MAPS.put( clazz, classMap ); + CLASS_MAPS.put(clazz, classMap); } return classMap; diff --git a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanResult.java b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanResult.java index 56a29247..9e947391 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanResult.java +++ b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanResult.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,20 +16,25 @@ * specific language governing permissions and limitations * under the License. */ - +package org.apache.maven.shared.utils.io; /** * Scan for files in a directory at a given time and reports removed and added files * between captures. + * + * @deprecated use {@code java.nio.file.DirectoryStream} and related classes */ -public class DirectoryScanResult -{ +@Deprecated +public class DirectoryScanResult { private final String[] filesAdded; private final String[] filesRemoved; - public DirectoryScanResult( String[] filesAdded, String[] filesRemoved ) - { + /** + * @param filesAdded Added files. + * @param filesRemoved Removed files. + */ + public DirectoryScanResult(String[] filesAdded, String[] filesRemoved) { this.filesAdded = filesAdded; this.filesRemoved = filesRemoved; } @@ -39,17 +42,14 @@ public DirectoryScanResult( String[] filesAdded, String[] filesRemoved ) /** * @return all files which got detected as being added between 2 capture calls */ - public String[] getFilesAdded() - { + public String[] getFilesAdded() { return filesAdded; } /** * @return all files which got detected as being removed between 2 capture calls */ - public String[] getFilesRemoved() - { + public String[] getFilesRemoved() { return filesRemoved; } - } diff --git a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java index 91415bcc..3c613ab0 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java +++ b/src/main/java/org/apache/maven/shared/utils/io/DirectoryScanner.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,69 +16,77 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - /** - * Class for scanning a directory for files/directories which match certain criteria. - * + *Class for scanning a directory for files/directories which match certain criteria.
+ ** These criteria consist of selectors and patterns which have been specified. With the selectors you can select which * files you want to have included. Files which are not selected are excluded. With patterns you can include or exclude * files based on their filename. - *
+ * + ** The idea is simple. A given directory is recursively scanned for all files and directories. Each file/directory is * matched against a set of selectors, including special support for matching against filenames with include and and * exclude patterns. Only files/directories which match at least one pattern of the include pattern list or other file * selector, and don't match any pattern of the exclude pattern list or fail to match against a required selector will * be placed in the list of files/directories found. - *
+ * + ** When no list of include patterns is supplied, "**" will be used, which means that everything will be matched. When no * list of exclude patterns is supplied, an empty list is used, such that nothing will be excluded. When no selectors * are supplied, none are applied. - *
+ * + ** The filename pattern matching is done as follows: The name to be matched is split up in path segments. A path segment * is the name of a directory or file, which is bounded by
+ * + *File.separator
('/' under UNIX, '\' under * Windows). For example, "abc/def/ghi/xyz.java" is split up in the segments "abc", "def","ghi" and "xyz.java". The same * is done for the pattern against which should be matched. - ** The segments of the name and the pattern are then matched against each other. When '**' is used for a path segment in * the pattern, it matches zero or more path segments of the name. - *
+ * + ** There is a special case regarding the use of
+ * + *File.separator
s at the beginning of the pattern and the * string to match:
* When a pattern starts with aFile.separator
, the string to match must also start with a *File.separator
. When a pattern does not start with aFile.separator
, the string to match * may not start with aFile.separator
. When one of these rules is not obeyed, the string will not match. - ** When a name path segment is matched against a pattern path segment, the following special characters can be used:
+ * + *
* '*' matches zero or more characters
* '?' matches one character. - ** Examples: - *
- * "**\*.class" matches all .class files/dirs in a directory tree. - * - * "test\a??.java" matches all files/dirs which start with an 'a', then two more characters and then ".java", in a - * directory called test. - * - * "**" matches everything in a directory tree. - * - * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where there is a parent directory called test - * (e.g. "abc\test\def\ghi\XYZ123"). - * + *+ *
+ *- "**\*.class" matches all .class files/dirs in a directory tree.
+ *- "test\a??.java" matches all files/dirs which start with an 'a', then two more characters and then ".java", in a + * directory called test.
+ *- "**" matches everything in a directory tree.
+ *- "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where there is a parent directory called test + * (e.g. "abc\test\def\ghi\XYZ123").
+ ** Case sensitivity may be turned off if necessary. By default, it is turned on. - *
+ * + ** Example of usage: - *
+ * ** String[] includes = { "**\\*.class" }; * String[] excludes = { "modules\\*\\**" }; @@ -97,19 +103,23 @@ * System.out.println( files[i] ); * } *- * + ** This will scan a directory called test for .class files, but excludes all files in all proper subdirectories of a * directory called "modules" - *
+ * + ** This class must not be used from multiple Threads concurrently! + *
* * @author Arnout J. Kuiper ajkuiper@wxs.nl * @author Magesh Umasankar * @author Bruce Atherton * @author Antoine Levy-Lambert + * @deprecated use {@code java.nio.file.DirectoryStream} or {@code java.nio.Files.walkFileTree()} + * and related classes */ -public class DirectoryScanner -{ +@Deprecated +public class DirectoryScanner { /** * Patterns which should be excluded by default. * @@ -117,28 +127,28 @@ public class DirectoryScanner */ public static final String[] DEFAULTEXCLUDES = { // Miscellaneous typical temporary files - "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*", + "**/*~", + "**/#*#", + "**/.#*", + "**/%*%", + "**/._*", // CVS - "**/CVS", "**/CVS/**", "**/.cvsignore", - - // RCS - "**/RCS", "**/RCS/**", - - // SCCS - "**/SCCS", "**/SCCS/**", - - // Visual SourceSafe - "**/vssver.scc", + "**/CVS", + "**/CVS/**", + "**/.cvsignore", // Subversion - "**/.svn", "**/.svn/**", + "**/.svn", + "**/.svn/**", // Arch - "**/.arch-ids", "**/.arch-ids/**", + "**/.arch-ids", + "**/.arch-ids/**", // Bazaar - "**/.bzr", "**/.bzr/**", + "**/.bzr", + "**/.bzr/**", // SurroundSCM "**/.MySCMServerInfo", @@ -147,19 +157,31 @@ public class DirectoryScanner "**/.DS_Store", // Serena Dimensions Version 10 - "**/.metadata", "**/.metadata/**", + "**/.metadata", + "**/.metadata/**", // Mercurial - "**/.hg", "**/.hg/**", + "**/.hg", + "**/.hg/**", // git - "**/.git", "**/.git/**", + "**/.git", + "**/.git/**", // BitKeeper - "**/BitKeeper", "**/BitKeeper/**", "**/ChangeSet", "**/ChangeSet/**", + "**/BitKeeper", + "**/BitKeeper/**", + "**/ChangeSet", + "**/ChangeSet/**", // darcs - "**/_darcs", "**/_darcs/**", "**/.darcsrepo", "**/.darcsrepo/**", "**/-darcs-backup*", "**/.darcs-temp-mail" }; + "**/_darcs", + "**/_darcs/**", + "**/.darcsrepo", + "**/.darcsrepo/**", + "**/-darcs-backup*", + "**/.darcs-temp-mail" + }; /** * The base directory to be scanned. @@ -180,7 +202,6 @@ public class DirectoryScanner private MatchPatterns includesPatterns; - /** * The files which matched at least one include and no excludes and were selected. */ @@ -224,11 +245,10 @@ public class DirectoryScanner /** * Whether or not symbolic links should be followed. * - * + * */ private boolean followSymlinks = true; - /** * A {@link ScanConductor} an control the scanning process. */ @@ -242,9 +262,7 @@ public class DirectoryScanner /** * Sole constructor. */ - public DirectoryScanner() - { - } + public DirectoryScanner() {} /** * Sets the base directory to be scanned. This is the directory which is scanned recursively. All '/' and '\' @@ -253,9 +271,8 @@ public DirectoryScanner() * * @param basedir The base directory to scan. Must not benull
. */ - public void setBasedir( final String basedir ) - { - setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) ); + public void setBasedir(final String basedir) { + setBasedir(new File(basedir.replace('/', File.separatorChar).replace('\\', File.separatorChar))); } /** @@ -263,8 +280,7 @@ public void setBasedir( final String basedir ) * * @param basedir The base directory for scanning. Should not benull
. */ - public void setBasedir( @Nonnull final File basedir ) - { + public void setBasedir(@Nonnull final File basedir) { this.basedir = basedir; } @@ -273,19 +289,17 @@ public void setBasedir( @Nonnull final File basedir ) * * @return the base directory to be scanned */ - public File getBasedir() - { + public File getBasedir() { return basedir; } /** * Sets whether or not the file system should be regarded as case sensitive. * - * @param isCaseSensitive whether or not the file system should be regarded as a case sensitive one + * @param isCaseSensitiveParameter whether or not the file system should be regarded as a case sensitive one */ - public void setCaseSensitive( final boolean isCaseSensitive ) - { - this.isCaseSensitive = isCaseSensitive; + public void setCaseSensitive(final boolean isCaseSensitiveParameter) { + this.isCaseSensitive = isCaseSensitiveParameter; } /** @@ -293,35 +307,32 @@ public void setCaseSensitive( final boolean isCaseSensitive ) * * @param followSymlinks whether or not symbolic links should be followed */ - public void setFollowSymlinks( final boolean followSymlinks ) - { + public void setFollowSymlinks(final boolean followSymlinks) { this.followSymlinks = followSymlinks; } /** * Sets the list of include patterns to use. All '/' and '\' characters are replaced by *File.separatorChar
, so the separator used need not matchFile.separatorChar
. - * + ** When a pattern ends with a '/' or '\', "**" is appended. + *
* * @param includes A list of include patterns. May benull
, indicating that all files should be * included. If a non-null
list is given, all elements must be non-null
. */ - public void setIncludes( final String... includes ) - { - if ( includes == null ) - { + public void setIncludes(final String... includes) { + if (includes == null) { this.includes = null; - } - else - { + } else { this.includes = new String[includes.length]; - for ( int i = 0; i < includes.length; i++ ) - { + for (int i = 0; i < includes.length; i++) { + if (includes[i] == null) { + throw new NullPointerException(messageForNullListElement("includes")); + } String pattern; - pattern = includes[i].trim().replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); - if ( pattern.endsWith( File.separator ) ) - { + pattern = includes[i].trim().replace('/', File.separatorChar).replace('\\', File.separatorChar); + if (pattern.endsWith(File.separator)) { pattern += "**"; } this.includes[i] = pattern; @@ -332,27 +343,25 @@ public void setIncludes( final String... includes ) /** * Sets the list of exclude patterns to use. All '/' and '\' characters are replaced by *File.separatorChar
, so the separator used need not matchFile.separatorChar
. - * + ** When a pattern ends with a '/' or '\', "**" is appended. + *
* * @param excludes A list of exclude patterns. May benull
, indicating that no files should be * excluded. If a non-null
list is given, all elements must be non-null
. */ - public void setExcludes( final String... excludes ) - { - if ( excludes == null ) - { + public void setExcludes(final String... excludes) { + if (excludes == null) { this.excludes = null; - } - else - { + } else { this.excludes = new String[excludes.length]; - for ( int i = 0; i < excludes.length; i++ ) - { + for (int i = 0; i < excludes.length; i++) { + if (excludes[i] == null) { + throw new NullPointerException(messageForNullListElement("excludes")); + } String pattern; - pattern = excludes[i].trim().replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); - if ( pattern.endsWith( File.separator ) ) - { + pattern = excludes[i].trim().replace('/', File.separatorChar).replace('\\', File.separatorChar); + if (pattern.endsWith(File.separator)) { pattern += "**"; } this.excludes[i] = pattern; @@ -360,8 +369,14 @@ public void setExcludes( final String... excludes ) } } - public void setScanConductor( final ScanConductor scanConductor ) - { + private static String messageForNullListElement(String listName) { + return "If a non-null " + listName + " list is given, all elements must be non-null"; + } + + /** + * @param scanConductor {@link #scanConductor} + */ + public void setScanConductor(final ScanConductor scanConductor) { this.scanConductor = scanConductor; } @@ -372,20 +387,15 @@ public void setScanConductor( final ScanConductor scanConductor ) * @throws IllegalStateException if the base directory was set incorrectly (i.e. if it isnull
, * doesn't exist, or isn't a directory). */ - public void scan() - throws IllegalStateException - { - if ( basedir == null ) - { - throw new IllegalStateException( "No basedir set" ); + public void scan() throws IllegalStateException { + if (basedir == null) { + throw new IllegalStateException("No basedir set"); } - if ( !basedir.exists() ) - { - throw new IllegalStateException( "basedir " + basedir + " does not exist" ); + if (!basedir.exists()) { + throw new IllegalStateException("basedir " + basedir + " does not exist"); } - if ( !basedir.isDirectory() ) - { - throw new IllegalStateException( "basedir " + basedir + " is not a directory" ); + if (!basedir.isDirectory()) { + throw new IllegalStateException("basedir " + basedir + " is not a directory"); } setupDefaultFilters(); @@ -399,34 +409,26 @@ public void scan() dirsExcluded = new ArrayList(); scanAction = ScanConductor.ScanAction.CONTINUE; - if ( isIncluded( "" ) ) - { - if ( !isExcluded( "" ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitDirectory( "", basedir ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) - || ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) - { + if (isIncluded("")) { + if (!isExcluded("")) { + if (scanConductor != null) { + scanAction = scanConductor.visitDirectory("", basedir); + + if (ScanConductor.ScanAction.ABORT.equals(scanAction) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals(scanAction) + || ScanConductor.ScanAction.NO_RECURSE.equals(scanAction)) { return; } } - dirsIncluded.add( "" ); - } - else - { - dirsExcluded.add( "" ); + dirsIncluded.add(""); + } else { + dirsExcluded.add(""); } + } else { + dirsNotIncluded.add(""); } - else - { - dirsNotIncluded.add( "" ); - } - scandir( basedir, "", true ); + scandir(basedir, "", true); } /** @@ -434,58 +436,58 @@ public void scan() * a previously captured list of files. * This method will not look for a changed in content but sole in the * list of files given. - * + * * The method will compare the given array of file Strings with the result * of the last directory scan. It will execute a {@link #scan()} if no * result of a previous scan could be found. - *
+ * + ** The result of the diff can be queried by the methods * {@link DirectoryScanResult#getFilesAdded()} and {@link DirectoryScanResult#getFilesRemoved()} + *
* * @param oldFiles the list of previously captured files names. + * @return the result of the directory scan. */ - public DirectoryScanResult diffIncludedFiles( String... oldFiles ) - { - if ( filesIncluded == null ) - { + public DirectoryScanResult diffIncludedFiles(String... oldFiles) { + if (filesIncluded == null) { // perform a scan if the directory didn't got scanned yet scan(); } - return diffFiles( oldFiles, filesIncluded.toArray( new String[filesIncluded.size()] ) ); + return diffFiles(oldFiles, filesIncluded.toArray(new String[filesIncluded.size()])); } - public static DirectoryScanResult diffFiles( @Nullable String[] oldFiles, @Nullable String[] newFiles ) - { - SetoldFileSet = arrayAsHashSet( oldFiles ); - Set newFileSet = arrayAsHashSet( newFiles ); + /** + * @param oldFiles array of old files + * @param newFiles array of new files + * @return calculated difference + */ + public static DirectoryScanResult diffFiles(@Nullable String[] oldFiles, @Nullable String[] newFiles) { + Set oldFileSet = arrayAsHashSet(oldFiles); + Set newFileSet = arrayAsHashSet(newFiles); List added = new ArrayList (); List removed = new ArrayList (); - for ( String oldFile : oldFileSet ) - { - if ( !newFileSet.contains( oldFile ) ) - { - removed.add( oldFile ); + for (String oldFile : oldFileSet) { + if (!newFileSet.contains(oldFile)) { + removed.add(oldFile); } } - for ( String newFile : newFileSet ) - { - if ( !oldFileSet.contains( newFile ) ) - { - added.add( newFile ); + for (String newFile : newFileSet) { + if (!oldFileSet.contains(newFile)) { + added.add(newFile); } } - String[] filesAdded = added.toArray( new String[added.size()] ); - String[] filesRemoved = removed.toArray( new String[removed.size()] ); + String[] filesAdded = added.toArray(new String[added.size()]); + String[] filesRemoved = removed.toArray(new String[removed.size()]); - return new DirectoryScanResult( filesAdded, filesRemoved ); + return new DirectoryScanResult(filesAdded, filesRemoved); } - /** * Take an array of type T and convert it into a HashSet of type T. * If null
or an empty array gets passed, an empty Set will be returned. @@ -493,15 +495,13 @@ public static DirectoryScanResult diffFiles( @Nullable String[] oldFiles, @Nulla * @param array The array * @return the filled HashSet of type T */ - private staticSet arrayAsHashSet( @Nullable T[] array ) - { - if ( array == null || array.length == 0 ) - { + private static Set arrayAsHashSet(@Nullable T[] array) { + if (array == null || array.length == 0) { return Collections.emptySet(); } - Set set = new HashSet ( array.length ); - Collections.addAll( set, array ); + Set set = new HashSet (array.length); + Collections.addAll(set, array); return set; } @@ -513,30 +513,24 @@ private static Set arrayAsHashSet( @Nullable T[] array ) * * Returns immediately if a slow scan has already been completed. */ - void slowScan() - { - if ( haveSlowResults ) - { + void slowScan() { + if (haveSlowResults) { return; } - final String[] excl = dirsExcluded.toArray( new String[dirsExcluded.size()] ); + final String[] excl = dirsExcluded.toArray(new String[dirsExcluded.size()]); - final String[] notIncl = dirsNotIncluded.toArray( new String[dirsNotIncluded.size()] ); + final String[] notIncl = dirsNotIncluded.toArray(new String[dirsNotIncluded.size()]); - for ( String anExcl : excl ) - { - if ( !couldHoldIncluded( anExcl ) ) - { - scandir( new File( basedir, anExcl ), anExcl + File.separator, false ); + for (String anExcl : excl) { + if (!couldHoldIncluded(anExcl)) { + scandir(new File(basedir, anExcl), anExcl + File.separator, false); } } - for ( String aNotIncl : notIncl ) - { - if ( !couldHoldIncluded( aNotIncl ) ) - { - scandir( new File( basedir, aNotIncl ), aNotIncl + File.separator, false ); + for (String aNotIncl : notIncl) { + if (!couldHoldIncluded(aNotIncl)) { + scandir(new File(basedir, aNotIncl), aNotIncl + File.separator, false); } } @@ -560,12 +554,10 @@ void slowScan() * @see #dirsExcluded * @see #slowScan */ - void scandir( @Nonnull final File dir, @Nonnull final String vpath, final boolean fast ) - { + void scandir(@Nonnull final File dir, @Nonnull final String vpath, final boolean fast) { String[] newfiles = dir.list(); - if ( newfiles == null ) - { + if (newfiles == null) { /* * two reasons are mentioned in the API docs for File.list (1) dir is not a directory. This is impossible as * we wouldn't get here in this case. (2) an IO error occurred (why doesn't it throw an exception then???) @@ -581,161 +573,122 @@ void scandir( @Nonnull final File dir, @Nonnull final String vpath, final boolea // throw new IOException( "IO error scanning directory " + dir.getAbsolutePath() ); } - if ( !followSymlinks ) - { - final List noLinks = new ArrayList (); - for ( final String newfile : newfiles ) - { - try - { - if ( isSymbolicLink( dir, newfile ) ) - { - final String name = vpath + newfile; - final File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - dirsExcluded.add( name ); - } - else - { - filesExcluded.add( name ); - } - } - else - { - noLinks.add( newfile ); - } - } - catch ( final IOException ioe ) - { - final String msg = - "IOException caught while checking " + "for links, couldn't get cannonical path!"; - // will be caught and redirected to Ant's logging system - System.err.println( msg ); - noLinks.add( newfile ); - } - } - newfiles = noLinks.toArray( new String[noLinks.size()] ); + if (!followSymlinks) { + newfiles = doNotFollowSymbolicLinks(dir, vpath, newfiles); } - for ( final String newfile : newfiles ) - { + for (final String newfile : newfiles) { final String name = vpath + newfile; - final File file = new File( dir, newfile ); - if ( file.isDirectory() ) - { - if ( isIncluded( name ) ) - { - if ( !isExcluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitDirectory( name, file ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { + final File file = new File(dir, newfile); + if (file.isDirectory()) { + if (isIncluded(name)) { + if (!isExcluded(name)) { + if (scanConductor != null) { + scanAction = scanConductor.visitDirectory(name, file); + + if (ScanConductor.ScanAction.ABORT.equals(scanAction) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals(scanAction)) { return; } } - if ( !ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) - { - dirsIncluded.add( name ); - if ( fast ) - { - scandir( file, name + File.separator, fast ); + if (!ScanConductor.ScanAction.NO_RECURSE.equals(scanAction)) { + dirsIncluded.add(name); + if (fast) { + scandir(file, name + File.separator, fast); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { + if (ScanConductor.ScanAction.ABORT.equals(scanAction)) { return; } } } scanAction = null; - } - else - { - dirsExcluded.add( name ); - if ( fast && couldHoldIncluded( name ) ) - { - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { + } else { + dirsExcluded.add(name); + if (fast && couldHoldIncluded(name)) { + scandir(file, name + File.separator, fast); + if (ScanConductor.ScanAction.ABORT.equals(scanAction)) { return; } scanAction = null; } } - } - else - { - if ( fast && couldHoldIncluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitDirectory( name, file ); - - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { + } else { + if (fast && couldHoldIncluded(name)) { + if (scanConductor != null) { + scanAction = scanConductor.visitDirectory(name, file); + + if (ScanConductor.ScanAction.ABORT.equals(scanAction) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals(scanAction)) { return; } } - if ( !ScanConductor.ScanAction.NO_RECURSE.equals( scanAction ) ) - { - dirsNotIncluded.add( name ); + if (!ScanConductor.ScanAction.NO_RECURSE.equals(scanAction)) { + dirsNotIncluded.add(name); - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { + scandir(file, name + File.separator, fast); + if (ScanConductor.ScanAction.ABORT.equals(scanAction)) { return; } } scanAction = null; } } - if ( !fast ) - { - scandir( file, name + File.separator, fast ); - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) ) - { + if (!fast) { + scandir(file, name + File.separator, fast); + if (ScanConductor.ScanAction.ABORT.equals(scanAction)) { return; } scanAction = null; } - } - else if ( file.isFile() ) - { - if ( isIncluded( name ) ) - { - if ( !isExcluded( name ) ) - { - if ( scanConductor != null ) - { - scanAction = scanConductor.visitFile( name, file ); + } else if (file.isFile()) { + if (isIncluded(name)) { + if (!isExcluded(name)) { + if (scanConductor != null) { + scanAction = scanConductor.visitFile(name, file); } - if ( ScanConductor.ScanAction.ABORT.equals( scanAction ) - || ScanConductor.ScanAction.ABORT_DIRECTORY.equals( scanAction ) ) - { + if (ScanConductor.ScanAction.ABORT.equals(scanAction) + || ScanConductor.ScanAction.ABORT_DIRECTORY.equals(scanAction)) { return; } - filesIncluded.add( name ); - } - else - { - filesExcluded.add( name ); + filesIncluded.add(name); + } else { + filesExcluded.add(name); } + } else { + filesNotIncluded.add(name); } - else - { - filesNotIncluded.add( name ); + } + } + } + + private String[] doNotFollowSymbolicLinks(final File dir, final String vpath, String[] newfiles) { + final List noLinks = new ArrayList (); + for (final String newfile : newfiles) { + try { + if (isSymbolicLink(dir, newfile)) { + final String name = vpath + newfile; + final File file = new File(dir, newfile); + if (file.isDirectory()) { + dirsExcluded.add(name); + } else { + filesExcluded.add(name); + } + } else { + noLinks.add(newfile); } + } catch (final IOException ioe) { + final String msg = "IOException caught while checking " + "for links, couldn't get canonical path!"; + // will be caught and redirected to Ant's logging system + System.err.println(msg); + noLinks.add(newfile); } } + newfiles = noLinks.toArray(new String[noLinks.size()]); + return newfiles; } /** @@ -745,9 +698,8 @@ else if ( file.isFile() ) * @return true
when the name matches against at least one include pattern, orfalse
* otherwise. */ - boolean isIncluded( final String name ) - { - return includesPatterns.matches( name, isCaseSensitive ); + boolean isIncluded(final String name) { + return includesPatterns.matches(name, isCaseSensitive); } /** @@ -757,9 +709,8 @@ boolean isIncluded( final String name ) * @returntrue
when the name matches against the start of at least one include pattern, or *false
otherwise. */ - boolean couldHoldIncluded( @Nonnull final String name ) - { - return includesPatterns.matchesPatternStart( name, isCaseSensitive ); + boolean couldHoldIncluded(@Nonnull final String name) { + return includesPatterns.matchesPatternStart(name, isCaseSensitive); } /** @@ -769,25 +720,24 @@ boolean couldHoldIncluded( @Nonnull final String name ) * @returntrue
when the name matches against at least one exclude pattern, orfalse
* otherwise. */ - boolean isExcluded( @Nonnull final String name ) - { - return excludesPatterns.matches( name, isCaseSensitive ); + boolean isExcluded(@Nonnull final String name) { + return excludesPatterns.matches(name, isCaseSensitive); } /** * Returns the names of the files which matched at least one of the include patterns and none of the exclude * patterns. The names are relative to the base directory. * + * @deprecated this method does not work correctly on Windows. * @return the names of the files which matched at least one of the include patterns and none of the exclude * patterns. May also contain symbolic links to files. */ - public String[] getIncludedFiles() - { - if ( filesIncluded == null ) - { + @Deprecated + public String[] getIncludedFiles() { + if (filesIncluded == null) { return new String[0]; } - return filesIncluded.toArray( new String[filesIncluded.size()] ); + return filesIncluded.toArray(new String[filesIncluded.size()]); } /** @@ -797,10 +747,9 @@ public String[] getIncludedFiles() * @return the names of the files which matched none of the include patterns. * @see #slowScan */ - public String[] getNotIncludedFiles() - { + public String[] getNotIncludedFiles() { slowScan(); - return filesNotIncluded.toArray( new String[filesNotIncluded.size()] ); + return filesNotIncluded.toArray(new String[filesNotIncluded.size()]); } /** @@ -812,22 +761,22 @@ public String[] getNotIncludedFiles() * exclude patterns. * @see #slowScan */ - public String[] getExcludedFiles() - { + public String[] getExcludedFiles() { slowScan(); - return filesExcluded.toArray( new String[filesExcluded.size()] ); + return filesExcluded.toArray(new String[filesExcluded.size()]); } /** * Returns the names of the directories which matched at least one of the include patterns and none of the exclude * patterns. The names are relative to the base directory. * + * @deprecated this method is buggy. Do not depend on it. * @return the names of the directories which matched at least one of the include patterns and none of the exclude * patterns. May also contain symbolic links to directories. */ - public String[] getIncludedDirectories() - { - return dirsIncluded.toArray( new String[dirsIncluded.size()] ); + @Deprecated + public String[] getIncludedDirectories() { + return dirsIncluded.toArray(new String[dirsIncluded.size()]); } /** @@ -837,10 +786,9 @@ public String[] getIncludedDirectories() * @return the names of the directories which matched none of the include patterns. * @see #slowScan */ - public String[] getNotIncludedDirectories() - { + public String[] getNotIncludedDirectories() { slowScan(); - return dirsNotIncluded.toArray( new String[dirsNotIncluded.size()] ); + return dirsNotIncluded.toArray(new String[dirsNotIncluded.size()]); } /** @@ -852,28 +800,24 @@ public String[] getNotIncludedDirectories() * exclude patterns. * @see #slowScan */ - public String[] getExcludedDirectories() - { + public String[] getExcludedDirectories() { slowScan(); - return dirsExcluded.toArray( new String[dirsExcluded.size()] ); + return dirsExcluded.toArray(new String[dirsExcluded.size()]); } /** * Adds default exclusions to the current exclusions set. */ - public void addDefaultExcludes() - { + public void addDefaultExcludes() { final int excludesLength = excludes == null ? 0 : excludes.length; String[] newExcludes; newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length]; - if ( excludesLength > 0 ) - { - System.arraycopy( excludes, 0, newExcludes, 0, excludesLength ); + if (excludesLength > 0) { + System.arraycopy(excludes, 0, newExcludes, 0, excludesLength); } - for ( int i = 0; i < DEFAULTEXCLUDES.length; i++ ) - { + for (int i = 0; i < DEFAULTEXCLUDES.length; i++) { newExcludes[i + excludesLength] = - DEFAULTEXCLUDES[i].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); + DEFAULTEXCLUDES[i].replace('/', File.separatorChar).replace('\\', File.separatorChar); } excludes = newExcludes; } @@ -887,39 +831,25 @@ public void addDefaultExcludes() * * @param parent the parent directory of the file to test * @param name the name of the file to test. - * - */ - boolean isSymbolicLink( final File parent, final String name ) - throws IOException - { - if ( Java7Support.isAtLeastJava7() ) - { - return Java7Support.isSymLink( parent ); - } - final File resolvedParent = new File( parent.getCanonicalPath() ); - final File toTest = new File( resolvedParent, name ); - return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() ); + * + */ + boolean isSymbolicLink(final File parent, final String name) throws IOException { + return Files.isSymbolicLink(parent.toPath()); } - private void setupDefaultFilters() - { - if ( includes == null ) - { + private void setupDefaultFilters() { + if (includes == null) { // No includes supplied, so set it to 'matches all' includes = new String[1]; includes[0] = "**"; } - if ( excludes == null ) - { + if (excludes == null) { excludes = new String[0]; } } - - private void setupMatchPatterns() - { - includesPatterns = MatchPatterns.from( includes ); - excludesPatterns = MatchPatterns.from( excludes ); + private void setupMatchPatterns() { + includesPatterns = MatchPatterns.from(includes); + excludesPatterns = MatchPatterns.from(excludes); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalkListener.java b/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalkListener.java index ba580a04..fbb86770 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalkListener.java +++ b/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalkListener.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,35 +16,39 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; import java.io.File; /** - * DirectoryWalkListener + * DirectoryWalkListener. * - * @version $Id$ + * @deprecated use {@code java.nio.file.FileVisitor} and related classes */ -public interface DirectoryWalkListener -{ +@Deprecated +public interface DirectoryWalkListener { /** * The directory walking has begun. * - * @param basedir the basedir that walk started in. + * @param basedir the basedir that walk started in */ - void directoryWalkStarting( File basedir ); + void directoryWalkStarting(File basedir); /** * The included entry that was encountered. * * @param percentage rough percentage of the walk completed. (inaccurate) - * @param file the file that was included. + * @param file the file that was included */ - void directoryWalkStep( int percentage, File file ); + void directoryWalkStep(int percentage, File file); /** * The directory walking has finished. */ void directoryWalkFinished(); - void debug( String message ); + /** + * @param message the message for the debugging output + */ + void debug(String message); } diff --git a/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalker.java b/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalker.java deleted file mode 100644 index 33d214c7..00000000 --- a/src/main/java/org/apache/maven/shared/utils/io/DirectoryWalker.java +++ /dev/null @@ -1,337 +0,0 @@ -package org.apache.maven.shared.utils.io; - -/* - * 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. - */ - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -/** - * DirectoryWalker - * - * @version $Id$ - */ -class DirectoryWalker -{ - /** - * DirStackEntry is an Item on the {@link DirectoryWalker#dirStack} - */ - static class DirStackEntry - { - /** - * Count of files in the directory. - */ - private final int count; - - /** - * Current Directory. - */ - private final File dir; - - /** - * Index (or offset) within the directory count. - */ - private int index; - - /** - * Offset for percentage calculations. Based on parent DirStackEntry. - */ - private double percentageOffset; - - /** - * Size of percentage space to work with. - */ - private double percentageSize; - - /** - * Create a DirStackEntry. - * - * @param d the directory to track - * @param length the length of entries in the directory. - */ - public DirStackEntry( File d, int length ) - { - dir = d; - count = length; - } - - /** - * Calculate the next percentage offset. Used by the next DirStackEntry. - * - * @return the value for the next percentage offset. - */ - public double getNextPercentageOffset() - { - return percentageOffset + ( index * ( percentageSize / count ) ); - } - - /** - * Calculate the next percentage size. Used by the next DirStackEntry. - * - * @return the value for the next percentage size. - */ - public double getNextPercentageSize() - { - return ( percentageSize / count ); - } - - /** - * The percentage of the DirStackEntry right now. Based on count, index, percentageOffset, and percentageSize. - * - * @return the percentage right now. - */ - public int getPercentage() - { - double percentageWithinDir = (double) index / (double) count; - return (int) Math.floor( percentageOffset + ( percentageWithinDir * percentageSize ) ); - } - - public String toString() - { - return "DirStackEntry[" + "dir=" + dir.getAbsolutePath() + ",count=" + count + ",index=" + index - + ",percentageOffset=" + percentageOffset + ",percentageSize=" + percentageSize + ",percentage()=" - + getPercentage() + ",getNextPercentageOffset()=" + getNextPercentageOffset() - + ",getNextPercentageSize()=" + getNextPercentageSize() + "]"; - } - } - - private File baseDir; - - private int baseDirOffset; - - private StackdirStack; - - private final List excludes; - - private final List includes; - - private final List listeners; - - public DirectoryWalker() - { - this.includes = new ArrayList (); - this.excludes = new ArrayList (); - this.listeners = new ArrayList (); - } - - public void addDirectoryWalkListener( DirectoryWalkListener listener ) - { - this.listeners.add( listener ); - } - - void addExclude( String exclude ) - { - this.excludes.add( fixPattern( exclude ) ); - } - - void addInclude( String include ) - { - this.includes.add( fixPattern( include ) ); - } - - /** - * Add's to the Exclude List the default list of SCM excludes. - */ - public void addSCMExcludes() - { - String scmexcludes[] = DirectoryScanner.DEFAULTEXCLUDES; - for ( String scmexclude : scmexcludes ) - { - addExclude( scmexclude ); - } - } - - private void fireStep( File file ) - { - DirStackEntry dsEntry = dirStack.peek(); - int percentage = dsEntry.getPercentage(); - for ( DirectoryWalkListener listener : this.listeners ) - { - listener.directoryWalkStep( percentage, file ); - } - } - - private void fireWalkFinished() - { - for ( Object listener1 : this.listeners ) - { - DirectoryWalkListener listener = (DirectoryWalkListener) listener1; - listener.directoryWalkFinished(); - } - } - - private void fireWalkStarting() - { - for ( Object listener1 : this.listeners ) - { - DirectoryWalkListener listener = (DirectoryWalkListener) listener1; - listener.directoryWalkStarting( this.baseDir ); - } - } - - private void fireDebugMessage( String message ) - { - for ( Object listener1 : this.listeners ) - { - DirectoryWalkListener listener = (DirectoryWalkListener) listener1; - listener.debug( message ); - } - } - - private String fixPattern( String pattern ) - { - String cleanPattern = pattern; - - if ( File.separatorChar != '/' ) - { - cleanPattern = cleanPattern.replace( '/', File.separatorChar ); - } - - if ( File.separatorChar != '\\' ) - { - cleanPattern = cleanPattern.replace( '\\', File.separatorChar ); - } - - return cleanPattern; - } - - private boolean isExcluded( String name ) - { - return isMatch( this.excludes, name ); - } - - private boolean isIncluded( String name ) - { - return isMatch( this.includes, name ); - } - - private boolean isMatch( List patterns, String name ) - { - for ( String pattern : patterns ) - { - boolean caseSensitive = true; - if ( SelectorUtils.matchPath( pattern, name, caseSensitive ) ) - { - return true; - } - } - - return false; - } - - private String relativeToBaseDir( File file ) - { - return file.getAbsolutePath().substring( baseDirOffset + 1 ); - } - - /** - * Performs a Scan against the provided {@link #setBaseDir(File)} - */ - public void scan() - { - if ( baseDir == null ) - { - throw new IllegalStateException( "Scan Failure. BaseDir not specified." ); - } - - if ( !baseDir.exists() ) - { - throw new IllegalStateException( "Scan Failure. BaseDir does not exist." ); - } - - if ( !baseDir.isDirectory() ) - { - throw new IllegalStateException( "Scan Failure. BaseDir is not a directory." ); - } - - if ( this.includes.isEmpty() ) - { - // default to include all. - addInclude( "**" ); - } - - fireWalkStarting(); - dirStack = new Stack (); - scanDir( this.baseDir ); - fireWalkFinished(); - } - - private void scanDir( File dir ) - { - File files[] = dir.listFiles(); - - if ( files == null ) - { - return; - } - - DirStackEntry curStackEntry = new DirStackEntry( dir, files.length ); - if ( dirStack.isEmpty() ) - { - curStackEntry.percentageOffset = 0; - curStackEntry.percentageSize = 100; - } - else - { - DirStackEntry previousStackEntry = dirStack.peek(); - curStackEntry.percentageOffset = previousStackEntry.getNextPercentageOffset(); - curStackEntry.percentageSize = previousStackEntry.getNextPercentageSize(); - } - - dirStack.push( curStackEntry ); - - for ( int idx = 0; idx < files.length; idx++ ) - { - curStackEntry.index = idx; - String name = relativeToBaseDir( files[idx] ); - - if ( isExcluded( name ) ) - { - fireDebugMessage( name + " is excluded." ); - continue; - } - - if ( files[idx].isDirectory() ) - { - scanDir( files[idx] ); - } - else - { - if ( isIncluded( name ) ) - { - fireStep( files[idx] ); - } - } - } - - dirStack.pop(); - } - - /** - * @param baseDir The baseDir to set. - */ - public void setBaseDir( File baseDir ) - { - this.baseDir = baseDir; - this.baseDirOffset = baseDir.getAbsolutePath().length(); - } - -} diff --git a/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java b/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java index de8480ec..1ce26eb4 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/io/FileUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,64 +16,72 @@ * specific language governing permissions and limitations * under the License. */ - -import org.apache.maven.shared.utils.Os; -import org.apache.maven.shared.utils.StringUtils; +package org.apache.maven.shared.utils.io; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.WillClose; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.OutputStreamWriter; +import java.io.RandomAccessFile; import java.io.Reader; import java.io.Writer; import java.net.URL; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.SecureRandom; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Random; +import org.apache.commons.io.IOUtils; +import org.apache.maven.shared.utils.Os; +import org.apache.maven.shared.utils.StringUtils; + /** * This class provides basic facilities for manipulating files and file paths. - * - * Path-related methods
- * - *Methods exist to retrieve the components of a typical file path. For example + * + *
Path-related methods
+ * + * Methods exist to retrieve the components of a typical file path. For example */www/hosted/mysite/index.html
, can be broken into: **
- * - * - *- *
/www/hosted/mysite/index
-- retrievable through {@link #removeExtension}- *
html
-- retrievable through {@link #getExtension}File-related methods
- * - * There are methods to create a {@link #toFile File from a URL}, copy a - * copy a {@link #copyFile File to another File}, + * + *File-related methods
+ * + *There are methods to create a {@link #toFile File from a URL}, copy a + * {@link #copyFile File to another File}, * copy a {@link #copyURLToFile URL's contents to a File}, * as well as methods to {@link #deleteDirectory(File) delete} and {@link #cleanDirectory(File) * clean} a directory. *
- * - * Common {@link java.io.File} manipulation routines. - * + *Common {@link java.io.File} manipulation routines.
+ ** Taken from the commons-utils repo. * Also code from Alexandria's FileUtils. * And from Avalon Excalibur's IO. * And from Ant. + *
* * @author Kevin A. Burton * @author Scott Sanders @@ -83,13 +89,13 @@ * @author Christoph.Reck * @author Peter Donald * @author Jeff Turner - * @version $Id$ */ -public class FileUtils -{ - protected FileUtils() - { - // This is a utility class. Normally dont instantiate +public class FileUtils { + /** + * protected constructor. + */ + protected FileUtils() { + // This is a utility class. Normally don't instantiate } /** @@ -102,20 +108,15 @@ protected FileUtils() */ private static final int ONE_MB = ONE_KB * ONE_KB; - /** - * The number of bytes in a gigabyte. - */ - private static final int ONE_GB = ONE_KB * ONE_MB; - /** * The file copy buffer size (30 MB) */ - private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30; + private static final int FILE_COPY_BUFFER_SIZE = ONE_MB * 30; /** * The vm line separator */ - private static final String FS = System.getProperty( "file.separator" ); + private static final String FS = System.getProperty("file.separator"); /** * Non-valid Characters for naming files, folders under Windows:":", "*", "?", "\"", "<", ">", "|"
@@ -123,24 +124,24 @@ protected FileUtils() * @see * http://support.microsoft.com/?scid=kb%3Ben-us%3B177506&x=12&y=13 */ - private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = { ":", "*", "?", "\"", "<", ">", "|" }; + private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = {":", "*", "?", "\"", "<", ">", "|"}; /** * @return the default excludes pattern * @see DirectoryScanner#DEFAULTEXCLUDES */ - @Nonnull public static String[] getDefaultExcludes() - { + @Nonnull + public static String[] getDefaultExcludes() { return DirectoryScanner.DEFAULTEXCLUDES; } /** - * @return the default excludes pattern as list. + * @return the default excludes pattern as list * @see #getDefaultExcludes() */ - @Nonnull public static ListgetDefaultExcludesAsList() - { - return Arrays.asList( getDefaultExcludes() ); + @Nonnull + public static List getDefaultExcludesAsList() { + return Arrays.asList(getDefaultExcludes()); } /** @@ -148,79 +149,80 @@ protected FileUtils() * @see DirectoryScanner#DEFAULTEXCLUDES * @see StringUtils#join(Object[], String) */ - @Nonnull public static String getDefaultExcludesAsString() - { - return StringUtils.join( DirectoryScanner.DEFAULTEXCLUDES, "," ); + @Nonnull + public static String getDefaultExcludesAsString() { + return StringUtils.join(DirectoryScanner.DEFAULTEXCLUDES, ","); } /** * Returns the directory path portion of a file specification string. * Matches the equally named unix command. * - * @param filename the file path - * @return The directory portion excluding the ending file separator. + * @param path the file path + * @return the directory portion excluding the ending file separator + * @deprecated use {@code Paths.get(path).getParent().getName()} */ - @Nonnull public static String dirname( @Nonnull String filename ) - { - int i = filename.lastIndexOf( File.separator ); - return ( i >= 0 ? filename.substring( 0, i ) : "" ); + @Deprecated + @Nonnull + public static String dirname(@Nonnull String path) { + int i = path.lastIndexOf(File.separator); + return (i >= 0 ? path.substring(0, i) : ""); } /** - * Returns the filename portion of a file specification string. + * Returns the filename portion of a path. * - * @param filename the file path - * @return The filename string with extension. + * @param path the file path + * @return the filename string with extension + * @deprecated use {@code Paths.get(path).getName()} */ - @Nonnull public static String filename( @Nonnull String filename ) - { - int i = filename.lastIndexOf( File.separator ); - return ( i >= 0 ? filename.substring( i + 1 ) : filename ); + @Deprecated + @Nonnull + public static String filename(@Nonnull String path) { + int i = path.lastIndexOf(File.separator); + return (i >= 0 ? path.substring(i + 1) : path); } /** - * Returns the extension portion of a file specification string. - * This everything after the last dot '.' in the filename (NOT including - * the dot). + * Returns the extension portion of a file path. + * This is everything after the last dot '.' in the path (NOT including the dot). * - * @param filename the file path + * @param path the file path * @return the extension of the file + * @deprecated use {@code org.apache.commons.io.FilenameUtils.getExtension} */ - @Nonnull public static String extension( @Nonnull String filename ) - { + @Deprecated + @Nonnull + public static String extension(@Nonnull String path) { // Ensure the last dot is after the last file separator - int lastSep = filename.lastIndexOf( File.separatorChar ); + int lastSep = path.lastIndexOf(File.separatorChar); int lastDot; - if ( lastSep < 0 ) - { - lastDot = filename.lastIndexOf( '.' ); - } - else - { - lastDot = filename.substring( lastSep + 1 ).lastIndexOf( '.' ); - if ( lastDot >= 0 ) - { + if (lastSep < 0) { + lastDot = path.lastIndexOf('.'); + } else { + lastDot = path.substring(lastSep + 1).lastIndexOf('.'); + if (lastDot >= 0) { lastDot += lastSep + 1; } } - if ( lastDot >= 0 && lastDot > lastSep ) - { - return filename.substring( lastDot + 1 ); + if (lastDot >= 0 && lastDot > lastSep) { + return path.substring(lastDot + 1); } return ""; } /** - * Check if a file exits. + * Check if a file exists. * - * @param fileName the file path. - * @return true if file exists. + * @param fileName the file path + * @return true if file exists + * @deprecated use {@code java.io.File.exists()} */ - public static boolean fileExists( @Nonnull String fileName ) - { - File file = new File( fileName ); + @Deprecated + public static boolean fileExists(@Nonnull String fileName) { + File file = new File(fileName); return file.exists(); } @@ -228,133 +230,116 @@ public static boolean fileExists( @Nonnull String fileName ) * Note: the file content is read with platform encoding. * * @param file the file path - * @return the file content using the platform encoding. + * @return the file content using the platform encoding * @throws IOException if any + * @deprecated use {@code new String(java.nio.files.Files.readAllBytes(file))} */ - @Nonnull public static String fileRead( @Nonnull String file ) - throws IOException - { - return fileRead( file, null ); + @Deprecated + @Nonnull + public static String fileRead(@Nonnull String file) throws IOException { + return fileRead(file, null); } /** * @param file the file path * @param encoding the wanted encoding - * @return the file content using the specified encoding. + * @return the file content using the specified encoding * @throws IOException if any + * @deprecated use {@code new String(java.nio.files.Files.readAllBytes(Paths.get(file)), encoding)} */ - @Nonnull private static String fileRead( @Nonnull String file, @Nullable String encoding ) - throws IOException - { - return fileRead( new File( file ), encoding ); + @Deprecated + @Nonnull + private static String fileRead(@Nonnull String file, @Nullable String encoding) throws IOException { + return fileRead(new File(file), encoding); } /** - * Note: the file content is read with platform encoding + * Note: the file content is read with platform encoding. * * @param file the file path - * @return the file content using the platform encoding. + * @return the file content using the platform encoding * @throws IOException if any + * @deprecated use {@code new String(java.nio.files.Files.readAllBytes(file.toPath()))} */ - @Nonnull public static String fileRead( @Nonnull File file ) - throws IOException - { - return fileRead( file, null ); + @Deprecated + @Nonnull + public static String fileRead(@Nonnull File file) throws IOException { + return fileRead(file, null); } /** * @param file the file path * @param encoding the wanted encoding - * @return the file content using the specified encoding. + * @return the file content using the specified encoding * @throws IOException if any + * @deprecated use {@code new String(java.nio.files.Files.readAllBytes(file.toPath()), encoding)} */ - @Nonnull public static String fileRead( @Nonnull File file, @Nullable String encoding ) - throws IOException - { - StringBuilder buf = new StringBuilder(); + @Deprecated + @Nonnull + public static String fileRead(@Nonnull File file, @Nullable String encoding) throws IOException { + Charset charset = charset(encoding); - Reader reader = null; + StringBuilder buf = new StringBuilder(); - try - { - if ( encoding != null ) - { - reader = new InputStreamReader( new FileInputStream( file ), encoding ); - } - else - { - reader = new InputStreamReader( new FileInputStream( file ) ); - } + try (Reader reader = Files.newBufferedReader(file.toPath(), charset)) { int count; char[] b = new char[512]; - while ( ( count = reader.read( b ) ) > 0 ) // blocking read + while ((count = reader.read(b)) >= 0) // blocking read { - buf.append( b, 0, count ); + buf.append(b, 0, count); } } - finally - { - IOUtil.close( reader ); - } return buf.toString(); } /** * @param file the file path - * @return the file content lines as String[] using the systems default encoding. - * An empty List if the file didn't exist. - * @throws IOException + * @return the file content lines as String[] using the system default encoding. + * An empty List if the file doesn't exist. + * @throws IOException in case of failure + * @deprecated use {@code java.nio.files.Files.readAllLines()} */ - @Nonnull public static String[] fileReadArray( @Nonnull File file ) - throws IOException - { - List files = loadFile( file ); + @Deprecated + @Nonnull + public static String[] fileReadArray(@Nonnull File file) throws IOException { + List lines = loadFile(file); - return files.toArray( new String[files.size()] ); + return lines.toArray(new String[lines.size()]); } /** - * Appends data to a file. The file will be created if it does not exist. - * Note: the data is written with platform encoding + * Appends data to a file. The file is created if it does not exist. + * Note: the data is written with platform encoding. * - * @param fileName The path of the file to write. - * @param data The content to write to the file. + * @param fileName the path of the file to write + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(filename, data.getBytes(), + * StandardOpenOption.APPEND, StandardOpenOption.CREATE)} */ - public static void fileAppend( @Nonnull String fileName, @Nonnull String data ) - throws IOException - { - fileAppend( fileName, null, data ); + @Deprecated + public static void fileAppend(@Nonnull String fileName, @Nonnull String data) throws IOException { + fileAppend(fileName, null, data); } /** * Appends data to a file. The file will be created if it does not exist. * - * @param fileName The path of the file to write. - * @param encoding The encoding of the file. - * @param data The content to write to the file. + * @param fileName the path of the file to write + * @param encoding the encoding of the file + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(filename, data.getBytes(encoding), + * StandardOpenOption.APPEND, StandardOpenOption.CREATE)} */ - public static void fileAppend( @Nonnull String fileName, @Nullable String encoding, @Nonnull String data ) - throws IOException - { - FileOutputStream out = null; - try - { - out = new FileOutputStream( fileName, true ); - if ( encoding != null ) - { - out.write( data.getBytes( encoding ) ); - } - else - { - out.write( data.getBytes() ); - } - } - finally - { - IOUtil.close( out ); + @Deprecated + public static void fileAppend(@Nonnull String fileName, @Nullable String encoding, @Nonnull String data) + throws IOException { + Charset charset = charset(encoding); + + try (OutputStream out = new FileOutputStream(fileName, true)) { + out.write(data.getBytes(charset)); } } @@ -362,59 +347,51 @@ public static void fileAppend( @Nonnull String fileName, @Nullable String encodi * Writes data to a file. The file will be created if it does not exist. * Note: the data is written with platform encoding * - * @param fileName The path of the file to write. - * @param data The content to write to the file. + * @param fileName the path of the file to write + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(filename, + * data.getBytes(), StandardOpenOption.CREATE)} */ - public static void fileWrite( @Nonnull String fileName, @Nonnull String data ) - throws IOException - { - fileWrite( fileName, null, data ); + @Deprecated + public static void fileWrite(@Nonnull String fileName, @Nonnull String data) throws IOException { + fileWrite(fileName, null, data); } /** * Writes data to a file. The file will be created if it does not exist. * - * @param fileName The path of the file to write. - * @param encoding The encoding of the file. - * @param data The content to write to the file. + * @param fileName the path of the file to write + * @param encoding the encoding of the file + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(Paths.get(filename), + * data.getBytes(encoding), StandardOpenOption.CREATE)} */ - public static void fileWrite( @Nonnull String fileName, @Nullable String encoding, @Nonnull String data ) - throws IOException - { - File file = new File( fileName ); - fileWrite( file, encoding, data ); + @Deprecated + public static void fileWrite(@Nonnull String fileName, @Nullable String encoding, @Nonnull String data) + throws IOException { + File file = new File(fileName); + fileWrite(file, encoding, data); } /** * Writes data to a file. The file will be created if it does not exist. * - * @param file The path of the file to write. - * @param encoding The encoding of the file. - * @param data The content to write to the file. + * @param file the path of the file to write + * @param encoding the encoding of the file + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(file.toPath(), + * data.getBytes(encoding), StandardOpenOption.CREATE)} */ - public static void fileWrite( @Nonnull File file, @Nullable String encoding, @Nonnull String data ) - throws IOException - { - Writer writer = null; - try - { - OutputStream out = new FileOutputStream( file ); - if ( encoding != null ) - { - writer = new OutputStreamWriter( out, encoding ); - } - else - { - writer = new OutputStreamWriter( out ); - } - writer.write( data ); - } - finally - { - IOUtil.close( writer ); + @Deprecated + public static void fileWrite(@Nonnull File file, @Nullable String encoding, @Nonnull String data) + throws IOException { + Charset charset = charset(encoding); + + try (Writer writer = Files.newBufferedWriter(file.toPath(), charset)) { + writer.write(data); } } @@ -422,126 +399,103 @@ public static void fileWrite( @Nonnull File file, @Nullable String encoding, @No * Writes String array data to a file in the systems default encoding. * The file will be created if it does not exist. * - * @param file The path of the file to write. - * @param data The content to write to the file. + * @param file the path of the file to write + * @param data the content to write to the file * @throws IOException if any + * @deprecated use {@code java.nio.files.Files.write(file.toPath(), + * data.getBytes(encoding), StandardOpenOption.CREATE)} */ - public static void fileWriteArray( @Nonnull File file, @Nullable String... data ) - throws IOException - { - fileWriteArray( file, null, data ); + @Deprecated + public static void fileWriteArray(@Nonnull File file, @Nullable String... data) throws IOException { + fileWriteArray(file, null, data); } /** - * Writes String array data to a file. The file will be created if it does not exist. + * Writes String array data to a file. The file is created if it does not exist. * - * @param file The path of the file to write. - * @param encoding The encoding of the file. - * @param data The content to write to the file. + * @param file the path of the file to write + * @param encoding the encoding of the file + * @param data the content to write to the file * @throws IOException if any - */ - public static void fileWriteArray( @Nonnull File file, @Nullable String encoding, @Nullable String... data ) - throws IOException - { - Writer writer = null; - try - { - OutputStream out = new FileOutputStream( file ); - if ( encoding != null ) - { - writer = new OutputStreamWriter( out, encoding ); - } - else - { - writer = new OutputStreamWriter( out ); - } - - for ( int i = 0; data != null && i < data.length; i++ ) - { - writer.write( data[i] ); - if ( i < data.length ) - { - writer.write( "\n" ); + * @deprecated use {@code java.nio.files.Files.write(file.toPath(), + * data.getBytes(encoding), StandardOpenOption.CREATE)} + */ + @Deprecated + public static void fileWriteArray(@Nonnull File file, @Nullable String encoding, @Nullable String... data) + throws IOException { + Charset charset = charset(encoding); + + try (Writer writer = Files.newBufferedWriter(file.toPath(), charset)) { + for (int i = 0; data != null && i < data.length; i++) { + writer.write(data[i]); + if (i < data.length) { + writer.write("\n"); } } } - finally - { - IOUtil.close( writer ); - } } /** * Deletes a file. * - * @param fileName The path of the file to delete. + * @param fileName the path of the file to delete + * @deprecated use {@code Files.delete(Paths.get(fileName))} */ - public static void fileDelete( @Nonnull String fileName ) - { - File file = new File( fileName ); + @Deprecated + public static void fileDelete(@Nonnull String fileName) { + File file = new File(fileName); //noinspection ResultOfMethodCallIgnored - deleteLegacyStyle( file ); + deleteLegacyStyle(file); } /** * Given a directory and an array of extensions return an array of compliant files. - * - * TODO Should an ignore list be passed in? - * TODO Should a recurse flag be passed in? - * - * The given extensions should be like "java" and not like ".java" * - * @param directory The path of the directory. - * @param extensions an array of expected extensions. - * @return An array of files for the wanted extensions. + * The given extensions should be like "java" and not like ".java".
+ * + * @param directory the path of the directory + * @param extensions an array of expected extensions + * @return an array of files for the wanted extensions */ - public static String[] getFilesFromExtension( @Nonnull String directory, @Nonnull String... extensions ) - { + public static String[] getFilesFromExtension(@Nonnull String directory, @Nonnull String... extensions) { Listfiles = new ArrayList (); - File currentDir = new File( directory ); + File currentDir = new File(directory); String[] unknownFiles = currentDir.list(); - if ( unknownFiles == null ) - { + if (unknownFiles == null) { return new String[0]; } - for ( String unknownFile : unknownFiles ) - { - String currentFileName = directory + System.getProperty( "file.separator" ) + unknownFile; - File currentFile = new File( currentFileName ); + for (String unknownFile : unknownFiles) { + String currentFileName = directory + System.getProperty("file.separator") + unknownFile; + File currentFile = new File(currentFileName); - if ( currentFile.isDirectory() ) - { + if (currentFile.isDirectory()) { // ignore all CVS directories... - if ( currentFile.getName().equals( "CVS" ) ) - { + if (currentFile.getName().equals("CVS")) { continue; } - // ok... transverse into this directory and get all the files... then combine + // ok... traverse into this directory and get all the files... then combine // them with the current list. - String[] fetchFiles = getFilesFromExtension( currentFileName, extensions ); - files = blendFilesToList( files, fetchFiles ); - } - else - { + String[] fetchFiles = getFilesFromExtension(currentFileName, extensions); + files = blendFilesToList(files, fetchFiles); + } else { // ok... add the file String add = currentFile.getAbsolutePath(); - if ( isValidFile( add, extensions ) ) - { - files.add( add ); + if (isValidFile(add, extensions)) { + files.add(add); } } } // ok... move the Vector into the files list... String[] foundFiles = new String[files.size()]; - files.toArray( foundFiles ); + files.toArray(foundFiles); return foundFiles; } @@ -549,9 +503,9 @@ public static String[] getFilesFromExtension( @Nonnull String directory, @Nonnul /** * Private helper method for getFilesFromExtension() */ - @Nonnull private static List blendFilesToList( @Nonnull List v, @Nonnull String... files ) - { - Collections.addAll( v, files ); + @Nonnull + private static List blendFilesToList(@Nonnull List v, @Nonnull String... files) { + Collections.addAll(v, files); return v; } @@ -561,45 +515,40 @@ public static String[] getFilesFromExtension( @Nonnull String directory, @Nonnul * Note that if the file does not have an extension, an empty string * ("") is matched for. */ - private static boolean isValidFile( @Nonnull String file, @Nonnull String... extensions ) - { - String extension = extension( file ); + private static boolean isValidFile(@Nonnull String file, @Nonnull String... extensions) { + String extension = extension(file); // ok.. now that we have the "extension" go through the current know // excepted extensions and determine if this one is OK. - for ( String extension1 : extensions ) - { - if ( extension1.equals( extension ) ) - { + for (String extension1 : extensions) { + if (extension1.equals(extension)) { return true; } } return false; - } /** - * Simple way to make a directory + * Simple way to make a directory. * * @param dir the directory to create - * @throws IllegalArgumentException if the dir contains illegal Windows characters under Windows OS. + * @throws IllegalArgumentException if the dir contains illegal Windows characters under Windows OS * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME + * @deprecated use {@code java.nio.file.Files.createDirectories(Paths.get(dir))} */ - public static void mkdir( @Nonnull String dir ) - { - File file = new File( dir ); + @Deprecated + public static void mkdir(@Nonnull String dir) { + File file = new File(dir); - if ( Os.isFamily( Os.FAMILY_WINDOWS ) && !isValidWindowsFileName( file ) ) - { + if (Os.isFamily(Os.FAMILY_WINDOWS) && !isValidWindowsFileName(file)) { throw new IllegalArgumentException( - "The file (" + dir + ") cannot contain any of the following characters: \n" + StringUtils.join( - INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) ); + "The file (" + dir + ") cannot contain any of the following characters: \n" + + StringUtils.join(INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " ")); } - if ( !file.exists() ) - { + if (!file.exists()) { //noinspection ResultOfMethodCallIgnored file.mkdirs(); } @@ -613,69 +562,51 @@ public static void mkdir( @Nonnull String dir ) * @return true if the content of the files are equal or they both don't exist, false otherwise * @throws IOException if any */ - public static boolean contentEquals( @Nonnull final File file1, @Nonnull final File file2 ) - throws IOException - { + public static boolean contentEquals(@Nonnull final File file1, @Nonnull final File file2) throws IOException { final boolean file1Exists = file1.exists(); - if ( file1Exists != file2.exists() ) - { + if (file1Exists != file2.exists()) { return false; } - if ( !file1Exists ) - { + if (!file1Exists) { // two not existing files are equal return true; } - if ( file1.isDirectory() || file2.isDirectory() ) - { + if (file1.isDirectory() || file2.isDirectory()) { // don't want to compare directory contents return false; } - InputStream input1 = null; - InputStream input2 = null; - try - { - input1 = new FileInputStream( file1 ); - input2 = new FileInputStream( file2 ); - return IOUtil.contentEquals( input1, input2 ); - - } - finally - { - IOUtil.close( input1 ); - IOUtil.close( input2 ); + try (InputStream input1 = new FileInputStream(file1); + InputStream input2 = new FileInputStream(file2)) { + return IOUtils.contentEquals(input1, input2); } } /** * Convert from a URL
to aFile
. * - * @param url File URL. - * @return The equivalentFile
object, ornull
if the URL's protocol - * is notfile
- */ - public @Nullable static File toFile( final @Nullable URL url ) - { - if ( url == null || !url.getProtocol().equalsIgnoreCase( "file" ) ) - { + * @param url file URL + * @return the equivalentFile
object, ornull
if the URL's protocol + * is notfile
+ */ + @Nullable + public static File toFile(@Nullable final URL url) { + if (url == null || !url.getProtocol().equalsIgnoreCase("file")) { return null; } - String filename = url.getFile().replace( '/', File.separatorChar ); + String filename = url.getFile().replace('/', File.separatorChar); int pos = -1; - while ( ( pos = filename.indexOf( '%', pos + 1 ) ) >= 0 ) - { - if ( pos + 2 < filename.length() ) - { - String hexStr = filename.substring( pos + 1, pos + 3 ); - char ch = (char) Integer.parseInt( hexStr, 16 ); - filename = filename.substring( 0, pos ) + ch + filename.substring( pos + 3 ); + while ((pos = filename.indexOf('%', pos + 1)) >= 0) { + if (pos + 2 < filename.length()) { + String hexStr = filename.substring(pos + 1, pos + 3); + char ch = (char) Integer.parseInt(hexStr, 16); + filename = filename.substring(0, pos) + ch + filename.substring(pos + 3); } } - return new File( filename ); + return new File(filename); } /** @@ -685,61 +616,59 @@ public static boolean contentEquals( @Nonnull final File file1, @Nonnull final F * @return the array of URLs * @throws IOException if an error occurs */ - @Nonnull public static URL[] toURLs( @Nonnull final File... files ) - throws IOException - { + @Nonnull + public static URL[] toURLs(@Nonnull final File... files) throws IOException { final URL[] urls = new URL[files.length]; - for ( int i = 0; i < urls.length; i++ ) - { - // Although this method is deprecated, it is still the most solid way to translate a File to URL - //noinspection deprecation - urls[i] = files[i].toURL(); + for (int i = 0; i < urls.length; i++) { + urls[i] = files[i].toURI().toURL(); } return urls; } /** - * Remove extension from filename. - * ie + * Remove extension from a path. E.g. *- * foo.txt --> foo - * a\b\c.jpg --> a\b\c - * a\b\c --> a\b\c + * foo.txt → foo + * a\b\c.jpg → a\b\c + * a\b\c → a\b\c ** * @param filename the path of the file * @return the filename minus extension + * @deprecated use {@code org.apache.commons.io.FilenameUtils.removeExtension()} */ - @Nonnull public static String removeExtension( @Nonnull final String filename ) - { - String ext = extension( filename ); + @Deprecated + @Nonnull + public static String removeExtension(@Nonnull final String filename) { + String ext = extension(filename); - if ( "".equals( ext ) ) - { + if ("".equals(ext)) { return filename; } - final int index = filename.lastIndexOf( ext ) - 1; - return filename.substring( 0, index ); + final int index = filename.lastIndexOf(ext) - 1; + return filename.substring(0, index); } /** - * Get extension from filename. - * ie + * Get extension from a path. E.g. + * *- * foo.txt --> "txt" - * a\b\c.jpg --> "jpg" - * a\b\c --> "" + * foo.txt → "txt" + * a\b\c.jpg → "jpg" + * a\b\c → "" ** * @param filename the path of the file * @return the extension of filename or "" if none + * @deprecated use {@code org.apache.commons.io.FilenameUtils.getExtension()} */ - @Nonnull public static String getExtension( @Nonnull final String filename ) - { - return extension( filename ); + @Deprecated + @Nonnull + public static String getExtension(@Nonnull final String filename) { + return extension(filename); } /** @@ -747,137 +676,116 @@ public static boolean contentEquals( @Nonnull final File file1, @Nonnull final F * (and any parent directories) will be created. If a filesource
in *destinationDirectory
exists, it will be overwritten. * - * @param source An existingFile
to copy. - * @param destinationDirectory A directory to copysource
into. - * @throws java.io.FileNotFoundException ifsource
isn't a normal file. - * @throws IllegalArgumentException ifdestinationDirectory
isn't a directory. + * @param source an existingFile
to copy + * @param destinationDirectory a directory to copysource
into + * @throws java.io.FileNotFoundException ifsource
isn't a normal file + * @throws IllegalArgumentException ifdestinationDirectory
isn't a directory * @throws IOException ifsource
does not exist, the file in *destinationDirectory
cannot be written to, or an IO error - * occurs during copying. + * occurs during copying + * @deprecated use {@code org.apache.commons.io.FileUtils.copyFileToDirectory()} */ - public static void copyFileToDirectory( @Nonnull final File source, @Nonnull final File destinationDirectory ) - throws IOException - { - if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() ) - { - throw new IllegalArgumentException( "Destination is not a directory" ); + @Deprecated + public static void copyFileToDirectory(@Nonnull final File source, @Nonnull final File destinationDirectory) + throws IOException { + if (destinationDirectory.exists() && !destinationDirectory.isDirectory()) { + throw new IOException("Destination is not a directory"); } - copyFile( source, new File( destinationDirectory, source.getName() ) ); + copyFile(source, new File(destinationDirectory, source.getName())); } /** * Copy file from source to destination only if source is newer than the target file. * IfdestinationDirectory
does not exist, it - * (and any parent directories) will be created. If a filesource
in - *destinationDirectory
exists, it will be overwritten. + * (and any parent directories) is created. If a filesource
in + *destinationDirectory
exists, it is overwritten. * - * @param source An existingFile
to copy. - * @param destinationDirectory A directory to copysource
into. - * @throws java.io.FileNotFoundException ifsource
isn't a normal file. - * @throws IllegalArgumentException ifdestinationDirectory
isn't a directory. + * @param source an existingFile
to copy + * @param destinationDirectory a directory to copysource
into + * @throws java.io.FileNotFoundException ifsource
isn't a normal file + * @throws IllegalArgumentException ifdestinationDirectory
isn't a directory * @throws IOException ifsource
does not exist, the file in *destinationDirectory
cannot be written to, or an IO error - * occurs during copying. + * occurs during copying */ - private static void copyFileToDirectoryIfModified( @Nonnull final File source, - @Nonnull final File destinationDirectory ) - throws IOException - { - if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() ) - { - throw new IllegalArgumentException( "Destination is not a directory" ); + private static void copyFileToDirectoryIfModified( + @Nonnull final File source, @Nonnull final File destinationDirectory) throws IOException { + if (destinationDirectory.exists() && !destinationDirectory.isDirectory()) { + throw new IllegalArgumentException("Destination is not a directory"); } - copyFileIfModified( source, new File( destinationDirectory, source.getName() ) ); + copyFileIfModified(source, new File(destinationDirectory, source.getName())); } - /** * Copy file from source to destination. The directories up todestination
will be * created if they don't already exist.destination
will be overwritten if it * already exists. * - * @param source An existing non-directoryFile
to copy bytes from. - * @param destination A non-directoryFile
to write bytes to (possibly - * overwriting). - * @throws IOException ifsource
does not exist,destination
cannot be - * written to, or an IO error occurs during copying. + * @param source an existing non-directoryFile
to copy bytes from + * @param destination a non-directoryFile
to write bytes to (possibly + * overwriting) + * @throws IOException ifsource
does not exist,destination
cannot be + * written to, or an IO error occurs during copying * @throws java.io.FileNotFoundException ifdestination
is a directory + * @deprecated use {@code java.nio.Files.copy(source.toPath(), destination.toPath(), LinkOption.NOFOLLOW_LINKS, + * StandardCopyOption.REPLACE_EXISTING)} */ - public static void copyFile( @Nonnull final File source, @Nonnull final File destination ) - throws IOException - { - //check source exists - if ( !source.exists() ) - { + @Deprecated + public static void copyFile(@Nonnull final File source, @Nonnull final File destination) throws IOException { + // check source exists + if (!source.exists()) { final String message = "File " + source + " does not exist"; - throw new IOException( message ); + throw new IOException(message); } - if ( Java7Support.isAtLeastJava7() && Java7Support.isSymLink( source ) ) - { - File target = Java7Support.readSymbolicLink( source ); - Java7Support.createSymbolicLink( destination, target ); + if (Files.isSymbolicLink(source.toPath())) { + File target = Files.readSymbolicLink(source.toPath()).toFile(); + createSymbolicLink(destination, target); return; } - //check source != destination, see PLXUTILS-10 - if ( source.getCanonicalPath().equals( destination.getCanonicalPath() ) ) - { - //if they are equal, we can exit the method without doing any work + // check source != destination, see PLXUTILS-10 + if (destination.exists() && Files.isSameFile(source.toPath(), destination.toPath())) { + // if they are equal, we can exit the method without doing any work return; } - mkdirsFor( destination ); + mkdirsFor(destination); - doCopyFile( source, destination ); + doCopyFile(source, destination); - if ( source.length() != destination.length() ) - { + if (source.length() != destination.length()) { final String message = "Failed to copy full contents from " + source + " to " + destination; - throw new IOException( message ); + throw new IOException(message); } } - private static void mkdirsFor( @Nonnull File destination ) - { - //does destination directory exist ? - if ( destination.getParentFile() != null && !destination.getParentFile().exists() ) - { + private static void mkdirsFor(@Nonnull File destination) { + // does destination directory exist ? + if (destination.getParentFile() != null && !destination.getParentFile().exists()) { //noinspection ResultOfMethodCallIgnored destination.getParentFile().mkdirs(); } } - private static void doCopyFile( @Nonnull File source, @Nonnull File destination ) - throws IOException - { - FileInputStream fis = null; - FileOutputStream fos = null; - FileChannel input = null; - FileChannel output = null; - try - { - fis = new FileInputStream( source ); - fos = new FileOutputStream( destination ); - input = fis.getChannel(); - output = fos.getChannel(); + private static void doCopyFile(@Nonnull File source, @Nonnull File destination) throws IOException { + + try (FileInputStream fis = new FileInputStream(source); + FileOutputStream fos = new FileOutputStream(destination); + FileChannel input = fis.getChannel(); + FileChannel output = fos.getChannel()) { + long size = input.size(); long pos = 0; long count; - while ( pos < size ) - { + while (pos < size) { count = size - pos > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : size - pos; - pos += output.transferFrom( input, pos, count ); + pos += output.transferFrom(input, pos, count); } } - finally - { - IOUtil.close( output ); - IOUtil.close( fos ); - IOUtil.close( input ); - IOUtil.close( fis ); - } + + copyFilePermissions(source, destination); } /** @@ -888,16 +796,14 @@ private static void doCopyFile( @Nonnull File source, @Nonnull File destination * @param source An existing non-directoryFile
to copy bytes from. * @param destination A non-directoryFile
to write bytes to (possibly * overwriting). - * @return true if no problem occured + * @return true if no problem occurred * @throws IOException ifsource
does not exist,destination
cannot be * written to, or an IO error occurs during copying. */ - private static boolean copyFileIfModified( @Nonnull final File source, @Nonnull final File destination ) - throws IOException - { - if ( destination.lastModified() < source.lastModified() ) - { - copyFile( source, destination ); + private static boolean copyFileIfModified(@Nonnull final File source, @Nonnull final File destination) + throws IOException { + if (destination.lastModified() < source.lastModified()) { + copyFile(source, destination); return true; } @@ -910,20 +816,20 @@ private static boolean copyFileIfModified( @Nonnull final File source, @Nonnull * The directories up todestination
will be created if they don't already exist. *destination
will be overwritten if it already exists. * - * @param source AURL
to copy bytes from. - * @param destination A non-directoryFile
to write bytes to (possibly - * overwriting). + * @param source aURL
to copy bytes from + * @param destination a non-directoryFile
to write bytes to (possibly + * overwriting) * @throws IOException if **
+ * @deprecated use {@code java.nio.Files.copy(source.openStream(), destination.toPath(), + * StandardCopyOption.REPLACE_EXISTING)} */ - public static void copyURLToFile( @Nonnull final URL source, @Nonnull final File destination ) - throws IOException - { - copyStreamToFile( source.openStream(), destination ); + public static void copyURLToFile(@Nonnull final URL source, @Nonnull final File destination) throws IOException { + copyStreamToFile(source.openStream(), destination); } /** @@ -931,45 +837,37 @@ public static void copyURLToFile( @Nonnull final URL source, @Nonnull final File * The directories up to- *
source
URL cannot be opened- *
destination
cannot be written to- an IO error occurs during copying
*destination
will be created if they don't already exist. *destination
will be overwritten if it already exists. * - * @param source An {@link InputStream} to copy bytes from. This stream is + * @param source an {@link InputStream} to copy bytes from. This stream is * guaranteed to be closed. - * @param destination A non-directoryFile
to write bytes to (possibly - * overwriting). + * @param destination a non-directoryFile
to write bytes to (possibly + * overwriting) * @throws IOException if *- *
- */ - private static void copyStreamToFile( @Nonnull final @WillClose InputStream source, - @Nonnull final File destination ) - throws IOException - { - FileOutputStream output = null; - try - { - //does destination directory exist ? - if ( destination.getParentFile() != null && !destination.getParentFile().exists() ) - { - //noinspection ResultOfMethodCallIgnored - destination.getParentFile().mkdirs(); - } - - //make sure we can write to destination - if ( destination.exists() && !destination.canWrite() ) - { - final String message = "Unable to open file " + destination + " for writing."; - throw new IOException( message ); - } + * @deprecated use {@code java.nio.Files.copy(source, destination.toPath(), + * StandardCopyOption.REPLACE_EXISTING)} + */ + @Deprecated + private static void copyStreamToFile(@Nonnull @WillClose final InputStream source, @Nonnull final File destination) + throws IOException { + // does destination directory exist ? + if (destination.getParentFile() != null && !destination.getParentFile().exists()) { + // noinspection ResultOfMethodCallIgnored + destination.getParentFile().mkdirs(); + } - output = new FileOutputStream( destination ); - IOUtil.copy( source, output ); + // make sure we can write to destination + if (destination.exists() && !destination.canWrite()) { + final String message = "Unable to open file " + destination + " for writing."; + throw new IOException(message); } - finally - { - IOUtil.close( source ); - IOUtil.close( output ); + + try (OutputStream out = new FileOutputStream(destination); + InputStream in = source) { + IOUtil.copy(in, out); } } @@ -979,57 +877,52 @@ private static void copyStreamToFile( @Nonnull final @WillClose InputStream sour * root. * Eg: *- + *
source
URL cannot be opened- *
source
cannot be opened- - *
destination
cannot be written to- an IO error occurs during copying
+ *- an I/O error occurs during copying
*- * /foo// --> /foo/ - * /foo/./ --> /foo/ - * /foo/../bar --> /bar - * /foo/../bar/ --> /bar/ - * /foo/../bar/../baz --> /baz - * //foo//./bar --> /foo/bar - * /../ --> null + * /foo// → /foo/ + * /foo/./ → /foo/ + * /foo/../bar → /bar + * /foo/../bar/ → /bar/ + * /foo/../bar/../baz → /baz + * //foo//./bar → /foo/bar + * /../ → null ** * @param path the path to normalize - * @return the normalized String, ornull
if too many ..'s. + * @return the normalized String, ornull
if too many ..'s + * @deprecated use {@code org.apache.commons.io.FileNameUtils.normalize()} */ - public static @Nonnull String normalize( @Nonnull final String path ) - { + @Deprecated + @Nonnull + public static String normalize(@Nonnull final String path) { String normalized = path; // Resolve occurrences of "//" in the normalized path - while ( true ) - { - int index = normalized.indexOf( "//" ); - if ( index < 0 ) - { + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) { break; } - normalized = normalized.substring( 0, index ) + normalized.substring( index + 1 ); + normalized = normalized.substring(0, index) + normalized.substring(index + 1); } // Resolve occurrences of "/./" in the normalized path - while ( true ) - { - int index = normalized.indexOf( "/./" ); - if ( index < 0 ) - { + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) { break; } - normalized = normalized.substring( 0, index ) + normalized.substring( index + 2 ); + normalized = normalized.substring(0, index) + normalized.substring(index + 2); } // Resolve occurrences of "/../" in the normalized path - while ( true ) - { - int index = normalized.indexOf( "/../" ); - if ( index < 0 ) - { + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) { break; } - if ( index == 0 ) - { - return null; // Trying to go outside our context + if (index == 0) { + return null; // Trying to go outside our context } - int index2 = normalized.lastIndexOf( '/', index - 1 ); - normalized = normalized.substring( 0, index2 ) + normalized.substring( index + 3 ); + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + normalized.substring(index + 3); } // Return the normalized path that we have completed @@ -1037,39 +930,32 @@ private static void copyStreamToFile( @Nonnull final @WillClose InputStream sour } /** - * Resolve a filefilename
to it's canonical form. Iffilename
is - * relative (doesn't start with/
), it will be resolved relative to - *baseFile
, otherwise it is treated as a normal root-relative path. + * Resolve a filefilename
to its canonical form. Iffilename
is + * relative (doesn't start with/
), it is resolved relative to + *baseFile
. Otherwise it is treated as a normal root-relative path. * - * @param baseFile Where to resolvefilename
from, iffilename
is - * relative. - * @param filename Absolute or relative file path to resolve. - * @return The canonicalFile
offilename
. + * @param baseFile where to resolvefilename
from, iffilename
is relative + * @param filename absolute or relative file path to resolve + * @return the canonicalFile
offilename
*/ - public static @Nonnull File resolveFile( final File baseFile, @Nonnull String filename ) - { + @Nonnull + public static File resolveFile(final File baseFile, @Nonnull String filename) { String filenm = filename; - if ( '/' != File.separatorChar ) - { - filenm = filename.replace( '/', File.separatorChar ); + if ('/' != File.separatorChar) { + filenm = filename.replace('/', File.separatorChar); } - if ( '\\' != File.separatorChar ) - { - filenm = filename.replace( '\\', File.separatorChar ); + if ('\\' != File.separatorChar) { + filenm = filename.replace('\\', File.separatorChar); } // deal with absolute files - if ( filenm.startsWith( File.separator ) || ( Os.isFamily( Os.FAMILY_WINDOWS ) && filenm.indexOf( ":" ) > 0 ) ) - { - File file = new File( filenm ); + if (filenm.startsWith(File.separator) || (Os.isFamily(Os.FAMILY_WINDOWS) && filenm.indexOf(":") > 0)) { + File file = new File(filenm); - try - { + try { file = file.getCanonicalFile(); - } - catch ( final IOException ioe ) - { + } catch (final IOException ioe) { // nop } @@ -1080,37 +966,31 @@ private static void copyStreamToFile( @Nonnull final @WillClose InputStream sour final char[] chars = filename.toCharArray(); final StringBuilder sb = new StringBuilder(); - //remove duplicate file separators in succession - except - //on win32 at start of filename as UNC filenames can - //be \\AComputer\AShare\myfile.txt + // remove duplicate file separators in succession - except + // on win32 at start of filename as UNC filenames can + // be \\AComputer\AShare\myfile.txt int start = 0; - if ( '\\' == File.separatorChar ) - { - sb.append( filenm.charAt( 0 ) ); + if ('\\' == File.separatorChar) { + sb.append(filenm.charAt(0)); start++; } - for ( int i = start; i < chars.length; i++ ) - { + for (int i = start; i < chars.length; i++) { final boolean doubleSeparator = File.separatorChar == chars[i] && File.separatorChar == chars[i - 1]; - if ( !doubleSeparator ) - { - sb.append( chars[i] ); + if (!doubleSeparator) { + sb.append(chars[i]); } } filenm = sb.toString(); - //must be relative - File file = ( new File( baseFile, filenm ) ).getAbsoluteFile(); + // must be relative + File file = (new File(baseFile, filenm)).getAbsoluteFile(); - try - { + try { file = file.getCanonicalFile(); - } - catch ( final IOException ioe ) - { + } catch (final IOException ioe) { // nop } @@ -1118,86 +998,65 @@ private static void copyStreamToFile( @Nonnull final @WillClose InputStream sour } /** - * Delete a file. If file is directory delete it and all sub-directories. + * Delete a file. If file is directory, delete it and all sub-directories. * * @param file the file path * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.FileUtils.deleteQuietly()} */ - public static void forceDelete( @Nonnull final String file ) - throws IOException - { - forceDelete( new File( file ) ); + @Deprecated + public static void forceDelete(@Nonnull final String file) throws IOException { + forceDelete(new File(file)); } /** - * Delete a file. If file is directory delete it and all sub-directories. + * Delete a file. If file is directory, delete it and all sub-directories. * * @param file a file * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.FileUtils.deleteQuietly()} */ - public static void forceDelete( @Nonnull final File file ) - throws IOException - { - if ( file.isDirectory() ) - { - deleteDirectory( file ); - } - else - { + @Deprecated + public static void forceDelete(@Nonnull final File file) throws IOException { + if (file.isDirectory()) { + deleteDirectory(file); + } else { /* * NOTE: Always try to delete the file even if it appears to be non-existent. This will ensure that a * symlink whose target does not exist is deleted, too. */ boolean filePresent = file.getCanonicalFile().exists(); - if ( !deleteFile( file ) && filePresent ) - { + if (!deleteFile(file) && filePresent) { final String message = "File " + file + " unable to be deleted."; - throw new IOException( message ); + throw new IOException(message); } } } /** - * deletes a file. + * Deletes a file. * - * @param file The file to delete - * @throws IOException If the file cannot be delted. + * @param file the file to delete + * @throws IOException if the file cannot be deleted + * @deprecated use {@code java.nio.files.Files.delete(file.toPath())} */ - - - public static void delete( @Nonnull File file ) - throws IOException - { - if ( Java7Support.isAtLeastJava7() ) - { - Java7Support.delete( file ); - } - else - { - if ( !file.delete() ) - { - throw new IOException( "Could not delete " + file.getName() ); - } - } + @Deprecated + public static void delete(@Nonnull File file) throws IOException { + Files.delete(file.toPath()); } - public static boolean deleteLegacyStyle( @Nonnull File file ) - { - if ( Java7Support.isAtLeastJava7() ) - { - try - { - Java7Support.delete( file ); - return true; - } - catch ( IOException e ) - { - return false; - } - } - else - { - return file.delete(); + /** + * @param file the file + * @return true / false + * @deprecated use {@code java.nio.files.Files.delete(file.toPath())} + */ + @Deprecated + public static boolean deleteLegacyStyle(@Nonnull File file) { + try { + Files.delete(file.toPath()); + return true; + } catch (IOException e) { + return false; } } @@ -1209,71 +1068,52 @@ public static boolean deleteLegacyStyle( @Nonnull File file ) * @param file a file * @throws IOException if any */ - private static boolean deleteFile( @Nonnull File file ) - throws IOException - { - if ( file.isDirectory() ) - { - throw new IOException( "File " + file + " isn't a file." ); + private static boolean deleteFile(@Nonnull File file) throws IOException { + if (file.isDirectory()) { + throw new IOException("File " + file + " isn't a file."); } - if ( !deleteLegacyStyle( file ) ) - { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) - { + if (!deleteLegacyStyle(file)) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { file = file.getCanonicalFile(); - System.gc(); } - try - { - Thread.sleep( 10 ); - return deleteLegacyStyle( file ); - } - catch ( InterruptedException ex ) - { - return deleteLegacyStyle( file ); + try { + Thread.sleep(10); + return deleteLegacyStyle(file); + } catch (InterruptedException ex) { + return deleteLegacyStyle(file); } } return true; } - /** * Make a directory. * * @param file not null - * @throws IOException If there already exists a file with specified name or - * the directory is unable to be created + * @throws IOException if a file already exists with the specified name or the directory is unable to be created * @throws IllegalArgumentException if the file contains illegal Windows characters under Windows OS. * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME */ - public static void forceMkdir( @Nonnull final File file ) - throws IOException - { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) && !isValidWindowsFileName( file ) ) - { + public static void forceMkdir(@Nonnull final File file) throws IOException { + if (Os.isFamily(Os.FAMILY_WINDOWS) && !isValidWindowsFileName(file)) { throw new IllegalArgumentException( - "The file (" + file.getAbsolutePath() + ") cannot contain any of the following characters: \n" - + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) ); + "The file (" + file.getAbsolutePath() + ") cannot contain any of the following characters: \n" + + StringUtils.join(INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " ")); } - if ( file.exists() ) - { - if ( file.isFile() ) - { + if (file.exists()) { + if (file.isFile()) { final String message = - "File " + file + " exists and is " + "not a directory. Unable to create directory."; - throw new IOException( message ); + "File " + file + " exists and is " + "not a directory. Unable to create directory."; + throw new IOException(message); } - } - else - { - if ( !file.mkdirs() ) - { + } else { + if (!file.mkdirs()) { final String message = "Unable to create directory " + file; - throw new IOException( message ); + throw new IOException(message); } } } @@ -1283,11 +1123,11 @@ public static void forceMkdir( @Nonnull final File file ) * * @param directory a directory * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.FileUtils.deleteDirectory()} */ - public static void deleteDirectory( @Nonnull final String directory ) - throws IOException - { - deleteDirectory( new File( directory ) ); + @Deprecated + public static void deleteDirectory(@Nonnull final String directory) throws IOException { + deleteDirectory(new File(directory)); } /** @@ -1295,75 +1135,65 @@ public static void deleteDirectory( @Nonnull final String directory ) * * @param directory a directory * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.FileUtils.deleteDirectory()} */ - public static void deleteDirectory( @Nonnull final File directory ) - throws IOException - { - if ( !directory.exists() ) - { + @Deprecated + public static void deleteDirectory(@Nonnull final File directory) throws IOException { + if (!directory.exists()) { return; } /* try delete the directory before its contents, which will take * care of any directories that are really symbolic links. */ - if ( deleteLegacyStyle( directory ) ) - { + if (deleteLegacyStyle(directory)) { return; } - cleanDirectory( directory ); - if ( !deleteLegacyStyle( directory ) ) - { + cleanDirectory(directory); + if (!deleteLegacyStyle(directory)) { final String message = "Directory " + directory + " unable to be deleted."; - throw new IOException( message ); + throw new IOException(message); } } /** - * Clean a directory without deleting it. + * Remove all files from a directory without deleting it. * * @param directory a directory - * @throws IOException if any + * @throws IOException if any. This can leave cleaning in a half-finished state where + * some but not all files have been deleted. + * @deprecated use {@code org.apache.commons.io.FileUtils.cleanDirectory()} */ - public static void cleanDirectory( @Nonnull final File directory ) - throws IOException - { - if ( !directory.exists() ) - { + @Deprecated + public static void cleanDirectory(@Nonnull final File directory) throws IOException { + if (!directory.exists()) { final String message = directory + " does not exist"; - throw new IllegalArgumentException( message ); + throw new IllegalArgumentException(message); } - if ( !directory.isDirectory() ) - { + if (!directory.isDirectory()) { final String message = directory + " is not a directory"; - throw new IllegalArgumentException( message ); + throw new IllegalArgumentException(message); } IOException exception = null; final File[] files = directory.listFiles(); - if ( files == null ) - { + if (files == null) { return; } - for ( final File file : files ) - { - try - { - forceDelete( file ); - } - catch ( final IOException ioe ) - { + for (final File file : files) { + try { + forceDelete(file); + } catch (final IOException ioe) { exception = ioe; } } - if ( null != exception ) - { + if (null != exception) { throw exception; } } @@ -1372,49 +1202,44 @@ public static void cleanDirectory( @Nonnull final File directory ) * Recursively count size of a directory. * * @param directory a directory - * @return size of directory in bytes. + * @return size of directory in bytes + * @deprecated use {@code org.apache.commons.io.FileUtils.sizeOf()} */ - public static long sizeOfDirectory( @Nonnull final String directory ) - { - return sizeOfDirectory( new File( directory ) ); + @Deprecated + public static long sizeOfDirectory(@Nonnull final String directory) { + return sizeOfDirectory(new File(directory)); } /** * Recursively count size of a directory. * * @param directory a directory - * @return size of directory in bytes. + * @return size of directory in bytes + * @deprecated use {@code org.apache.commons.io.FileUtils.sizeOf()} */ - public static long sizeOfDirectory( @Nonnull final File directory ) - { - if ( !directory.exists() ) - { + @Deprecated + public static long sizeOfDirectory(@Nonnull final File directory) { + if (!directory.exists()) { final String message = directory + " does not exist"; - throw new IllegalArgumentException( message ); + throw new IllegalArgumentException(message); } - if ( !directory.isDirectory() ) - { + if (!directory.isDirectory()) { final String message = directory + " is not a directory"; - throw new IllegalArgumentException( message ); + throw new IllegalArgumentException(message); } long size = 0; final File[] files = directory.listFiles(); - if ( files == null ) - { - throw new IllegalArgumentException( "Problems reading directory" ); + if (files == null) { + throw new IllegalArgumentException("Problems reading directory"); } - for ( final File file : files ) - { - if ( file.isDirectory() ) - { - size += sizeOfDirectory( file ); - } - else - { + for (final File file : files) { + if (file.isDirectory()) { + size += sizeOfDirectory(file); + } else { size += file.length(); } } @@ -1427,17 +1252,16 @@ public static long sizeOfDirectory( @Nonnull final File directory ) * including the directory name in each of the files * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated * @return a list of File objects - * @throws IOException + * @throws IOException in case of failure. * @see #getFileNames(File, String, String, boolean) */ @Nonnull - public static ListgetFiles( @Nonnull File directory, @Nullable String includes, @Nullable String excludes ) - throws IOException - { - return getFiles( directory, includes, excludes, true ); + public static List getFiles(@Nonnull File directory, @Nullable String includes, @Nullable String excludes) + throws IOException { + return getFiles(directory, includes, excludes, true); } /** @@ -1448,21 +1272,19 @@ public static List getFiles( @Nonnull File directory, @Nullable String inc * @param excludes the excludes pattern, comma separated * @param includeBasedir true to include the base dir in each file * @return a list of File objects - * @throws IOException + * @throws IOException in case of failure. * @see #getFileNames(File, String, String, boolean) */ @Nonnull - public static List getFiles( @Nonnull File directory, @Nullable String includes, @Nullable String excludes, - boolean includeBasedir ) - throws IOException - { - List fileNames = getFileNames( directory, includes, excludes, includeBasedir ); + public static List getFiles( + @Nonnull File directory, @Nullable String includes, @Nullable String excludes, boolean includeBasedir) + throws IOException { + List fileNames = getFileNames(directory, includes, excludes, includeBasedir); List files = new ArrayList (); - for ( String filename : fileNames ) - { - files.add( new File( filename ) ); + for (String filename : fileNames) { + files.add(new File(filename)); } return files; @@ -1473,36 +1295,39 @@ public static List getFiles( @Nonnull File directory, @Nullable String inc * This method use case sensitive file name. * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated - * @param includeBasedir true to include the base dir in each String of file - * @return a list of files as String - * @throws IOException + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated + * @param includeBasedir true to include the base directory in each String of file + * @return a list of file names + * @throws IOException in case of failure */ - @Nonnull public static List getFileNames( @Nonnull File directory, @Nullable String includes, - @Nullable String excludes, boolean includeBasedir ) - throws IOException - { - return getFileNames( directory, includes, excludes, includeBasedir, true ); + @Nonnull + public static List getFileNames( + @Nonnull File directory, @Nullable String includes, @Nullable String excludes, boolean includeBasedir) + throws IOException { + return getFileNames(directory, includes, excludes, includeBasedir, true); } /** * Return a list of files as String depending options. * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated * @param includeBasedir true to include the base dir in each String of file * @param isCaseSensitive true if case sensitive * @return a list of files as String * @throws IOException */ - @Nonnull private static List getFileNames( @Nonnull File directory, @Nullable String includes, - @Nullable String excludes, boolean includeBasedir, - boolean isCaseSensitive ) - throws IOException - { - return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, true, false ); + @Nonnull + private static List getFileNames( + @Nonnull File directory, + @Nullable String includes, + @Nullable String excludes, + boolean includeBasedir, + boolean isCaseSensitive) + throws IOException { + return getFileAndDirectoryNames(directory, includes, excludes, includeBasedir, isCaseSensitive, true, false); } /** @@ -1510,105 +1335,100 @@ public static List getFiles( @Nonnull File directory, @Nullable String inc * This method use case sensitive file name. * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated * @param includeBasedir true to include the base dir in each String of file * @return a list of directories as String - * @throws IOException + * @throws IOException in case of failure. */ - @Nonnull public static List getDirectoryNames( @Nonnull File directory, @Nullable String includes, - @Nullable String excludes, boolean includeBasedir ) - throws IOException - { - return getDirectoryNames( directory, includes, excludes, includeBasedir, true ); + @Nonnull + public static List getDirectoryNames( + @Nonnull File directory, @Nullable String includes, @Nullable String excludes, boolean includeBasedir) + throws IOException { + return getDirectoryNames(directory, includes, excludes, includeBasedir, true); } /** - * Return a list of directories as String depending options. + * Return a list of directories as Strings. * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated - * @param includeBasedir true to include the base dir in each String of file + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated + * @param includeBasedir true to include the base directory in each String of file * @param isCaseSensitive true if case sensitive * @return a list of directories as String - * @throws IOException + * @throws IOException in case of failure */ - @Nonnull public static List getDirectoryNames( @Nonnull File directory, @Nullable String includes, - @Nullable String excludes, boolean includeBasedir, - boolean isCaseSensitive ) - throws IOException - { - return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, false, true ); + @Nonnull + public static List getDirectoryNames( + @Nonnull File directory, + @Nullable String includes, + @Nullable String excludes, + boolean includeBasedir, + boolean isCaseSensitive) + throws IOException { + return getFileAndDirectoryNames(directory, includes, excludes, includeBasedir, isCaseSensitive, false, true); } /** - * Return a list of files as String depending options. + * Return a list of file names as Strings. * * @param directory the directory to scan - * @param includes the includes pattern, comma separated - * @param excludes the excludes pattern, comma separated - * @param includeBasedir true to include the base dir in each String of file + * @param includes the Ant includes pattern, comma separated + * @param excludes the Ant excludes pattern, comma separated + * @param includeBasedir true to include the base directory in each String of file * @param isCaseSensitive true if case sensitive - * @param getFiles true if get files - * @param getDirectories true if get directories - * @return a list of files as String + * @param getFiles true to include regular files + * @param getDirectories true to include directories + * @return a list of file names */ - @Nonnull public static List getFileAndDirectoryNames( File directory, @Nullable String includes, - @Nullable String excludes, boolean includeBasedir, - boolean isCaseSensitive, boolean getFiles, - boolean getDirectories ) - { + @Nonnull + public static List getFileAndDirectoryNames( + File directory, + @Nullable String includes, + @Nullable String excludes, + boolean includeBasedir, + boolean isCaseSensitive, + boolean getFiles, + boolean getDirectories) { DirectoryScanner scanner = new DirectoryScanner(); - scanner.setBasedir( directory ); + scanner.setBasedir(directory); - if ( includes != null ) - { - scanner.setIncludes( StringUtils.split( includes, "," ) ); + if (includes != null) { + scanner.setIncludes(StringUtils.split(includes, ",")); } - if ( excludes != null ) - { - scanner.setExcludes( StringUtils.split( excludes, "," ) ); + if (excludes != null) { + scanner.setExcludes(StringUtils.split(excludes, ",")); } - scanner.setCaseSensitive( isCaseSensitive ); + scanner.setCaseSensitive(isCaseSensitive); scanner.scan(); List list = new ArrayList (); - if ( getFiles ) - { + if (getFiles) { String[] files = scanner.getIncludedFiles(); - for ( String file : files ) - { - if ( includeBasedir ) - { - list.add( directory + FileUtils.FS + file ); - } - else - { - list.add( file ); + for (String file : files) { + if (includeBasedir) { + list.add(directory + FileUtils.FS + file); + } else { + list.add(file); } } } - if ( getDirectories ) - { + if (getDirectories) { String[] directories = scanner.getIncludedDirectories(); - for ( String directory1 : directories ) - { - if ( includeBasedir ) - { - list.add( directory + FileUtils.FS + directory1 ); - } - else - { - list.add( directory1 ); + for (String directory1 : directories) { + if (includeBasedir) { + list.add(directory + FileUtils.FS + directory1); + } else { + list.add(directory1); } } } @@ -1617,146 +1437,146 @@ public static List getFiles( @Nonnull File directory, @Nullable String inc } /** - * Copy a directory to an other one. + * Copy the contents of a directory into another one. * - * @param sourceDirectory the source dir - * @param destinationDirectory the target dir + * @param sourceDirectory the source directory. If the source does not exist, + * the method simply returns. + * @param destinationDirectory the target directory; will be created if it doesn't exist * @throws IOException if any - */ - public static void copyDirectory( @Nonnull File sourceDirectory, @Nonnull File destinationDirectory ) - throws IOException - { - copyDirectory( sourceDirectory, destinationDirectory, "**", null ); + * @deprecated use {@code org.apache.commons.io.FileUtils.copyDirectory()} + */ + @Deprecated + public static void copyDirectory(@Nonnull File sourceDirectory, @Nonnull File destinationDirectory) + throws IOException { + Objects.requireNonNull(sourceDirectory); + Objects.requireNonNull(destinationDirectory); + if (destinationDirectory.equals(sourceDirectory)) { + throw new IOException("Can't copy directory " + sourceDirectory + " to itself."); + } else if (!destinationDirectory.exists()) { + if (!destinationDirectory.mkdirs()) { + throw new IOException("Can't create directory " + destinationDirectory); + } + } + copyDirectoryStructure(sourceDirectory, destinationDirectory); } /** - * Copy a directory to an other one. + * Copy the contents of a directory into another one. * - * @param sourceDirectory the source dir - * @param destinationDirectory the target dir - * @param includes include pattern - * @param excludes exlucde pattern - * @throws IOException if any + * @param sourceDirectory the source directory + * @param destinationDirectory the target directory + * @param includes Ant include pattern + * @param excludes Ant exclude pattern + * @throws IOException if the source is a file or cannot be copied * @see #getFiles(File, String, String) - */ - public static void copyDirectory( @Nonnull File sourceDirectory, @Nonnull File destinationDirectory, - @Nullable String includes, @Nullable String excludes ) - throws IOException - { - if ( !sourceDirectory.exists() ) - { + * @deprecated use {@code org.apache.commons.io.FileUtils.copyDirectory()} + */ + @Deprecated + public static void copyDirectory( + @Nonnull File sourceDirectory, + @Nonnull File destinationDirectory, + @Nullable String includes, + @Nullable String excludes) + throws IOException { + if (!sourceDirectory.exists()) { return; + } else if (!sourceDirectory.isDirectory()) { + throw new IOException(sourceDirectory + " is not a directory."); } - List files = getFiles( sourceDirectory, includes, excludes ); + List files = getFiles(sourceDirectory, includes, excludes); - for ( File file : files ) - { - copyFileToDirectory( file, destinationDirectory ); + for (File file : files) { + copyFileToDirectory(file, destinationDirectory); } } /** - * Copies a entire directory structure. - * - * Note: + * Copies an entire directory structure. + * Note:
**
* - * @param sourceDirectory the source dir - * @param destinationDirectory the target dir + * @param sourceDirectory the existing directory to be copied + * @param destinationDirectory the new directory to be created * @throws IOException if any + * @deprecated use {@code org.apache.commons.io.FileUtils.copyDirectory()} */ - public static void copyDirectoryStructure( @Nonnull File sourceDirectory, @Nonnull File destinationDirectory ) - throws IOException - { - copyDirectoryStructure( sourceDirectory, destinationDirectory, destinationDirectory, false ); + @Deprecated + public static void copyDirectoryStructure(@Nonnull File sourceDirectory, @Nonnull File destinationDirectory) + throws IOException { + copyDirectoryStructure(sourceDirectory, destinationDirectory, destinationDirectory, false); } - private static void copyDirectoryStructure( @Nonnull File sourceDirectory, @Nonnull File destinationDirectory, - File rootDestinationDirectory, boolean onlyModifiedFiles ) - throws IOException - { + private static void copyDirectoryStructure( + @Nonnull File sourceDirectory, + @Nonnull File destinationDirectory, + File rootDestinationDirectory, + boolean onlyModifiedFiles) + throws IOException { //noinspection ConstantConditions - if ( sourceDirectory == null ) - { - throw new IOException( "source directory can't be null." ); + if (sourceDirectory == null) { + throw new IOException("source directory can't be null."); } //noinspection ConstantConditions - if ( destinationDirectory == null ) - { - throw new IOException( "destination directory can't be null." ); + if (destinationDirectory == null) { + throw new IOException("destination directory can't be null."); } - if ( sourceDirectory.equals( destinationDirectory ) ) - { - throw new IOException( "source and destination are the same directory." ); + if (sourceDirectory.equals(destinationDirectory)) { + throw new IOException("source and destination are the same directory."); } - if ( !sourceDirectory.exists() ) - { - throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." ); + if (!sourceDirectory.exists()) { + throw new IOException("Source directory doesn't exist (" + sourceDirectory.getAbsolutePath() + ")."); } File[] files = sourceDirectory.listFiles(); - if ( files == null ) - { + if (files == null) { return; } String sourcePath = sourceDirectory.getAbsolutePath(); - for ( File file : files ) - { - if ( file.equals( rootDestinationDirectory ) ) - { + for (File file : files) { + if (file.equals(rootDestinationDirectory)) { // We don't copy the destination directory in itself continue; } String dest = file.getAbsolutePath(); - dest = dest.substring( sourcePath.length() + 1 ); + dest = dest.substring(sourcePath.length() + 1); - File destination = new File( destinationDirectory, dest ); + File destination = new File(destinationDirectory, dest); - if ( file.isFile() ) - { + if (file.isFile()) { destination = destination.getParentFile(); - if ( onlyModifiedFiles ) - { - copyFileToDirectoryIfModified( file, destination ); - } - else - { - copyFileToDirectory( file, destination ); + if (onlyModifiedFiles) { + copyFileToDirectoryIfModified(file, destination); + } else { + copyFileToDirectory(file, destination); } - } - else if ( file.isDirectory() ) - { - if ( !destination.exists() && !destination.mkdirs() ) - { + } else if (file.isDirectory()) { + if (!destination.exists() && !destination.mkdirs()) { throw new IOException( - "Could not create destination directory '" + destination.getAbsolutePath() + "'." ); + "Could not create destination directory '" + destination.getAbsolutePath() + "'."); } - copyDirectoryStructure( file, destination, rootDestinationDirectory, onlyModifiedFiles ); - } - else - { - throw new IOException( "Unknown file type: " + file.getAbsolutePath() ); + copyDirectoryStructure(file, destination, rootDestinationDirectory, onlyModifiedFiles); + } else { + throw new IOException("Unknown file type: " + file.getAbsolutePath()); } } } /** * Renames a file, even if that involves crossing file system boundaries. - * *- It will include empty directories. - *
- The
sourceDirectory
must exists. + *- The
sourceDirectory
must exist. *This will remove
+ *to
(if it exists), ensure that *to
's parent directory exists and move *from
, which involves deletingfrom
as @@ -1766,87 +1586,77 @@ else if ( file.isDirectory() ) * @param to the new file name * @throws IOException if anything bad happens during this process. * Note thatto
may have been deleted already when this happens. + * @deprecated use {@code java.nio.Files.move()} */ - public static void rename( @Nonnull File from, @Nonnull File to ) - throws IOException - { - if ( to.exists() && !deleteLegacyStyle( to ) ) - { - throw new IOException( "Failed to delete " + to + " while trying to rename " + from ); + @Deprecated + public static void rename(@Nonnull File from, @Nonnull File to) throws IOException { + if (to.exists() && !deleteLegacyStyle(to)) { + throw new IOException("Failed to delete " + to + " while trying to rename " + from); } File parent = to.getParentFile(); - if ( parent != null && !parent.exists() && !parent.mkdirs() ) - { - throw new IOException( "Failed to create directory " + parent + " while trying to rename " + from ); + if (parent != null && !parent.exists() && !parent.mkdirs()) { + throw new IOException("Failed to create directory " + parent + " while trying to rename " + from); } - if ( !from.renameTo( to ) ) - { - copyFile( from, to ); - if ( !deleteLegacyStyle( from ) ) - { - throw new IOException( "Failed to delete " + from + " while trying to rename it." ); + if (!from.renameTo(to)) { + copyFile(from, to); + if (!deleteLegacyStyle(from)) { + throw new IOException("Failed to delete " + from + " while trying to rename it."); } } } /** - * Create a temporary file in a given directory. - *Create a temporary file in a given directory.
*The file denoted by the returned abstract pathname did not * exist before this method was invoked, any subsequent invocation * of this method will yield a different file name.
- * + ** The filename is prefixNNNNNsuffix where NNNN is a random number *
- *This method is different to {@link File#createTempFile(String, String, File)} of JDK 1.2 + *
This method is different to {@link File#createTempFile(String, String, File)} * as it doesn't create the file itself. * It uses the location pointed to by java.io.tmpdir - * when the parentDir attribute is - * null.
- *To delete automatically the file created by this method, use the + * when the parentDir attribute is null.
+ *To automatically delete the file created by this method, use the * {@link File#deleteOnExit()} method.
* * @param prefix prefix before the random number * @param suffix file extension; include the '.' - * @param parentDir Directory to create the temporary file in-java.io.tmpdir
- * used if not specificed + * @param parentDir directory to create the temporary file in-java.io.tmpdir
+ * used if not specified * @return a File reference to the new temporary file. + * @deprecated use {@code java.nio.Files.createTempFile()} */ - public static File createTempFile( @Nonnull String prefix, @Nonnull String suffix, @Nullable File parentDir ) - { + @Deprecated + public static File createTempFile(@Nonnull String prefix, @Nonnull String suffix, @Nullable File parentDir) { File result; - String parent = System.getProperty( "java.io.tmpdir" ); - if ( parentDir != null ) - { + String parent = System.getProperty("java.io.tmpdir"); + if (parentDir != null) { parent = parentDir.getPath(); } - DecimalFormat fmt = new DecimalFormat( "#####" ); + DecimalFormat fmt = new DecimalFormat("#####"); SecureRandom secureRandom = new SecureRandom(); long secureInitializer = secureRandom.nextLong(); - Random rand = new Random( secureInitializer + Runtime.getRuntime().freeMemory() ); - do - { - result = new File( parent, prefix + fmt.format( positiveRandom( rand ) ) + suffix ); - } - while ( result.exists() ); + Random rand = new Random(secureInitializer + Runtime.getRuntime().freeMemory()); + do { + result = new File(parent, prefix + fmt.format(positiveRandom(rand)) + suffix); + } while (result.exists()); return result; } - private static int positiveRandom( Random rand ) - { + private static int positiveRandom(Random rand) { int a = rand.nextInt(); - while ( a == Integer.MIN_VALUE ) - { + while (a == Integer.MIN_VALUE) { a = rand.nextInt(); } - return Math.abs( a ); + return Math.abs(a); } /** - * If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified() + * If wrappers is null or empty, the file will be copied only if to.lastModified() < from.lastModified() * * @param from the file to copy * @param to the destination file @@ -1854,126 +1664,183 @@ private static int positiveRandom( Random rand ) * @param wrappers array of {@link FilterWrapper} * @throws IOException if an IO error occurs during copying or filtering */ - public static void copyFile( @Nonnull File from, @Nonnull File to, @Nullable String encoding, - @Nullable FilterWrapper... wrappers ) - throws IOException - { - copyFile( from, to, encoding, wrappers, false ); + public static void copyFile( + @Nonnull File from, @Nonnull File to, @Nullable String encoding, @Nullable FilterWrapper... wrappers) + throws IOException { + copyFile(from, to, encoding, wrappers, false); } /** - * + * Wrapper class for Filter. */ - public abstract static class FilterWrapper - { - public abstract Reader getReader( Reader fileReader ); + public abstract static class FilterWrapper { + /** + * @param fileReader {@link Reader} + * @return the Reader instance + */ + public abstract Reader getReader(Reader fileReader); } /** - * If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified() or if + * If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified() or if * overwrite is true * * @param from the file to copy * @param to the destination file * @param encoding the file output encoding (only if wrappers is not empty) * @param wrappers array of {@link FilterWrapper} - * @param overwrite if true and f wrappers is null or empty, the file will be copy enven if to.lastModified() < - * from.lastModified() + * @param overwrite if true and wrappers is null or empty, the file will be copied even if + * to.lastModified() < from.lastModified() * @throws IOException if an IO error occurs during copying or filtering */ - public static void copyFile( @Nonnull File from, @Nonnull File to, @Nullable String encoding, - @Nullable FilterWrapper[] wrappers, boolean overwrite ) - throws IOException - { - if ( wrappers != null && wrappers.length > 0 ) - { - // buffer so it isn't reading a byte at a time! - Reader fileReader = null; - Writer fileWriter = null; - try - { - if ( encoding == null || encoding.length() < 1 ) - { - fileReader = new BufferedReader( new FileReader( from ) ); - fileWriter = new FileWriter( to ); - } - else - { - FileInputStream instream = new FileInputStream( from ); - - FileOutputStream outstream = new FileOutputStream( to ); - - fileReader = new BufferedReader( new InputStreamReader( instream, encoding ) ); + public static void copyFile( + @Nonnull File from, + @Nonnull File to, + @Nullable String encoding, + @Nullable FilterWrapper[] wrappers, + boolean overwrite) + throws IOException { + if (wrappers == null || wrappers.length == 0) { + if (overwrite || !to.exists() || to.lastModified() < from.lastModified()) { + copyFile(from, to); + } + } else { + Charset charset = charset(encoding); - fileWriter = new OutputStreamWriter( outstream, encoding ); + // buffer so it isn't reading a byte at a time! + try (Reader fileReader = Files.newBufferedReader(from.toPath(), charset)) { + Reader wrapped = fileReader; + for (FilterWrapper wrapper : wrappers) { + wrapped = wrapper.getReader(wrapped); } - Reader reader = fileReader; - for ( FilterWrapper wrapper : wrappers ) - { - reader = wrapper.getReader( reader ); + if (overwrite || !to.exists()) { + try (Writer fileWriter = Files.newBufferedWriter(to.toPath(), charset)) { + IOUtil.copy(wrapped, fileWriter); + } + } else { + CharsetEncoder encoder = charset.newEncoder(); + + int totalBufferSize = FILE_COPY_BUFFER_SIZE; + + int charBufferSize = (int) Math.floor(totalBufferSize / (2 + 2 * encoder.maxBytesPerChar())); + int byteBufferSize = (int) Math.ceil(charBufferSize * encoder.maxBytesPerChar()); + + CharBuffer newChars = CharBuffer.allocate(charBufferSize); + ByteBuffer newBytes = ByteBuffer.allocate(byteBufferSize); + ByteBuffer existingBytes = ByteBuffer.allocate(byteBufferSize); + + CoderResult coderResult; + int existingRead; + boolean writing = false; + + try (RandomAccessFile existing = new RandomAccessFile(to, "rw")) { + int n; + while (-1 != (n = wrapped.read(newChars))) { + ((Buffer) newChars).flip(); + + coderResult = encoder.encode(newChars, newBytes, n != 0); + if (coderResult.isError()) { + coderResult.throwException(); + } + + ((Buffer) newBytes).flip(); + + if (!writing) { + existingRead = existing.read(existingBytes.array(), 0, newBytes.remaining()); + ((Buffer) existingBytes).position(existingRead); + ((Buffer) existingBytes).flip(); + + if (newBytes.compareTo(existingBytes) != 0) { + writing = true; + if (existingRead > 0) { + existing.seek(existing.getFilePointer() - existingRead); + } + } + } + + if (writing) { + existing.write(newBytes.array(), 0, newBytes.remaining()); + } + + ((Buffer) newChars).clear(); + ((Buffer) newBytes).clear(); + ((Buffer) existingBytes).clear(); + } + + if (existing.length() > existing.getFilePointer()) { + existing.setLength(existing.getFilePointer()); + } + } } - - IOUtil.copy( reader, fileWriter ); - } - finally - { - IOUtil.close( fileReader ); - IOUtil.close( fileWriter ); } } - else - { - if ( to.lastModified() < from.lastModified() || overwrite ) - { - copyFile( from, to ); - } + + copyFilePermissions(from, to); + } + + /** + * Attempts to copy file permissions from the source to the destination file. + * Initially attempts to copy posix file permissions, assuming that the files are both on posix filesystems. + * If the initial attempts fail then a second attempt using less precise permissions model. + * Note that permissions are copied on a best-efforts basis, + * failure to copy permissions will not result in an exception. + * + * @param source the file to copy permissions from. + * @param destination the file to copy permissions to. + */ + private static void copyFilePermissions(@Nonnull File source, @Nonnull File destination) throws IOException { + try { + // attempt to copy posix file permissions + Files.setPosixFilePermissions(destination.toPath(), Files.getPosixFilePermissions(source.toPath())); + } catch (UnsupportedOperationException e) { + // fallback to setting partial permissions + destination.setExecutable(source.canExecute()); + destination.setReadable(source.canRead()); + destination.setWritable(source.canWrite()); } } /** - * Note: the file content is read with platform encoding + * Note: the file content is read with platform encoding. * * @param file the file * @return a List containing every every line not starting with # and not empty * @throws IOException if any + * @deprecated assumes the platform default character set */ - @Nonnull public static ListloadFile( @Nonnull File file ) - throws IOException - { + @Deprecated + @Nonnull + public static List loadFile(@Nonnull File file) throws IOException { List lines = new ArrayList (); - if ( file.exists() ) - { - FileReader fileReader = new FileReader( file ); - try - { - BufferedReader reader = new BufferedReader( fileReader ); - - String line = reader.readLine(); - - while ( line != null ) - { + if (file.exists()) { + try (BufferedReader reader = Files.newBufferedReader(file.toPath(), Charset.defaultCharset())) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { line = line.trim(); - - if ( !line.startsWith( "#" ) && line.length() != 0 ) - { - lines.add( line ); + if (!line.startsWith("#") && line.length() != 0) { + lines.add(line); } - line = reader.readLine(); } - - reader.close(); - } - finally - { - fileReader.close(); } } return lines; } + /** + * Returns the named charset or the default charset. + * @param encoding the name or alias of the charset, null or empty + * @return A charset object for the named or default charset. + */ + private static Charset charset(String encoding) { + if (encoding == null || encoding.isEmpty()) { + return Charset.defaultCharset(); + } else { + return Charset.forName(encoding); + } + } + /** * For Windows OS, check if the file name contains any of the following characters: * ":", "*", "?", "\"", "<", ">", "|"
@@ -1983,18 +1850,14 @@ public static void copyFile( @Nonnull File from, @Nonnull File to, @Nullable Str *true
if the Os is not Windows or if the file path respect the Windows constraints. * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME */ - private static boolean isValidWindowsFileName( @Nonnull File f ) - { - if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) - { - if ( StringUtils.indexOfAny( f.getName(), INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME ) != -1 ) - { + private static boolean isValidWindowsFileName(@Nonnull File f) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + if (StringUtils.indexOfAny(f.getName(), INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME) != -1) { return false; } - if ( f.getParentFile() != null ) - { - return isValidWindowsFileName( f.getParentFile() ); + if (f.getParentFile() != null) { + return isValidWindowsFileName(f.getParentFile()); } } @@ -2004,63 +1867,52 @@ private static boolean isValidWindowsFileName( @Nonnull File f ) /** * Checks whether a given file is a symbolic link. * - * This only works reliably on java7 and higher. For earlier version we use a highly crappy heuristic - * that mostly does not work. - *- * It doesn't really test for symbolic links but whether the canonical and absolute paths of the file are identical - * - this may lead to false positives on some platforms. - *
- * * @param file the file to check - * + * @throws IOException in case of failure. + * @return true if symbolic link false otherwise. + * @deprecated use {@code java.nio.file.Files.isSymbolicLink(file.toPath())} */ - public static boolean isSymbolicLink( final @Nonnull File file ) - throws IOException - { - if ( Java7Support.isAtLeastJava7() ) - { - return Java7Support.isSymLink( file ); - } - return isSymbolicLinkLegacy( file ); + @Deprecated + public static boolean isSymbolicLink(@Nonnull final File file) throws IOException { + return Files.isSymbolicLink(file.toPath()); } /** * Checks whether a given file is a symbolic link. * * @param file the file to check - * @return true if and only if we reliably can say this is a symlink. This will - * always return false for java versions prior to 1.7. + * @return true if and only if we reliably can say this is a symlink * + * @throws IOException in case of failure + * @deprecated use {@code java.nio.file.Files.isSymbolicLink(file.toPath())} */ - public static boolean isSymbolicLinkForSure( final @Nonnull File file ) - throws IOException - { - return Java7Support.isAtLeastJava7() && Java7Support.isSymLink( file ); + @Deprecated + public static boolean isSymbolicLinkForSure(@Nonnull final File file) throws IOException { + return Files.isSymbolicLink(file.toPath()); } /** - * Checks whether a given file is a symbolic link. - *- * It doesn't really test for symbolic links but whether the canonical and absolute - * paths of the file are identical - this may lead to false positives on some platforms. + * Create a new symbolic link, possibly replacing an existing symbolic link. * - * It also returns true for any file that has been reached via a symbolic link, - * if you decide to traverse into the symlink. - * - * As can be seen from the "return" clause of this method, there is really no - * guarantee of any sort from this method. Small wonder this ever got used for - * anything. - *
- * - * @param file the file to check - * @return true if the file is a symbolic link or if we're on some crappy os. - * false if the file is not a symlink or we're not able to detect it. + * @param symlink the link name + * @param target the target + * @return the linked file + * @throws IOException in case of an error + * @see Files#createSymbolicLink(Path, Path, FileAttribute[]) which creates a new symbolic link but does + * not replace existing symbolic links */ - static boolean isSymbolicLinkLegacy( final @Nonnull File file ) - throws IOException - { - final File canonical = new File( file.getCanonicalPath() ); - return !file.getAbsolutePath().equals( canonical.getPath() ); - } + @Nonnull + public static File createSymbolicLink(@Nonnull File symlink, @Nonnull File target) throws IOException { + final Path symlinkPath = symlink.toPath(); + + if (Files.exists(symlinkPath)) { + if (target.equals(Files.readSymbolicLink(symlinkPath).toFile())) { + return symlink; + } + Files.delete(symlinkPath); + } + + return Files.createSymbolicLink(symlinkPath, target.toPath()).toFile(); + } } diff --git a/src/main/java/org/apache/maven/shared/utils/io/IOUtil.java b/src/main/java/org/apache/maven/shared/utils/io/IOUtil.java index 04801702..bb90a270 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/IOUtil.java +++ b/src/main/java/org/apache/maven/shared/utils/io/IOUtil.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -37,40 +36,35 @@ import java.nio.channels.Channel; /** - * General IO Stream manipulation. + *General IO Stream manipulation.
** This class provides static utility methods for input/output operations, particularly buffered * copying between sources (
- * + *InputStream
,Reader
,String
and *byte[]
) and destinations (OutputStream
,Writer
, - *String
andbyte[]
). - *String
andbyte[]
). + * *Unless otherwise noted, these
- * + * mechanism. + * *copy
methods do not flush or close the * streams. Often, doing so would require making non-portable assumptions about the streams' origin * and further use. This means that both streams'close()
methods must be called after * copying. if one omits this step, then the stream resources (sockets, file descriptors) are * released when the associated Stream is garbage-collected. It is not a good idea to rely on this - * mechanism. For a good overview of the distinction between "memory management" and "resource - * management", see this - * UnixReview articleFor each
- * *copy
method, a variant is provided that allows the caller to specify the * buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this * may be worth tweaking. Often "large buffer -> faster" does not hold, even for large data * transfers.For byte-to-char methods, a
- * *copy
variant allows the encoding to be selected * (otherwise the platform default is used).The
- * + *copy
methods use an internal buffer when copying. It is therefore advisable * not to deliberately wrap the stream arguments to thecopy
methods in *Buffered*
streams. For example, don't do the * following:*
+ * *copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );
- *The rationale is as follows:
- * + * *Imagine that an InputStream's read() is a very expensive operation, which would usually suggest * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to @@ -84,7 +78,7 @@ * @author Peter Donald * @author Jeff Turner * @version CVS $Revision$ $Date$ - * + * */ public final class IOUtil /* @@ -123,9 +117,7 @@ public final class IOUtil /** * Private constructor to prevent instantiation. */ - private IOUtil() - { - } + private IOUtil() {} /////////////////////////////////////////////////////////////// // Core copy methods @@ -133,52 +125,68 @@ private IOUtil() /** * Copy bytes from an
InputStream
to anOutputStream
. + * + * @param input the stream to read from + * @param output the stream to write to + * @throws IOException in case of an error + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()} or in + * Java 9 and later {@code InputStream.transferTo()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final OutputStream output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final InputStream input, @Nonnull final OutputStream output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** * Copy bytes from anInputStream
to anOutputStream
. * - * @param bufferSize Size of internal buffer to use. + * In Java 9 and later this is replaced by {@code InputStream.transferTo()}. + * + * @param input the stream to read from + * @param output the stream to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of an error + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()} or in + * Java 9 and later {@code InputStream.transferTo()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final OutputStream output, - final int bufferSize ) - throws IOException - { + @Deprecated + public static void copy(@Nonnull final InputStream input, @Nonnull final OutputStream output, final int bufferSize) + throws IOException { final byte[] buffer = new byte[bufferSize]; int n; - while ( -1 != ( n = input.read( buffer ) ) ) - { - output.write( buffer, 0, n ); + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); } } /** * Copy chars from aReader
to aWriter
. + * + * @param input the reader to read from + * @param output the writer to write to + * @throws IOException in case of failure * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final Reader input, @Nonnull final Writer output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final Reader input, @Nonnull final Writer output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** * Copy chars from aReader
to aWriter
. * - * @param bufferSize Size of internal buffer to use. + * @param input the reader to read from + * @param output the writer to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final Reader input, @Nonnull final Writer output, final int bufferSize ) - throws IOException - { + @Deprecated + public static void copy(@Nonnull final Reader input, @Nonnull final Writer output, final int bufferSize) + throws IOException { final char[] buffer = new char[bufferSize]; int n; - while ( -1 != ( n = input.read( buffer ) ) ) - { - output.write( buffer, 0, n ); + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); } output.flush(); } @@ -194,12 +202,17 @@ public static void copy( @Nonnull final Reader input, @Nonnull final Writer outp /** * Copy and convert bytes from anInputStream
to chars on a *Writer
. + * * The platform's default encoding is used for the byte-to-char conversion. + * + * @param input the reader to read from + * @param output the writer to write to + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final Writer output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final InputStream input, @Nonnull final Writer output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** @@ -207,46 +220,61 @@ public static void copy( @Nonnull final InputStream input, @Nonnull final Writer *Writer
. * The platform's default encoding is used for the byte-to-char conversion. * - * @param bufferSize Size of internal buffer to use. + * @param input the input stream to read from + * @param output the writer to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final Writer output, final int bufferSize ) - throws IOException - { - final InputStreamReader in = new InputStreamReader( input ); - copy( in, output, bufferSize ); + @Deprecated + public static void copy(@Nonnull final InputStream input, @Nonnull final Writer output, final int bufferSize) + throws IOException { + final InputStreamReader in = new InputStreamReader(input); + copy(in, output, bufferSize); } /** * Copy and convert bytes from anInputStream
to chars on a *Writer
, using the specified encoding. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param input the input stream to read from + * @param output the writer to write to + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final Writer output, - @Nonnull final String encoding ) - throws IOException - { - final InputStreamReader in = new InputStreamReader( input, encoding ); - copy( in, output ); + @Deprecated + public static void copy( + @Nonnull final InputStream input, @Nonnull final Writer output, @Nonnull final String encoding) + throws IOException { + final InputStreamReader in = new InputStreamReader(input, encoding); + copy(in, output); } /** * Copy and convert bytes from anInputStream
to chars on a *Writer
, using the specified encoding. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. - * @param bufferSize Size of internal buffer to use. + * @param input the input stream to read from + * @param output the writer to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.copy()}. */ - public static void copy( @Nonnull final InputStream input, @Nonnull final Writer output, - @Nonnull final String encoding, final int bufferSize ) - throws IOException - { - final InputStreamReader in = new InputStreamReader( input, encoding ); - copy( in, output, bufferSize ); + @Deprecated + public static void copy( + @Nonnull final InputStream input, + @Nonnull final Writer output, + @Nonnull final String encoding, + final int bufferSize) + throws IOException { + final InputStreamReader in = new InputStreamReader(input, encoding); + copy(in, output, bufferSize); } /////////////////////////////////////////////////////////////// @@ -255,54 +283,71 @@ public static void copy( @Nonnull final InputStream input, @Nonnull final Writer /** * Get the contents of anInputStream
as a String. * The platform's default encoding is used for the byte-to-char conversion. + * + * @param input the InputStream to read from + * @return the resulting string + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static String toString( @Nonnull final InputStream input ) - throws IOException - { - return toString( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static String toString(@Nonnull final InputStream input) throws IOException { + return toString(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of anInputStream
as a String. * The platform's default encoding is used for the byte-to-char conversion. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param bufferSize size of internal buffer + * @return the resulting string + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static String toString( @Nonnull final InputStream input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static String toString(@Nonnull final InputStream input, final int bufferSize) throws IOException { final StringWriter sw = new StringWriter(); - copy( input, sw, bufferSize ); + copy(input, sw, bufferSize); return sw.toString(); } /** * Get the contents of anInputStream
as a String. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param input the InputStream to read from + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. + * @return the converted string + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.toString()}. */ - @Nonnull public static String toString( @Nonnull final InputStream input, @Nonnull final String encoding ) - throws IOException - { - return toString( input, encoding, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static String toString(@Nonnull final InputStream input, @Nonnull final String encoding) throws IOException { + return toString(input, encoding, DEFAULT_BUFFER_SIZE); } /** * Get the contents of anInputStream
as a String. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param input the InputStream to read from + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. - * @param bufferSize Size of internal buffer to use. + * @param bufferSize size of internal buffer + * @return The converted string. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.toString()}. */ - @Nonnull public static String toString( @Nonnull final InputStream input, @Nonnull final String encoding, - final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static String toString( + @Nonnull final InputStream input, @Nonnull final String encoding, final int bufferSize) throws IOException { final StringWriter sw = new StringWriter(); - copy( input, sw, encoding, bufferSize ); + copy(input, sw, encoding, bufferSize); return sw.toString(); } @@ -311,23 +356,32 @@ public static void copy( @Nonnull final InputStream input, @Nonnull final Writer /** * Get the contents of anInputStream
as abyte[]
. + * + * @param input the InputStream to read from + * @return the resulting byte array. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.readFully()}. */ - @Nonnull public static byte[] toByteArray( @Nonnull final InputStream input ) - throws IOException - { - return toByteArray( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final InputStream input) throws IOException { + return toByteArray(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of anInputStream
as abyte[]
. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param bufferSize size of internal buffer + * @return the resulting byte array. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.readFully()}. */ - @Nonnull public static byte[] toByteArray( @Nonnull final InputStream input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final InputStream input, final int bufferSize) throws IOException { final ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy( input, output, bufferSize ); + copy(input, output, bufferSize); return output.toByteArray(); } @@ -342,24 +396,32 @@ public static void copy( @Nonnull final InputStream input, @Nonnull final Writer /** * Serialize chars from aReader
to bytes on anOutputStream
, and * flush theOutputStream
. + * + * @param input the InputStream to read from + * @param output the output stream to write to + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final Reader input, @Nonnull final OutputStream output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final Reader input, @Nonnull final OutputStream output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** * Serialize chars from aReader
to bytes on anOutputStream
, and * flush theOutputStream
. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param output the output to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final Reader input, @Nonnull final OutputStream output, final int bufferSize ) - throws IOException - { - final OutputStreamWriter out = new OutputStreamWriter( output ); - copy( input, out, bufferSize ); + @Deprecated + public static void copy(@Nonnull final Reader input, @Nonnull final OutputStream output, final int bufferSize) + throws IOException { + final OutputStreamWriter out = new OutputStreamWriter(output); + copy(input, out, bufferSize); // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush // here. out.flush(); @@ -370,23 +432,31 @@ public static void copy( @Nonnull final Reader input, @Nonnull final OutputStrea /** * Get the contents of aReader
as a String. + * @param input the InputStream to read from + * @return The converted string. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.toString()}. */ - @Nonnull public static String toString( @Nonnull final Reader input ) - throws IOException - { - return toString( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static String toString(@Nonnull final Reader input) throws IOException { + return toString(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of aReader
as a String. * - * @param bufferSize Size of internal buffer to use. + * @param input the reader to read from + * @param bufferSize size of internal buffer + * @return the resulting byte array. + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.toString()}. */ - @Nonnull public static String toString( @Nonnull final Reader input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static String toString(@Nonnull final Reader input, final int bufferSize) throws IOException { final StringWriter sw = new StringWriter(); - copy( input, sw, bufferSize ); + copy(input, sw, bufferSize); return sw.toString(); } @@ -395,23 +465,32 @@ public static void copy( @Nonnull final Reader input, @Nonnull final OutputStrea /** * Get the contents of aReader
as abyte[]
. + * + * @param input the InputStream to read from + * @return the resulting byte array. + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static byte[] toByteArray( @Nonnull final Reader input ) - throws IOException - { - return toByteArray( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final Reader input) throws IOException { + return toByteArray(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of aReader
as abyte[]
. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param bufferSize size of internal buffer + * @return the resulting byte array. + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static byte[] toByteArray( @Nonnull final Reader input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final Reader input, final int bufferSize) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy( input, output, bufferSize ); + copy(input, output, bufferSize); return output.toByteArray(); } @@ -426,25 +505,32 @@ public static void copy( @Nonnull final Reader input, @Nonnull final OutputStrea /** * Serialize chars from aString
to bytes on anOutputStream
, and * flush theOutputStream
. + * @param input the InputStream to read from + * @param output the output to write to + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final String input, @Nonnull final OutputStream output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final String input, @Nonnull final OutputStream output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** * Serialize chars from aString
to bytes on anOutputStream
, and * flush theOutputStream
. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param output the output to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final String input, @Nonnull final OutputStream output, final int bufferSize ) - throws IOException - { - final StringReader in = new StringReader( input ); - final OutputStreamWriter out = new OutputStreamWriter( output ); - copy( in, out, bufferSize ); + @Deprecated + public static void copy(@Nonnull final String input, @Nonnull final OutputStream output, final int bufferSize) + throws IOException { + final StringReader in = new StringReader(input); + final OutputStreamWriter out = new OutputStreamWriter(output); + copy(in, out, bufferSize); // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush // here. out.flush(); @@ -455,11 +541,15 @@ public static void copy( @Nonnull final String input, @Nonnull final OutputStrea /** * Copy chars from aString
to aWriter
. + * + * @param input the string to write + * @param output resulting output {@link Writer} + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.write()}. */ - public static void copy( @Nonnull final String input, @Nonnull final Writer output ) - throws IOException - { - output.write( input ); + @Deprecated + public static void copy(@Nonnull final String input, @Nonnull final Writer output) throws IOException { + output.write(input); } /////////////////////////////////////////////////////////////// @@ -467,23 +557,32 @@ public static void copy( @Nonnull final String input, @Nonnull final Writer outp /** * Get the contents of aString
as abyte[]
. + * + * @param input the String to read from + * @return the resulting byte array + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static byte[] toByteArray( @Nonnull final String input ) - throws IOException - { - return toByteArray( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final String input) throws IOException { + return toByteArray(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of aString
as abyte[]
. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param bufferSize size of internal buffer + * @return the resulting byte array + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static byte[] toByteArray( @Nonnull final String input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static byte[] toByteArray(@Nonnull final String input, final int bufferSize) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy( input, output, bufferSize ); + copy(input, output, bufferSize); return output.toByteArray(); } @@ -499,11 +598,15 @@ public static void copy( @Nonnull final String input, @Nonnull final Writer outp * Copy and convert bytes from abyte[]
to chars on a *Writer
. * The platform's default encoding is used for the byte-to-char conversion. + * + * @param input the InputStream to read from + * @param output the output to write to + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final byte[] input, @Nonnull final Writer output ) - throws IOException - { - copy( input, output, DEFAULT_BUFFER_SIZE ); + @Deprecated + public static void copy(@Nonnull final byte[] input, @Nonnull final Writer output) throws IOException { + copy(input, output, DEFAULT_BUFFER_SIZE); } /** @@ -511,45 +614,60 @@ public static void copy( @Nonnull final byte[] input, @Nonnull final Writer outp *Writer
. * The platform's default encoding is used for the byte-to-char conversion. * - * @param bufferSize Size of internal buffer to use. + * @param input the InputStream to read from + * @param output the output to write to + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - public static void copy( @Nonnull final byte[] input, @Nonnull final Writer output, final int bufferSize ) - throws IOException - { - final ByteArrayInputStream in = new ByteArrayInputStream( input ); - copy( in, output, bufferSize ); + @Deprecated + public static void copy(@Nonnull final byte[] input, @Nonnull final Writer output, final int bufferSize) + throws IOException { + final ByteArrayInputStream in = new ByteArrayInputStream(input); + copy(in, output, bufferSize); } /** * Copy and convert bytes from abyte[]
to chars on a *Writer
, using the specified encoding. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. + * @param input the data to write + * @param output the writer to write to + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.write()}. */ - public static void copy( @Nonnull final byte[] input, @Nonnull final Writer output, final String encoding ) - throws IOException - { - final ByteArrayInputStream in = new ByteArrayInputStream( input ); - copy( in, output, encoding ); + @Deprecated + public static void copy(@Nonnull final byte[] input, @Nonnull final Writer output, final String encoding) + throws IOException { + final ByteArrayInputStream in = new ByteArrayInputStream(input); + copy(in, output, encoding); } /** * Copy and convert bytes from abyte[]
to chars on a *Writer
, using the specified encoding. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. - * @param bufferSize Size of internal buffer to use. + * @param input the input bytes + * @param output The output buffer {@link Writer} + * @param bufferSize size of internal buffer + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.write()}. */ - public static void copy( @Nonnull final byte[] input, @Nonnull final Writer output, @Nonnull final String encoding, - final int bufferSize ) - throws IOException - { - final ByteArrayInputStream in = new ByteArrayInputStream( input ); - copy( in, output, encoding, bufferSize ); + @Deprecated + public static void copy( + @Nonnull final byte[] input, + @Nonnull final Writer output, + @Nonnull final String encoding, + final int bufferSize) + throws IOException { + final ByteArrayInputStream in = new ByteArrayInputStream(input); + copy(in, output, encoding, bufferSize); } /////////////////////////////////////////////////////////////// @@ -558,54 +676,70 @@ public static void copy( @Nonnull final byte[] input, @Nonnull final Writer outp /** * Get the contents of abyte[]
as a String. * The platform's default encoding is used for the byte-to-char conversion. + * @param input the input bytes + * @return the resulting string + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static String toString( @Nonnull final byte[] input ) - throws IOException - { - return toString( input, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static String toString(@Nonnull final byte[] input) throws IOException { + return toString(input, DEFAULT_BUFFER_SIZE); } /** * Get the contents of abyte[]
as a String. * The platform's default encoding is used for the byte-to-char conversion. * - * @param bufferSize Size of internal buffer to use. + * @param bufferSize size of internal buffer + * @param input the input bytes + * @return the created string + * @throws IOException in case of failure + * @deprecated always specify a character encoding */ - @Nonnull public static String toString( @Nonnull final byte[] input, final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static String toString(@Nonnull final byte[] input, final int bufferSize) throws IOException { final StringWriter sw = new StringWriter(); - copy( input, sw, bufferSize ); + copy(input, sw, bufferSize); return sw.toString(); } /** * Get the contents of abyte[]
as a String. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. + * @param input the input bytes + * @return the resulting string + * @throws IOException in case of failure + * @deprecated use {@code new String(input, encoding)} */ - @Nonnull public static String toString( @Nonnull final byte[] input, @Nonnull final String encoding ) - throws IOException - { - return toString( input, encoding, DEFAULT_BUFFER_SIZE ); + @Deprecated + @Nonnull + public static String toString(@Nonnull final byte[] input, @Nonnull final String encoding) throws IOException { + return toString(input, encoding, DEFAULT_BUFFER_SIZE); } /** * Get the contents of abyte[]
as a String. * - * @param encoding The name of a supported character encoding. See the - * IANA + * @param encoding the name of a supported character encoding. See the + * IANA * Charset Registry for a list of valid encoding types. - * @param bufferSize Size of internal buffer to use. + * @param bufferSize size of internal buffer + * @param input input bytes + * @return the resulting string + * @throws IOException in case of failure + * @deprecated use {@code new String(input, encoding)} */ - @Nonnull public static String toString( @Nonnull final byte[] input, @Nonnull final String encoding, - final int bufferSize ) - throws IOException - { + @Deprecated + @Nonnull + public static String toString(@Nonnull final byte[] input, @Nonnull final String encoding, final int bufferSize) + throws IOException { final StringWriter sw = new StringWriter(); - copy( input, sw, encoding, bufferSize ); + copy(input, sw, encoding, bufferSize); return sw.toString(); } @@ -614,32 +748,36 @@ public static void copy( @Nonnull final byte[] input, @Nonnull final Writer outp /** * Copy bytes from abyte[]
to anOutputStream
. + * + * @param input Input byte array. + * @param output output stream {@link OutputStream} + * @throws IOException in case of failure + * @deprecated inline this method */ - public static void copy( @Nonnull final byte[] input, @Nonnull final OutputStream output ) - throws IOException - { - output.write( input ); + @Deprecated + public static void copy(@Nonnull final byte[] input, @Nonnull final OutputStream output) throws IOException { + output.write(input); } /** - * Compare the contents of two Streams to determine if they are equal or not. + * Compare the contents of two streams to determine if they are equal or not. * * @param input1 the first stream * @param input2 the second stream * @return true if the content of the streams are equal or they both don't exist, false otherwise + * @throws IOException in case of failure + * @deprecated use {@code org.apache.commons.io.IOUtils.contentEquals()} */ - public static boolean contentEquals( @Nonnull final InputStream input1, @Nonnull final InputStream input2 ) - throws IOException - { - final InputStream bufferedInput1 = new BufferedInputStream( input1 ); - final InputStream bufferedInput2 = new BufferedInputStream( input2 ); + @Deprecated + public static boolean contentEquals(@Nonnull final InputStream input1, @Nonnull final InputStream input2) + throws IOException { + final InputStream bufferedInput1 = new BufferedInputStream(input1); + final InputStream bufferedInput2 = new BufferedInputStream(input2); int ch = bufferedInput1.read(); - while ( -1 != ch ) - { + while (-1 != ch) { final int ch2 = bufferedInput2.read(); - if ( ch != ch2 ) - { + if (ch != ch2) { return false; } ch = bufferedInput1.read(); @@ -654,112 +792,507 @@ public static boolean contentEquals( @Nonnull final InputStream input1, @Nonnull // ---------------------------------------------------------------------- /** - * Closes a channel. Channel can be null and any IOException's will be swallowed. + *Closes a {@code Channel} suppressing any {@code IOException}.
+ *+ * Note: The use case justifying this method is a shortcoming of the Java language up to but not including + * Java 7. For any code targeting Java 7 or later use of this method is highly discouraged and the + * {@code try-with-resources} statement should be used instead. Care must be taken to not use this method in a way + * {@code IOException}s get suppressed incorrectly. + * You must close all resources in use inside the {@code try} block to not suppress exceptions in the + * {@code finally} block incorrectly by using this method. + *
+ *+ * Example: + *
+ *+ * // Introduce variables for the resources and initialize them to null. This cannot throw an exception. + * Closeable resource1 = null; + * Closeable resource2 = null; + * try + * { + * // Obtain a resource object and assign it to variable resource1. This may throw an exception. + * // If successful, resource1 != null. + * resource1 = ... + * + * // Obtain a resource object and assign it to variable resource2. This may throw an exception. + * // If successful, resource2 != null. Not reached if an exception has been thrown above. + * resource2 = ... + * + * // Perform operations on the resources. This may throw an exception. Not reached if an exception has been + * // thrown above. Note: Treat the variables resource1 and resource2 the same way as if they would have been + * // declared with the final modifier - that is - do NOT write anyting like resource1 = something else or + * // resource2 = something else here. + * resource1 ... + * resource2 ... + * + * // Finally, close the resources and set the variables to null indicating successful completion. + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource1.close(); + * resource1 = null; + * // Not reached if an exception has been thrown above. + * resource2.close(); + * resource2 = null; + * + * // All resources are closed at this point and all operations (up to here) completed successfully without + * // throwing an exception we would need to handle (by letting it propagate or by catching and handling it). + * } + * finally + * { + * // Cleanup any resource not closed in the try block due to an exception having been thrown and suppress any + * // exception this may produce to not stop the exception from the try block to be propagated. If the try + * // block completed successfully, all variables will have been set to null there and this will not do + * // anything. This is just to cleanup properly in case of an exception. * - * @param channel The stream to close. + * IOUtil.close( resource1 ); + * IOUtil.close( resource2 ); + * + * // Without that utility method you would need to write the following: + * // + * // try + * // { + * // if ( resource1 != null ) + * // { + * // resource1.close(); + * // } + * // } + * // catch( IOException e ) + * // { + * // Suppressed. If resource1 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // finally + * // { + * // try + * // { + * // if ( resource2 != null ) + * // { + * // resource2.close(); + * // } + * // } + * // catch ( IOException e ) + * // { + * // Suppressed. If resource2 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // } + * } + *+ * + * @param channel The channel to close or {@code null}. + * @deprecated use try-with-resources */ - public static void close( @Nullable Channel channel ) - { - if ( channel == null ) - { - return; - } - - try - { - channel.close(); - } - catch ( IOException ex ) - { - // ignore + @Deprecated + public static void close(@Nullable Channel channel) { + try { + if (channel != null) { + channel.close(); + } + } catch (IOException ex) { + // Suppressed } } /** - * Closes the input stream. The input stream can be null and any IOException's will be swallowed. + *Closes an {@code InputStream} suppressing any {@code IOException}.
+ *+ * Note: The use case justifying this method is a shortcoming of the Java language up to but not including + * Java 7. For any code targeting Java 7 or later use of this method is highly discouraged and the + * {@code try-with-resources} statement should be used instead. Care must be taken to not use this method in a way + * {@code IOException}s get suppressed incorrectly. + * You must close all resources in use inside the {@code try} block to not suppress exceptions in the + * {@code finally} block incorrectly by using this method. + *
+ *+ * Example: + *
+ *+ * // Introduce variables for the resources and initialize them to null. This cannot throw an exception. + * Closeable resource1 = null; + * Closeable resource2 = null; + * try + * { + * // Obtain a resource object and assign it to variable resource1. This may throw an exception. + * // If successful, resource1 != null. + * resource1 = ... + * + * // Obtain a resource object and assign it to variable resource2. This may throw an exception. + * // If successful, resource2 != null. Not reached if an exception has been thrown above. + * resource2 = ... + * + * // Perform operations on the resources. This may throw an exception. Not reached if an exception has been + * // thrown above. Note: Treat the variables resource1 and resource2 the same way as if they would have been + * // declared with the final modifier - that is - do NOT write anyting like resource1 = something else or + * // resource2 = something else here. + * resource1 ... + * resource2 ... + * + * // Finally, close the resources and set the variables to null indicating successful completion. + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource1.close(); + * resource1 = null; + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource2.close(); + * resource2 = null; * - * @param inputStream The stream to close. + * // All resources are closed at this point and all operations (up to here) completed successfully without + * // throwing an exception we would need to handle (by letting it propagate or by catching and handling it). + * } + * finally + * { + * // Cleanup any resource not closed in the try block due to an exception having been thrown and suppress any + * // exception this may produce to not stop the exception from the try block to be propagated. If the try + * // block completed successfully, all variables will have been set to null there and this will not do + * // anything. This is just to cleanup properly in case of an exception. + * + * IOUtil.close( resource1 ); + * IOUtil.close( resource2 ); + * + * // Without that utility method you would need to write the following: + * // + * // try + * // { + * // if ( resource1 != null ) + * // { + * // resource1.close(); + * // } + * // } + * // catch( IOException e ) + * // { + * // Suppressed. If resource1 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // finally + * // { + * // try + * // { + * // if ( resource2 != null ) + * // { + * // resource2.close(); + * // } + * // } + * // catch ( IOException e ) + * // { + * // Suppressed. If resource2 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // } + * } + *+ * + * @param inputStream The stream to close or {@code null}. + * @deprecated use try-with-resources */ - public static void close( @Nullable InputStream inputStream ) - { - if ( inputStream == null ) - { - return; - } - - try - { - inputStream.close(); - } - catch ( IOException ex ) - { - // ignore + @Deprecated + public static void close(@Nullable InputStream inputStream) { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException ex) { + // Suppressed } } /** - * Closes the output stream. The output stream can be null and any IOException's will be swallowed. + *Closes an {@code OutputStream} suppressing any {@code IOException}.
+ *+ * Note: The use case justifying this method is a shortcoming of the Java language up to but not including + * Java 7. For any code targeting Java 7 or later use of this method is highly discouraged and the + * {@code try-with-resources} statement should be used instead. Care must be taken to not use this method in a way + * {@code IOException}s get suppressed incorrectly. + * You must close all resources in use inside the {@code try} block to not suppress exceptions in the + * {@code finally} block incorrectly by using this method. + *
+ *+ * Example: + *
+ *+ * // Introduce variables for the resources and initialize them to null. This cannot throw an exception. + * Closeable resource1 = null; + * Closeable resource2 = null; + * try + * { + * // Obtain a resource object and assign it to variable resource1. This may throw an exception. + * // If successful, resource1 != null. + * resource1 = ... + * + * // Obtain a resource object and assign it to variable resource2. This may throw an exception. + * // If successful, resource2 != null. Not reached if an exception has been thrown above. + * resource2 = ... + * + * // Perform operations on the resources. This may throw an exception. Not reached if an exception has been + * // thrown above. Note: Treat the variables resource1 and resource2 the same way as if they would have been + * // declared with the final modifier - that is - do NOT write anyting like resource1 = something else or + * // resource2 = something else here. + * resource1 ... + * resource2 ... + * + * // Finally, close the resources and set the variables to null indicating successful completion. + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource1.close(); + * resource1 = null; + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource2.close(); + * resource2 = null; * - * @param outputStream The stream to close. + * // All resources are closed at this point and all operations (up to here) completed successfully without + * // throwing an exception we would need to handle (by letting it propagate or by catching and handling it). + * } + * finally + * { + * // Cleanup any resource not closed in the try block due to an exception having been thrown and suppress any + * // exception this may produce to not stop the exception from the try block to be propagated. If the try + * // block completed successfully, all variables will have been set to null there and this will not do + * // anything. This is just to cleanup properly in case of an exception. + * + * IOUtil.close( resource1 ); + * IOUtil.close( resource2 ); + * + * // Without that utility method you would need to write the following: + * // + * // try + * // { + * // if ( resource1 != null ) + * // { + * // resource1.close(); + * // } + * // } + * // catch( IOException e ) + * // { + * // Suppressed. If resource1 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // finally + * // { + * // try + * // { + * // if ( resource2 != null ) + * // { + * // resource2.close(); + * // } + * // } + * // catch ( IOException e ) + * // { + * // Suppressed. If resource2 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // } + * } + *+ * + * @param outputStream The stream to close or {@code null}. + * @deprecated use try-with-resources */ - public static void close( @Nullable OutputStream outputStream ) - { - if ( outputStream == null ) - { - return; - } - - try - { - outputStream.close(); - } - catch ( IOException ex ) - { - // ignore + @Deprecated + public static void close(@Nullable OutputStream outputStream) { + try { + if (outputStream != null) { + outputStream.close(); + } + } catch (IOException ex) { + // Suppressed } } /** - * Closes the reader. The reader can be null and any IOException's will be swallowed. + *Closes a {@code Reader} suppressing any {@code IOException}.
+ *+ * Note: The use case justifying this method is a shortcoming of the Java language up to but not including + * Java 7. For any code targeting Java 7 or later use of this method is highly discouraged and the + * {@code try-with-resources} statement should be used instead. Care must be taken to not use this method in a way + * {@code IOException}s get suppressed incorrectly. + * You must close all resources in use inside the {@code try} block to not suppress exceptions in the + * {@code finally} block incorrectly by using this method. + *
+ *+ * Example: + *
+ *+ * // Introduce variables for the resources and initialize them to null. This cannot throw an exception. + * Closeable resource1 = null; + * Closeable resource2 = null; + * try + * { + * // Obtain a resource object and assign it to variable resource1. This may throw an exception. + * // If successful, resource1 != null. + * resource1 = ... + * + * // Obtain a resource object and assign it to variable resource2. This may throw an exception. + * // If successful, resource2 != null. Not reached if an exception has been thrown above. + * resource2 = ... + * + * // Perform operations on the resources. This may throw an exception. Not reached if an exception has been + * // thrown above. Note: Treat the variables resource1 and resource2 the same way as if they would have been + * // declared with the final modifier - that is - do NOT write anyting like resource1 = something else or + * // resource2 = something else here. + * resource1 ... + * resource2 ... * - * @param reader The reader to close. + * // Finally, close the resources and set the variables to null indicating successful completion. + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource1.close(); + * resource1 = null; + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource2.close(); + * resource2 = null; + * + * // All resources are closed at this point and all operations (up to here) completed successfully without + * // throwing an exception we would need to handle (by letting it propagate or by catching and handling it). + * } + * finally + * { + * // Cleanup any resource not closed in the try block due to an exception having been thrown and suppress any + * // exception this may produce to not stop the exception from the try block to be propagated. If the try + * // block completed successfully, all variables will have been set to null there and this will not do + * // anything. This is just to cleanup properly in case of an exception. + * + * IOUtil.close( resource1 ); + * IOUtil.close( resource2 ); + * + * // Without that utility method you would need to write the following: + * // + * // try + * // { + * // if ( resource1 != null ) + * // { + * // resource1.close(); + * // } + * // } + * // catch( IOException e ) + * // { + * // Suppressed. If resource1 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // finally + * // { + * // try + * // { + * // if ( resource2 != null ) + * // { + * // resource2.close(); + * // } + * // } + * // catch ( IOException e ) + * // { + * // Suppressed. If resource2 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // } + * } + *+ * + * @param reader The reader to close or {@code null}. + * @deprecated use try-with-resources */ - public static void close( @Nullable Reader reader ) - { - if ( reader == null ) - { - return; - } - - try - { - reader.close(); - } - catch ( IOException ex ) - { - // ignore + @Deprecated + public static void close(@Nullable Reader reader) { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException ex) { + // Suppressed } } /** - * Closes the writer. The writer can be null and any IOException's will be swallowed. + *Closes a {@code Writer} suppressing any {@code IOException}.
+ *+ * Note: The use case justifying this method is a shortcoming of the Java language up to but not including + * Java 7. For any code targeting Java 7 or later use of this method is highly discouraged and the + * {@code try-with-resources} statement should be used instead. Care must be taken to not use this method in a way + * {@code IOException}s get suppressed incorrectly. + * You must close all resources in use inside the {@code try} block to not suppress exceptions in the + * {@code finally} block incorrectly by using this method. + *
+ *+ * Example: + *
+ *+ * // Introduce variables for the resources and initialize them to null. This cannot throw an exception. + * Closeable resource1 = null; + * Closeable resource2 = null; + * try + * { + * // Obtain a resource object and assign it to variable resource1. This may throw an exception. + * // If successful, resource1 != null. + * resource1 = ... + * + * // Obtain a resource object and assign it to variable resource2. This may throw an exception. + * // If successful, resource2 != null. Not reached if an exception has been thrown above. + * resource2 = ... * - * @param writer The writer to close. + * // Perform operations on the resources. This may throw an exception. Not reached if an exception has been + * // thrown above. Note: Treat the variables resource1 and resource2 the same way as if they would have been + * // declared with the final modifier - that is - do NOT write anyting like resource1 = something else or + * // resource2 = something else here. + * resource1 ... + * resource2 ... + * + * // Finally, close the resources and set the variables to null indicating successful completion. + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource1.close(); + * resource1 = null; + * // This may throw an exception. Not reached if an exception has been thrown above. + * resource2.close(); + * resource2 = null; + * + * // All resources are closed at this point and all operations (up to here) completed successfully without + * // throwing an exception we would need to handle (by letting it propagate or by catching and handling it). + * } + * finally + * { + * // Cleanup any resource not closed in the try block due to an exception having been thrown and suppress any + * // exception this may produce to not stop the exception from the try block to be propagated. If the try + * // block completed successfully, all variables will have been set to null there and this will not do + * // anything. This is just to cleanup properly in case of an exception. + * + * IOUtil.close( resource1 ); + * IOUtil.close( resource2 ); + * + * // Without that utility method you would need to write the following: + * // + * // try + * // { + * // if ( resource1 != null ) + * // { + * // resource1.close(); + * // } + * // } + * // catch( IOException e ) + * // { + * // Suppressed. If resource1 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // finally + * // { + * // try + * // { + * // if ( resource2 != null ) + * // { + * // resource2.close(); + * // } + * // } + * // catch ( IOException e ) + * // { + * // Suppressed. If resource2 != null, an exception has already been thrown in the try block we need to + * // propagate instead of this one. + * // } + * // } + * } + *+ * + * @param writer The writer to close or {@code null}. + * @deprecated use try-with-resources */ - public static void close( @Nullable Writer writer ) - { - if ( writer == null ) - { - return; - } - - try - { - writer.close(); - } - catch ( IOException ex ) - { - // ignore + @Deprecated + public static void close(@Nullable Writer writer) { + try { + if (writer != null) { + writer.close(); + } + } catch (IOException ex) { + // Suppressed } } } diff --git a/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java b/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java index 6d16aeed..1aa87d88 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java +++ b/src/main/java/org/apache/maven/shared/utils/io/Java7Support.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,201 +16,81 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; import javax.annotation.Nonnull; + import java.io.File; import java.io.IOException; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.nio.file.Files; /** * Java7 feature detection * * @author Kristian Rosenvold + * + * @deprecated no longer needed, prefer to use {@link java.nio.file.Files} methods directly. */ -public class Java7Support -{ - - private static final boolean IS_JAVA7; - - private static Method isSymbolicLink; - - private static Method delete; - - private static Method toPath; - - private static Method exists; - - private static Method toFile; - - private static Method readSymlink; - - private static Method createSymlink; - - private static Object emptyLinkOpts; - - private static Object emptyFileAttributes; - - static - { - boolean isJava7x = true; - try - { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Class> files = cl.loadClass( "java.nio.file.Files" ); - Class> path = cl.loadClass( "java.nio.file.Path" ); - Class> fa = cl.loadClass( "java.nio.file.attribute.FileAttribute" ); - Class> linkOption = cl.loadClass( "java.nio.file.LinkOption" ); - isSymbolicLink = files.getMethod( "isSymbolicLink", path ); - delete = files.getMethod( "delete", path ); - readSymlink = files.getMethod( "readSymbolicLink", path ); - - emptyFileAttributes = Array.newInstance( fa, 0 ); - final Object o = emptyFileAttributes; - createSymlink = files.getMethod( "createSymbolicLink", path, path, o.getClass() ); - emptyLinkOpts = Array.newInstance( linkOption, 0 ); - exists = files.getMethod( "exists", path, emptyLinkOpts.getClass() ); - toPath = File.class.getMethod( "toPath" ); - toFile = path.getMethod( "toFile" ); - } - catch ( ClassNotFoundException e ) - { - isJava7x = false; - } - catch ( NoSuchMethodException e ) - { - isJava7x = false; - } - IS_JAVA7 = isJava7x; +@Deprecated +public class Java7Support { + /** + * @param file The file to check for being a symbolic link. + * @return true if the file is a symlink false otherwise. + */ + public static boolean isSymLink(@Nonnull File file) { + return Files.isSymbolicLink(file.toPath()); } - public static boolean isSymLink( @Nonnull File file ) - { - try - { - Object path = toPath.invoke( file ); - return (Boolean) isSymbolicLink.invoke( null, path ); - } - catch ( IllegalAccessException e ) - { - throw new RuntimeException( e ); - } - catch ( InvocationTargetException e ) - { - throw new RuntimeException( e ); - } + /** + * @param symlink The sym link. + * @return The file. + * @throws IOException in case of error. + */ + @Nonnull + public static File readSymbolicLink(@Nonnull File symlink) throws IOException { + return Files.readSymbolicLink(symlink.toPath()).toFile(); } - - public static @Nonnull File readSymbolicLink( @Nonnull File symlink ) - throws IOException - { - try - { - Object path = toPath.invoke( symlink ); - Object resultPath = readSymlink.invoke( null, path ); - return (File) toFile.invoke( resultPath ); - } - catch ( IllegalAccessException e ) - { - throw new RuntimeException( e ); - } - catch ( InvocationTargetException e ) - { - throw new RuntimeException( e ); - } + /** + * @param file The file to check. + * @return true if exist false otherwise. + * @throws IOException in case of failure. + */ + public static boolean exists(@Nonnull File file) throws IOException { + return Files.exists(file.toPath()); } - - public static boolean exists( @Nonnull File file ) - throws IOException - { - try - { - Object path = toPath.invoke( file ); - final Object invoke = exists.invoke( null, path, emptyLinkOpts ); - return (Boolean) invoke; - } - catch ( IllegalAccessException e ) - { - throw new RuntimeException( e ); - } - catch ( InvocationTargetException e ) - { - throw (RuntimeException) e.getTargetException(); - } - + /** + * @param symlink The link name. + * @param target The target. + * @return The linked file. + * @throws IOException in case of an error. + */ + @Nonnull + public static File createSymbolicLink(@Nonnull File symlink, @Nonnull File target) throws IOException { + return FileUtils.createSymbolicLink(symlink, target); } - public static @Nonnull File createSymbolicLink( @Nonnull File symlink, @Nonnull File target ) - throws IOException - { - try - { - if ( !exists( symlink ) ) - { - Object link = toPath.invoke( symlink ); - Object path = createSymlink.invoke( null, link, toPath.invoke( target ), emptyFileAttributes ); - return (File) toFile.invoke( path ); - } - return symlink; - } - catch ( IllegalAccessException e ) - { - throw new RuntimeException( e ); - } - catch ( InvocationTargetException e ) - { - final Throwable targetException = e.getTargetException(); - if ( targetException instanceof IOException ) - { - throw (IOException) targetException; - } - else if ( targetException instanceof RuntimeException ) - { - // java.lang.UnsupportedOperationException: Symbolic links not supported on this operating system - // java.lang.SecurityException: denies certain permissions see Javadoc - throw ( RuntimeException ) targetException; - } - else - { - throw new IOException( targetException.getClass() + ": " + targetException.getLocalizedMessage() ); - } - } - - } /** * Performs a nio delete * @param file the file to delete - * @throws IOException + * @throws IOException in case of error. */ - public static void delete( @Nonnull File file ) - throws IOException - { - try - { - Object path = toPath.invoke( file ); - delete.invoke( null, path ); - } - catch ( IllegalAccessException e ) - { - throw new RuntimeException( e ); - } - catch ( InvocationTargetException e ) - { - throw (IOException) e.getTargetException(); - } + public static void delete(@Nonnull File file) throws IOException { + Files.delete(file.toPath()); } - public static boolean isJava7() - { - return IS_JAVA7; + /** + * @return true in case of Java 7. + */ + public static boolean isJava7() { + return true; } - public static boolean isAtLeastJava7() - { - return IS_JAVA7; + /** + * @return true in case of Java7 or greater. + */ + public static boolean isAtLeastJava7() { + return true; } - } diff --git a/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java b/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java index d5c2c21d..523b0a92 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java +++ b/src/main/java/org/apache/maven/shared/utils/io/MatchPattern.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; + +import javax.annotation.Nonnull; import java.io.File; import java.util.ArrayList; @@ -25,17 +26,16 @@ import java.util.StringTokenizer; import java.util.regex.Pattern; -import javax.annotation.Nonnull; - /** - * Describes a match target for SelectorUtils. - * - * Significantly more efficient than using strings, since re-evaluation and re-tokenizing is avoided. + *Describes a match target for SelectorUtils.
+ *+ * Significantly more efficient than using strings, since re-evaluation and re-tokenizing is avoided.
* * @author Kristian Rosenvold + * @deprecated use {@code java.nio.file.DirectoryStream.Filter} and related classes */ -public class MatchPattern -{ +@Deprecated +public class MatchPattern { private final String source; private final String regexPattern; @@ -46,87 +46,90 @@ public class MatchPattern private final String[] tokenized; - private MatchPattern( @Nonnull String source, @Nonnull String separator ) - { - regexPattern = SelectorUtils.isRegexPrefixedPattern( source ) ? source.substring( - SelectorUtils.REGEX_HANDLER_PREFIX.length(), - source.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length() ) : null; - regexPatternRegex = regexPattern != null ? Pattern.compile( regexPattern ) : null; - this.source = SelectorUtils.isAntPrefixedPattern( source ) ? source.substring( - SelectorUtils.ANT_HANDLER_PREFIX.length(), - source.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length() ) : source; + private MatchPattern(@Nonnull String source, @Nonnull String separator) { + regexPattern = SelectorUtils.isRegexPrefixedPattern(source) + ? source.substring( + SelectorUtils.REGEX_HANDLER_PREFIX.length(), + source.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length()) + : null; + regexPatternRegex = regexPattern != null ? Pattern.compile(regexPattern) : null; + this.source = SelectorUtils.isAntPrefixedPattern(source) + ? source.substring( + SelectorUtils.ANT_HANDLER_PREFIX.length(), + source.length() - SelectorUtils.PATTERN_HANDLER_SUFFIX.length()) + : source; this.separator = separator; - tokenized = tokenizePathToString( this.source, separator ); + tokenized = tokenizePathToString(this.source, separator); } - - public boolean matchPath( String str, boolean isCaseSensitive ) - { - if ( regexPattern != null ) - { - return regexPatternRegex.matcher( str ).matches(); - } - else - { - return SelectorUtils.matchAntPathPattern( this, str, separator, isCaseSensitive ); + /** + * @param str The string to match for. + * @param isCaseSensitive case sensitive true false otherwise. + * @return true if matches false otherwise. + */ + public boolean matchPath(String str, boolean isCaseSensitive) { + if (regexPattern != null) { + return regexPatternRegex.matcher(str).matches(); + } else { + return SelectorUtils.matchAntPathPattern(this, str, separator, isCaseSensitive); } } - boolean matchPath( String str, String[] strDirs, boolean isCaseSensitive ) - { - if ( regexPattern != null ) - { - return regexPatternRegex.matcher( str ).matches(); - } - else - { - return SelectorUtils.matchAntPathPattern( getTokenizedPathString(), strDirs, isCaseSensitive ); + boolean matchPath(String str, String[] strDirs, boolean isCaseSensitive) { + if (regexPattern != null) { + return regexPatternRegex.matcher(str).matches(); + } else { + return SelectorUtils.matchAntPathPattern(getTokenizedPathString(), strDirs, isCaseSensitive); } } - public boolean matchPatternStart( @Nonnull String str, boolean isCaseSensitive ) - { - if ( regexPattern != null ) - { - // FIXME: ICK! But we can't do partial matches for regex, so we have to reserve judgement until we have + /** + * @param str The string to check. + * @param isCaseSensitive Check case sensitive or not. + * @return true in case of matching pattern. + */ + public boolean matchPatternStart(@Nonnull String str, boolean isCaseSensitive) { + if (regexPattern != null) { + // FIXME: ICK! But we can't do partial matches for regex, so we have to reserve judgment until we have // a file to deal with, or we can definitely say this is an exclusion... return true; - } - else - { - String altStr = source.replace( '\\', '/' ); + } else { + String altStr = source.replace('\\', '/'); - return SelectorUtils.matchAntPathPatternStart( this, str, File.separator, isCaseSensitive ) - || SelectorUtils.matchAntPathPatternStart( this, altStr, "/", isCaseSensitive ); + return SelectorUtils.matchAntPathPatternStart(this, str, File.separator, isCaseSensitive) + || SelectorUtils.matchAntPathPatternStart(this, altStr, "/", isCaseSensitive); } } - public String[] getTokenizedPathString() - { + /** + * @return Tokenized string. + */ + public String[] getTokenizedPathString() { return tokenized; } - - public boolean startsWith( String string ) - { - return source.startsWith( string ); + /** + * @param string The part which will be checked to start with. + * @return true in case of starting with the string false otherwise. + */ + public boolean startsWith(String string) { + return source.startsWith(string); } - - static String[] tokenizePathToString( @Nonnull String path, @Nonnull String separator ) - { + static String[] tokenizePathToString(@Nonnull String path, @Nonnull String separator) { List ret = new ArrayList (); - StringTokenizer st = new StringTokenizer( path, separator ); - while ( st.hasMoreTokens() ) - { - ret.add( st.nextToken() ); + StringTokenizer st = new StringTokenizer(path, separator); + while (st.hasMoreTokens()) { + ret.add(st.nextToken()); } - return ret.toArray( new String[ret.size()] ); + return ret.toArray(new String[ret.size()]); } - public static MatchPattern fromString( String source ) - { - return new MatchPattern( source, File.separator ); + /** + * @param source The source. + * @return The match pattern. + */ + public static MatchPattern fromString(String source) { + return new MatchPattern(source, File.separator); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java b/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java index 4ebc699c..f083aa5b 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java +++ b/src/main/java/org/apache/maven/shared/utils/io/MatchPatterns.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,68 +16,68 @@ * specific language governing permissions and limitations * under the License. */ - -import java.io.File; +package org.apache.maven.shared.utils.io; import javax.annotation.Nonnull; +import java.io.File; + /** * A list of patterns to be matched * * @author Kristian Rosenvold + * @deprecated use {@code java.nio.file.DirectoryStream.Filter } and related classes */ -public class MatchPatterns -{ +@Deprecated +public class MatchPatterns { private final MatchPattern[] patterns; - private MatchPatterns( @Nonnull MatchPattern... patterns ) - { + private MatchPatterns(@Nonnull MatchPattern... patterns) { this.patterns = patterns; } /** - * Checks these MatchPatterns against a specified string. - * - * Uses far less string tokenization than any of the alternatives. + * Checks these MatchPatterns against a specified string.
+ *Uses far less string tokenization than any of the alternatives.
* * @param name The name to look for * @param isCaseSensitive If the comparison is case sensitive * @return true if any of the supplied patterns match */ - public boolean matches( @Nonnull String name, boolean isCaseSensitive ) - { - String[] tokenized = MatchPattern.tokenizePathToString( name, File.separator ); - for ( MatchPattern pattern : patterns ) - { - if ( pattern.matchPath( name, tokenized, isCaseSensitive ) ) - { + public boolean matches(@Nonnull String name, boolean isCaseSensitive) { + String[] tokenized = MatchPattern.tokenizePathToString(name, File.separator); + for (MatchPattern pattern : patterns) { + if (pattern.matchPath(name, tokenized, isCaseSensitive)) { return true; } } return false; } - public boolean matchesPatternStart( @Nonnull String name, boolean isCaseSensitive ) - { - for ( MatchPattern includesPattern : patterns ) - { - if ( includesPattern.matchPatternStart( name, isCaseSensitive ) ) - { + /** + * @param name The name. + * @param isCaseSensitive being case sensetive. + * @return true if any of the supplied patterns match start. + */ + public boolean matchesPatternStart(@Nonnull String name, boolean isCaseSensitive) { + for (MatchPattern includesPattern : patterns) { + if (includesPattern.matchPatternStart(name, isCaseSensitive)) { return true; } } return false; } - public static MatchPatterns from( @Nonnull String... sources ) - { + /** + * @param sources The sources + * @return Converted match patterns. + */ + public static MatchPatterns from(@Nonnull String... sources) { final int length = sources.length; MatchPattern[] result = new MatchPattern[length]; - for ( int i = 0; i < length; i++ ) - { - result[i] = MatchPattern.fromString( sources[i] ); + for (int i = 0; i < length; i++) { + result[i] = MatchPattern.fromString(sources[i]); } - return new MatchPatterns( result ); + return new MatchPatterns(result); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java b/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java index ec3c5c5a..b2213ec0 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java +++ b/src/main/java/org/apache/maven/shared/utils/io/ScanConductor.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,29 +16,29 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; import java.io.File; /** *Visitor pattern for the DirectoryScanner. A ScanConductor controls the scanning process.
- * *Create an instance and pass it to * {@link org.apache.maven.shared.utils.io.DirectoryScanner#setScanConductor(ScanConductor)}. * You will get notified about every visited directory and file. You can use the {@link ScanAction} * to control what should happen next.
- * *A ScanConductor might also store own information but users must make sure that the state gets * cleaned between two scan() invocations.
* * @author Mark Struberg + * + * @deprecated use {@code java.nio.file.Files.walkFileTree()} and related classes */ -public interface ScanConductor -{ +@Deprecated +public interface ScanConductor { /** - * + * */ - public enum ScanAction - { + enum ScanAction { /** * Abort the whole scanning process. The current file will not * be added anymore. @@ -71,17 +69,17 @@ public enum ScanAction * This method will get invoked for every detected directory. * * @param name the directory name (contains parent folders up to the pwd) - * @param directory + * @param directory The directory. * @return the ScanAction to control how to proceed with the scanning */ - ScanAction visitDirectory( String name, File directory ); + ScanAction visitDirectory(String name, File directory); /** * This method will get invoked for every detected file. * * @param name the file name (contains parent folders up to the pwd) - * @param file + * @param file The file. * @return the ScanAction to control how to proceed with the scanning */ - ScanAction visitFile( String name, File file ); + ScanAction visitFile(String name, File file); } diff --git a/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java b/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java index 2480ebcd..f22dee0f 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/io/SelectorUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,14 +16,15 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; + +import javax.annotation.Nonnull; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; -import javax.annotation.Nonnull; - /** *This is a utility class used by selectors and DirectoryScanner. The * functionality more properly belongs just to selectors, but unfortunately @@ -38,33 +37,44 @@ * ajkuiper@wxs.nl * @author Magesh Umasankar * @author Bruce Atherton - * + * + * @deprecated use {@code java.nio.file.Files.walkFileTree()} and related classes */ -public final class SelectorUtils -{ +@Deprecated +public final class SelectorUtils { + /** + * Pattern handler prefix. + */ private static final String PATTERN_HANDLER_PREFIX = "["; + /** + * Pattern handler suffix. + */ public static final String PATTERN_HANDLER_SUFFIX = "]"; + /** + * Regex start pattern. + */ public static final String REGEX_HANDLER_PREFIX = "%regex" + PATTERN_HANDLER_PREFIX; + /** + * ANT pattern prefix. + */ public static final String ANT_HANDLER_PREFIX = "%ant" + PATTERN_HANDLER_PREFIX; /** * Private Constructor */ - private SelectorUtils() - { - } + private SelectorUtils() {} /** - * Tests whether or not a given path matches the start of a given - * pattern up to the first "**". - *
+ *Tests whether or not a given path matches the start of a given + * pattern up to the first "**".
+ ** This is not a general purpose test and should only be used if you * can live with false positives. For example,
* * @param pattern The pattern to match against. Must not be *pattern=**\a
- * andstr=b
will yieldtrue
. + * andstr=b
will yieldtrue
.null
. @@ -73,18 +83,16 @@ private SelectorUtils() * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ - public static boolean matchPatternStart( String pattern, String str ) - { - return matchPatternStart( pattern, str, true ); + public static boolean matchPatternStart(String pattern, String str) { + return matchPatternStart(pattern, str, true); } /** - * Tests whether or not a given path matches the start of a given - * pattern up to the first "**". - * - * This is not a general purpose test and should only be used if you + *Tests whether or not a given path matches the start of a given + * pattern up to the first "**".
+ *This is not a general purpose test and should only be used if you * can live with false positives. For example,
* * @param pattern The pattern to match against. Must not be *pattern=**\a
- * andstr=b
will yieldtrue
. + * andstr=b
will yieldtrue
.null
. @@ -95,43 +103,36 @@ public static boolean matchPatternStart( String pattern, String str ) * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ - public static boolean matchPatternStart( String pattern, String str, boolean isCaseSensitive ) - { - if ( isRegexPrefixedPattern( pattern ) ) - { + public static boolean matchPatternStart(String pattern, String str, boolean isCaseSensitive) { + if (isRegexPrefixedPattern(pattern)) { // FIXME: ICK! But we can't do partial matches for regex, so we have to reserve judgement until we have // a file to deal with, or we can definitely say this is an exclusion... return true; - } - else - { - if ( isAntPrefixedPattern( pattern ) ) - { - pattern = pattern.substring( ANT_HANDLER_PREFIX.length(), - pattern.length() - PATTERN_HANDLER_SUFFIX.length() ); + } else { + if (isAntPrefixedPattern(pattern)) { + pattern = pattern.substring( + ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length()); } - String altPattern = pattern.replace( '\\', '/' ); - String altStr = str.replace( '\\', '/' ); + String altPattern = pattern.replace('\\', '/'); + String altStr = str.replace('\\', '/'); - return matchAntPathPatternStart( altPattern, altStr, "/", isCaseSensitive ); + return matchAntPathPatternStart(altPattern, altStr, "/", isCaseSensitive); } } - private static boolean matchAntPathPatternStart( String pattern, String str, String separator, - boolean isCaseSensitive ) - { + private static boolean matchAntPathPatternStart( + String pattern, String str, String separator, boolean isCaseSensitive) { // When str starts with a File.separator, pattern has to start with a // File.separator. // When pattern starts with a File.separator, str has to start with a // File.separator. - if ( separatorPatternStartSlashMismatch( pattern, str, separator ) ) - { + if (separatorPatternStartSlashMismatch(pattern, str, separator)) { return false; } - ListpatDirs = tokenizePath( pattern, separator ); - List strDirs = tokenizePath( str, separator ); + List patDirs = tokenizePath(pattern, separator); + List strDirs = tokenizePath(str, separator); int patIdxStart = 0; int patIdxEnd = patDirs.size() - 1; @@ -139,15 +140,12 @@ private static boolean matchAntPathPatternStart( String pattern, String str, Str int strIdxEnd = strDirs.size() - 1; // up to first '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { - String patDir = patDirs.get( patIdxStart ); - if ( "**".equals( patDir ) ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = patDirs.get(patIdxStart); + if ("**".equals(patDir)) { break; } - if ( !match( patDir, strDirs.get( strIdxStart ), isCaseSensitive ) ) - { + if (!match(patDir, strDirs.get(strIdxStart), isCaseSensitive)) { return false; } patIdxStart++; @@ -167,9 +165,8 @@ private static boolean matchAntPathPatternStart( String pattern, String str, Str * @return true
if the pattern matches against the string, * orfalse
otherwise. */ - public static boolean matchPath( String pattern, String str ) - { - return matchPath( pattern, str, true ); + public static boolean matchPath(String pattern, String str) { + return matchPath(pattern, str, true); } /** @@ -184,42 +181,37 @@ public static boolean matchPath( String pattern, String str ) * @returntrue
if the pattern matches against the string, * orfalse
otherwise. */ - public static boolean matchPath( String pattern, String str, boolean isCaseSensitive ) - { - if ( pattern.length() > ( REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 ) - && pattern.startsWith( REGEX_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) ) - { - pattern = - pattern.substring( REGEX_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length() ); + public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) { + if (pattern.length() > (REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1) + && pattern.startsWith(REGEX_HANDLER_PREFIX) + && pattern.endsWith(PATTERN_HANDLER_SUFFIX)) { + pattern = pattern.substring( + REGEX_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length()); - return str.matches( pattern ); - } - else - { - if ( pattern.length() > ( ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 ) - && pattern.startsWith( ANT_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ) ) - { - pattern = pattern.substring( ANT_HANDLER_PREFIX.length(), - pattern.length() - PATTERN_HANDLER_SUFFIX.length() ); + return str.matches(pattern); + } else { + if (pattern.length() > (ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1) + && pattern.startsWith(ANT_HANDLER_PREFIX) + && pattern.endsWith(PATTERN_HANDLER_SUFFIX)) { + pattern = pattern.substring( + ANT_HANDLER_PREFIX.length(), pattern.length() - PATTERN_HANDLER_SUFFIX.length()); } - return matchAntPathPattern( pattern, str, isCaseSensitive ); + return matchAntPathPattern(pattern, str, isCaseSensitive); } } - private static boolean matchAntPathPattern( String pattern, String str, boolean isCaseSensitive ) - { + private static boolean matchAntPathPattern(String pattern, String str, boolean isCaseSensitive) { // When str starts with a File.separator, pattern has to start with a // File.separator. // When pattern starts with a File.separator, str has to start with a // File.separator. - if ( str.startsWith( File.separator ) != pattern.startsWith( File.separator ) ) - { + if (str.startsWith(File.separator) != pattern.startsWith(File.separator)) { return false; } - ListpatDirs = tokenizePath( pattern, File.separator ); - List strDirs = tokenizePath( str, File.separator ); + List patDirs = tokenizePath(pattern, File.separator); + List strDirs = tokenizePath(str, File.separator); int patIdxStart = 0; int patIdxEnd = patDirs.size() - 1; @@ -227,100 +219,78 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean int strIdxEnd = strDirs.size() - 1; // up to first '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { - String patDir = patDirs.get( patIdxStart ); - if ( "**".equals( patDir ) ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = patDirs.get(patIdxStart); + if ("**".equals(patDir)) { break; } - if ( !match( patDir, strDirs.get( strIdxStart ), isCaseSensitive ) ) - { + if (!match(patDir, strDirs.get(strIdxStart), isCaseSensitive)) { return false; } patIdxStart++; strIdxStart++; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // String is exhausted - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !"**".equals( patDirs.get( i ) ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!"**".equals(patDirs.get(i))) { return false; } } return true; - } - else - { - if ( patIdxStart > patIdxEnd ) - { + } else { + if (patIdxStart > patIdxEnd) { // String not exhausted, but pattern is. Failure. return false; } } // up to last '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { - String patDir = patDirs.get( patIdxEnd ); - if ( "**".equals( patDir ) ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = patDirs.get(patIdxEnd); + if ("**".equals(patDir)) { break; } - if ( !match( patDir, strDirs.get( strIdxEnd ), isCaseSensitive ) ) - { + if (!match(patDir, strDirs.get(strIdxEnd), isCaseSensitive)) { return false; } patIdxEnd--; strIdxEnd--; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // String is exhausted - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !"**".equals( patDirs.get( i ) ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!"**".equals(patDirs.get(i))) { return false; } } return true; } - while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; - for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) - { - if ( "**".equals( patDirs.get( i ) ) ) - { + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if ("**".equals(patDirs.get(i))) { patIdxTmp = i; break; } } - if ( patIdxTmp == patIdxStart + 1 ) - { + if (patIdxTmp == patIdxStart + 1) { // '**/**' situation, so skip one patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd - int patLength = ( patIdxTmp - patIdxStart - 1 ); - int strLength = ( strIdxEnd - strIdxStart + 1 ); + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: - for ( int i = 0; i <= strLength - patLength; i++ ) - { - for ( int j = 0; j < patLength; j++ ) - { - String subPat = patDirs.get( patIdxStart + j + 1 ); - String subStr = strDirs.get( strIdxStart + i + j ); - if ( !match( subPat, subStr, isCaseSensitive ) ) - { + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + String subPat = patDirs.get(patIdxStart + j + 1); + String subStr = strDirs.get(strIdxStart + i + j); + if (!match(subPat, subStr, isCaseSensitive)) { continue strLoop; } } @@ -329,8 +299,7 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean break; } - if ( foundIdx == -1 ) - { + if (foundIdx == -1) { return false; } @@ -338,10 +307,8 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean strIdxStart = foundIdx + patLength; } - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !"**".equals( patDirs.get( i ) ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!"**".equals(patDirs.get(i))) { return false; } } @@ -362,9 +329,8 @@ private static boolean matchAntPathPattern( String pattern, String str, boolean * @return true
if the string matches against the pattern, * orfalse
otherwise. */ - public static boolean match( String pattern, String str ) - { - return match( pattern, str, true ); + public static boolean match(String pattern, String str) { + return match(pattern, str, true); } /** @@ -382,8 +348,7 @@ public static boolean match( String pattern, String str ) * @returntrue
if the string matches against the pattern, * orfalse
otherwise. */ - public static boolean match( String pattern, String str, boolean isCaseSensitive ) - { + public static boolean match(String pattern, String str, boolean isCaseSensitive) { char[] patArr = pattern.toCharArray(); char[] strArr = str.toCharArray(); int patIdxStart = 0; @@ -393,58 +358,47 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive char ch; boolean containsStar = false; - for ( char aPatArr : patArr ) - { - if ( aPatArr == '*' ) - { + for (char aPatArr : patArr) { + if (aPatArr == '*') { containsStar = true; break; } } - if ( !containsStar ) - { + if (!containsStar) { // No '*'s, so we make a shortcut - if ( patIdxEnd != strIdxEnd ) - { + if (patIdxEnd != strIdxEnd) { return false; // Pattern and string do not have the same size } - for ( int i = 0; i <= patIdxEnd; i++ ) - { + for (int i = 0; i <= patIdxEnd; i++) { ch = patArr[i]; - if ( ch != '?' && !equals( ch, strArr[i], isCaseSensitive ) ) - { + if (ch != '?' && !equals(ch, strArr[i], isCaseSensitive)) { return false; // Character mismatch } } return true; // String matches against pattern } - if ( patIdxEnd == 0 ) - { + if (patIdxEnd == 0) { return true; // Pattern contains only '*', which matches anything } // Process characters before first star // CHECKSTYLE_OFF: InnerAssignment - while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= strIdxEnd ) + while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) // CHECKSTYLE_ON: InnerAssignment { - if ( ch != '?' && !equals( ch, strArr[strIdxStart], isCaseSensitive ) ) - { + if (ch != '?' && !equals(ch, strArr[strIdxStart], isCaseSensitive)) { return false; // Character mismatch } patIdxStart++; strIdxStart++; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( patArr[i] != '*' ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { return false; } } @@ -453,24 +407,20 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive // Process characters after last star // CHECKSTYLE_OFF: InnerAssignment - while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd ) + while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) // CHECKSTYLE_ON: InnerAssignment { - if ( ch != '?' && !equals( ch, strArr[strIdxEnd], isCaseSensitive ) ) - { + if (ch != '?' && !equals(ch, strArr[strIdxEnd], isCaseSensitive)) { return false; // Character mismatch } patIdxEnd--; strIdxEnd--; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( patArr[i] != '*' ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { return false; } } @@ -479,36 +429,29 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive // process pattern between stars. padIdxStart and patIdxEnd point // always to a '*'. - while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; - for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) - { - if ( patArr[i] == '*' ) - { + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (patArr[i] == '*') { patIdxTmp = i; break; } } - if ( patIdxTmp == patIdxStart + 1 ) - { + if (patIdxTmp == patIdxStart + 1) { // Two stars next to each other, skip the first one. patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd - int patLength = ( patIdxTmp - patIdxStart - 1 ); - int strLength = ( strIdxEnd - strIdxStart + 1 ); + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: - for ( int i = 0; i <= strLength - patLength; i++ ) - { - for ( int j = 0; j < patLength; j++ ) - { + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { ch = patArr[patIdxStart + j + 1]; - if ( ch != '?' && !equals( ch, strArr[strIdxStart + i + j], isCaseSensitive ) ) - { + if (ch != '?' && !equals(ch, strArr[strIdxStart + i + j], isCaseSensitive)) { continue strLoop; } } @@ -517,8 +460,7 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive break; } - if ( foundIdx == -1 ) - { + if (foundIdx == -1) { return false; } @@ -528,10 +470,8 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( patArr[i] != '*' ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { return false; } } @@ -541,18 +481,14 @@ public static boolean match( String pattern, String str, boolean isCaseSensitive /** * Tests whether two characters are equal. */ - private static boolean equals( char c1, char c2, boolean isCaseSensitive ) - { - if ( c1 == c2 ) - { + private static boolean equals(char c1, char c2, boolean isCaseSensitive) { + if (c1 == c2) { return true; } - if ( !isCaseSensitive ) - { + if (!isCaseSensitive) { // NOTE: Try both upper case and lower case as done by String.equalsIgnoreCase() - if ( Character.toUpperCase( c1 ) == Character.toUpperCase( c2 ) - || Character.toLowerCase( c1 ) == Character.toLowerCase( c2 ) ) - { + if (Character.toUpperCase(c1) == Character.toUpperCase(c2) + || Character.toLowerCase(c1) == Character.toLowerCase(c2)) { return true; } } @@ -567,51 +503,38 @@ private static boolean equals( char c1, char c2, boolean isCaseSensitive ) * @param separator The separator to use * @return a List of path elements from the tokenized path */ - private static ListtokenizePath( String path, String separator ) - { + private static List tokenizePath(String path, String separator) { List ret = new ArrayList (); - StringTokenizer st = new StringTokenizer( path, separator ); - while ( st.hasMoreTokens() ) - { - ret.add( st.nextToken() ); + StringTokenizer st = new StringTokenizer(path, separator); + while (st.hasMoreTokens()) { + ret.add(st.nextToken()); } return ret; } - - static boolean matchAntPathPatternStart( @Nonnull MatchPattern pattern, - @Nonnull String str, - @Nonnull String separator, - boolean isCaseSensitive ) - { - return !separatorPatternStartSlashMismatch( pattern, str, separator ) - && matchAntPathPatternStart( pattern.getTokenizedPathString(), str, separator, isCaseSensitive ); + static boolean matchAntPathPatternStart( + @Nonnull MatchPattern pattern, @Nonnull String str, @Nonnull String separator, boolean isCaseSensitive) { + return !separatorPatternStartSlashMismatch(pattern, str, separator) + && matchAntPathPatternStart(pattern.getTokenizedPathString(), str, separator, isCaseSensitive); } - private static String[] tokenizePathToString( @Nonnull String path, @Nonnull String separator ) - { + private static String[] tokenizePathToString(@Nonnull String path, @Nonnull String separator) { List ret = new ArrayList (); - StringTokenizer st = new StringTokenizer( path, separator ); - while ( st.hasMoreTokens() ) - { - ret.add( st.nextToken() ); + StringTokenizer st = new StringTokenizer(path, separator); + while (st.hasMoreTokens()) { + ret.add(st.nextToken()); } - return ret.toArray( new String[ret.size()] ); + return ret.toArray(new String[ret.size()]); } - private static boolean matchAntPathPatternStart( @Nonnull String[] patDirs, - @Nonnull String str, - @Nonnull String separator, - boolean isCaseSensitive ) - { - String[] strDirs = tokenizePathToString( str, separator ); - return matchAntPathPatternStart( patDirs, strDirs, isCaseSensitive ); + private static boolean matchAntPathPatternStart( + @Nonnull String[] patDirs, @Nonnull String str, @Nonnull String separator, boolean isCaseSensitive) { + String[] strDirs = tokenizePathToString(str, separator); + return matchAntPathPatternStart(patDirs, strDirs, isCaseSensitive); } - private static boolean matchAntPathPatternStart( @Nonnull String[] patDirs, - @Nonnull String[] tokenizedFileName, - boolean isCaseSensitive ) - { + private static boolean matchAntPathPatternStart( + @Nonnull String[] patDirs, @Nonnull String[] tokenizedFileName, boolean isCaseSensitive) { int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; @@ -619,15 +542,12 @@ private static boolean matchAntPathPatternStart( @Nonnull String[] patDirs, int strIdxEnd = tokenizedFileName.length - 1; // up to first '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = patDirs[patIdxStart]; - if ( patDir.equals( "**" ) ) - { + if (patDir.equals("**")) { break; } - if ( !match( patDir, tokenizedFileName[strIdxStart], isCaseSensitive ) ) - { + if (!match(patDir, tokenizedFileName[strIdxStart], isCaseSensitive)) { return false; } patIdxStart++; @@ -637,120 +557,94 @@ private static boolean matchAntPathPatternStart( @Nonnull String[] patDirs, return strIdxStart > strIdxEnd || patIdxStart <= patIdxEnd; } - private static boolean separatorPatternStartSlashMismatch( @Nonnull MatchPattern matchPattern, @Nonnull String str, - @Nonnull String separator ) - { - return str.startsWith( separator ) != matchPattern.startsWith( separator ); + private static boolean separatorPatternStartSlashMismatch( + @Nonnull MatchPattern matchPattern, @Nonnull String str, @Nonnull String separator) { + return str.startsWith(separator) != matchPattern.startsWith(separator); } - private static boolean separatorPatternStartSlashMismatch( String pattern, String str, String separator ) - { - return str.startsWith( separator ) != pattern.startsWith( separator ); + private static boolean separatorPatternStartSlashMismatch(String pattern, String str, String separator) { + return str.startsWith(separator) != pattern.startsWith(separator); } - - static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean isCaseSensitive ) - { + static boolean matchAntPathPattern(String[] patDirs, String[] strDirs, boolean isCaseSensitive) { int patIdxStart = 0; int patIdxEnd = patDirs.length - 1; int strIdxStart = 0; int strIdxEnd = strDirs.length - 1; // up to first '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = patDirs[patIdxStart]; - if ( patDir.equals( "**" ) ) - { + if (patDir.equals("**")) { break; } - if ( !match( patDir, strDirs[strIdxStart], isCaseSensitive ) ) - { + if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { return false; } patIdxStart++; strIdxStart++; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // String is exhausted - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !patDirs[i].equals( "**" ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!patDirs[i].equals("**")) { return false; } } return true; - } - else - { - if ( patIdxStart > patIdxEnd ) - { + } else { + if (patIdxStart > patIdxEnd) { // String not exhausted, but pattern is. Failure. return false; } } // up to last '**' - while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { String patDir = patDirs[patIdxEnd]; - if ( patDir.equals( "**" ) ) - { + if (patDir.equals("**")) { break; } - if ( !match( patDir, strDirs[strIdxEnd], isCaseSensitive ) ) - { + if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { return false; } patIdxEnd--; strIdxEnd--; } - if ( strIdxStart > strIdxEnd ) - { + if (strIdxStart > strIdxEnd) { // String is exhausted - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !patDirs[i].equals( "**" ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!patDirs[i].equals("**")) { return false; } } return true; } - while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) - { + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; - for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) - { - if ( patDirs[i].equals( "**" ) ) - { + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (patDirs[i].equals("**")) { patIdxTmp = i; break; } } - if ( patIdxTmp == patIdxStart + 1 ) - { + if (patIdxTmp == patIdxStart + 1) { // '**/**' situation, so skip one patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd - int patLength = ( patIdxTmp - patIdxStart - 1 ); - int strLength = ( strIdxEnd - strIdxStart + 1 ); + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: - for ( int i = 0; i <= strLength - patLength; i++ ) - { - for ( int j = 0; j < patLength; j++ ) - { + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { String subPat = patDirs[patIdxStart + j + 1]; String subStr = strDirs[strIdxStart + i + j]; - if ( !match( subPat, subStr, isCaseSensitive ) ) - { + if (!match(subPat, subStr, isCaseSensitive)) { continue strLoop; } } @@ -759,8 +653,7 @@ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean break; } - if ( foundIdx == -1 ) - { + if (foundIdx == -1) { return false; } @@ -768,10 +661,8 @@ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean strIdxStart = foundIdx + patLength; } - for ( int i = patIdxStart; i <= patIdxEnd; i++ ) - { - if ( !patDirs[i].equals( "**" ) ) - { + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!patDirs[i].equals("**")) { return false; } } @@ -779,27 +670,28 @@ static boolean matchAntPathPattern( String[] patDirs, String[] strDirs, boolean return true; } - static boolean isRegexPrefixedPattern( String pattern ) - { - return pattern.length() > ( REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 ) - && pattern.startsWith( REGEX_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ); + static boolean isRegexPrefixedPattern(String pattern) { + return pattern.length() > (REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1) + && pattern.startsWith(REGEX_HANDLER_PREFIX) + && pattern.endsWith(PATTERN_HANDLER_SUFFIX); } - static boolean isAntPrefixedPattern( String pattern ) - { - return pattern.length() > ( ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1 ) - && pattern.startsWith( ANT_HANDLER_PREFIX ) && pattern.endsWith( PATTERN_HANDLER_SUFFIX ); + static boolean isAntPrefixedPattern(String pattern) { + return pattern.length() > (ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1) + && pattern.startsWith(ANT_HANDLER_PREFIX) + && pattern.endsWith(PATTERN_HANDLER_SUFFIX); } - static boolean matchAntPathPattern( @Nonnull MatchPattern matchPattern, @Nonnull String str, - @Nonnull String separator, boolean isCaseSensitive ) - { - if ( separatorPatternStartSlashMismatch( matchPattern, str, separator ) ) - { + static boolean matchAntPathPattern( + @Nonnull MatchPattern matchPattern, + @Nonnull String str, + @Nonnull String separator, + boolean isCaseSensitive) { + if (separatorPatternStartSlashMismatch(matchPattern, str, separator)) { return false; } String[] patDirs = matchPattern.getTokenizedPathString(); - String[] strDirs = tokenizePathToString( str, separator ); - return matchAntPathPattern( patDirs, strDirs, isCaseSensitive ); + String[] strDirs = tokenizePathToString(str, separator); + return matchAntPathPattern(patDirs, strDirs, isCaseSensitive); } } diff --git a/src/main/java/org/apache/maven/shared/utils/io/WalkCollector.java b/src/main/java/org/apache/maven/shared/utils/io/WalkCollector.java index d5d35d33..f2923bc8 100644 --- a/src/main/java/org/apache/maven/shared/utils/io/WalkCollector.java +++ b/src/main/java/org/apache/maven/shared/utils/io/WalkCollector.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.io; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,17 +16,17 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.io; import java.io.File; import java.util.ArrayList; import java.util.List; /** - * + * @deprecated use {@code java.nio.file.FileVisitor} and related classes */ -public class WalkCollector - implements DirectoryWalkListener -{ +@Deprecated +public class WalkCollector implements DirectoryWalkListener { final List steps; File startingDir; @@ -41,8 +39,10 @@ public class WalkCollector int percentageHigh; - public WalkCollector() - { + /** + * Create an instance. + */ + public WalkCollector() { steps = new ArrayList (); startCount = 0; finishCount = 0; @@ -50,26 +50,26 @@ public WalkCollector() percentageHigh = 0; } - public void debug( String message ) - { + /** {@inheritDoc} */ + public void debug(String message) { // can be used to set some message } - public void directoryWalkStarting( File basedir ) - { + /** {@inheritDoc} */ + public void directoryWalkStarting(File basedir) { startingDir = basedir; startCount++; } - public void directoryWalkStep( int percentage, File file ) - { - steps.add( file ); - percentageLow = Math.min( percentageLow, percentage ); - percentageHigh = Math.max( percentageHigh, percentage ); + /** {@inheritDoc} */ + public void directoryWalkStep(int percentage, File file) { + steps.add(file); + percentageLow = Math.min(percentageLow, percentage); + percentageHigh = Math.max(percentageHigh, percentage); } - public void directoryWalkFinished() - { + /** {@inheritDoc} */ + public void directoryWalkFinished() { finishCount++; } } diff --git a/src/main/java/org/apache/maven/shared/utils/logging/AnsiMessageBuilder.java b/src/main/java/org/apache/maven/shared/utils/logging/AnsiMessageBuilder.java new file mode 100644 index 00000000..ddb9ab79 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/AnsiMessageBuilder.java @@ -0,0 +1,136 @@ +/* + * 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.maven.shared.utils.logging; + +import org.fusesource.jansi.Ansi; + +/** + * Message builder implementation that supports ANSI colors through + * Jansi with configurable styles through {@link Style}. + */ +class AnsiMessageBuilder implements MessageBuilder, LoggerLevelRenderer { + private Ansi ansi; + + AnsiMessageBuilder() { + this(Ansi.ansi()); + } + + AnsiMessageBuilder(StringBuilder builder) { + this(Ansi.ansi(builder)); + } + + AnsiMessageBuilder(int size) { + this(Ansi.ansi(size)); + } + + AnsiMessageBuilder(Ansi ansi) { + this.ansi = ansi; + } + + public String debug(String message) { + return Style.DEBUG.apply(ansi).a(message).reset().toString(); + } + + public String info(String message) { + return Style.INFO.apply(ansi).a(message).reset().toString(); + } + + public String warning(String message) { + return Style.WARNING.apply(ansi).a(message).reset().toString(); + } + + public String error(String message) { + return Style.ERROR.apply(ansi).a(message).reset().toString(); + } + + public AnsiMessageBuilder success(Object message) { + Style.SUCCESS.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder warning(Object message) { + Style.WARNING.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder failure(Object message) { + Style.FAILURE.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder strong(Object message) { + Style.STRONG.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder mojo(Object message) { + Style.MOJO.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder project(Object message) { + Style.PROJECT.apply(ansi).a(message).reset(); + return this; + } + + public AnsiMessageBuilder a(char[] value, int offset, int len) { + ansi.a(value, offset, len); + return this; + } + + public AnsiMessageBuilder a(char[] value) { + ansi.a(value); + return this; + } + + public AnsiMessageBuilder a(CharSequence value, int start, int end) { + ansi.a(value, start, end); + return this; + } + + public AnsiMessageBuilder a(CharSequence value) { + ansi.a(value); + return this; + } + + public AnsiMessageBuilder a(Object value) { + ansi.a(value); + return this; + } + + public AnsiMessageBuilder newline() { + ansi.newline(); + return this; + } + + public AnsiMessageBuilder format(String pattern, Object... args) { + ansi.format(pattern, args); + return this; + } + + @Override + public String toString() { + return build(); + } + + @Override + public String build() { + return ansi.toString(); + } +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/LoggerLevelRenderer.java b/src/main/java/org/apache/maven/shared/utils/logging/LoggerLevelRenderer.java new file mode 100644 index 00000000..829487f5 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/LoggerLevelRenderer.java @@ -0,0 +1,55 @@ +/* + * 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.maven.shared.utils.logging; + +/** + * Logger level renderer, intended for Maven slf4j logging provider implementers to render + * logger level. + * + * @since 3.2.0 + */ +public interface LoggerLevelRenderer { + /** + * Render a message at DEBUG level. + * @param message the message to render. + * @return the formatted message. + */ + String debug(String message); + + /** + * Render a message at INFO level. + * @param message the message to render. + * @return the formatted message. + */ + String info(String message); + + /** + * Render a message at WARNING level. + * @param message the message to render. + * @return the formatted message. + */ + String warning(String message); + + /** + * Render a message at ERROR level. + * @param message the message to render. + * @return the formatted message. + */ + String error(String message); +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/MessageBuilder.java b/src/main/java/org/apache/maven/shared/utils/logging/MessageBuilder.java new file mode 100644 index 00000000..fa1c07b0 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/MessageBuilder.java @@ -0,0 +1,153 @@ +/* + * 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.maven.shared.utils.logging; + +import java.util.Formatter; + +/** + * Message builder that supports configurable styling. + * An instance of this interface can be retrieved with {@link MessageUtils#buffer()}. + * After the message has been constructed with any of the append methods its content can be retrieved + * with {@link #build()}. + * + * @see MessageUtils + * @since 3.1.0 + */ +public interface MessageBuilder { + /** + * Append message content in success style. + * By default, bold green + * @param message the message to append + * @return the current builder + */ + MessageBuilder success(Object message); + + /** + * Append message content in warning style. + * By default, bold yellow + * @param message the message to append + * @return the current builder + */ + MessageBuilder warning(Object message); + + /** + * Append message content in failure style. + * By default, bold red + * @param message the message to append + * @return the current builder + */ + MessageBuilder failure(Object message); + + /** + * Append message content in strong style. + * By default, bold + * @param message the message to append + * @return the current builder + */ + MessageBuilder strong(Object message); + + /** + * Append message content in mojo style. + * By default, green + * @param message the message to append + * @return the current builder + */ + MessageBuilder mojo(Object message); + + /** + * Append message content in project style. + * By default, cyan + * @param message the message to append + * @return the current builder + */ + MessageBuilder project(Object message); + + // + // message building methods modelled after Ansi methods + // + /** + * Append content to the message buffer. + * @param value the content to append + * @param offset the index of the first {@code char} to append + * @param len the number of {@code char}s to append + * @return the current builder + */ + MessageBuilder a(char[] value, int offset, int len); + + /** + * Append content to the message buffer. + * @param value the content to append + * @return the current builder + */ + MessageBuilder a(char[] value); + + /** + * Append content to the message buffer. + * @param value the content to append + * @param start the starting index of the subsequence to be appended + * @param end the end index of the subsequence to be appended + * @return the current builder + */ + MessageBuilder a(CharSequence value, int start, int end); + + /** + * Append content to the message buffer. + * @param value the content to append + * @return the current builder + */ + MessageBuilder a(CharSequence value); + + /** + * Append content to the message buffer. + * @param value the content to append + * @return the current builder + */ + MessageBuilder a(Object value); + + /** + * Append newline to the message buffer. + * @return the current builder + */ + MessageBuilder newline(); + + /** + * Append formatted content to the buffer. + * @see String#format(String, Object...) + * @param pattern a format string according to the {@link Formatter} syntax + * @param args arguments referenced by the format specifiers in the format string. + * @return the current builder + */ + MessageBuilder format(String pattern, Object... args); + + /** + * Get the message constructed by this builder. + * The underlying buffer is not reset with this method, i.e. if you continue using this builder you just + * append content to the existing one. + * @return the message + * @since 4.0.0 + */ + String build(); + + /** + * Same as {@link MessageBuilder#build()}. + * @deprecated Rather use {@link MessageBuilder#build()} + */ + @Deprecated + String toString(); +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/MessageUtils.java b/src/main/java/org/apache/maven/shared/utils/logging/MessageUtils.java new file mode 100644 index 00000000..7f2f4bea --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/MessageUtils.java @@ -0,0 +1,201 @@ +/* + * 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.maven.shared.utils.logging; + +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.AnsiConsole; +import org.fusesource.jansi.AnsiMode; + +/** + * Colored message utils, to manage colors consistently across plugins (only if Maven version is at least 3.5.0). + * For Maven version before 3.5.0, message built with this util will never add color. + * + * Internally, Jansi is used to render + * ANSI colors on any platform. + * @since 3.1.0 + */ +public class MessageUtils { + private static final boolean JANSI; + + /** Reference to the JVM shutdown hook, if registered */ + private static Thread shutdownHook; + + /** Synchronization monitor for the "uninstall" */ + private static final Object STARTUP_SHUTDOWN_MONITOR = new Object(); + + static { + boolean jansi = true; + try { + // Jansi is provided by Maven core since 3.5.0 + Class.forName("org.fusesource.jansi.Ansi"); + } catch (ClassNotFoundException cnfe) { + jansi = false; + } + JANSI = jansi; + } + + /** + * Install color support. + * This method is called by Maven core, and calling it is not necessary in plugins. + */ + public static void systemInstall() { + if (JANSI) { + AnsiConsole.systemInstall(); + } + } + + /** + * Undo a previous {@link #systemInstall()}. If {@link #systemInstall()} was called + * multiple times, {@link #systemUninstall()} must be called call the same number of times before + * it is actually uninstalled. + */ + public static void systemUninstall() { + synchronized (STARTUP_SHUTDOWN_MONITOR) { + doSystemUninstall(); + + // hook can only set when Jansi is true + if (shutdownHook != null) { + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (IllegalStateException ex) { + // ignore - VM is already shutting down + } + } + } + } + + private static void doSystemUninstall() { + if (JANSI) { + AnsiConsole.systemUninstall(); + } + } + + /** + * Enables message color (if Jansi is available). + * @param flag to enable Jansi + */ + public static void setColorEnabled(boolean flag) { + if (JANSI) { + AnsiConsole.out().setMode(flag ? AnsiMode.Force : AnsiMode.Strip); + Ansi.setEnabled(flag); + System.setProperty( + AnsiConsole.JANSI_MODE, flag ? AnsiConsole.JANSI_MODE_FORCE : AnsiConsole.JANSI_MODE_STRIP); + boolean installed = AnsiConsole.isInstalled(); + while (AnsiConsole.isInstalled()) { + AnsiConsole.systemUninstall(); + } + if (installed) { + AnsiConsole.systemInstall(); + } + } + } + + /** + * Is message color enabled: requires Jansi available (through Maven) and the color has not been disabled. + * @return whether colored messages are enabled + */ + public static boolean isColorEnabled() { + return JANSI ? Ansi.isEnabled() : false; + } + + /** + * Create a default message buffer. + * @return a new buffer + */ + public static MessageBuilder buffer() { + return JANSI ? new AnsiMessageBuilder() : new PlainMessageBuilder(); + } + + /** + * Create a message buffer with defined String builder. + * @param builder initial content of the message buffer + * @return a new buffer + */ + public static MessageBuilder buffer(StringBuilder builder) { + return JANSI ? new AnsiMessageBuilder(builder) : new PlainMessageBuilder(builder); + } + + /** + * Create a message buffer with an internal buffer of defined size. + * @param size size of the buffer + * @return a new buffer + */ + public static MessageBuilder buffer(int size) { + return JANSI ? new AnsiMessageBuilder(size) : new PlainMessageBuilder(size); + } + + /** + * Create a logger level renderer. + * @return a logger level renderer + * @since 3.2.0 + */ + @SuppressWarnings("checkstyle:magicnumber") + public static LoggerLevelRenderer level() { + return JANSI ? new AnsiMessageBuilder(20) : new PlainMessageBuilder(7); + } + + /** + * Remove any ANSI code from a message (colors or other escape sequences). + * @param msg message eventually containing ANSI codes + * @return the message with ANSI codes removed + */ + public static String stripAnsiCodes(String msg) { + return msg.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", ""); + } + + /** + * Register a shutdown hook with the JVM runtime, uninstalling Ansi support on + * JVM shutdown unless is has already been uninstalled at that time. + *
Delegates to {@link #doSystemUninstall()} for the actual uninstall procedure + * + * @see Runtime#addShutdownHook(Thread) + * @see MessageUtils#systemUninstall() + * @see #doSystemUninstall() + */ + public static void registerShutdownHook() { + if (JANSI && shutdownHook == null) { + // No shutdown hook registered yet. + shutdownHook = new Thread() { + @Override + public void run() { + synchronized (STARTUP_SHUTDOWN_MONITOR) { + while (AnsiConsole.isInstalled()) { + doSystemUninstall(); + } + } + } + }; + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + } + + /** + * Get the terminal width or -1 if the width cannot be determined. + * + * @return the terminal width + */ + public static int getTerminalWidth() { + if (JANSI) { + int width = AnsiConsole.getTerminalWidth(); + return width > 0 ? width : -1; + } else { + return -1; + } + } +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/PlainMessageBuilder.java b/src/main/java/org/apache/maven/shared/utils/logging/PlainMessageBuilder.java new file mode 100644 index 00000000..86b3e2ad --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/PlainMessageBuilder.java @@ -0,0 +1,123 @@ +/* + * 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.maven.shared.utils.logging; + +/** + * Message builder implementation that just ignores styling, for Maven version earlier than 3.5.0. + */ +class PlainMessageBuilder implements MessageBuilder, LoggerLevelRenderer { + private StringBuilder buffer; + + PlainMessageBuilder() { + buffer = new StringBuilder(); + } + + PlainMessageBuilder(StringBuilder builder) { + buffer = builder; + } + + PlainMessageBuilder(int size) { + buffer = new StringBuilder(size); + } + + public String debug(String message) { + return a(message).toString(); + } + + public String info(String message) { + return a(message).toString(); + } + + public String warning(String message) { + return a(message).toString(); + } + + public String error(String message) { + return a(message).toString(); + } + + public PlainMessageBuilder success(Object message) { + return a(message); + } + + public PlainMessageBuilder warning(Object message) { + return a(message); + } + + public PlainMessageBuilder failure(Object message) { + return a(message); + } + + public PlainMessageBuilder strong(Object message) { + return a(message); + } + + public PlainMessageBuilder mojo(Object message) { + return a(message); + } + + public PlainMessageBuilder project(Object message) { + return a(message); + } + + public PlainMessageBuilder a(char[] value, int offset, int len) { + buffer.append(value, offset, len); + return this; + } + + public PlainMessageBuilder a(char[] value) { + buffer.append(value); + return this; + } + + public PlainMessageBuilder a(CharSequence value, int start, int end) { + buffer.append(value, start, end); + return this; + } + + public PlainMessageBuilder a(CharSequence value) { + buffer.append(value); + return this; + } + + public PlainMessageBuilder a(Object value) { + buffer.append(value); + return this; + } + + public PlainMessageBuilder newline() { + buffer.append(System.getProperty("line.separator")); + return this; + } + + public PlainMessageBuilder format(String pattern, Object... args) { + buffer.append(String.format(pattern, args)); + return this; + } + + @Override + public String toString() { + return build(); + } + + @Override + public String build() { + return buffer.toString(); + } +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/Style.java b/src/main/java/org/apache/maven/shared/utils/logging/Style.java new file mode 100644 index 00000000..f14b3e04 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/Style.java @@ -0,0 +1,147 @@ +/* + * 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.maven.shared.utils.logging; + +import java.util.Locale; + +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.Ansi.Color; + +/** + * Configurable message styles. + * @since 3.1.0 + */ +enum Style { + DEBUG("bold,cyan"), + INFO("bold,blue"), + WARNING("bold,yellow"), + ERROR("bold,red"), + SUCCESS("bold,green"), + FAILURE("bold,red"), + STRONG("bold"), + MOJO("green"), + PROJECT("cyan"); + + private final boolean bold; + + private final boolean bright; + + private final Color color; + + private final boolean bgBright; + + private final Color bgColor; + + Style(String defaultValue) { + boolean currentBold = false; + boolean currentBright = false; + Color currentColor = null; + boolean currentBgBright = false; + Color currentBgColor = null; + + String value = System.getProperty("style." + name().toLowerCase(Locale.ENGLISH), defaultValue) + .toLowerCase(Locale.ENGLISH); + + for (String token : value.split(",")) { + if ("bold".equals(token)) { + currentBold = true; + } else if (token.startsWith("bg")) { + token = token.substring(2); + if (token.startsWith("bright")) { + currentBgBright = true; + token = token.substring(6); + } + currentBgColor = toColor(token); + } else { + if (token.startsWith("bright")) { + currentBright = true; + token = token.substring(6); + } + currentColor = toColor(token); + } + } + + this.bold = currentBold; + this.bright = currentBright; + this.color = currentColor; + this.bgBright = currentBgBright; + this.bgColor = currentBgColor; + } + + private static Color toColor(String token) { + for (Color color : Color.values()) { + if (color.toString().equalsIgnoreCase(token)) { + return color; + } + } + return null; + } + + Ansi apply(Ansi ansi) { + if (bold) { + ansi.bold(); + } + if (color != null) { + if (bright) { + ansi.fgBright(color); + } else { + ansi.fg(color); + } + } + if (bgColor != null) { + if (bgBright) { + ansi.bgBright(bgColor); + } else { + ansi.bg(bgColor); + } + } + return ansi; + } + + @Override + public String toString() { + if (!bold && color == null && bgColor == null) { + return name(); + } + StringBuilder sb = new StringBuilder(name() + '='); + if (bold) { + sb.append("bold"); + } + if (color != null) { + if (sb.length() > 0) { + sb.append(','); + } + if (bright) { + sb.append("bright"); + } + sb.append(color.name()); + } + if (bgColor != null) { + if (sb.length() > 0) { + sb.append(','); + } + sb.append("bg"); + if (bgBright) { + sb.append("bright"); + } + sb.append(bgColor.name()); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/apache/maven/shared/utils/logging/package-info.java b/src/main/java/org/apache/maven/shared/utils/logging/package-info.java new file mode 100644 index 00000000..e97d7015 --- /dev/null +++ b/src/main/java/org/apache/maven/shared/utils/logging/package-info.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** + * An API to write Maven messages to console with styled color content, consistently across whole + * Maven ecosystem (Maven itself or any plugin or extension). + *
+ * Messages are built with instances of {@code MessageBuilder} + * which provides a fluent API, while error level are colored by slf4j provider with + * {@code LoggerLevelRenderer}. + *
+ * {@code MessageUtils} gives access to these builders. + *
+ * Plugins can use this API with any Maven version: color + * just won't be activated when run with Maven versions older than 3.5.0. + *
+ * Styles are:
+ *
+ * Default styles colors can be overridden through system properties, that can be set in- + *
debug
,info
,warning
anderror
for + * logger level rendering,- + *
success
,warning
,failure
,strong
,mojo
+ * andproject
for message contentMAVEN_OPTS
+ * environment variable (eventually in.mavenrc
script):+ *
+ * + * @since 3.1.0 + */ +package org.apache.maven.shared.utils.logging; diff --git a/src/main/java/org/apache/maven/shared/utils/reflection/Reflector.java b/src/main/java/org/apache/maven/shared/utils/reflection/Reflector.java deleted file mode 100644 index f35cf129..00000000 --- a/src/main/java/org/apache/maven/shared/utils/reflection/Reflector.java +++ /dev/null @@ -1,573 +0,0 @@ -package org.apache.maven.shared.utils.reflection; - -/* - * 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. - */ - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** - * Utility class used to instantiate an object using reflection. This utility hides many of the gory details needed to - * do this. - * - * @author John Casey - */ -final class Reflector -{ - private static final String CONSTRUCTOR_METHOD_NAME = "$$CONSTRUCTOR$$"; - - private static final String GET_INSTANCE_METHOD_NAME = "getInstance"; - - private final Map- system properties are named
+ *style.<style name>
,- values are comma separated combination of
+ *bold
,<color>
and + *bg<color>
(for background), where<color>
is + * an ANSI color:black
, + *red
,green
,yellow
,blue
,magenta
, + *cyan
orwhite
, eventually withbright
prefix>> classMaps = - new HashMap >>(); - - /** - * Ensure no instances of Reflector are created...this is a utility. - */ - public Reflector() - { - } - - /** - * Create a new instance of a class, given the array of parameters... Uses constructor caching to find a constructor - * that matches the parameter types, either specifically (first choice) or abstractly... - * - * @param theClass The class to instantiate - * @param params The parameters to pass to the constructor - * @return The instantiated object - * @throws ReflectorException In case anything goes wrong here... - */ - public Object newInstance( Class> theClass, Object... params ) - throws ReflectorException - { - if ( params == null ) - { - params = new Object[0]; - } - - Class>[] paramTypes = new Class[params.length]; - - for ( int i = 0, len = params.length; i < len; i++ ) - { - paramTypes[i] = params[i].getClass(); - } - - try - { - Constructor> con = getConstructor( theClass, paramTypes ); - - return con.newInstance( params ); - } - catch ( InstantiationException ex ) - { - throw new ReflectorException( ex ); - } - catch ( InvocationTargetException ex ) - { - throw new ReflectorException( ex ); - } - catch ( IllegalAccessException ex ) - { - throw new ReflectorException( ex ); - } - } - - /** - * Retrieve the singleton instance of a class, given the array of parameters... Uses constructor caching to find a - * constructor that matches the parameter types, either specifically (first choice) or abstractly... - * - * @param theClass The class to retrieve the singleton of - * @param initParams The parameters to pass to the constructor - * @return The singleton object - * @throws ReflectorException In case anything goes wrong here... - */ - public Object getSingleton( Class> theClass, Object... initParams ) - throws ReflectorException - { - Class>[] paramTypes = new Class[initParams.length]; - - for ( int i = 0, len = initParams.length; i < len; i++ ) - { - paramTypes[i] = initParams[i].getClass(); - } - - try - { - Method method = getMethod( theClass, GET_INSTANCE_METHOD_NAME, paramTypes ); - - return method.invoke( null, initParams ); - } - catch ( InvocationTargetException ex ) - { - throw new ReflectorException( ex ); - } - catch ( IllegalAccessException ex ) - { - throw new ReflectorException( ex ); - } - } - - /** - * Invoke the specified method on the specified target with the specified params... - * - * @param target The target of the invocation - * @param methodName The method name to invoke - * @param params The parameters to pass to the method invocation - * @return The result of the method call - * @throws ReflectorException In case of an error looking up or invoking the method. - */ - public Object invoke( Object target, String methodName, Object... params ) - throws ReflectorException - { - if ( params == null ) - { - params = new Object[0]; - } - - Class>[] paramTypes = new Class[params.length]; - - for ( int i = 0, len = params.length; i < len; i++ ) - { - paramTypes[i] = params[i].getClass(); - } - - try - { - Method method = getMethod( target.getClass(), methodName, paramTypes ); - - return method.invoke( target, params ); - } - catch ( InvocationTargetException ex ) - { - throw new ReflectorException( ex ); - } - catch ( IllegalAccessException ex ) - { - throw new ReflectorException( ex ); - } - } - - public Object getStaticField( Class> targetClass, String fieldName ) - throws ReflectorException - { - try - { - Field field = targetClass.getField( fieldName ); - - return field.get( null ); - } - catch ( SecurityException e ) - { - throw new ReflectorException( e ); - } - catch ( NoSuchFieldException e ) - { - throw new ReflectorException( e ); - } - catch ( IllegalArgumentException e ) - { - throw new ReflectorException( e ); - } - catch ( IllegalAccessException e ) - { - throw new ReflectorException( e ); - } - } - - public Object getField( Object target, String fieldName ) - throws ReflectorException - { - return getField( target, fieldName, false ); - } - - public Object getField( Object target, String fieldName, boolean breakAccessibility ) - throws ReflectorException - { - Class> targetClass = target.getClass(); - while ( targetClass != null ) - { - try - { - Field field = targetClass.getDeclaredField( fieldName ); - - boolean accessibilityBroken = false; - if ( !field.isAccessible() && breakAccessibility ) - { - field.setAccessible( true ); - accessibilityBroken = true; - } - - Object result = field.get( target ); - - if ( accessibilityBroken ) - { - field.setAccessible( false ); - } - - return result; - } - catch ( SecurityException e ) - { - throw new ReflectorException( e ); - } - catch ( NoSuchFieldException e ) - { - if ( targetClass == Object.class ) - { - throw new ReflectorException( e ); - } - targetClass = targetClass.getSuperclass(); - } - catch ( IllegalAccessException e ) - { - throw new ReflectorException( e ); - } - } - // Never reached, but needed to satisfy compiler - return null; - } - - /** - * Invoke the specified static method with the specified params... - * - * @param targetClass The target class of the invocation - * @param methodName The method name to invoke - * @param params The parameters to pass to the method invocation - * @return The result of the method call - * @throws ReflectorException In case of an error looking up or invoking the method. - */ - public Object invokeStatic( Class> targetClass, String methodName, Object... params ) - throws ReflectorException - { - if ( params == null ) - { - params = new Object[0]; - } - - Class>[] paramTypes = new Class[params.length]; - - for ( int i = 0, len = params.length; i < len; i++ ) - { - paramTypes[i] = params[i].getClass(); - } - - try - { - Method method = getMethod( targetClass, methodName, paramTypes ); - - return method.invoke( null, params ); - } - catch ( InvocationTargetException ex ) - { - throw new ReflectorException( ex ); - } - catch ( IllegalAccessException ex ) - { - throw new ReflectorException( ex ); - } - } - - /** - * Return the constructor, checking the cache first and storing in cache if not already there.. - * - * @param targetClass The class to get the constructor from - * @param params The classes of the parameters which the constructor should match. - * @return the Constructor object that matches, never {@code null} - * @throws ReflectorException In case we can't retrieve the proper constructor. - */ - public Constructor> getConstructor( Class> targetClass, Class>... params ) - throws ReflectorException - { - Map constructorMap = getConstructorMap( targetClass ); - - @SuppressWarnings( "checkstyle:magicnumber" ) - StringBuilder key = new StringBuilder( 200 ); - - key.append( "(" ); - - for ( Class> param : params ) - { - key.append( param.getName() ); - key.append( "," ); - } - - if ( params.length > 0 ) - { - key.setLength( key.length() - 1 ); - } - - key.append( ")" ); - - Constructor> constructor; - - String paramKey = key.toString(); - - synchronized ( paramKey.intern() ) - { - constructor = (Constructor>) constructorMap.get( paramKey ); - - if ( constructor == null ) - { - Constructor>[] cands = targetClass.getConstructors(); - - for ( Constructor> cand : cands ) - { - Class>[] types = cand.getParameterTypes(); - - if ( params.length != types.length ) - { - continue; - } - - for ( int j = 0, len2 = params.length; j < len2; j++ ) - { - if ( !types[j].isAssignableFrom( params[j] ) ) - { - continue; - } - } - - // we got it, so store it! - constructor = cand; - constructorMap.put( paramKey, constructor ); - } - } - } - - if ( constructor == null ) - { - throw new ReflectorException( "Error retrieving constructor object for: " + targetClass.getName() - + paramKey ); - } - - return constructor; - } - - public Object getObjectProperty( Object target, String propertyName ) - throws ReflectorException - { - Object returnValue; - - if ( propertyName == null || propertyName.trim().length() < 1 ) - { - throw new ReflectorException( "Cannot retrieve value for empty property." ); - } - - String beanAccessor = "get" + Character.toUpperCase( propertyName.charAt( 0 ) ); - if ( propertyName.trim().length() > 1 ) - { - beanAccessor += propertyName.substring( 1 ).trim(); - } - - Class> targetClass = target.getClass(); - Class>[] emptyParams = {}; - - Method method = _getMethod( targetClass, beanAccessor, emptyParams ); - if ( method == null ) - { - method = _getMethod( targetClass, propertyName, emptyParams ); - } - - if ( method != null ) - { - try - { - returnValue = method.invoke( target, new Object[] {} ); - } - catch ( IllegalAccessException e ) - { - throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" - + targetClass + "\'", e ); - } - catch ( InvocationTargetException e ) - { - throw new ReflectorException( "Error retrieving property \'" + propertyName + "\' from \'" - + targetClass + "\'", e ); - } - } - else - { - returnValue = getField( target, propertyName, true ); - if ( returnValue == null ) - { - // TODO: Check if exception is the right action! Field exists, but contains null - throw new ReflectorException( "Neither method: \'" + propertyName + "\' nor bean accessor: \'" - + beanAccessor + "\' can be found for class: \'" + targetClass + "\', and retrieval of field: \'" - + propertyName + "\' returned null as value." ); - } - } - - return returnValue; - } - - /** - * Return the method, checking the cache first and storing in cache if not already there.. - * - * @param targetClass The class to get the method from - * @param params The classes of the parameters which the method should match. - * @return the Method object that matches, never {@code null} - * @throws ReflectorException In case we can't retrieve the proper method. - */ - public Method getMethod( Class> targetClass, String methodName, Class>... params ) - throws ReflectorException - { - Method method = _getMethod( targetClass, methodName, params ); - - if ( method == null ) - { - throw new ReflectorException( "Method: \'" + methodName + "\' not found in class: \'" + targetClass - + "\'" ); - } - - return method; - } - - @SuppressWarnings( "checkstyle:methodname" ) - private Method _getMethod( Class> targetClass, String methodName, Class>... params ) - throws ReflectorException - { - Map methodMap = getMethodMap( targetClass, methodName ); - - @SuppressWarnings( "checkstyle:magicnumber" ) - StringBuilder key = new StringBuilder( 200 ); - - key.append( "(" ); - - for ( Class> param : params ) - { - key.append( param.getName() ); - key.append( "," ); - } - - key.append( ")" ); - - Method method; - - String paramKey = key.toString(); - - synchronized ( paramKey.intern() ) - { - method = (Method) methodMap.get( paramKey ); - - if ( method == null ) - { - Method[] cands = targetClass.getMethods(); - - for ( Method cand : cands ) - { - String name = cand.getName(); - - if ( !methodName.equals( name ) ) - { - continue; - } - - Class>[] types = cand.getParameterTypes(); - - if ( params.length != types.length ) - { - continue; - } - - for ( int j = 0, len2 = params.length; j < len2; j++ ) - { - if ( !types[j].isAssignableFrom( params[j] ) ) - { - continue; - } - } - - // we got it, so store it! - method = cand; - methodMap.put( paramKey, method ); - } - } - } - - return method; - } - - /** - * Retrieve the cache of constructors for the specified class. - * - * @param theClass the class to lookup. - * @return The cache of constructors. - * @throws ReflectorException in case of a lookup error. - */ - private Map getConstructorMap( Class> theClass ) - throws ReflectorException - { - return getMethodMap( theClass, CONSTRUCTOR_METHOD_NAME ); - } - - /** - * Retrieve the cache of methods for the specified class and method name. - * - * @param theClass the class to lookup. - * @param methodName The name of the method to lookup. - * @return The cache of constructors. - */ - private Map getMethodMap( Class> theClass, String methodName ) - { - Map methodMap; - - if ( theClass == null ) - { - return null; - } - - String className = theClass.getName(); - - synchronized ( className.intern() ) - { - Map > classMethods = classMaps.get( className ); - - if ( classMethods == null ) - { - classMethods = new HashMap >(); - methodMap = new HashMap (); - classMethods.put( methodName, methodMap ); - - classMaps.put( className, classMethods ); - } - else - { - String key = className + "::" + methodName; - - synchronized ( key.intern() ) - { - methodMap = classMethods.get( methodName ); - - if ( methodMap == null ) - { - methodMap = new HashMap (); - classMethods.put( methodName, methodMap ); - } - } - } - } - - return methodMap; - } -} diff --git a/src/main/java/org/apache/maven/shared/utils/reflection/ReflectorException.java b/src/main/java/org/apache/maven/shared/utils/reflection/ReflectorException.java deleted file mode 100644 index 5910662c..00000000 --- a/src/main/java/org/apache/maven/shared/utils/reflection/ReflectorException.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.apache.maven.shared.utils.reflection; - -/* - * 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. - */ - -/** - * Exception indicating that an error has occurred while instantiating a class - * with the Reflector class. This exception is meant to put a more user-friendly - * face on the myriad other exceptions throws during reflective object creation. - * - * @author John Casey - */ -class ReflectorException - extends Exception -{ - /** - * Create a new ReflectorException. - */ - public ReflectorException() - { - } - - /** - * Create a new ReflectorException with the specified message. - * - * @param msg The message. - */ - public ReflectorException( String msg ) - { - super( msg ); - } - - /** - * Create a new ReflectorException with the specified root cause. - * - * @param root The root cause. - */ - public ReflectorException( Throwable root ) - { - super( root ); - } - - /** - * Create a new ReflectorException with the specified message and root - * cause. - * - * @param msg The message. - * @param root The root cause. - */ - public ReflectorException( String msg, Throwable root ) - { - super( msg, root ); - } -} diff --git a/src/main/java/org/apache/maven/shared/utils/xml/PrettyPrintXMLWriter.java b/src/main/java/org/apache/maven/shared/utils/xml/PrettyPrintXMLWriter.java index d9ee8838..673703a7 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/PrettyPrintXMLWriter.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/PrettyPrintXMLWriter.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,24 +16,24 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; -import org.apache.maven.shared.utils.Os; - +import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; /** - * XMLWriter with nice indentation + * XMLWriter with nice indentation. + * + * @author kama */ -public class PrettyPrintXMLWriter - implements XMLWriter -{ +public class PrettyPrintXMLWriter implements XMLWriter { private static final char[] CLOSE_1 = "/>".toCharArray(); private static final char[] CLOSE_2 = "".toCharArray(); - private static final char[] DEFAULT_LINE_INDENT = new char[]{ ' ', ' ' }; + private static final char[] DEFAULT_LINE_INDENT = new char[] {' ', ' '}; private PrintWriter writer; @@ -59,103 +57,94 @@ public class PrettyPrintXMLWriter /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. + * @param lineIndent can be null, but the normal way is some spaces */ - public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent ) - { - this( writer, lineIndent, null, null ); + public PrettyPrintXMLWriter(PrintWriter writer, String lineIndent) { + this(writer, lineIndent, null, null); } /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. + * @param lineIndent can be null, but the normal way is some spaces. */ - public PrettyPrintXMLWriter( Writer writer, String lineIndent ) - { - this( new PrintWriter( writer ), lineIndent ); + public PrettyPrintXMLWriter(Writer writer, String lineIndent) { + this(new PrintWriter(writer), lineIndent); } /** * @param writer not null */ - public PrettyPrintXMLWriter( PrintWriter writer ) - { - this( writer, null, null ); + public PrettyPrintXMLWriter(PrintWriter writer) { + this(writer, null, null); } /** * @param writer not null */ - public PrettyPrintXMLWriter( Writer writer ) - { - this( new PrintWriter( writer ) ); + public PrettyPrintXMLWriter(Writer writer) { + this(new PrintWriter(writer)); } /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. - * @param encoding could be null or invalid. - * @param doctype could be null. + * @param lineIndent can be null, but the normal way is some spaces + * @param encoding can be null or invalid + * @param doctype can be null */ - public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String encoding, String doctype ) - { - this( writer, lineIndent.toCharArray(), Os.LINE_SEP.toCharArray(), encoding, doctype ); + public PrettyPrintXMLWriter(PrintWriter writer, String lineIndent, String encoding, String doctype) { + this(writer, lineIndent.toCharArray(), "\n".toCharArray(), encoding, doctype); } /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. - * @param encoding could be null or invalid. - * @param doctype could be null. + * @param lineIndent can be null, but the normal way is some spaces + * @param encoding can be null or invalid + * @param doctype can be null */ - public PrettyPrintXMLWriter( Writer writer, String lineIndent, String encoding, String doctype ) - { - this( new PrintWriter( writer ), lineIndent, encoding, doctype ); + public PrettyPrintXMLWriter(Writer writer, String lineIndent, String encoding, String doctype) { + this(new PrintWriter(writer), lineIndent, encoding, doctype); } /** * @param writer not null - * @param encoding could be null or invalid. - * @param doctype could be null. + * @param encoding can be null or invalid + * @param doctype can be null */ - public PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype ) - { - this( writer, DEFAULT_LINE_INDENT, Os.LINE_SEP.toCharArray(), encoding, doctype ); + public PrettyPrintXMLWriter(PrintWriter writer, String encoding, String doctype) { + this(writer, DEFAULT_LINE_INDENT, "\n".toCharArray(), encoding, doctype); } /** * @param writer not null - * @param encoding could be null or invalid. - * @param doctype could be null. + * @param encoding can be null or invalid + * @param doctype can be null */ - public PrettyPrintXMLWriter( Writer writer, String encoding, String doctype ) - { - this( new PrintWriter( writer ), encoding, doctype ); + public PrettyPrintXMLWriter(Writer writer, String encoding, String doctype) { + this(new PrintWriter(writer), encoding, doctype); } /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. - * @param lineSeparator could be null, but the normal way is valid line separator - * @param encoding could be null or the encoding to use. - * @param doctype could be null. + * @param lineIndent can be null, but the normal way is some spaces. + * @param lineSeparator can be null, but the normal way is valid line separator + * @param encoding can be null or the encoding to use. + * @param doctype can be null */ - public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String lineSeparator, String encoding, - String doctype ) - { - this( writer, lineIndent.toCharArray(), lineSeparator.toCharArray(), encoding, doctype ); + public PrettyPrintXMLWriter( + PrintWriter writer, String lineIndent, String lineSeparator, String encoding, String doctype) { + this(writer, lineIndent.toCharArray(), lineSeparator.toCharArray(), encoding, doctype); } /** * @param writer not null - * @param lineIndent could be null, but the normal way is some spaces. - * @param lineSeparator could be null, but the normal way is valid line separator - * @param encoding could be null or the encoding to use. - * @param doctype could be null. + * @param lineIndent can be null, but the normal way is some spaces + * @param lineSeparator can be null, but the normal way is valid line separator + * @param encoding can be null or the encoding to use + * @param doctype can be null */ - private PrettyPrintXMLWriter( PrintWriter writer, char[] lineIndent, char[] lineSeparator, String encoding, - String doctype ) - { + private PrettyPrintXMLWriter( + PrintWriter writer, char[] lineIndent, char[] lineSeparator, String encoding, String doctype) { + super(); this.writer = writer; this.lineIndent = lineIndent; this.lineSeparator = lineSeparator; @@ -163,137 +152,154 @@ private PrettyPrintXMLWriter( PrintWriter writer, char[] lineIndent, char[] line this.docType = doctype; depth = 0; + + // Fail early with assertions enabled. Issue is in the calling code not having checked for any errors. + assert !writer.checkError() : "Unexpected error state PrintWriter passed to PrettyPrintXMLWriter."; } - public void addAttribute( String key, String value ) - { - if ( !processingElement ) - { - throw new IllegalStateException( "currently processing no element" ); + /** {@inheritDoc} */ + public void addAttribute(String key, String value) throws IOException { + if (!processingElement) { + throw new IllegalStateException("currently processing no element"); } - writer.write( ' ' ); - writer.write( key ); - writer.write( '=' ); - XMLEncode.xmlEncodeTextAsPCDATA( value, true, '"', writer ); + writer.write(' '); + writer.write(key); + writer.write('='); + XMLEncode.xmlEncodeTextAsPCDATA(value, true, '"', writer); + if (writer.checkError()) { + throw new IOException("Failure adding attribute '" + key + "' with value '" + value + "'"); + } } - public void setEncoding( String encoding ) - { - if ( documentStarted ) - { - throw new IllegalStateException( "Document headers already written!" ); + /** {@inheritDoc} */ + public void setEncoding(String encoding) { + if (documentStarted) { + throw new IllegalStateException("Document headers already written!"); } this.encoding = encoding; } - public void setDocType( String docType ) - { - if ( documentStarted ) - { - throw new IllegalStateException( "Document headers already written!" ); + /** {@inheritDoc} */ + public void setDocType(String docType) { + if (documentStarted) { + throw new IllegalStateException("Document headers already written!"); } this.docType = docType; } - public void setLineSeparator( String lineSeparator ) - { - if ( documentStarted ) - { - throw new IllegalStateException( "Document headers already written!" ); + /** + * @param lineSeparator the line separator to be output + */ + public void setLineSeparator(String lineSeparator) { + if (documentStarted) { + throw new IllegalStateException("Document headers already written!"); } this.lineSeparator = lineSeparator.toCharArray(); } - public void setLineIndenter( String lineIndent ) - { - if ( documentStarted ) - { - throw new IllegalStateException( "Document headers already written!" ); + /** + * @param lineIndentParameter the line indent parameter + */ + public void setLineIndenter(String lineIndentParameter) { + if (documentStarted) { + throw new IllegalStateException("Document headers already written!"); } - this.lineIndent = lineIndent.toCharArray(); + this.lineIndent = lineIndentParameter.toCharArray(); } - public void startElement( String elementName ) - { + /** {@inheritDoc} */ + public void startElement(String elementName) throws IOException { + + if (elementName.isEmpty()) { + throw new IllegalArgumentException("Element name cannot be empty"); + } + boolean firstLine = ensureDocumentStarted(); completePreviouslyOpenedElement(); - if ( !firstLine ) - { + if (!firstLine) { newLine(); } - writer.write( '<' ); - writer.write( elementName ); + writer.write('<'); + writer.write(elementName); + if (writer.checkError()) { + throw new IOException("Failure starting element '" + elementName + "'."); + } processingElement = true; - elementStack.add( depth++, elementName ); + elementStack.add(depth++, elementName); } - public void writeText( String text ) - { + /** {@inheritDoc} */ + public void writeText(String text) throws IOException { ensureDocumentStarted(); completePreviouslyOpenedElement(); - XMLEncode.xmlEncodeText( text, writer ); + XMLEncode.xmlEncodeText(text, writer); endOnSameLine = true; + + if (writer.checkError()) { + throw new IOException("Failure writing text."); + } } - public void writeMarkup( String markup ) - { + /** {@inheritDoc} */ + public void writeMarkup(String markup) throws IOException { ensureDocumentStarted(); completePreviouslyOpenedElement(); - writer.write( markup ); + writer.write(markup); + + if (writer.checkError()) { + throw new IOException("Failure writing markup."); + } } - public void endElement() - { - String chars = elementStack.get( --depth ); - if ( processingElement ) - { + /** {@inheritDoc} */ + public void endElement() throws IOException { + String chars = elementStack.get(--depth); + if (processingElement) { // this means we don't have any content yet so we just add a /> - writer.write( CLOSE_1 ); + writer.write(CLOSE_1); processingElement = false; - } - else - { - if ( !endOnSameLine ) - { + } else { + if (!endOnSameLine) { newLine(); } // otherwise we need a full closing tag for that element - writer.write( CLOSE_2 ); - writer.write( chars ); - writer.write( '>' ); + writer.write(CLOSE_2); + writer.write(chars); + writer.write('>'); } endOnSameLine = false; + + if (writer.checkError()) { + throw new IOException("Failure ending element."); + } } /** - * Write the documents if not already done. + * Write the document if not already done. * * @return true
if the document headers have freshly been written. */ - private boolean ensureDocumentStarted() - { - if ( !documentStarted ) - { - if ( docType != null || encoding != null ) - { + private boolean ensureDocumentStarted() { + if (!documentStarted) { + if (docType != null || encoding != null) { writeDocumentHeader(); } @@ -305,47 +311,39 @@ private boolean ensureDocumentStarted() return false; } - private void writeDocumentHeader() - { - writer.write( "" ); + writer.write("?>"); newLine(); - if ( docType != null ) - { + if (docType != null) { + writer.write("'); newLine(); - writer.write( "' ); } } - private void newLine() - { - writer.write( lineSeparator ); + private void newLine() { + writer.write(lineSeparator); - for ( int i = 0; i < depth; i++ ) - { - writer.write( lineIndent ); + for (int i = 0; i < depth; i++) { + writer.write(lineIndent); } } - private void completePreviouslyOpenedElement() - { - if ( processingElement ) - { - writer.write( '>' ); + private void completePreviouslyOpenedElement() { + if (processingElement) { + writer.write('>'); processingElement = false; } } - } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XMLEncode.java b/src/main/java/org/apache/maven/shared/utils/xml/XMLEncode.java index 8d8c9f67..44b6dd9c 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/XMLEncode.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/XMLEncode.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; import java.io.IOException; -import java.io.StringWriter; import java.io.Writer; /** @@ -28,236 +26,109 @@ * This is all about the special characters & and <, and for attributes * " and '. These must be encoded/decoded from/to XML. */ -final class XMLEncode -{ +final class XMLEncode { private static final int CDATA_BLOCK_THRESHOLD_LENGTH = 12; private static final char DEFAULT_QUOTE_CHAR = '"'; - /** - * Checks if this text purely consists of the white space characters - * ' ', TAB, NEWLINE. - */ - public static boolean isWhiteSpace( String text ) - { - for ( int i = 0; i < text.length(); i++ ) - { - char c = text.charAt( i ); - if ( !Character.isWhitespace( c ) ) - { - return false; - } - } - return true; - } - - /** - * Makes any text fit into XML attributes. - */ - public static String xmlEncodeTextForAttribute( String text, char quoteChar ) - { - if ( text == null ) - { - return null; - } - return xmlEncodeTextAsPCDATA( text, true, quoteChar ); - } - - /** - * Encodes text as XML in the most suitable way, either CDATA block or PCDATA. - */ - public static String xmlEncodeText( String text ) - { - if ( text == null ) - { - return null; + static void xmlEncodeText(String text, Writer writer) throws IOException { + if (text == null) { + return; } - StringWriter writer = new StringWriter( text.length() * 2 ); - xmlEncodeText( text, writer ); - return writer.toString(); - } - public static void xmlEncodeText( String text, Writer writer ) - { - if ( text == null ) - { + if (!needsEncoding(text)) { + writer.write(text); return; - } - try - { - if ( !needsEncoding( text ) ) - { - writer.write( text ); - return; - } - else - { - // only encode as cdata if is is longer than CDATA block overhead: - if ( text.length() > CDATA_BLOCK_THRESHOLD_LENGTH ) - { - String cdata = xmlEncodeTextAsCDATABlock( text ); - if ( cdata != null ) - { - writer.write( cdata ); - return; - } + } else { + // only encode as cdata if is is longer than CDATA block overhead: + if (text.length() > CDATA_BLOCK_THRESHOLD_LENGTH) { + String cdata = xmlEncodeTextAsCDATABlock(text); + if (cdata != null) { + writer.write(cdata); + return; } } } - catch ( IOException e ) - { - throw new RuntimeException( e ); - } - // if every thing else fails, do it the save way... - xmlEncodeTextAsPCDATA( text, false, DEFAULT_QUOTE_CHAR, writer ); - } - - /** - * Encodes any text as PCDATA. - */ - public static String xmlEncodeTextAsPCDATA( String text ) - { - if ( text == null ) - { - return null; - } - return xmlEncodeTextAsPCDATA( text, false ); - } - - /** - * Encodes any text as PCDATA. - * - * @param forAttribute if you want - * quotes and apostrophes specially treated for attributes - */ - public static String xmlEncodeTextAsPCDATA( String text, boolean forAttribute ) - { - return xmlEncodeTextAsPCDATA( text, forAttribute, DEFAULT_QUOTE_CHAR ); - } - /** - * Encodes any text as PCDATA. - * - * @param forAttribute if you want - * quotes and apostrophes specially treated for attributes - * @param quoteChar if this is for attributes thischar
is used to quote the attribute value - */ - public static String xmlEncodeTextAsPCDATA( String text, boolean forAttribute, char quoteChar ) - { - if ( text == null ) - { - return null; - } - StringWriter writer = new StringWriter( text.length() * 2 ); - xmlEncodeTextAsPCDATA( text, forAttribute, quoteChar, writer ); - return writer.toString(); + // if every thing else fails, do it the save way... + xmlEncodeTextAsPCDATA(text, false, DEFAULT_QUOTE_CHAR, writer); } - public static void xmlEncodeTextAsPCDATA( String text, boolean forAttribute, char quoteChar, Writer n ) - { - if ( text == null ) - { + static void xmlEncodeTextAsPCDATA(String text, boolean forAttribute, char quoteChar, Writer n) throws IOException { + if (text == null) { return; } - try - { - char c; - int length = text.length(); - if ( forAttribute ) - { - n.append( quoteChar ); - } - - for ( int i = 0; i < length; i++ ) - { - c = text.charAt( i ); - switch ( c ) - { - case '&': - n.append( "&" ); - break; - case '<': - n.append( "<" ); - break; - case '>': // FIX for sourceforge bug #802520 ("]]>" needs encoding) - n.append( ">" ); - break; - case '"': - if ( forAttribute ) - { - n.append( """ ); - } - else - { - n.append( c ); - } - break; - case '\'': - if ( forAttribute ) - { - n.append( "'" ); - } - else - { - n.append( c ); - } - break; - case '\r': - if ( forAttribute ) - { - if ( i == ( length - 1 ) || text.charAt( i + 1 ) != '\n' ) - { - n.append( " " ); - } - } - else - { - n.append( c ); - } - // but skip the \r in \r\n - break; - case '\n': - if ( forAttribute ) - { - n.append( " " ); + int length = text.length(); + if (forAttribute) { + n.append(quoteChar); + } + + for (int i = 0; i < length; i++) { + char c = text.charAt(i); + switch (c) { + case '&': + n.append("&"); + break; + case '<': + n.append("<"); + break; + case '>': // FIX for sourceforge bug #802520 ("]]>" needs encoding) + n.append(">"); + break; + case '"': + if (forAttribute) { + n.append("""); + } else { + n.append(c); + } + break; + case '\'': + if (forAttribute) { + n.append("'"); + } else { + n.append(c); + } + break; + case '\r': + if (forAttribute) { + if (i == (length - 1) || text.charAt(i + 1) != '\n') { + n.append(" "); } - break; + } else { + n.append(c); + } + // but skip the \r in \r\n - default: - n.append( c ); - break; - } - } + break; + case '\n': + if (forAttribute) { + n.append(" "); + } + break; - if ( forAttribute ) - { - n.append( quoteChar ); + default: + n.append(c); + break; } } - catch ( IOException e ) - { - throw new RuntimeException( e ); - } + if (forAttribute) { + n.append(quoteChar); + } } /** * Returns string as CDATA block if possible, otherwise null. */ - public static String xmlEncodeTextAsCDATABlock( String text ) - { - if ( text == null ) - { + private static String xmlEncodeTextAsCDATABlock(String text) { + if (text == null) { return null; } - if ( isCompatibleWithCDATABlock( text ) ) - { + if (!text.contains("]]>")) { return ""; - } - else - { + } else { return null; } } @@ -265,135 +136,16 @@ public static String xmlEncodeTextAsCDATABlock( String text ) /** * Checks if this text needs encoding in order to be represented in XML. */ - public static boolean needsEncoding( String text ) - { - return needsEncoding( text, false ); - } - - /** - * Checks if this text needs encoding in order to be represented in XML. - * - * SetcheckForAttr
if you want to check for storability in - * an attribute. - */ - public static boolean needsEncoding( String data, boolean checkForAttr ) - { - if ( data == null ) - { + private static boolean needsEncoding(String text) { + if (text == null) { return false; } - char c; - for ( int i = 0; i < data.length(); i++ ) - { - c = data.charAt( i ); - if ( c == '&' || c == '<' || ( checkForAttr && ( c == '"' || c == '\'' ) ) ) - { + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c == '&' || c == '<') { return true; } } return false; } - - /** - * Can this text be stored into a CDATA block? - */ - public static boolean isCompatibleWithCDATABlock( String text ) - { - return text != null && ( !text.contains( "]]>" ) ); - } - - /** - * Make CDATA out of possibly encoded PCDATA.
- * E.g. make '&' out of '&' - */ - public static String xmlDecodeTextToCDATA( String pcdata ) - { - if ( pcdata == null ) - { - return null; - } - char c, c1, c2, c3, c4, c5; - StringBuilder n = new StringBuilder( pcdata.length() ); - for ( int i = 0; i < pcdata.length(); i++ ) - { - c = pcdata.charAt( i ); - if ( c == '&' ) - { - c1 = lookAhead( 1, i, pcdata ); - c2 = lookAhead( 2, i, pcdata ); - c3 = lookAhead( 3, i, pcdata ); - c4 = lookAhead( 4, i, pcdata ); - c5 = lookAhead( 5, i, pcdata ); - - if ( c1 == 'a' && c2 == 'm' && c3 == 'p' && c4 == ';' ) - { - n.append( "&" ); - i += 4; - } - else if ( c1 == 'l' && c2 == 't' && c3 == ';' ) - { - n.append( "<" ); - i += 3; - } - else if ( c1 == 'g' && c2 == 't' && c3 == ';' ) - { - n.append( ">" ); - i += 3; - } - else if ( c1 == 'q' && c2 == 'u' && c3 == 'o' && c4 == 't' && c5 == ';' ) - { - n.append( "\"" ); - i += 5; - } - else if ( c1 == 'a' && c2 == 'p' && c3 == 'o' && c4 == 's' && c5 == ';' ) - { - n.append( "'" ); - i += 5; - } - else - { - n.append( "&" ); - } - } - else - { - n.append( c ); - } - } - return n.toString(); - } - - private static char lookAhead( int la, int offset, String data ) - { - try - { - return data.charAt( offset + la ); - } - catch ( StringIndexOutOfBoundsException e ) - { - return 0x0; - } - } - - // combine multiple checks in one methods for speed - private static boolean contains( String text, char[] chars ) - { - if ( text == null || chars == null || chars.length == 0 ) - { - return false; - } - for ( int i = 0; i < text.length(); i++ ) - { - char c = text.charAt( i ); - for ( char aChar : chars ) - { - if ( aChar == c ) - { - return true; - } - } - } - return false; - } - } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XMLWriter.java b/src/main/java/org/apache/maven/shared/utils/xml/XMLWriter.java index 48b03bb0..83ee0abd 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/XMLWriter.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/XMLWriter.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,67 +16,75 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; +import java.io.IOException; /** * Interface for tools writing XML files. * XMLWriters are not thread safe and must not be accessed concurrently. */ -public interface XMLWriter -{ +public interface XMLWriter { /** * Sets the encoding of the document. - * If not set, UTF-8 is being used + * If not set, UTF-8 is used. * * @param encoding the encoding * @throws IllegalStateException if the generation of the document has already started */ - void setEncoding( String encoding ); + void setEncoding(String encoding); /** - * Sets the docType of the document. + * Sets the DOCTYPE of the document. * * @param docType the docType * @throws IllegalStateException if the generation of the document has already started */ - void setDocType( String docType ); - + void setDocType(String docType); /** * Start an XML Element tag. - * @param name + * + * @param name the name of the tag + * @throws IOException if starting the element fails */ - void startElement( String name ); - + void startElement(String name) throws IOException; /** * Add a XML attribute to the current XML Element. - * This method must get called immediately after {@link #startElement(String)} - * @param key - * @param value + * This method must get called immediately after {@link #startElement(String)}. + * + * @param key The key of the attribute. + * @param value The value of the attribute. * @throws IllegalStateException if no element tag is currently in process + * @throws IOException if adding the attribute fails. */ - void addAttribute( String key, String value ); + void addAttribute(String key, String value) throws IOException; /** - * Add a value text to the current element tag - * This will perform XML escaping to guarantee valid content - * @param text + * Add text to the current element tag. + * This performs XML escaping to guarantee well-formed content. + * + * @param text The text which should be written. * @throws IllegalStateException if no element tag got started yet + * @throws IOException if writing the text fails. */ - void writeText( String text ); + void writeText(String text) throws IOException; /** - * Add a preformatted markup to the current element tag - * @param text - * @throws IllegalStateException if no element tag got started yet + * Add preformatted markup to the current element tag. + * + * @param text the text which should be written + * @throws IllegalStateException if no element tag is started yet + * @throws IOException if writing the markup fails */ - void writeMarkup( String text ); + void writeMarkup(String text) throws IOException; /** * End the previously opened element. * @see #startElement(String) + * @throws IOException if ending the element fails. */ - void endElement(); + void endElement() throws IOException; } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XmlReaderException.java b/src/main/java/org/apache/maven/shared/utils/xml/XmlReaderException.java deleted file mode 100644 index ecced002..00000000 --- a/src/main/java/org/apache/maven/shared/utils/xml/XmlReaderException.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.apache.maven.shared.utils.xml; - -/* - * 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. - */ - -import java.io.IOException; -import java.io.InputStream; - -/** - * The XmlReaderException is thrown by the XmlReader constructors if the charset encoding can not be determined - * according to the XML 1.0 specification and RFC 3023. - * - * The exception returns the unconsumed InputStream to allow the application to do an alternate processing with the - * stream. Note that the original InputStream given to the XmlReader cannot be used as that one has been already read. - * - * - * @author Alejandro Abdelnur - * @version revision 1.1 taken on 26/06/2007 from Rome (see https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReaderException.java) - */ -class XmlReaderException - extends IOException -{ - private final String bomEncoding; - - private final String xmlGuessEncoding; - - private final String xmlEncoding; - - private final String contentTypeMime; - - private final String contentTypeEncoding; - - private final InputStream is; - - /** - * Creates an exception instance if the charset encoding could not be determined. - * - * Instances of this exception are thrown by the XmlReader. - * - * - * @param msg message describing the reason for the exception. - * @param bomEnc BOM encoding. - * @param xmlGuessEnc XML guess encoding. - * @param xmlEnc XML prolog encoding. - * @param is the unconsumed InputStream. - */ - XmlReaderException( String msg, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) - { - this( msg, null, null, bomEnc, xmlGuessEnc, xmlEnc, is ); - } - - /** - * Creates an exception instance if the charset encoding could not be determined. - * - * Instances of this exception are thrown by the XmlReader. - * - * - * @param msg message describing the reason for the exception. - * @param ctMime MIME type in the content-type. - * @param ctEnc encoding in the content-type. - * @param bomEnc BOM encoding. - * @param xmlGuessEnc XML guess encoding. - * @param xmlEnc XML prolog encoding. - * @param is the unconsumed InputStream. - */ - XmlReaderException( String msg, String ctMime, String ctEnc, String bomEnc, String xmlGuessEnc, - String xmlEnc, InputStream is ) - { - super( msg ); - contentTypeMime = ctMime; - contentTypeEncoding = ctEnc; - bomEncoding = bomEnc; - xmlGuessEncoding = xmlGuessEnc; - xmlEncoding = xmlEnc; - this.is = is; - } - - /** - * Returns the BOM encoding found in the InputStream. - * - * - * @return the BOM encoding, null if none. - */ - public String getBomEncoding() - { - return bomEncoding; - } - - /** - * Returns the encoding guess based on the first bytes of the InputStream. - * - * - * @return the encoding guess, null if it couldn't be guessed. - */ - public String getXmlGuessEncoding() - { - return xmlGuessEncoding; - } - - /** - * Returns the encoding found in the XML prolog of the InputStream. - * - * - * @return the encoding of the XML prolog, null if none. - */ - public String getXmlEncoding() - { - return xmlEncoding; - } - - /** - * Returns the MIME type in the content-type used to attempt determining the encoding. - * - * - * @return the MIME type in the content-type, null if there was not content-type or the encoding detection did not - * involve HTTP. - */ - public String getContentTypeMime() - { - return contentTypeMime; - } - - /** - * Returns the encoding in the content-type used to attempt determining the encoding. - * - * - * @return the encoding in the content-type, null if there was not content-type, no encoding in it or the encoding - * detection did not involve HTTP. - */ - public String getContentTypeEncoding() - { - return contentTypeEncoding; - } - - /** - * Returns the unconsumed InputStream to allow the application to do an alternate encoding detection on the - * InputStream. - * - * - * @return the unconsumed InputStream. - */ - public InputStream getInputStream() - { - return is; - } -} diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReader.java b/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReader.java index f5da0400..3eb29cf7 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReader.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReader.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; import java.io.File; import java.io.FileInputStream; @@ -29,94 +28,118 @@ import java.util.regex.Pattern; /** - * + * @deprecated use org.apache.commons.io.input.XmlStreamReader instead */ -public class XmlStreamReader - extends Reader -{ +@Deprecated +public class XmlStreamReader extends Reader { private final org.apache.commons.io.input.XmlStreamReader reader; - @SuppressWarnings( "checkstyle:staticvariablename" ) - private static String _staticDefaultEncoding = null; + private static String staticDefaultEncoding = null; - public static void setDefaultEncoding( String encoding ) - { - _staticDefaultEncoding = encoding; + /** + * @param encoding define the default encoding. + */ + public static void setDefaultEncoding(String encoding) { + staticDefaultEncoding = encoding; } - public static String getDefaultEncoding() - { - return _staticDefaultEncoding; + /** + * @return the default encoding. + */ + public static String getDefaultEncoding() { + return staticDefaultEncoding; } - public XmlStreamReader( File file ) - throws IOException - { - this( new FileInputStream( file ) ); + /** + * @param file The file to create it from. + * @throws IOException in case of an error + */ + public XmlStreamReader(File file) throws IOException { + this(new FileInputStream(file)); } - public XmlStreamReader( InputStream is ) - throws IOException - { - this( is, true ); + /** + * @param is {@link InputStream} + * @throws IOException in case of an error + */ + public XmlStreamReader(InputStream is) throws IOException { + this(is, true); } - public XmlStreamReader( InputStream is, boolean lenient ) - throws IOException, XmlStreamReaderException - { - reader = new org.apache.commons.io.input.XmlStreamReader( is, lenient, _staticDefaultEncoding ); + /** + * @param is {@link InputStream} + * @param lenient yes/no + * @throws IOException in case of an error + */ + public XmlStreamReader(InputStream is, boolean lenient) throws IOException { + reader = new org.apache.commons.io.input.XmlStreamReader(is, lenient, staticDefaultEncoding); } - public XmlStreamReader( URL url ) - throws IOException - { - this( url.openConnection() ); + /** + * @param url {@link URL} + * @throws IOException in case of error + */ + public XmlStreamReader(URL url) throws IOException { + this(url.openConnection()); } - public XmlStreamReader( URLConnection conn ) - throws IOException - { - reader = new org.apache.commons.io.input.XmlStreamReader( conn, _staticDefaultEncoding ); + /** + * @param conn The URL connection {@link URLConnection} + * @throws IOException in case of error + */ + public XmlStreamReader(URLConnection conn) throws IOException { + reader = new org.apache.commons.io.input.XmlStreamReader(conn, staticDefaultEncoding); } - public XmlStreamReader( InputStream is, String httpContentType ) - throws IOException - { - this( is, httpContentType, true ); + /** + * @param is {@link InputStream} + * @param httpContentType content type + * @throws IOException in case of error + */ + public XmlStreamReader(InputStream is, String httpContentType) throws IOException { + this(is, httpContentType, true); } - public XmlStreamReader( InputStream is, String httpContentType, boolean lenient, String defaultEncoding ) - throws IOException, XmlStreamReaderException - { - reader = new org.apache.commons.io.input.XmlStreamReader( is, httpContentType, lenient, - ( defaultEncoding == null ) - ? _staticDefaultEncoding - : defaultEncoding ); + /** + * @param is {@link InputStream} + * @param httpContentType content type + * @param lenient yes/no + * @param defaultEncoding the default encoding + * @throws IOException in case of error + */ + public XmlStreamReader(InputStream is, String httpContentType, boolean lenient, String defaultEncoding) + throws IOException { + reader = new org.apache.commons.io.input.XmlStreamReader( + is, httpContentType, lenient, (defaultEncoding == null) ? staticDefaultEncoding : defaultEncoding); } - public XmlStreamReader( InputStream is, String httpContentType, boolean lenient ) - throws IOException, XmlStreamReaderException - { - this( is, httpContentType, lenient, null ); + /** + * @param is {@link InputStream} + * @param httpContentType content type + * @param lenient yes/no + * @throws IOException in case of error + */ + public XmlStreamReader(InputStream is, String httpContentType, boolean lenient) throws IOException { + this(is, httpContentType, lenient, null); } - public String getEncoding() - { + /** + * @return the current encoding + */ + public String getEncoding() { return reader.getEncoding(); } - public int read( char[] buf, int offset, int len ) - throws IOException - { - return reader.read( buf, offset, len ); + /** {@inheritDoc} */ + public int read(char[] buf, int offset, int len) throws IOException { + return reader.read(buf, offset, len); } - public void close() - throws IOException - { + /** {@inheritDoc} */ + public void close() throws IOException { reader.close(); } static final Pattern ENCODING_PATTERN = - Pattern.compile( "<\\?xml.*encoding[\\s]*=[\\s]*((?:\".[^\"]*\")|(?:'.[^']*'))", Pattern.MULTILINE ); + Pattern.compile("<\\?xml.*encoding[\\s]*=[\\s]*((?:\".[^\"]*\")|(?:'.[^']*'))", Pattern.MULTILINE); } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReaderException.java b/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReaderException.java deleted file mode 100644 index 65251d5c..00000000 --- a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamReaderException.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.apache.maven.shared.utils.xml; - -/* - * 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. - */ - -import java.io.InputStream; - -/** - * The XmlStreamReaderException is thrown by the XmlStreamReader constructors if the charset encoding can not be - * determined according to the XML 1.0 specification and RFC 3023. - * - * The exception returns the unconsumed InputStream to allow the application to do an alternate processing with the - * stream. Note that the original InputStream given to the XmlStreamReader cannot be used as that one has been already - * read. - * - * - * @author Alejandro Abdelnur - * @version revision 1.1 taken on 26/06/2007 from Rome (see - * https://rome.dev.java.net/source/browse/rome/src/java/com/sun/syndication/io/XmlReaderException.java) - */ -class XmlStreamReaderException - extends XmlReaderException -{ - /** - * Creates an exception instance if the charset encoding could not be determined. - * - * Instances of this exception are thrown by the XmlReader. - * - * - * @param msg message describing the reason for the exception. - * @param bomEnc BOM encoding. - * @param xmlGuessEnc XML guess encoding. - * @param xmlEnc XML prolog encoding. - * @param is the unconsumed InputStream. - */ - public XmlStreamReaderException( String msg, String bomEnc, String xmlGuessEnc, String xmlEnc, InputStream is ) - { - super( msg, bomEnc, xmlGuessEnc, xmlEnc, is ); - } - - /** - * Creates an exception instance if the charset encoding could not be determined. - * - * Instances of this exception are thrown by the XmlReader. - * - * - * @param msg message describing the reason for the exception. - * @param ctMime MIME type in the content-type. - * @param ctEnc encoding in the content-type. - * @param bomEnc BOM encoding. - * @param xmlGuessEnc XML guess encoding. - * @param xmlEnc XML prolog encoding. - * @param is the unconsumed InputStream. - */ - public XmlStreamReaderException( String msg, String ctMime, String ctEnc, String bomEnc, String xmlGuessEnc, - String xmlEnc, InputStream is ) - { - super( msg, ctMime, ctEnc, bomEnc, xmlGuessEnc, xmlEnc, is ); - } -} diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamWriter.java b/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamWriter.java index cc5f512e..fa5afbac 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamWriter.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/XmlStreamWriter.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,26 +16,29 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; import java.io.File; import java.io.FileNotFoundException; import java.io.OutputStream; /** - * We just wrap the commons StreamWriter to not get into troubles - * by exposing shaded commons-io packages + * @deprecated use org.apache.commons.io.input.XmlStreamWriter instead */ -public class XmlStreamWriter - extends org.apache.commons.io.output.XmlStreamWriter -{ - public XmlStreamWriter( OutputStream out ) - { - super( out ); +@Deprecated +public class XmlStreamWriter extends org.apache.commons.io.output.XmlStreamWriter { + /** + * @param out {@link OutputStream} + */ + public XmlStreamWriter(OutputStream out) { + super(out); } - public XmlStreamWriter( File file ) - throws FileNotFoundException - { - super( file ); + /** + * @param file The file to use. + * @throws FileNotFoundException in case of not found file. + */ + public XmlStreamWriter(File file) throws FileNotFoundException { + super(file); } } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/XmlWriterUtil.java b/src/main/java/org/apache/maven/shared/utils/xml/XmlWriterUtil.java index b0d33dec..e2d14dec 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/XmlWriterUtil.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/XmlWriterUtil.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,9 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; + +import java.io.IOException; import org.apache.maven.shared.utils.StringUtils; @@ -25,12 +26,14 @@ * Utility class for theXmlWriter
class. * * @author Vincent Siveton - * @version $Id$ + * */ -public class XmlWriterUtil -{ +public class XmlWriterUtil { /** The vm line separator */ - public static final String LS = System.getProperty( "line.separator" ); + public static final String LS = System.getProperty("line.separator"); + + /** Platform independent line separator */ + private static final String CRLF = "\r\n"; /** The default line indenter size i.e. 2. */ public static final int DEFAULT_INDENTATION_SIZE = 2; @@ -42,10 +45,10 @@ public class XmlWriterUtil * Convenience method to write oneCRLF
. * * @param writer not null writer + * @throws IOException if writing fails */ - public static void writeLineBreak( XMLWriter writer ) - { - writeLineBreak( writer, 1 ); + public static void writeLineBreak(XMLWriter writer) throws IOException { + writeLineBreak(writer, 1); } /** @@ -53,12 +56,11 @@ public static void writeLineBreak( XMLWriter writer ) * * @param writer not null * @param repeat positive number + * @throws IOException if writing fails */ - public static void writeLineBreak( XMLWriter writer, int repeat ) - { - for ( int i = 0; i < repeat; i++ ) - { - writer.writeMarkup( LS ); + public static void writeLineBreak(XMLWriter writer, int repeat) throws IOException { + for (int i = 0; i < repeat; i++) { + writer.writeMarkup(CRLF); } } @@ -70,10 +72,10 @@ public static void writeLineBreak( XMLWriter writer, int repeat ) * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeLineBreak(XMLWriter, int, int, int) + * @throws IOException if writing fails */ - public static void writeLineBreak( XMLWriter writer, int repeat, int indent ) - { - writeLineBreak( writer, repeat, indent, DEFAULT_INDENTATION_SIZE ); + public static void writeLineBreak(XMLWriter writer, int repeat, int indent) throws IOException { + writeLineBreak(writer, repeat, indent, DEFAULT_INDENTATION_SIZE); } /** @@ -83,22 +85,20 @@ public static void writeLineBreak( XMLWriter writer, int repeat, int indent ) * @param repeat The number of repetitions of the indent * @param indent positive number * @param indentSize positive number + * @throws IOException if writing fails */ - public static void writeLineBreak( XMLWriter writer, int repeat, int indent, int indentSize ) - { - writeLineBreak( writer, repeat ); + public static void writeLineBreak(XMLWriter writer, int repeat, int indent, int indentSize) throws IOException { + writeLineBreak(writer, repeat); - if ( indent < 0 ) - { + if (indent < 0) { indent = 0; } - if ( indentSize < 0 ) - { + if (indentSize < 0) { indentSize = 0; } - writer.writeText( StringUtils.repeat( " ", indent * indentSize ) ); + writer.writeText(StringUtils.repeat(" ", indent * indentSize)); } /** @@ -107,10 +107,10 @@ public static void writeLineBreak( XMLWriter writer, int repeat, int indent, int * @param writer not null * @see #DEFAULT_COLUMN_LINE * @see #writeCommentLineBreak(XMLWriter, int) + * @throws IOException if writing fails */ - public static void writeCommentLineBreak( XMLWriter writer ) - { - writeCommentLineBreak( writer, DEFAULT_COLUMN_LINE ); + public static void writeCommentLineBreak(XMLWriter writer) throws IOException { + writeCommentLineBreak(writer, DEFAULT_COLUMN_LINE); } /** @@ -118,29 +118,28 @@ public static void writeCommentLineBreak( XMLWriter writer ) * * @param writer not null * @param columnSize positive number + * @throws IOException if writing fails */ - public static void writeCommentLineBreak( XMLWriter writer, int columnSize ) - { - if ( columnSize < 10 ) - { + public static void writeCommentLineBreak(XMLWriter writer, int columnSize) throws IOException { + if (columnSize < 10) { columnSize = DEFAULT_COLUMN_LINE; } - writer.writeMarkup( "" + LS ); + writer.writeMarkup("" + CRLF); } /** - * Convenience method to write XML comment line. Thecomment
is splitted to have a size of + * Convenience method to write XML comment line. Thecomment
is split to have a size of *80
. * * @param writer not null * @param comment The comment to write * @see #DEFAULT_INDENTATION_SIZE * @see #writeComment(XMLWriter, String, int, int) + * @throws IOException if writing fails */ - public static void writeComment( XMLWriter writer, String comment ) - { - writeComment( writer, comment, 0, DEFAULT_INDENTATION_SIZE ); + public static void writeComment(XMLWriter writer, String comment) throws IOException { + writeComment(writer, comment, 0, DEFAULT_INDENTATION_SIZE); } /** @@ -152,10 +151,10 @@ public static void writeComment( XMLWriter writer, String comment ) * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeComment(XMLWriter, String, int, int) + * @throws IOException if writing fails */ - public static void writeComment( XMLWriter writer, String comment, int indent ) - { - writeComment( writer, comment, indent, DEFAULT_INDENTATION_SIZE ); + public static void writeComment(XMLWriter writer, String comment, int indent) throws IOException { + writeComment(writer, comment, indent, DEFAULT_INDENTATION_SIZE); } /** @@ -168,12 +167,12 @@ public static void writeComment( XMLWriter writer, String comment, int indent ) * @param indentSize positive number * @see #DEFAULT_COLUMN_LINE * @see #writeComment(XMLWriter, String, int, int, int) + * @throws IOException if writing fails */ - public static void writeComment( XMLWriter writer, String comment, int indent, int indentSize ) - { - writeComment( writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE ); + public static void writeComment(XMLWriter writer, String comment, int indent, int indentSize) throws IOException { + writeComment(writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE); } - + /** * Convenience method to write XML comment line. Thecomment
is split to have a size of *columnSize
and is indented byindent
usingindentSize
. @@ -183,76 +182,64 @@ public static void writeComment( XMLWriter writer, String comment, int indent, i * @param indent positive number * @param indentSize positive number * @param columnSize positive number + * @throws IOException if writing fails */ - public static void writeComment( XMLWriter writer, String comment, int indent, int indentSize, int columnSize ) - { - if ( comment == null ) - { + public static void writeComment(XMLWriter writer, String comment, int indent, int indentSize, int columnSize) + throws IOException { + if (comment == null) { comment = "null"; } - if ( indent < 0 ) - { + if (indent < 0) { indent = 0; } - if ( indentSize < 0 ) - { + if (indentSize < 0) { indentSize = 0; } - if ( columnSize < 0 ) - { + if (columnSize < 0) { columnSize = DEFAULT_COLUMN_LINE; } - String indentation = StringUtils.repeat( " ", indent * indentSize ); + String indentation = StringUtils.repeat(" ", indent * indentSize); int magicNumber = indentation.length() + columnSize - "-->".length() - 1; - String[] sentences = StringUtils.split( comment, LS ); - - StringBuffer line = new StringBuffer( indentation + "" ).append( LS ); - writer.writeMarkup( line.toString() ); + line.append("-->").append(CRLF); + writer.writeMarkup(line.toString()); } - line = new StringBuffer( indentation + "" ).append( LS ); + line.append("-->").append(CRLF); - writer.writeMarkup( line.toString() ); + writer.writeMarkup(line.toString()); } /** @@ -263,10 +250,10 @@ public static void writeComment( XMLWriter writer, String comment, int indent, i * @param comment The comment to write * @see #DEFAULT_INDENTATION_SIZE * @see #writeCommentText(XMLWriter, String, int, int) + * @throws IOException if writing fails */ - public static void writeCommentText( XMLWriter writer, String comment ) - { - writeCommentText( writer, comment, 0, DEFAULT_INDENTATION_SIZE ); + public static void writeCommentText(XMLWriter writer, String comment) throws IOException { + writeCommentText(writer, comment, 0, DEFAULT_INDENTATION_SIZE); } /** @@ -279,10 +266,10 @@ public static void writeCommentText( XMLWriter writer, String comment ) * @param indent positive number * @see #DEFAULT_INDENTATION_SIZE * @see #writeCommentText(XMLWriter, String, int, int) + * @throws IOException if writing fails */ - public static void writeCommentText( XMLWriter writer, String comment, int indent ) - { - writeCommentText( writer, comment, indent, DEFAULT_INDENTATION_SIZE ); + public static void writeCommentText(XMLWriter writer, String comment, int indent) throws IOException { + writeCommentText(writer, comment, indent, DEFAULT_INDENTATION_SIZE); } /** @@ -295,10 +282,11 @@ public static void writeCommentText( XMLWriter writer, String comment, int inden * @param indentSize positive number * @see #DEFAULT_COLUMN_LINE * @see #writeCommentText(XMLWriter, String, int, int, int) + * @throws IOException if writing fails */ - public static void writeCommentText( XMLWriter writer, String comment, int indent, int indentSize ) - { - writeCommentText( writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE ); + public static void writeCommentText(XMLWriter writer, String comment, int indent, int indentSize) + throws IOException { + writeCommentText(writer, comment, indent, indentSize, DEFAULT_COLUMN_LINE); } /** @@ -311,34 +299,32 @@ public static void writeCommentText( XMLWriter writer, String comment, int inden * @param indent positive number * @param indentSize positive number * @param columnSize positive number + * @throws IOException if writing fails */ - public static void writeCommentText( XMLWriter writer, String comment, int indent, int indentSize, int columnSize ) - { - if ( indent < 0 ) - { + public static void writeCommentText(XMLWriter writer, String comment, int indent, int indentSize, int columnSize) + throws IOException { + if (indent < 0) { indent = 0; } - if ( indentSize < 0 ) - { + if (indentSize < 0) { indentSize = 0; } - if ( columnSize < 0 ) - { + if (columnSize < 0) { columnSize = DEFAULT_COLUMN_LINE; } - writeLineBreak( writer, 1 ); + writeLineBreak(writer, 1); - writer.writeMarkup( StringUtils.repeat( " ", indent * indentSize ) ); - writeCommentLineBreak( writer, columnSize ); + writer.writeMarkup(StringUtils.repeat(" ", indent * indentSize)); + writeCommentLineBreak(writer, columnSize); - writeComment( writer, comment, indent, indentSize, columnSize ); + writeComment(writer, comment, indent, indentSize, columnSize); - writer.writeMarkup( StringUtils.repeat( " ", indent * indentSize ) ); - writeCommentLineBreak( writer, columnSize ); + writer.writeMarkup(StringUtils.repeat(" ", indent * indentSize)); + writeCommentLineBreak(writer, columnSize); - writeLineBreak( writer, 1, indent, indentSize ); + writeLineBreak(writer, 1, indent, indentSize); } } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3Dom.java b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3Dom.java index aef182b7..aece7643 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3Dom.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3Dom.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,7 +16,11 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; + +import javax.annotation.Nonnull; +import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; @@ -27,17 +29,12 @@ import java.util.List; import java.util.Map; -import javax.annotation.Nonnull; - /** * A reimplementation of Plexus Xpp3Dom based on the public interface of Plexus Xpp3Dom. * * @author Kristian Rosenvold */ -public class Xpp3Dom - implements Iterable-{ - @SuppressWarnings( "UnusedDeclaration" ) +public class Xpp3Dom implements Iterable { private static final long serialVersionUID = 2567894443061173996L; private String name; // plexus: protected @@ -52,270 +49,338 @@ public class Xpp3Dom private Xpp3Dom parent; // plexus: protected + /** + * The attribute which identifies merge/append. + */ public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children"; private static final String CHILDREN_COMBINATION_MERGE = "merge"; + /** + * The attribute append. + */ public static final String CHILDREN_COMBINATION_APPEND = "append"; - @SuppressWarnings( "UnusedDeclaration" ) + @SuppressWarnings("UnusedDeclaration") private static final String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE; // plexus: public + /** + * The name of the attribute. + */ public static final String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self"; - public static final String SELF_COMBINATION_OVERRIDE = "override"; // plexus: public + /** + * The attributes which identifies override
. + */ + public static final String SELF_COMBINATION_OVERRIDE = "override"; // plexus: public + /** + * The attribute which identifiesmerge
+ */ public static final String SELF_COMBINATION_MERGE = "merge"; - @SuppressWarnings( "UnusedDeclaration" ) - private static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE; // plexus: public + @SuppressWarnings("UnusedDeclaration") + private static final String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE; // plexus: public private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final Xpp3Dom[] EMPTY_DOM_ARRAY = new Xpp3Dom[0]; - public Xpp3Dom( String name ) - { + /** + * @param name The name of the instance. + */ + public Xpp3Dom(String name) { this.name = name; childList = new ArrayList(); childMap = new HashMap (); } - public Xpp3Dom( Xpp3Dom source ) - { - this( source, source.getName() ); + /** + * Create instance. + * @param source The source. + */ + public Xpp3Dom(Xpp3Dom source) { + this(source, source.getName()); } - public Xpp3Dom( @Nonnull Xpp3Dom src, String name ) - { + /** + * Create instance. + * @param src The source Dom. + * @param name The name of the Dom. + */ + public Xpp3Dom(@Nonnull Xpp3Dom src, String name) { this.name = name; int size = src.getChildCount(); - childList = new ArrayList ( size ); + childList = new ArrayList (size); childMap = new HashMap (); - setValue( src.getValue() ); + setValue(src.getValue()); - for ( String attributeName : src.getAttributeNames() ) - { - setAttribute( attributeName, src.getAttribute( attributeName ) ); + for (String attributeName : src.getAttributeNames()) { + setAttribute(attributeName, src.getAttribute(attributeName)); } - for ( Xpp3Dom xpp3Dom : src.getChildren() ) - { - addChild( new Xpp3Dom( xpp3Dom ) ); + for (Xpp3Dom xpp3Dom : src.getChildren()) { + addChild(new Xpp3Dom(xpp3Dom)); } } - public String getName() - { + /** + * @return The current name. + */ + public String getName() { return name; } - @Nonnull public String getValue() - { + /** + * @return The current value. + */ + @Nonnull + public String getValue() { return value; } - public void setValue( @Nonnull String value ) - { + /** + * @param value The value to be set. + */ + public void setValue(@Nonnull String value) { this.value = value; } - - public String[] getAttributeNames() - { + /** + * @return The array of attribute names. + */ + public String[] getAttributeNames() { boolean isNothing = attributes == null || attributes.isEmpty(); - return isNothing ? EMPTY_STRING_ARRAY : attributes.keySet().toArray( new String[attributes.size()] ); + return isNothing ? EMPTY_STRING_ARRAY : attributes.keySet().toArray(new String[attributes.size()]); } - - public String getAttribute( String name ) - { - return attributes != null ? attributes.get( name ) : null; + /** + * @param nameParameter The name of the attribute. + * @return The attribute value. + */ + public String getAttribute(String nameParameter) { + return this.attributes != null ? this.attributes.get(nameParameter) : null; } - @SuppressWarnings( "ConstantConditions" ) - public void setAttribute( @Nonnull String name, @Nonnull String value ) - { - if ( value == null ) - { - throw new NullPointerException( "value can not be null" ); + /** + * @param nameParameter The name of the attribute. + * @param valueParameter The value of the attribute. + */ + public void setAttribute(@Nonnull String nameParameter, @Nonnull String valueParameter) { + if (valueParameter == null) { + throw new NullPointerException("value can not be null"); } - if ( name == null ) - { - throw new NullPointerException( "name can not be null" ); + if (nameParameter == null) { + throw new NullPointerException("name can not be null"); } - if ( attributes == null ) - { + if (attributes == null) { attributes = new HashMap (); } - attributes.put( name, value ); + attributes.put(nameParameter, valueParameter); } - public Xpp3Dom getChild( int i ) - { - return childList.get( i ); + /** + * @param i The index to be selected. + * @return The child selected by index. + */ + public Xpp3Dom getChild(int i) { + return childList.get(i); } - public Xpp3Dom getChild( String name ) - { - return childMap.get( name ); + /** + * @param nameParameter The name of the child. + * @return The child selected by name. + */ + public Xpp3Dom getChild(String nameParameter) { + return childMap.get(nameParameter); } - public void addChild( Xpp3Dom child ) - { - child.setParent( this ); - childList.add( child ); - childMap.put( child.getName(), child ); + /** + * @param child The child to be added. + */ + public void addChild(Xpp3Dom child) { + child.setParent(this); + childList.add(child); + childMap.put(child.getName(), child); } - public Xpp3Dom[] getChildren() - { + /** + * @return The array of childs. + */ + public Xpp3Dom[] getChildren() { boolean isNothing = childList == null || childList.isEmpty(); - return isNothing ? EMPTY_DOM_ARRAY : childList.toArray( new Xpp3Dom[childList.size()] ); + return isNothing ? EMPTY_DOM_ARRAY : childList.toArray(new Xpp3Dom[childList.size()]); } - private List getChildrenList() - { + private List getChildrenList() { boolean isNothing = childList == null || childList.isEmpty(); return isNothing ? Collections. emptyList() : childList; } - public Xpp3Dom[] getChildren( String name ) - { - List children = getChildrenList( name ); - return children.toArray( new Xpp3Dom[children.size()] ); + /** + * @param nameParameter The name of the child. + * @return The array of the Dom. + */ + public Xpp3Dom[] getChildren(String nameParameter) { + List children = getChildrenList(nameParameter); + return children.toArray(new Xpp3Dom[children.size()]); } - List getChildrenList( String name ) - { - if ( childList == null ) - { + List getChildrenList(String nameParameter) { + if (childList == null) { return Collections.emptyList(); - } - else - { + } else { ArrayList children = new ArrayList (); - for ( Xpp3Dom aChildList : childList ) - { - if ( name.equals( aChildList.getName() ) ) - { - children.add( aChildList ); + for (Xpp3Dom aChildList : childList) { + if (nameParameter.equals(aChildList.getName())) { + children.add(aChildList); } } return children; } } - public int getChildCount() - { - if ( childList == null ) - { + /** + * @return The number of childs. + */ + public int getChildCount() { + if (childList == null) { return 0; } return childList.size(); } - public void removeChild( int i ) - { - Xpp3Dom child = childList.remove( i ); - childMap.values().remove( child ); - child.setParent( null ); + /** + * @param i The child to be removed. + */ + public void removeChild(int i) { + Xpp3Dom child = childList.remove(i); + childMap.values().remove(child); + child.setParent(null); } - public Xpp3Dom getParent() - { + /** + * @return The current parent. + */ + public Xpp3Dom getParent() { return parent; } - public void setParent( Xpp3Dom parent ) - { - this.parent = parent; - } - - // Todo: Support writing to serializer (>1.0) - // public void writeToSerializer( String namespace, XmlSerializer serializer ) - // throws IOException - - private static Xpp3Dom merge( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) - { - return Xpp3DomUtils.merge( dominant, recessive, childMergeOverride ); + /** + * @param parent Set the parent. + */ + public void setParent(Xpp3Dom parent) { + this.parent = parent; } - public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) - { - return Xpp3DomUtils.mergeXpp3Dom( dominant, recessive, childMergeOverride ); + /** + * @param dominant The dominant part. + * @param recessive The recessive part. + * @param childMergeOverride true if child merge will take precedence false otherwise. + * @return The merged Xpp3Dom. + */ + public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) { + return Xpp3DomUtils.mergeXpp3Dom(dominant, recessive, childMergeOverride); } - public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive ) - { - return Xpp3DomUtils.mergeXpp3Dom( dominant, recessive ); + /** + * @param dominant The dominant part. + * @param recessive The recessive part. + * @return The merged Xpp3Dom. + */ + public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive) { + return Xpp3DomUtils.mergeXpp3Dom(dominant, recessive); } - public boolean equals( Object obj ) - { - if ( obj == this ) - { + /** {@inheritDoc} */ + public boolean equals(Object obj) { + if (obj == this) { return true; } - if ( !( obj instanceof Xpp3Dom ) ) - { + if (!(obj instanceof Xpp3Dom)) { return false; } Xpp3Dom dom = (Xpp3Dom) obj; - return !( name == null ? dom.name != null : !name.equals( dom.name ) ) - && !( value == null ? dom.value != null : !value.equals( dom.value ) ) - && !( attributes == null ? dom.attributes != null : !attributes.equals( dom.attributes ) ) - && !( childList == null ? dom.childList != null : !childList.equals( dom.childList ) ); + return !(name == null ? dom.name != null : !name.equals(dom.name)) + && !(value == null ? dom.value != null : !value.equals(dom.value)) + && !(attributes == null ? dom.attributes != null : !attributes.equals(dom.attributes)) + && !(childList == null ? dom.childList != null : !childList.equals(dom.childList)); } - public int hashCode() - { + /** {@inheritDoc} */ + public int hashCode() { int result = 17; - result = 37 * result + ( name != null ? name.hashCode() : 0 ); - result = 37 * result + ( value != null ? value.hashCode() : 0 ); - result = 37 * result + ( attributes != null ? attributes.hashCode() : 0 ); - result = 37 * result + ( childList != null ? childList.hashCode() : 0 ); + result = 37 * result + (name != null ? name.hashCode() : 0); + result = 37 * result + (value != null ? value.hashCode() : 0); + result = 37 * result + (attributes != null ? attributes.hashCode() : 0); + result = 37 * result + (childList != null ? childList.hashCode() : 0); return result; } - public String toString() - { - StringWriter writer = new StringWriter(); - Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this ); - return writer.toString(); - + /** {@inheritDoc} */ + public String toString() { + try { + StringWriter writer = new StringWriter(); + Xpp3DomWriter.write(getPrettyPrintXMLWriter(writer), this); + return writer.toString(); + } catch (final IOException e) { + // JDK error in StringWriter. + throw (AssertionError) new AssertionError("Unexpected IOException from StringWriter.").initCause(e); + } } - public String toUnescapedString() - { - StringWriter writer = new StringWriter(); - Xpp3DomWriter.write( getPrettyPrintXMLWriter( writer ), this, false ); - return writer.toString(); + /** + * @return Unescaped string. + */ + public String toUnescapedString() { + try { + StringWriter writer = new StringWriter(); + Xpp3DomWriter.write(getPrettyPrintXMLWriter(writer), this, false); + return writer.toString(); + } catch (final IOException e) { + // JDK error in StringWriter. + throw (AssertionError) new AssertionError("Unexpected IOException from StringWriter.").initCause(e); + } } - private PrettyPrintXMLWriter getPrettyPrintXMLWriter( StringWriter writer ) - { - return new PrettyPrintXMLWriter( writer, "UTF-8", null ); + private PrettyPrintXMLWriter getPrettyPrintXMLWriter(StringWriter writer) { + return new PrettyPrintXMLWriter(writer, "UTF-8", null); } - public static boolean isNotEmpty( String str ) - { + /** + * Warning: this is not the reverse of {@link #isEmpty}. + * Whitespace only strings are both empty and not empty. + * + * @param str the string to be checked + * @return true if the string is not empty (length > 0) and not null
+ * @deprecated usestr != null && !str.isEmpty()
+ */ + @Deprecated + public static boolean isNotEmpty(String str) { return str != null && str.length() > 0; } - public static boolean isEmpty( String str ) - { + /** + * Warning: this is not the reverse of {@link #isNotEmpty}. + * Whitespace only strings are both empty and not empty. + * + * @param str the string to be checked + * @return true if the string only contains whitespace or isnull
+ * @deprecated usestr == null || str.trim().isEmpty()
+ */ + @Deprecated + public static boolean isEmpty(String str) { return str == null || str.trim().length() == 0; } - public Iteratoriterator() - { + /** {@inheritDoc} */ + public Iterator iterator() { return getChildrenList().iterator(); } } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomBuilder.java b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomBuilder.java index 78fa4f69..b03da580 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomBuilder.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomBuilder.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,15 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - -import org.apache.maven.shared.utils.io.IOUtil; -import org.apache.maven.shared.utils.xml.pull.XmlPullParserException; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; +package org.apache.maven.shared.utils.xml; import javax.annotation.Nonnull; import javax.annotation.WillClose; @@ -39,258 +29,197 @@ import java.util.ArrayList; import java.util.List; +import org.apache.maven.shared.utils.xml.pull.XmlPullParserException; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + /** * @author Kristian Rosenvold */ -public class Xpp3DomBuilder -{ - private static final boolean DEFAULT_TRIM = true; - - public static Xpp3Dom build( @WillClose @Nonnull Reader reader ) - throws XmlPullParserException - { - return build( reader, DEFAULT_TRIM ); +public class Xpp3DomBuilder { + + /** + * @param reader {@link Reader} + * @return the built DOM + * @throws XmlPullParserException in case of an error + */ + public static Xpp3Dom build(@WillClose @Nonnull Reader reader) throws XmlPullParserException { + return build(reader, false); } - public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding ) - throws XmlPullParserException - { - return build( is, encoding, DEFAULT_TRIM ); + /** + * @param is {@link InputStream} + * @param encoding the encoding + * @return the built DOM + * @throws XmlPullParserException in case of an error + */ + public static Xpp3Dom build(@WillClose InputStream is, @Nonnull String encoding) throws XmlPullParserException { + return build(is, encoding, false); } - public static Xpp3Dom build( @WillClose InputStream is, @Nonnull String encoding, boolean trim ) - throws XmlPullParserException - { - try - { - Reader reader = new InputStreamReader( is, encoding ); - return build( reader, trim ); - } - catch ( UnsupportedEncodingException e ) - { - throw new RuntimeException( e ); + /** + * @param is {@link InputStream} + * @param encoding the encoding + * @param noop vestigial argument with no effect + * @return the built DOM + * @throws XmlPullParserException in case of an error + * @deprecated use the two-arg variant + */ + @Deprecated + public static Xpp3Dom build(@WillClose InputStream is, @Nonnull String encoding, boolean noop) + throws XmlPullParserException { + try { + Reader reader = new InputStreamReader(is, encoding); + return build(reader); + } catch (UnsupportedEncodingException e) { + throw new XmlPullParserException(e); } } - public static Xpp3Dom build( @WillClose Reader reader, boolean trim ) - throws XmlPullParserException - { - try - { - DocHandler docHandler = parseSax( new InputSource( reader ), trim ); + /** + * @param in {@link Reader} + * @param noop vestigial argument with no effect + * @return the built DOM + * @throws XmlPullParserException in case of an error + * @deprecated use {#build(java.io.Reader)} + */ + @Deprecated + public static Xpp3Dom build(@WillClose Reader in, boolean noop) throws XmlPullParserException { + try (Reader reader = in) { + DocHandler docHandler = parseSax(new InputSource(reader)); + reader.close(); return docHandler.result; - } - finally - { - IOUtil.close( reader ); + } catch (final IOException e) { + throw new XmlPullParserException(e); } } - private static DocHandler parseSax( @Nonnull InputSource inputSource, boolean trim ) - throws XmlPullParserException - { - try - { - DocHandler ch = new DocHandler( trim ); + private static DocHandler parseSax(@Nonnull InputSource inputSource) throws XmlPullParserException { + try { + DocHandler ch = new DocHandler(); XMLReader parser = createXmlReader(); - parser.setContentHandler( ch ); - parser.parse( inputSource ); + parser.setContentHandler(ch); + parser.parse(inputSource); return ch; - } - catch ( IOException e ) - { - throw new XmlPullParserException( e ); - } - catch ( SAXException e ) - { - throw new XmlPullParserException( e ); + } catch (IOException e) { + throw new XmlPullParserException(e); + } catch (SAXException e) { + throw new XmlPullParserException(e); } } - - private static XMLReader createXmlReader() - throws SAXException - { - XMLReader comSunXmlReader = instantiate( "com.sun.org.apache.xerces.internal.parsers.SAXParser" ); - if ( comSunXmlReader != null ) - { + private static XMLReader createXmlReader() throws SAXException { + XMLReader comSunXmlReader = instantiate("com.sun.org.apache.xerces.internal.parsers.SAXParser"); + if (comSunXmlReader != null) { return comSunXmlReader; } String key = "org.xml.sax.driver"; - String oldParser = System.getProperty( key ); - System.clearProperty( key ); // There's a "slight" problem with this an parallel maven: It does not work ;) + String oldParser = System.getProperty(key); + System.clearProperty(key); // There's a "slight" problem with this an parallel maven: It does not work ;) - try - { + try { return org.xml.sax.helpers.XMLReaderFactory.createXMLReader(); - } - finally - { - if ( oldParser != null ) - { - System.setProperty( key, oldParser ); + } finally { + if (oldParser != null) { + System.setProperty(key, oldParser); } } - } - private static XMLReader instantiate( String s ) - { - try - { - Class> aClass = Thread.currentThread().getContextClassLoader().loadClass( s ); + private static XMLReader instantiate(String s) { + try { + Class> aClass = Thread.currentThread().getContextClassLoader().loadClass(s); return (XMLReader) aClass.newInstance(); - } - catch ( ClassNotFoundException e ) - { - return null; - } - catch ( InstantiationException e ) - { - return null; - } - catch ( IllegalAccessException e ) - { - return null; + } catch (ClassNotFoundException e) { + return null; + } catch (InstantiationException e) { + return null; + } catch (IllegalAccessException e) { + return null; } } - - private static class DocHandler - extends DefaultHandler - { + private static class DocHandler extends DefaultHandler { private final List elemStack = new ArrayList (); private final List values = new ArrayList (); - // Todo: Use these for something smart ! - private final List warnings = new ArrayList (); - - private final List errors = new ArrayList (); - - private final List fatals = new ArrayList (); - - Xpp3Dom result = null; - private final boolean trim; - private boolean spacePreserve = false; - DocHandler( boolean trim ) - { - this.trim = trim; - } - @Override - public void startElement( String uri, String localName, String qName, Attributes attributes ) - throws SAXException - { + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { spacePreserve = false; - Xpp3Dom child = new Xpp3Dom( localName ); + Xpp3Dom child = new Xpp3Dom(localName); - attachToParent( child ); - pushOnStack( child ); + attachToParent(child); + pushOnStack(child); - // Todo: Detecting tags that close immediately seem to be impossible in sax ? - // http://stackoverflow.com/questions/12968390/detecting-self-closing-tags-in-sax - values.add( new StringBuilder() ); + values.add(new StringBuilder()); int size = attributes.getLength(); - for ( int i = 0; i < size; i++ ) - { - String name = attributes.getQName( i ); - String value = attributes.getValue( i ); - child.setAttribute( name, value ); - spacePreserve = spacePreserve || ( "xml:space".equals( name ) && "preserve".equals( value ) ); + for (int i = 0; i < size; i++) { + String name = attributes.getQName(i); + String value = attributes.getValue(i); + child.setAttribute(name, value); + spacePreserve = spacePreserve || ("xml:space".equals(name) && "preserve".equals(value)); } } - private boolean pushOnStack( Xpp3Dom child ) - { - return elemStack.add( child ); + private boolean pushOnStack(Xpp3Dom child) { + return elemStack.add(child); } - private void attachToParent( Xpp3Dom child ) - { + private void attachToParent(Xpp3Dom child) { int depth = elemStack.size(); - if ( depth > 0 ) - { - elemStack.get( depth - 1 ).addChild( child ); + if (depth > 0) { + elemStack.get(depth - 1).addChild(child); } } - @Override - public void warning( SAXParseException e ) - throws SAXException - { - warnings.add( e ); - } - - @Override - public void error( SAXParseException e ) - throws SAXException - { - errors.add( e ); - } - - @Override - public void fatalError( SAXParseException e ) - throws SAXException - { - fatals.add( e ); - } - - private Xpp3Dom pop() - { + private Xpp3Dom pop() { int depth = elemStack.size() - 1; - return elemStack.remove( depth ); + return elemStack.remove(depth); } @Override - public void endElement( String uri, String localName, String qName ) - throws SAXException - { + public void endElement(String uri, String localName, String qName) throws SAXException { int depth = elemStack.size() - 1; Xpp3Dom element = pop(); /* this Object could be null if it is a singleton tag */ - Object accumulatedValue = values.remove( depth ); + Object accumulatedValue = values.remove(depth); - if ( element.getChildCount() == 0 ) - { - if ( accumulatedValue == null ) - { - element.setValue( "" ); // null in xpp3dom, but we don't do that around here - } - else - { - element.setValue( accumulatedValue.toString() ); + if (element.getChildCount() == 0) { + if (accumulatedValue == null) { + element.setValue(""); // null in xpp3dom, but we don't do that around here + } else { + element.setValue(accumulatedValue.toString()); } } - if ( depth == 0 ) - { + if (depth == 0) { result = element; } } @Override - public void characters( char[] ch, int start, int length ) - throws SAXException - { - String text = new String( ch, start, length ); - appendToTopValue( ( trim && !spacePreserve ) ? text.trim() : text ); + public void characters(char[] ch, int start, int length) throws SAXException { + String text = new String(ch, start, length); + appendToTopValue(text); } - private void appendToTopValue( String toAppend ) - { + private void appendToTopValue(String toAppend) { // noinspection MismatchedQueryAndUpdateOfStringBuilder - StringBuilder stringBuilder = values.get( values.size() - 1 ); - stringBuilder.append( toAppend ); + StringBuilder stringBuilder = values.get(values.size() - 1); + stringBuilder.append(toAppend); } } - } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomUtils.java b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomUtils.java index 6627a958..d6d066c6 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomUtils.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; import java.util.HashMap; import java.util.Iterator; @@ -25,117 +24,112 @@ import java.util.Map; /** - * + * */ -public class Xpp3DomUtils -{ - public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) - { - return dominant != null ? merge( dominant, recessive, childMergeOverride ) : recessive; +public class Xpp3DomUtils { + /** + * @param dominant {@link Xpp3Dom} + * @param recessive {@link Xpp3Dom} + * @param childMergeOverride true/false. + * @return Merged dom. + */ + public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) { + return dominant != null ? merge(dominant, recessive, childMergeOverride) : recessive; } - public static Xpp3Dom mergeXpp3Dom( Xpp3Dom dominant, Xpp3Dom recessive ) - { - return dominant != null ? merge( dominant, recessive, null ) : recessive; + /** + * @param dominant {@link Xpp3Dom} + * @param recessive {@link Xpp3Dom} + * @return Merged dom. + */ + public static Xpp3Dom mergeXpp3Dom(Xpp3Dom dominant, Xpp3Dom recessive) { + return dominant != null ? merge(dominant, recessive, null) : recessive; } - public static Xpp3Dom merge( Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride ) - { - if ( recessive == null || isCombineSelfOverride( dominant ) ) - { + /** + * @param dominant {@link Xpp3Dom} + * @param recessive {@link Xpp3Dom} + * @param childMergeOverride true/false. + * @return Merged dom. + */ + public static Xpp3Dom merge(Xpp3Dom dominant, Xpp3Dom recessive, Boolean childMergeOverride) { + if (recessive == null || isCombineSelfOverride(dominant)) { return dominant; } - if ( isEmpty( dominant.getValue() ) ) - { - dominant.setValue( recessive.getValue() ); + if (isEmpty(dominant.getValue())) { + dominant.setValue(recessive.getValue()); } - for ( String attr : recessive.getAttributeNames() ) - { - if ( isEmpty( dominant.getAttribute( attr ) ) ) - { - dominant.setAttribute( attr, recessive.getAttribute( attr ) ); + for (String attr : recessive.getAttributeNames()) { + if (isEmpty(dominant.getAttribute(attr))) { + dominant.setAttribute(attr, recessive.getAttribute(attr)); } } - if ( recessive.getChildCount() > 0 ) - { - boolean mergeChildren = isMergeChildren( dominant, childMergeOverride ); + if (recessive.getChildCount() > 0) { + boolean mergeChildren = isMergeChildren(dominant, childMergeOverride); - if ( mergeChildren ) - { - Map > commonChildren = getCommonChildren( dominant, recessive ); - for ( Xpp3Dom recessiveChild : recessive ) - { - Iterator it = commonChildren.get( recessiveChild.getName() ); - if ( it == null ) - { - dominant.addChild( new Xpp3Dom( recessiveChild ) ); - } - else if ( it.hasNext() ) - { + if (mergeChildren) { + Map > commonChildren = getCommonChildren(dominant, recessive); + for (Xpp3Dom recessiveChild : recessive) { + Iterator it = commonChildren.get(recessiveChild.getName()); + if (it == null) { + dominant.addChild(new Xpp3Dom(recessiveChild)); + } else if (it.hasNext()) { Xpp3Dom dominantChild = it.next(); - merge( dominantChild, recessiveChild, childMergeOverride ); + merge(dominantChild, recessiveChild, childMergeOverride); } } - } - else - { + } else { Xpp3Dom[] dominantChildren = dominant.getChildren(); dominant.childList.clear(); - for ( Xpp3Dom child : recessive ) - { - dominant.addChild( new Xpp3Dom( child ) ); + for (Xpp3Dom child : recessive) { + dominant.addChild(new Xpp3Dom(child)); } - for ( Xpp3Dom aDominantChildren : dominantChildren ) - { - dominant.addChild( aDominantChildren ); + for (Xpp3Dom aDominantChildren : dominantChildren) { + dominant.addChild(aDominantChildren); } } } return dominant; } - private static Map > getCommonChildren( Xpp3Dom dominant, Xpp3Dom recessive ) - { + private static Map > getCommonChildren(Xpp3Dom dominant, Xpp3Dom recessive) { Map > commonChildren = new HashMap >(); - for ( String childName : recessive.childMap.keySet() ) - { - List dominantChildren = dominant.getChildrenList( childName ); - if ( dominantChildren.size() > 0 ) - { - commonChildren.put( childName, dominantChildren.iterator() ); + for (String childName : recessive.childMap.keySet()) { + List dominantChildren = dominant.getChildrenList(childName); + if (dominantChildren.size() > 0) { + commonChildren.put(childName, dominantChildren.iterator()); } } return commonChildren; } - private static boolean isCombineSelfOverride( Xpp3Dom xpp3Dom ) - { - String selfMergeMode = xpp3Dom.getAttribute( Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE ); - return Xpp3Dom.SELF_COMBINATION_OVERRIDE.equals( selfMergeMode ); + private static boolean isCombineSelfOverride(Xpp3Dom xpp3Dom) { + String selfMergeMode = xpp3Dom.getAttribute(Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE); + return Xpp3Dom.SELF_COMBINATION_OVERRIDE.equals(selfMergeMode); } - private static boolean isMergeChildren( Xpp3Dom dominant, Boolean override ) - { - return override != null ? override : !isMergeChildren( dominant ); + private static boolean isMergeChildren(Xpp3Dom dominant, Boolean override) { + return override != null ? override : !isMergeChildren(dominant); } - private static boolean isMergeChildren( Xpp3Dom dominant ) - { + private static boolean isMergeChildren(Xpp3Dom dominant) { return Xpp3Dom.CHILDREN_COMBINATION_APPEND.equals( - dominant.getAttribute( Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE ) ); + dominant.getAttribute(Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE)); } - public static boolean isEmpty( String str ) - { + /** + * @deprecated use str == null || String.isBlank(str)
(Java 11+) + * ororg.apache.commons.lang3.StringUtils.isBlank(str)
+ * @param str the string to be checked + * @returntrue
if the string is null, empty, or whitespace only;false
otherwise + */ + @Deprecated + public static boolean isEmpty(String str) { return str == null || str.trim().length() == 0; } - - - - } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomWriter.java b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomWriter.java index 293814a9..f4924985 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomWriter.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/Xpp3DomWriter.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,57 +16,68 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml; +import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; /** * @author Brett Porter */ -public class Xpp3DomWriter -{ - public static void write( Writer writer, Xpp3Dom dom ) - { - write( new PrettyPrintXMLWriter( writer ), dom ); +public class Xpp3DomWriter { + /** + * @param writer {@link Writer} + * @param dom {@link Xpp3Dom} + * @throws IOException if writing fails. + */ + public static void write(Writer writer, Xpp3Dom dom) throws IOException { + write(new PrettyPrintXMLWriter(writer), dom); } - public static void write( PrintWriter writer, Xpp3Dom dom ) - { - write( new PrettyPrintXMLWriter( writer ), dom ); + /** + * @param writer {@link PrintWriter} + * @param dom {@link Xpp3Dom} + * @throws IOException if writing fails. + */ + public static void write(PrintWriter writer, Xpp3Dom dom) throws IOException { + write(new PrettyPrintXMLWriter(writer), dom); } - public static void write( XMLWriter xmlWriter, Xpp3Dom dom ) - { - write( xmlWriter, dom, true ); + /** + * @param xmlWriter {@link XMLWriter} + * @param dom {@link Xpp3Dom} + * @throws IOException if writing fails. + */ + public static void write(XMLWriter xmlWriter, Xpp3Dom dom) throws IOException { + write(xmlWriter, dom, true); } - public static void write( XMLWriter xmlWriter, Xpp3Dom dom, boolean escape ) - { - xmlWriter.startElement( dom.getName() ); + /** + * @param xmlWriter {@link XMLWriter} + * @param dom {@link Xpp3Dom} + * @param escape true/false. + * @throws IOException if writing fails. + */ + public static void write(XMLWriter xmlWriter, Xpp3Dom dom, boolean escape) throws IOException { + xmlWriter.startElement(dom.getName()); String[] attributeNames = dom.getAttributeNames(); - for ( String attributeName : attributeNames ) - { - xmlWriter.addAttribute( attributeName, dom.getAttribute( attributeName ) ); + for (String attributeName : attributeNames) { + xmlWriter.addAttribute(attributeName, dom.getAttribute(attributeName)); } Xpp3Dom[] children = dom.getChildren(); - for ( Xpp3Dom aChildren : children ) - { - write( xmlWriter, aChildren, escape ); + for (Xpp3Dom aChildren : children) { + write(xmlWriter, aChildren, escape); } String value = dom.getValue(); - if ( value != null ) - { - if ( escape ) - { - xmlWriter.writeText( value ); - } - else - { - xmlWriter.writeMarkup( value ); + if (value != null) { + if (escape) { + xmlWriter.writeText(value); + } else { + xmlWriter.writeMarkup(value); } } xmlWriter.endElement(); } - } diff --git a/src/main/java/org/apache/maven/shared/utils/xml/pull/XmlPullParserException.java b/src/main/java/org/apache/maven/shared/utils/xml/pull/XmlPullParserException.java index 5d6d2c3b..5f495b11 100644 --- a/src/main/java/org/apache/maven/shared/utils/xml/pull/XmlPullParserException.java +++ b/src/main/java/org/apache/maven/shared/utils/xml/pull/XmlPullParserException.java @@ -1,5 +1,3 @@ -package org.apache.maven.shared.utils.xml.pull; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -9,7 +7,7 @@ * "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 + * 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 @@ -18,30 +16,34 @@ * specific language governing permissions and limitations * under the License. */ +package org.apache.maven.shared.utils.xml.pull; + +import java.io.IOException; import org.xml.sax.SAXException; -import java.io.IOException; +public class XmlPullParserException extends RuntimeException { -/** - * - */ -public class XmlPullParserException - extends RuntimeException -{ + private static final long serialVersionUID = 117075811816936575L; - public XmlPullParserException( IOException e ) - { - super( e ); + /** + * @param e IOException. + */ + public XmlPullParserException(IOException e) { + super(e); } - public XmlPullParserException( SAXException e ) - { - super( e ); + /** + * @param e The exception. + */ + public XmlPullParserException(SAXException e) { + super(e); } - public XmlPullParserException( String message ) - { - super( message ); + /** + * @param message The message. + */ + public XmlPullParserException(String message) { + super(message); } } diff --git a/src/site/apt/index.apt.vm b/src/site/apt/index.apt.vm index 76069f42..419146d8 100644 --- a/src/site/apt/index.apt.vm +++ b/src/site/apt/index.apt.vm @@ -30,27 +30,23 @@ ${project.name} This project aims to be a functional replacement for - {{{http://plexus.codehaus.org/plexus-utils}plexus-utils}} in Maven. + {{{http://codehaus-plexus.github.io/plexus-utils/}plexus-utils}} in Maven. It is not a 100% API compatible replacement though but a replacement: lots of methods got cleaned up, generics got added and we dropped a lot of unused code. -Why ? + Then there are additions, like + {{{./apidocs/org/apache/maven/shared/utils/logging/package-summary.html}styled message API}}. - plexus-utils consisted mostly of code that was forked from various apache projects. - maven-shared-utils is based on the original from the apache sources. +Why? -Why not commons ? + plexus-utils consisted mostly of code that was forked from various Apache projects. + maven-shared-utils is based on the original from the Apache sources. - We would prefer code to use commons-* code where appropriate, but the plexus-utils became +Why not commons? + + We would prefer code to use commons-* where appropriate, but the plexus-utils became slightly incompatible (different) from the commons over the years, so migrating is not always a 1:1 operation. Migrating to maven-shared-utils is a 1:1 operation in most cases. -Relation to Commons-* - - maven-shared-utils internally use {{{http://commons.apache.org/io/}commons-io}}. We shade all commons - classes into our own private package to prevent classpath clashes. - - This is the reason why any public API in maven-shared-utils must - avoid to expose commons-io classes directly. Most times it's sufficient - to just create an empty subclass and expose that instead. + [] diff --git a/src/site/site.xml b/src/site/site.xml index 563b34ca..e607a00b 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -20,13 +20,14 @@ under the License. --> + diff --git a/src/site/xdoc/download.xml.vm b/src/site/xdoc/download.xml.vm index 5d1650bd..2b848a91 100644 --- a/src/site/xdoc/download.xml.vm +++ b/src/site/xdoc/download.xml.vm @@ -23,102 +23,51 @@ under the License. + Download ${project.name} Source - ${project.name} ${project.version} is distributed in source format. Use a source archive if you intend to build - ${project.name} yourself. Otherwise, simply use the ready-made binary artifacts from central repository.
- -You will be prompted for a mirror - if the file is not found on yours, please be patient, as it may take 24 - hours to reach all mirrors.
- -In order to guard against corrupted downloads/installations, it is highly recommended to -