diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..b551b6bd --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '41 8 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3c37caf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..f4ea1bed --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,52 @@ +plugins { + `java-library` +} + +group = "de.sebli" +version = "2.8" + +repositories { + mavenCentral() + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") { + name = "spigotmc-repo" + } + maven("https://oss.sonatype.org/content/groups/public/") { + name = "sonatype" + } +} + +dependencies { + compileOnly("org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT") + implementation("commons-io:commons-io:2.11.0") + implementation("commons-net:commons-net:3.8.0") + compileOnly("org.junit.jupiter:junit-jupiter:5.8.2") +} + +val targetJavaVersion = 8 +java { + val javaVersion = JavaVersion.toVersion(targetJavaVersion) + sourceCompatibility = javaVersion + targetCompatibility = javaVersion +} + +tasks { + compileJava { + options.encoding = Charsets.UTF_8.name() + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible) + options.release.set(targetJavaVersion) + } + processResources { + filesMatching("plugin.yml") { + expand("version" to project.version) + } + } + test { + useJUnitPlatform() + } + jar { + val dependencies = configurations.runtimeClasspath.get().map(::zipTree) + from(dependencies) + exclude("META-INF/LICENSE.txt", "META-INF/NOTICE.txt", "META-INF/maven/**") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..aad36f79 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx3G +org.gradle.caching=true +org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..41d9927a Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..aa991fce --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..1b6c7873 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..d1f6f53b --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "ServerBackup" diff --git a/src/de/sebli/serverbackup/BackupManager.java b/src/de/sebli/serverbackup/BackupManager.java deleted file mode 100644 index 898343a3..00000000 --- a/src/de/sebli/serverbackup/BackupManager.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.sebli.serverbackup; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; -import java.util.logging.Level; - -import org.apache.commons.io.FileUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -public class BackupManager { - - private String filePath; - private CommandSender sender; - - public BackupManager(String filePath, CommandSender sender) { - this.filePath = filePath; - this.sender = sender; - } - - public void createBackup() { - File worldFolder = new File(filePath); - - if (filePath.equalsIgnoreCase("@server")) { - worldFolder = new File(Bukkit.getWorldContainer().getPath()); - filePath = worldFolder.getPath(); - } - - Date date = new Date(); - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'~'HH-mm-ss"); - df.setTimeZone(TimeZone.getDefault()); - - File backupFolder = new File(ServerBackup.getInstance().backupDestination + "//backup-" + df.format(date) + "-" + filePath + "//" + filePath); - - if (worldFolder.exists()) { - for (Player all : Bukkit.getOnlinePlayers()) { - if (all.hasPermission("backup.notification")) { - all.sendMessage("Backup [" + worldFolder + "] started."); - } - } - - try { - if (!backupFolder.exists()) { - ZipManager zm = new ZipManager(worldFolder.getName(), - ServerBackup.getInstance().backupDestination + "//backup-" + df.format(date) + "-" + filePath + ".zip", Bukkit.getConsoleSender(), - true, true); - - zm.zip(); - } else { - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Backup already exists."); - } - } catch (IOException e) { - e.printStackTrace(); - - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Backup failed."); -// System.out.println("Backup failed."); - } - } else { - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Couldn't find '" + filePath + "' folder."); - } - } - - public void removeBackup() { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); - - if (file.exists()) { - if (file.isDirectory()) { - try { - FileUtils.deleteDirectory(file); - - sender.sendMessage("Backup [" + filePath + "] removed."); - } catch (IOException e) { - e.printStackTrace(); - - sender.sendMessage("Error while deleting '" + filePath + "'."); - } - } else { - file.delete(); - - sender.sendMessage("Backup [" + filePath + "] removed."); - } - } else { - sender.sendMessage("No Backup named '" + filePath + "' found."); - } - }); - } - -} diff --git a/src/de/sebli/serverbackup/BackupTimer.java b/src/de/sebli/serverbackup/BackupTimer.java deleted file mode 100644 index b8aa6549..00000000 --- a/src/de/sebli/serverbackup/BackupTimer.java +++ /dev/null @@ -1,184 +0,0 @@ -package de.sebli.serverbackup; - -import java.io.File; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; - -import org.bukkit.Bukkit; - -public class BackupTimer implements Runnable { - - List worlds = ServerBackup.getInstance().getConfig().getStringList("BackupWorlds"); - List days = ServerBackup.getInstance().getConfig().getStringList("BackupTimer.Days"); - List times = ServerBackup.getInstance().getConfig().getStringList("BackupTimer.Times"); - - Calendar cal = Calendar.getInstance(); - - @Override - public void run() { - cal = Calendar.getInstance(); - - boolean isBackupDay = days.stream().filter(d -> d.equalsIgnoreCase(getDayName(cal.get(Calendar.DAY_OF_WEEK)))) - .findFirst().isPresent(); - - if (isBackupDay) { - for (String time : times) { - try { - String[] timeStr = time.split("-"); - - if (timeStr[0].startsWith("0")) { - timeStr[0] = timeStr[0].substring(1); - } - - if (timeStr[1].startsWith("0")) { - timeStr[1] = timeStr[1].substring(1); - } - - int hour = Integer.valueOf(timeStr[0]); - int minute = Integer.valueOf(timeStr[1]); - - if (cal.get(Calendar.HOUR_OF_DAY) == hour && cal.get(Calendar.MINUTE) == minute) { - for (String world : worlds) { - BackupManager bm = new BackupManager(world, Bukkit.getConsoleSender()); - bm.createBackup(); - } - } - } catch (Exception e) { - ServerBackup.getInstance().getLogger().log(Level.WARNING, - "ServerBackup: Automatic Backup failed. Please check that you set the BackupTimer correctly."); - } - } - } - - if (ServerBackup.getInstance().getConfig().getInt("BackupLimiter") <= 0) { - if (cal.get(Calendar.HOUR_OF_DAY) == 0 && cal.get(Calendar.MINUTE) == 0) { - if (ServerBackup.getInstance().getConfig().getInt("DeleteOldBackups") <= 0) - return; - - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - if (backups.length == 0) - return; - - Arrays.sort(backups, Collections.reverseOrder()); - - LocalDate date = LocalDate.now() - .minusDays(ServerBackup.getInstance().getConfig().getInt("DeleteOldBackups")); - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Backup deletion started..."); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - - long time = System.currentTimeMillis(); - - List backupNames = new ArrayList<>(); - - for (int i = 0; i < backups.length; i++) { - try { - String[] backupDateStr = backups[i].getName().split("-"); - LocalDate backupDate = LocalDate.parse( - backupDateStr[1] + "-" + backupDateStr[2] + "-" + backupDateStr[3].split("~")[0]); - String backupName = backupDateStr[6]; - - if (ServerBackup.getInstance().getConfig().getBoolean("KeepUniqueBackups")) { - if (!backupNames.contains(backupName)) { - backupNames.add(backupName); - continue; - } - } - - if (backupDate.isBefore(date.plusDays(1))) { - if (backups[i].exists()) { - backups[i].delete(); - - ServerBackup.getInstance().getLogger().log(Level.INFO, - "Backup [" + backups[i].getName() + "] removed."); - } else { - ServerBackup.getInstance().getLogger().log(Level.WARNING, - "No Backup named '" + backups[i].getName() + "' found."); - } - } - } catch (Exception e) { - continue; - } - -// if (backups[i].getName().contains(df.format(date))) { -// if (backups[i].exists()) { -// backups[i].delete(); -// -// System.out.println("Backup [" + backups[i].getName() + "] removed."); -// } else { -// System.out.println("No Backup named '" + backups[i].getName() + "' found."); -// } -// } - } - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Backup deletion finished. [" - + Long.valueOf(System.currentTimeMillis() - time) + "ms]"); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - } - } else { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - Arrays.sort(backups); - - int dobc = ServerBackup.getInstance().getConfig().getInt("BackupLimiter"); - int c = 0; - - while (backups.length > dobc) { - if (backups[c].exists()) { - backups[c].delete(); - - ServerBackup.getInstance().getLogger().log(Level.INFO, - "Backup [" + backups[c].getName() + "] removed."); - } else { - ServerBackup.getInstance().getLogger().log(Level.WARNING, - "No Backup named '" + backups[c].getName() + "' found."); - } - - c++; - dobc++; - } - } - } - - private String getDayName(int dayNumber) { - if (dayNumber == 1) { - return "SUNDAY"; - } - - if (dayNumber == 2) { - return "MONDAY"; - } - - if (dayNumber == 3) { - return "TUESDAY"; - } - - if (dayNumber == 4) { - return "WEDNESDAY"; - } - - if (dayNumber == 5) { - return "THURSDAY"; - } - - if (dayNumber == 6) { - return "FRIDAY"; - } - - if (dayNumber == 7) { - return "SATURDAY"; - } - - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while converting number in day."); - - return null; - } - -} diff --git a/src/de/sebli/serverbackup/FtpManager.java b/src/de/sebli/serverbackup/FtpManager.java deleted file mode 100644 index 2a38a0d1..00000000 --- a/src/de/sebli/serverbackup/FtpManager.java +++ /dev/null @@ -1,211 +0,0 @@ -package de.sebli.serverbackup; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.net.ftp.FTP; -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPSClient; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; - -public class FtpManager { - - private CommandSender sender; - - String server = ServerBackup.getInstance().getConfig().getString("Ftp.Server.IP"); - int port = ServerBackup.getInstance().getConfig().getInt("Ftp.Server.Port"); - String user = ServerBackup.getInstance().getConfig().getString("Ftp.Server.User"); - String pass = ServerBackup.getInstance().getConfig().getString("Ftp.Server.Password"); - - public FtpManager(CommandSender sender) { - this.sender = sender; - } - - public void uploadFileToFtp(String filePath) { - File file = new File(filePath); - - if (!file.getPath().contains(ServerBackup.getInstance().backupDestination.replaceAll("/", ""))) { - file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); - } - - if (!file.exists()) { - sender.sendMessage("Ftp: Backup '" + file.getName() + "' not found."); - - return; - } - - FTPSClient ftpClient = new FTPSClient(); - - try { - ftpClient.connect(server, port); - ftpClient.login(user, pass); - ftpClient.enterLocalPassiveMode(); - - ftpClient.execPBSZ(0); - ftpClient.execPROT("P"); - - ftpClient.setFileType(FTP.BINARY_FILE_TYPE); - - sender.sendMessage("Ftp: Uploading backup [" + file.getName() + "] ..."); - - InputStream inputStream = new FileInputStream(file); - - boolean done = ftpClient.storeFile(file.getName(), inputStream); - inputStream.close(); - if (done) { - sender.sendMessage("Ftp: Upload successfull. Backup stored on ftp server."); - - if (ServerBackup.getInstance().getConfig().getBoolean("Ftp.DeleteLocalBackup")) { - boolean exists = false; - for (FTPFile backup : ftpClient.listFiles()) { - if (backup.getName().equalsIgnoreCase(file.getName())) - exists = true; - } - - if (exists) { - file.delete(); - } else { - sender.sendMessage( - "Ftp: Local backup deletion failed because the uploaded file was not found on the ftp server. Try again."); - } - } - } else { - sender.sendMessage( - "Ftp: Error while uploading backup to ftp server. Check server details in config.yml (ip, port, user, password)."); - } - } catch (IOException e) { - sender.sendMessage("Ftp: Error while uploading backup to ftp server."); - e.printStackTrace(); - } finally { - try { - if (ftpClient.isConnected()) { - ftpClient.logout(); - ftpClient.disconnect(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public void downloadFileFromFtp(String filePath) { - File file = new File(filePath); - - FTPSClient ftpClient = new FTPSClient(); - - try { - ftpClient.connect(server, port); - ftpClient.login(user, pass); - ftpClient.enterLocalPassiveMode(); - - ftpClient.execPBSZ(0); - ftpClient.execPROT("P"); - - ftpClient.setFileType(FTP.BINARY_FILE_TYPE); - - boolean exists = false; - for (FTPFile backup : ftpClient.listFiles()) { - if (backup.getName().equalsIgnoreCase(file.getName())) - exists = true; - } - - if (!exists) { - sender.sendMessage("Ftp: ftp-backup '" + file.getName() + "' not found."); - - return; - } - - sender.sendMessage("Ftp: Downloading backup [" + file.getName() + "] ..."); - - OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file)); - boolean success = ftpClient.retrieveFile(file.getName(), outputStream); - outputStream.close(); - - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File dFile = new File(ServerBackup.getInstance().backupDestination + "//" + file.getPath()); - - try { - FileUtils.copyFile(file, dFile); - } catch (IOException e) { - e.printStackTrace(); - } - - if (dFile.exists()) { - file.delete(); - } - }); - - if (success) { - sender.sendMessage("Ftp: Download successfull. Backup downloaded from ftp server."); - } else { - sender.sendMessage( - "Ftp: Error while downloading backup from ftp server. Check server details in config.yml (ip, port, user, password)."); - } - } catch (IOException e) { - sender.sendMessage("Ftp: Error while downloading backup from ftp server."); - e.printStackTrace(); - } finally { - try { - if (ftpClient.isConnected()) { - ftpClient.logout(); - ftpClient.disconnect(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public List getFtpBackupList() { - List backups = new ArrayList<>(); - - FTPSClient ftpClient = new FTPSClient(); - - try { - ftpClient.connect(server, port); - ftpClient.login(user, pass); - ftpClient.enterLocalPassiveMode(); - - ftpClient.execPBSZ(0); - ftpClient.execPROT("P"); - - FTPFile[] files = ftpClient.listFiles(); - - int c = 1; - - for (FTPFile file : files) { - double fileSize = (double) file.getSize() / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - backups.add("§7[" + c + "]§f " + file.getName() + " §7[" + fileSize + "MB]"); - - c++; - } - - } catch (IOException e) { - sender.sendMessage("Error while connecting to FTP server."); - e.printStackTrace(); - } finally { - try { - if (ftpClient.isConnected()) { - ftpClient.logout(); - ftpClient.disconnect(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - return backups; - } - -} diff --git a/src/de/sebli/serverbackup/ServerBackup.java b/src/de/sebli/serverbackup/ServerBackup.java deleted file mode 100644 index 7a55c43b..00000000 --- a/src/de/sebli/serverbackup/ServerBackup.java +++ /dev/null @@ -1,296 +0,0 @@ -package de.sebli.serverbackup; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; -import java.util.logging.Level; -import java.util.concurrent.Callable; - -import org.apache.commons.io.FileUtils; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitTask; - -import de.sebli.serverbackup.commands.SBCommand; -import de.sebli.serverbackup.utils.Metrics; - -public class ServerBackup extends JavaPlugin implements Listener { - - private static ServerBackup sb; - - public static ServerBackup getInstance() { - return sb; - } - - public String backupDestination = "Backups//"; - - @Override - public void onDisable() { - stopTimer(); - - for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) { - task.cancel(); - - this.getLogger().log(Level.WARNING, "WARNING - ServerBackup: Task [" + task.getTaskId() - + "] cancelled due to server shutdown. There might be some unfinished Backups."); - } - - this.getLogger().log(Level.INFO, "ServerBackup: Plugin disabled."); -// System.out.println("ServerBackup: Plugin disabled."); - } - - @Override - public void onEnable() { - sb = this; - - loadFiles(); - - getCommand("backup").setExecutor(new SBCommand()); - - Bukkit.getPluginManager().registerEvents(this, this); - - startTimer(); - - this.getLogger().log(Level.INFO, "ServerBackup: Plugin enabled."); -// System.out.println("ServerBackup: Plugin enabled."); - - if (getConfig().getBoolean("UpdateAvailabeMessage")) { - checkVersion(); - } - - int mpid = 14673; - - Metrics metrics = new Metrics(this, mpid); - - metrics.addCustomChart(new Metrics.SimplePie("player_per_server", new Callable() { - @Override - public String call() throws Exception { - return String.valueOf(Bukkit.getOnlinePlayers().size()); - } - })); - - metrics.addCustomChart(new Metrics.SimplePie("using_ftp_server", new Callable() { - @Override - public String call() throws Exception { - if (getConfig().getBoolean("Ftp.UploadBackup")) { - return "yes"; - } else { - return "no"; - } - } - })); - - metrics.addCustomChart(new Metrics.SingleLineChart("total_backup_space", new Callable() { - @Override - public Integer call() throws Exception { - File file = new File(backupDestination); - - double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - return (int) fileSize; - } - })); - } - - private void checkVersion() { - this.getLogger().log(Level.INFO, "ServerBackup: Searching for updates..."); - - Bukkit.getScheduler().runTaskAsynchronously(this, () -> { - int resourceID = 79320; - try (InputStream inputStream = (new URL( - "https://api.spigotmc.org/legacy/update.php?resource=" + resourceID)).openStream(); - Scanner scanner = new Scanner(inputStream)) { - if (scanner.hasNext()) { - String latest = scanner.next(); - String current = getDescription().getVersion(); - - int late = Integer.parseInt(latest.replaceAll("\\.", "")); - int curr = Integer.parseInt(current.replaceAll("\\.", "")); - - if (curr >= late) { - this.getLogger().log(Level.INFO, - "ServerBackup: No updates found. The server is running the latest version."); - -// System.out.println("ServerBackup: No updates found. The server is running the latest version."); - } else { - this.getLogger().log(Level.INFO, "\nServerBackup: There is a newer version available - " - + latest + ", you are on - " + current); - this.getLogger().log(Level.INFO, - "ServerBackup: Please download the latest version - https://www.spigotmc.org/resources/" - + resourceID + "\n"); - -// System.out.println(""); -// System.out.println("ServerBackup: There is a newer version available - " + latest -// + ", you are on - " + current); -// System.out.println( -// "ServerBackup: Please download the latest version - https://www.spigotmc.org/resources/" -// + resourceID); -// System.out.println(""); - } - } - } catch (IOException exception) { - this.getLogger().log(Level.WARNING, - "ServerBackup: Cannot search for updates - " + exception.getMessage()); -// System.err.println("ServerBackup: Cannot search for updates - " + exception.getMessage()); - } - }); - - } - - @SuppressWarnings("deprecation") - public void loadFiles() { - if (getConfig().contains("BackupDestination")) - backupDestination = getConfig().getString("BackupDestination"); - - if (!Files.exists(Paths.get(backupDestination))) { - try { - Files.createDirectories(Paths.get(backupDestination)); - } catch (IOException e) { - e.printStackTrace(); - } - } - - File files = new File(backupDestination + "//Files"); - - if (!files.exists()) { - files.mkdir(); - } - - getConfig().options() - .header("BackupTimer = At what time should a Backup be created? The format is: 'hh-mm' e.g. '12-30'." - + "\nDeleteOldBackups = Deletes old backups automatically after a specific time (in days, standard = 7 days)" - + "\nDeleteOldBackups - Type '0' at DeleteOldBackups to disable the deletion of old backups." - + "\nBackupLimiter = Deletes old backups automatically if number of total backups is greater than this number (e.g. if you enter '5' - the oldest backup will be deleted if there are more than 5 backups, so you will always keep the latest 5 backups)" - + "\nBackupLimiter - Type '0' to disable this feature. If you don't type '0' the feature 'DeleteOldBackups' will be disabled and this feature ('BackupLimiter') will be enabled." - + "\nKeepUniqueBackups - Type 'true' to disable the deletion of unique backups. The plugin will keep the newest backup of all backed up worlds or folders, no matter how old it is." - + "\nCollectiveZipFile - Type 'true' if you want to have all backed up worlds in just one zip file.\n" - + "\nIMPORTANT FTP information [BETA feature]: Set 'UploadBackup' to 'true' if you want to store your backups on a ftp server (sftp does not work at the moment - if you host your own server (e.g. vps/root server) you need to set up a ftp server on it)." - + "\nIf you use ftp backups, you can set 'DeleteLocalBackup' to 'true' if you want the plugin to remove the created backup from your server once it has been uploaded to your ftp server." - + "\nContact me if you need help or have a question: https://www.spigotmc.org/conversations/add?to=SebliYT"); - getConfig().options().copyDefaults(true); - - getConfig().addDefault("AutomaticBackups", true); - - List days = new ArrayList<>(); - days.add("MONDAY"); - days.add("TUESDAY"); - days.add("WEDNESDAY"); - days.add("THURSDAY"); - days.add("FRIDAY"); - days.add("SATURDAY"); - days.add("SUNDAY"); - - List times = new ArrayList<>(); - times.add("00-00"); - - getConfig().addDefault("BackupTimer.Days", days); - getConfig().addDefault("BackupTimer.Times", times); - - List worlds = new ArrayList<>(); - worlds.add("world"); - worlds.add("world_nether"); - worlds.add("world_the_end"); - - getConfig().addDefault("BackupWorlds", worlds); - - getConfig().addDefault("DeleteOldBackups", 14); - getConfig().addDefault("BackupLimiter", 0); - - getConfig().addDefault("KeepUniqueBackups", false); - getConfig().addDefault("CollectiveZipFile", false); - getConfig().addDefault("UpdateAvailabeMessage", true); - -// getConfig().addDefault("ZipCompression", true); - - if (getConfig().contains("ZipCompression")) { - getConfig().set("ZipCompression", null); - } - - if (getConfig().contains("BackupDestination")) { - if (getConfig().getString("BackupDestination") - .equalsIgnoreCase("- this feature will be available soon -")) { - getConfig().set("BackupDestination", null); - } - } - - getConfig().addDefault("BackupDestination", "Backups//"); - - getConfig().addDefault("Ftp.UploadBackup", false); - getConfig().addDefault("Ftp.DeleteLocalBackup", false); - getConfig().addDefault("Ftp.Server.IP", "127.0.0.1"); - getConfig().addDefault("Ftp.Server.Port", 21); - getConfig().addDefault("Ftp.Server.User", "username"); - getConfig().addDefault("Ftp.Server.Password", "password"); - - getConfig().addDefault("SendLogMessages", false); - - if (getConfig().contains("FirstStart")) { - getConfig().set("FirstStart", null); - } - - saveConfig(); - - backupDestination = getConfig().getString("BackupDestination"); - } - - public void startTimer() { - if (getConfig().getBoolean("AutomaticBackups")) { - Bukkit.getScheduler().runTaskTimerAsynchronously(this, new BackupTimer(), 20 * 60, 20 * 60); - } - } - - public void stopTimer() { - Bukkit.getScheduler().cancelTasks(this); - } - - // Events - @EventHandler - public void onJoin(PlayerJoinEvent e) { - Player p = e.getPlayer(); - - if (p.hasPermission("backup.admin")) { - if (getConfig().getBoolean("UpdateAvailabeMessage")) { - Bukkit.getScheduler().runTaskAsynchronously(this, () -> { - int resourceID = 79320; - try (InputStream inputStream = (new URL( - "https://api.spigotmc.org/legacy/update.php?resource=" + resourceID)).openStream(); - Scanner scanner = new Scanner(inputStream)) { - if (scanner.hasNext()) { - String latest = scanner.next(); - String current = getDescription().getVersion(); - - int late = Integer.parseInt(latest.replaceAll("\\.", "")); - int curr = Integer.parseInt(current.replaceAll("\\.", "")); - - if (curr >= late) { - } else { - p.sendMessage("§8=====§fServerBackup§8====="); - p.sendMessage(""); - p.sendMessage("§7There is a newer version available - §a" + latest - + "§7, you are on - §c" + current); - p.sendMessage( - "§7Please download the latest version - §4https://www.spigotmc.org/resources/" - + resourceID); - p.sendMessage(""); - p.sendMessage("§8=====§9Plugin by Seblii§8====="); - } - } - } catch (IOException exception) { - } - }); - } - } - } - -} diff --git a/src/de/sebli/serverbackup/ZipManager.java b/src/de/sebli/serverbackup/ZipManager.java deleted file mode 100644 index 9b51f1cd..00000000 --- a/src/de/sebli/serverbackup/ZipManager.java +++ /dev/null @@ -1,191 +0,0 @@ -package de.sebli.serverbackup; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.logging.Level; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import org.apache.commons.io.FileUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -public class ZipManager { - - private String sourceFilePath; - private String targetFilePath; - private CommandSender sender; - private boolean sendDebugMsg; - private boolean isSaving; - - public ZipManager(String sourceFilePath, String targetFilePath, CommandSender sender, boolean sendDebugMsg, - boolean isSaving) { - this.sourceFilePath = sourceFilePath; - this.targetFilePath = targetFilePath; - this.sender = sender; - this.sendDebugMsg = sendDebugMsg; - this.isSaving = isSaving; - } - - public void zip() throws IOException { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - - long sTime = System.nanoTime(); - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Start zipping..."); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - - Path p; - try { - p = Files.createFile(Paths.get(targetFilePath)); - } catch (IOException e) { - e.printStackTrace(); - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); - return; - } - - try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p))) { - Path pp = Paths.get(sourceFilePath); - Files.walk(pp).filter(path -> !Files.isDirectory(path)).forEach(path -> { - ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString()); - try { - if (sendDebugMsg) { - if (ServerBackup.getInstance().getConfig().getBoolean("SendLogMessages")) { - ServerBackup.getInstance().getLogger().log(Level.INFO, "Zipping '" + path.toString()); - - if (Bukkit.getConsoleSender() != sender) { - sender.sendMessage("Zipping '" + path.toString()); - } - } - } - - zs.putNextEntry(zipEntry); - - if (System.getProperty("os.name").startsWith("Windows") - && path.toString().contains("session.lock")) { - } else { - try { - Files.copy(path, zs); - } catch (IOException e) { - e.printStackTrace(); - } - } - - zs.closeEntry(); - } catch (IOException e) { - e.printStackTrace(); - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); - return; - } - }); - } catch (IOException e) { - e.printStackTrace(); - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); - return; - } - - long time = (System.nanoTime() - sTime) / 1000000; - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Files zipped. [" + time + "ms]"); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - - if (!isSaving) { - File file = new File(sourceFilePath); - - try { - FileUtils.deleteDirectory(file); - } catch (IOException e) { - e.printStackTrace(); - } - } - - sender.sendMessage(""); - sender.sendMessage("Backup [" + sourceFilePath + "] zipped."); - sender.sendMessage("Backup [" + sourceFilePath + "] saved."); - - if (ServerBackup.getInstance().getConfig().getBoolean("Ftp.UploadBackup")) { - FtpManager ftpm = new FtpManager(sender); - ftpm.uploadFileToFtp(targetFilePath); - } - - for (Player all : Bukkit.getOnlinePlayers()) { - if (all.hasPermission("backup.notification")) { - all.sendMessage("Backup [" + sourceFilePath + "] saved."); - } - } - }); - } - - public void unzip() { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - - long sTime = System.nanoTime(); - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Start unzipping..."); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - - byte[] buffer = new byte[1024]; - try { - File folder = new File(targetFilePath); - if (!folder.exists()) { - folder.mkdir(); - } - ZipInputStream zis = new ZipInputStream(new FileInputStream(sourceFilePath)); - ZipEntry ze = zis.getNextEntry(); - while (ze != null) { - String fileName = ze.getName(); - File newFile = new File(targetFilePath + File.separator + fileName); - - if (sendDebugMsg) { - if (ServerBackup.getInstance().getConfig().getBoolean("SendLogMessages")) { - ServerBackup.getInstance().getLogger().log(Level.INFO, "Unzipping '" + newFile.getPath()); - - if (Bukkit.getConsoleSender() != sender) { - sender.sendMessage("Unzipping '" + newFile.getPath()); - } - } - } - - new File(newFile.getParent()).mkdirs(); - FileOutputStream fos = new FileOutputStream(newFile); - int len; - while ((len = zis.read(buffer)) > 0) { - fos.write(buffer, 0, len); - } - fos.close(); - ze = zis.getNextEntry(); - } - zis.closeEntry(); - zis.close(); - } catch (IOException e) { - e.printStackTrace(); - ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while unzipping files."); - return; - } - - long time = (System.nanoTime() - sTime) / 1000000; - - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Files unzipped. [" + time + "ms]"); - ServerBackup.getInstance().getLogger().log(Level.INFO, ""); - - File file = new File(sourceFilePath); - - file.delete(); - - sender.sendMessage(""); - sender.sendMessage("Backup [" + sourceFilePath + "] unzipped."); - }); - } - -} diff --git a/src/de/sebli/serverbackup/commands/SBCommand.java b/src/de/sebli/serverbackup/commands/SBCommand.java deleted file mode 100644 index 63a121d7..00000000 --- a/src/de/sebli/serverbackup/commands/SBCommand.java +++ /dev/null @@ -1,688 +0,0 @@ -package de.sebli.serverbackup.commands; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import com.google.common.io.Files; - -import de.sebli.serverbackup.BackupManager; -import de.sebli.serverbackup.FtpManager; -import de.sebli.serverbackup.ServerBackup; -import de.sebli.serverbackup.ZipManager; -import net.md_5.bungee.api.chat.ClickEvent; -import net.md_5.bungee.api.chat.ComponentBuilder; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; - -public class SBCommand implements CommandExecutor, TabCompleter { - - @SuppressWarnings("deprecation") - @Override - public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - - if (sender.hasPermission("backup.admin")) { - if (args.length == 1) { - if (args[0].equalsIgnoreCase("list")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - if (backups.length == 0) { - sender.sendMessage("No backups found."); - - return; - } - - Arrays.sort(backups); - - if (backups.length < 10) { - sender.sendMessage("----- Backup 1-" + backups.length + "/" + backups.length + " -----"); - } else { - sender.sendMessage("----- Backup 1-10/" + backups.length + " -----"); - } - sender.sendMessage(""); - - for (int i = 0; i < backups.length && i < 10; i++) { - double fileSize = (double) FileUtils.sizeOf(backups[i]) / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - if (sender instanceof Player) { - Player p = (Player) sender; - - TextComponent msg = new TextComponent("§7[" + Integer.valueOf(i + 1) + "] §r" - + backups[i].getName() + " §7[" + fileSize + "MB]"); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent( - new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, backups[i].getName())); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(backups[i].getName()); - } - } - - int maxPages = backups.length / 10; - - if (backups.length % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("-------- Page 1/" + maxPages + " --------"); - }); - } else if (args[0].equalsIgnoreCase("reload") || args[0].equalsIgnoreCase("rl")) { - ServerBackup.getInstance().reloadConfig(); - - ServerBackup.getInstance().stopTimer(); - ServerBackup.getInstance().startTimer(); - - String oldDes = ServerBackup.getInstance().backupDestination; - - if (!oldDes - .equalsIgnoreCase(ServerBackup.getInstance().getConfig().getString("BackupDestination"))) { - ServerBackup.getInstance().backupDestination = ServerBackup.getInstance().getConfig() - .getString("BackupDestination"); - - ServerBackup.getInstance().getLogger().log(Level.INFO, - "ServerBackup: Backup destination [" + oldDes + " >> " - + ServerBackup.getInstance().backupDestination + "] updated successfully."); - } - - ServerBackup.getInstance().loadFiles(); - - sender.sendMessage("Config reloaded."); - } else { - sendHelp(sender); - } - } else if (args.length == 2) { - if (args[0].equalsIgnoreCase("list")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - if (backups.length == 0) { - sender.sendMessage("No backups found."); - - return; - } - - Arrays.sort(backups); - - try { - int page = Integer.valueOf(args[1]); - - if (backups.length < page * 10 - 9) { - sender.sendMessage("Try a lower value."); - - return; - } - - if (backups.length <= page * 10 && backups.length >= page * 10 - 10) { - sender.sendMessage("----- Backup " + Integer.valueOf(page * 10 - 9) + "-" - + backups.length + "/" + backups.length + " -----"); - } else { - sender.sendMessage("----- Backup " + Integer.valueOf(page * 10 - 9) + "-" - + Integer.valueOf(page * 10) + "/" + backups.length + " -----"); - } - sender.sendMessage(""); - - for (int i = page * 10 - 10; i < backups.length && i < page * 10; i++) { - double fileSize = (double) FileUtils.sizeOf(backups[i]) / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - if (sender instanceof Player) { - Player p = (Player) sender; - - TextComponent msg = new TextComponent("§7[" + Integer.valueOf(i + 1) + "] §r" - + backups[i].getName() + " §7[" + fileSize + "MB]"); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent( - new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, backups[i].getName())); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(backups[i].getName()); - } - } - - int maxPages = backups.length / 10; - - if (backups.length % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("-------- Page " + page + "/" + maxPages + " --------"); - } catch (Exception e) { - sender.sendMessage("'" + args[1] + "' is not a valid number."); - } - }); - } else if (args[0].equalsIgnoreCase("ftp")) { - if (args[1].equalsIgnoreCase("list")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - FtpManager ftpm = new FtpManager(sender); - - List backups = ftpm.getFtpBackupList(); - - if (backups.size() == 0) { - sender.sendMessage("No ftp backups found."); - - return; - } - - if (backups.size() < 10) { - sender.sendMessage( - "----- Ftp-Backup 1-" + backups.size() + "/" + backups.size() + " -----"); - } else { - sender.sendMessage("----- Ftp-Backup 1-10/" + backups.size() + " -----"); - } - sender.sendMessage(""); - - for (int i = 0; i < backups.size() && i < 10; i++) { - if (sender instanceof Player) { - Player p = (Player) sender; - TextComponent msg = new TextComponent(backups.get(i)); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, - backups.get(i).split(" ")[1])); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(backups.get(i)); - } - } - - int maxPages = backups.size() / 10; - - if (backups.size() % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("--------- Page 1/" + maxPages + " ---------"); - }); - } - } else if (args[0].equalsIgnoreCase("zip")) { - String filePath = args[1]; - - if (args[1].contains(".zip")) { - sender.sendMessage("'" + args[1] + "' is already a ZIP file."); - return false; - } - - File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); - File newFile = new File(ServerBackup.getInstance().backupDestination + "//" + filePath + ".zip"); - - if (!newFile.exists()) { - sender.sendMessage("Zipping Backup..."); - sender.sendMessage(""); - - if (file.exists()) { - try { - ZipManager zm = new ZipManager(file.getPath(), newFile.getPath(), sender, true, false); - - zm.zip(); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - sender.sendMessage("No Backup named '" + args[1] + "' found."); - } - } else { - sender.sendMessage("There is already a folder named '" + args[1].replaceAll(".zip", "") + "'"); - } - } else if (args[0].equalsIgnoreCase("unzip")) { - String filePath = args[1]; - - if (!args[1].contains(".zip")) { - sender.sendMessage("'" + args[1] + "' is not a ZIP file."); - return false; - } - - File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); - File newFile = new File( - ServerBackup.getInstance().backupDestination + "//" + filePath.replaceAll(".zip", "")); - - if (!newFile.exists()) { - sender.sendMessage("Unzipping Backup..."); - sender.sendMessage(""); - - if (file.exists()) { - ZipManager zm = new ZipManager(file.getPath(), - ServerBackup.getInstance().backupDestination + "//" + newFile.getName(), sender, - false, true); - - zm.unzip(); - } else { - sender.sendMessage("No Backup named '" + args[1] + "' found."); - } - } else { - sender.sendMessage("There is already a ZIP file named '" + args[1] + ".zip'"); - } - } else if (args[0].equalsIgnoreCase("delete") || args[0].equalsIgnoreCase("remove")) { - if (args[1].equalsIgnoreCase("Files")) { - sender.sendMessage("You can not delete the 'Files' backup folder."); - - return false; - } - - BackupManager bm = new BackupManager(args[1], sender); - - bm.removeBackup(); - } else if (args[0].equalsIgnoreCase("create")) { - File file = new File(args[1]); - if (!file.isDirectory()) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), new Runnable() { - - @Override - public void run() { - try { - File des = new File(ServerBackup.getInstance().backupDestination + "//Files//" - + args[1].replaceAll("/", "-")); - - if (des.exists()) { - des = new File(des.getPath() - .replaceAll("." + FilenameUtils.getExtension(des.getName()), "") + " " - + String.valueOf(System.currentTimeMillis() / 1000) + "." - + FilenameUtils.getExtension(file.getName())); - } - - Files.copy(file, des); - - sender.sendMessage("Backup [" + args[1] + "] saved."); - } catch (IOException e) { - sender.sendMessage("An error occured while saving Backup [" + args[1] - + "]. See console for more information."); - e.printStackTrace(); - } - } - - }); - } else { - BackupManager bm = new BackupManager(args[1], sender); - - bm.createBackup(); - } - } else if (args[0].equalsIgnoreCase("search")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - if (backups.length == 0) { - sender.sendMessage("No backups found."); - - return; - } - - List backupsMatch = new ArrayList<>(); - - for (int i = 0; i < backups.length; i++) { - if (backups[i].getName().contains(args[1])) { - backupsMatch.add(backups[i]); - } - } - - if (backupsMatch.size() == 0) { - sender.sendMessage("No backups for search argument '" + args[1] + "' found."); - - return; - } - - Collections.sort(backupsMatch); - - int count = 1; - - if (backupsMatch.size() < 10) { - sender.sendMessage( - "----- Backup 1-" + backupsMatch.size() + "/" + backupsMatch.size() + " -----"); - } else { - sender.sendMessage("----- Backup 1-10/" + backupsMatch.size() + " -----"); - } - sender.sendMessage(""); - - for (File file : backupsMatch) { - if (count <= 10 && count <= backupsMatch.size()) { - double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - if (sender instanceof Player) { - Player p = (Player) sender; - - TextComponent msg = new TextComponent("§7[" + Integer.valueOf(count) + "] §r" - + file.getName() + " §7[" + fileSize + "MB]"); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, - "/backup remove " + file.getName())); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(file.getName()); - } - } - count++; - } - - int maxPages = backupsMatch.size() / 10; - - if (backupsMatch.size() % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("-------- Page 1/" + maxPages + " --------"); - }); - } else { - sendHelp(sender); - } - } else if (args.length == 3) { - if (args[0].equalsIgnoreCase("search")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - if (backups.length == 0) { - sender.sendMessage("No backups found."); - - return; - } - - List backupsMatch = new ArrayList<>(); - - for (int i = 0; i < backups.length; i++) { - if (backups[i].getName().contains(args[1])) { - backupsMatch.add(backups[i]); - } - } - - if (backupsMatch.size() == 0) { - sender.sendMessage("No backups for search argument '" + args[1] + "' found."); - - return; - } - - Collections.sort(backupsMatch); - - try { - int page = Integer.valueOf(args[2]); - - if (backups.length < page * 10 - 9) { - sender.sendMessage("Try a lower value."); - - return; - } - - int count = page * 10 - 9; - - if (backupsMatch.size() <= page * 10 && backupsMatch.size() >= page * 10 - 10) { - sender.sendMessage("----- Backup " + Integer.valueOf(page * 10 - 9) + "-" - + backupsMatch.size() + "/" + backupsMatch.size() + " -----"); - } else { - sender.sendMessage("----- Backup " + Integer.valueOf(page * 10 - 9) + "-" - + Integer.valueOf(page * 10) + "/" + backupsMatch.size() + " -----"); - } - sender.sendMessage(""); - - for (File file : backupsMatch) { - if (count <= page * 10 && count <= backupsMatch.size()) { - double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; - fileSize = Math.round(fileSize * 100.0) / 100.0; - - if (sender instanceof Player) { - Player p = (Player) sender; - - TextComponent msg = new TextComponent("§7[" + Integer.valueOf(count) + "] §r" - + file.getName() + " §7[" + fileSize + "MB]"); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, - "/backup remove " + file.getName())); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(file.getName()); - } - } - count++; - } - - int maxPages = backupsMatch.size() / 10; - - if (backupsMatch.size() % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("-------- Page " + page + "/" + maxPages + " --------"); - } catch (Exception e) { - sender.sendMessage("'" + args[2] + "' is not a valid number."); - } - }); - } else if (args[0].equalsIgnoreCase("ftp")) { - if (args[1].equalsIgnoreCase("list")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - FtpManager ftpm = new FtpManager(sender); - - List backups = ftpm.getFtpBackupList(); - - if (backups.size() == 0) { - sender.sendMessage("No ftp backups found."); - - return; - } - - try { - int page = Integer.valueOf(args[2]); - - if (backups.size() < page * 10 - 9) { - sender.sendMessage("Try a lower value."); - - return; - } - - if (backups.size() <= page * 10 && backups.size() >= page * 10 - 10) { - sender.sendMessage("----- Ftp-Backup " + Integer.valueOf(page * 10 - 9) + "-" - + backups.size() + "/" + backups.size() + " -----"); - } else { - sender.sendMessage("----- Ftp-Backup " + Integer.valueOf(page * 10 - 9) + "-" - + Integer.valueOf(page * 10) + "/" + backups.size() + " -----"); - } - sender.sendMessage(""); - - for (int i = page * 10 - 10; i < backups.size() && i < page * 10; i++) { - if (sender instanceof Player) { - Player p = (Player) sender; - - TextComponent msg = new TextComponent(backups.get(i)); - msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder("Click to get Backup name").create())); - msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, - backups.get(i).split(" ")[1])); - - p.spigot().sendMessage(msg); - } else { - sender.sendMessage(backups.get(i)); - } - } - - int maxPages = backups.size() / 10; - - if (backups.size() % 10 != 0) { - maxPages++; - } - - sender.sendMessage(""); - sender.sendMessage("--------- Page " + page + "/" + maxPages + " ---------"); - } catch (Exception e) { - sender.sendMessage("'" + args[1] + "' is not a valid number."); - } - }); - } else if (args[1].equalsIgnoreCase("download")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - FtpManager ftpm = new FtpManager(sender); - - ftpm.downloadFileFromFtp(args[2]); - }); - } else if (args[1].equalsIgnoreCase("upload")) { - Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { - FtpManager ftpm = new FtpManager(sender); - - ftpm.uploadFileToFtp(args[2]); - }); - } - } else { - sendHelp(sender); - } - } else { - sendHelp(sender); - } - } else { - sender.sendMessage("§cI'm sorry but you do not have permission to perform this command."); - } - - return false; - } - - private void sendHelp(CommandSender sender) { - sender.sendMessage("/backup reload - reloads the config"); - sender.sendMessage(""); - sender.sendMessage("/backup list - shows a list of 10 backups"); - sender.sendMessage(""); - sender.sendMessage( - "/backup search - shows a list of 10 backups that contain the given search argument"); - sender.sendMessage(""); - sender.sendMessage("/backup create - creates a new backup of a world"); - sender.sendMessage(""); - sender.sendMessage("/backup remove - removes an existing backup"); - sender.sendMessage(""); - sender.sendMessage("/backup zip - zipping folder"); - sender.sendMessage(""); - sender.sendMessage("/backup unzip - unzipping file"); - sender.sendMessage(""); - sender.sendMessage( - "/backup ftp - download, upload or list ftp backup files [BETA feature]"); - } - - @Override - public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { - List completions = new ArrayList<>(); - List commands = new ArrayList<>(); - - if (sender.hasPermission("backup.admin")) { - if (args.length == 1) { - commands.add("reload"); - commands.add("list"); - commands.add("search"); - commands.add("create"); - commands.add("remove"); - commands.add("zip"); - commands.add("unzip"); - commands.add("ftp"); - - StringUtil.copyPartialMatches(args[0], commands, completions); - } else if (args.length == 2) { - if (args[0].equalsIgnoreCase("list")) { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - int maxPages = backups.length / 10; - - if (backups.length % 10 != 0) { - maxPages++; - } - - for (int i = 1; i < maxPages + 1; i++) { - commands.add(String.valueOf(i)); - } - } else if (args[0].equalsIgnoreCase("remove")) { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - for (int i = 0; i < backups.length; i++) { - commands.add(backups[i].getName()); - } - } else if (args[0].equalsIgnoreCase("create")) { - for (World world : Bukkit.getWorlds()) { - commands.add(world.getName()); - } - } else if (args[0].equalsIgnoreCase("zip")) { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - for (File backup : backups) { - if (!backup.getName().endsWith(".zip")) { - commands.add(backup.getName()); - } - } - } else if (args[0].equalsIgnoreCase("unzip")) { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - for (File backup : backups) { - if (backup.getName().endsWith(".zip")) { - commands.add(backup.getName()); - } - } - } else if (args[0].equalsIgnoreCase("ftp")) { - commands.add("list"); - commands.add("download"); - commands.add("upload"); - } - - StringUtil.copyPartialMatches(args[1], commands, completions); - } else if (args.length == 3) { - if (args[0].equalsIgnoreCase("ftp")) { - if (args[1].equalsIgnoreCase("list")) { - FtpManager ftpm = new FtpManager(sender); - - List backups = ftpm.getFtpBackupList(); - - int maxPages = backups.size() / 10; - - if (backups.size() % 10 != 0) { - maxPages++; - } - - for (int i = 1; i < maxPages + 1; i++) { - commands.add(String.valueOf(i)); - } - } else if (args[1].equalsIgnoreCase("download")) { - FtpManager ftpm = new FtpManager(sender); - - List backups = ftpm.getFtpBackupList(); - - for (String backup : backups) { - commands.add(backup.split(" ")[1]); - } - } else if (args[1].equalsIgnoreCase("upload")) { - File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); - - for (File backup : backups) { - if (backup.getName().endsWith(".zip")) { - commands.add(backup.getName()); - } - } - } - } - - StringUtil.copyPartialMatches(args[2], commands, completions); - } - } - - Collections.sort(completions); - - return completions; - } - -} diff --git a/src/main/java/de/sebli/serverbackup/BackupManager.java b/src/main/java/de/sebli/serverbackup/BackupManager.java new file mode 100644 index 00000000..45a5e267 --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/BackupManager.java @@ -0,0 +1,87 @@ +package de.sebli.serverbackup; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.logging.Level; + +public class BackupManager { + + private final CommandSender sender; + private String filePath; + + public BackupManager(String filePath, CommandSender sender) { + this.filePath = filePath; + this.sender = sender; + } + + public void createBackup() { + File worldFolder = new File(filePath); + + if (filePath.equalsIgnoreCase("@server")) { + worldFolder = new File(Bukkit.getWorldContainer().getPath()); + filePath = worldFolder.getPath(); + } + + Date date = new Date(); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'~'HH-mm-ss"); + df.setTimeZone(TimeZone.getDefault()); + + File backupFolder = new File(ServerBackup.getInstance().backupDestination + "//backup-" + df.format(date) + "-" + filePath + "//" + filePath); + + if (worldFolder.exists()) { + for (Player all : Bukkit.getOnlinePlayers()) { + if (all.hasPermission("backup.notification")) { + all.sendMessage("Backup [" + worldFolder + "] started."); + } + } + + if (!backupFolder.exists()) { + ZipManager zm = new ZipManager(worldFolder.getName(), + ServerBackup.getInstance().backupDestination + "//backup-" + df.format(date) + "-" + filePath + ".zip", Bukkit.getConsoleSender(), + true, true); + + zm.zip(); + } else { + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Backup already exists."); + } + + } else { + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Couldn't find '" + filePath + "' folder."); + } + } + + public void removeBackup() { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); + + if (file.exists()) { + if (file.isDirectory()) { + try { + Files.delete(file.toPath()); + + sender.sendMessage("Backup [" + filePath + "] removed."); + } catch (IOException e) { + e.printStackTrace(); + + sender.sendMessage("Error while deleting '" + filePath + "'."); + } + } else { + file.delete(); + + sender.sendMessage("Backup [" + filePath + "] removed."); + } + } else { + sender.sendMessage("No Backup named '" + filePath + "' found."); + } + }); + } + +} diff --git a/src/main/java/de/sebli/serverbackup/BackupTimer.java b/src/main/java/de/sebli/serverbackup/BackupTimer.java new file mode 100644 index 00000000..66d9867d --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/BackupTimer.java @@ -0,0 +1,163 @@ +package de.sebli.serverbackup; + +import org.bukkit.Bukkit; + +import java.io.File; +import java.time.LocalDate; +import java.util.*; +import java.util.logging.Level; + +public class BackupTimer implements Runnable { + + final List worlds = ServerBackup.getInstance().getConfig().getStringList("BackupWorlds"); + final List days = ServerBackup.getInstance().getConfig().getStringList("BackupTimer.Days"); + final List times = ServerBackup.getInstance().getConfig().getStringList("BackupTimer.Times"); + + final Calendar cal = Calendar.getInstance(); + + @Override + public void run() { + boolean isBackupDay = days.stream().anyMatch(d -> d.equalsIgnoreCase(getDayName(cal.get(Calendar.DAY_OF_WEEK)))); + + if (isBackupDay) { + for (String time : times) { + try { + String[] timeStr = time.split("-"); + + if (timeStr[0].startsWith("0")) { + timeStr[0] = timeStr[0].substring(1); + } + + if (timeStr[1].startsWith("0")) { + timeStr[1] = timeStr[1].substring(1); + } + + int hour = Integer.parseInt(timeStr[0]); + int minute = Integer.parseInt(timeStr[1]); + + if (cal.get(Calendar.HOUR_OF_DAY) == hour && cal.get(Calendar.MINUTE) == minute) { + for (String world : worlds) { + BackupManager bm = new BackupManager(world, Bukkit.getConsoleSender()); + bm.createBackup(); + } + } + } catch (Exception e) { + ServerBackup.getInstance().getLogger().log(Level.WARNING, + "ServerBackup: Automatic Backup failed. Please check that you set the BackupTimer correctly."); + } + } + } + + if (ServerBackup.getInstance().getConfig().getInt("BackupLimiter") <= 0) { + if (cal.get(Calendar.HOUR_OF_DAY) == 0 && cal.get(Calendar.MINUTE) == 0) { + if (ServerBackup.getInstance().getConfig().getInt("DeleteOldBackups") <= 0) + return; + + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + if (backups.length == 0) + return; + + Arrays.sort(backups, Collections.reverseOrder()); + + LocalDate date = LocalDate.now() + .minusDays(ServerBackup.getInstance().getConfig().getInt("DeleteOldBackups")); + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Backup deletion started..."); + + long time = System.currentTimeMillis(); + + List backupNames = new ArrayList<>(); + + for (File backup : backups) { + try { + String[] backupDateStr = backup.getName().split("-"); + LocalDate backupDate = LocalDate.parse( + backupDateStr[1] + "-" + backupDateStr[2] + "-" + backupDateStr[3].split("~")[0]); + String backupName = backupDateStr[6]; + + if (ServerBackup.getInstance().getConfig().getBoolean("KeepUniqueBackups")) { + if (!backupNames.contains(backupName)) { + backupNames.add(backupName); + continue; + } + } + + if (backupDate.isBefore(date.plusDays(1))) { + if (backup.exists()) { + backup.delete(); + + ServerBackup.getInstance().getLogger().log(Level.INFO, + "Backup [" + backup.getName() + "] removed."); + } else { + ServerBackup.getInstance().getLogger().log(Level.WARNING, + "No Backup named '" + backup.getName() + "' found."); + } + } + } catch (Exception ignored) { + } + + } + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Backup deletion finished. [" + + (System.currentTimeMillis() - time) + "ms]"); + } + } else { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + Arrays.sort(backups); + + int dobc = ServerBackup.getInstance().getConfig().getInt("BackupLimiter"); + int c = 0; + + while (backups.length > dobc) { + if (backups[c].exists()) { + backups[c].delete(); + + ServerBackup.getInstance().getLogger().log(Level.INFO, + "Backup [" + backups[c].getName() + "] removed."); + } else { + ServerBackup.getInstance().getLogger().log(Level.WARNING, + "No Backup named '" + backups[c].getName() + "' found."); + } + + c++; + dobc++; + } + } + } + + private String getDayName(int dayNumber) { + if (dayNumber == 1) { + return "SUNDAY"; + } + + if (dayNumber == 2) { + return "MONDAY"; + } + + if (dayNumber == 3) { + return "TUESDAY"; + } + + if (dayNumber == 4) { + return "WEDNESDAY"; + } + + if (dayNumber == 5) { + return "THURSDAY"; + } + + if (dayNumber == 6) { + return "FRIDAY"; + } + + if (dayNumber == 7) { + return "SATURDAY"; + } + + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while converting number in day."); + + return null; + } + +} diff --git a/src/main/java/de/sebli/serverbackup/FtpManager.java b/src/main/java/de/sebli/serverbackup/FtpManager.java new file mode 100644 index 00000000..06dee02c --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/FtpManager.java @@ -0,0 +1,204 @@ +package de.sebli.serverbackup; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPSClient; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +public class FtpManager { + + final String server = ServerBackup.getInstance().getConfig().getString("Ftp.Server.IP"); + final int port = ServerBackup.getInstance().getConfig().getInt("Ftp.Server.Port"); + final String user = ServerBackup.getInstance().getConfig().getString("Ftp.Server.User"); + final String pass = ServerBackup.getInstance().getConfig().getString("Ftp.Server.Password"); + private final CommandSender sender; + + public FtpManager(CommandSender sender) { + this.sender = sender; + } + + public void uploadFileToFtp(String filePath) { + File file = new File(filePath); + + if (!file.getPath().contains(ServerBackup.getInstance().backupDestination.replaceAll("/", ""))) { + file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); + } + + if (!file.exists()) { + sender.sendMessage("Ftp: Backup '" + file.getName() + "' not found."); + + return; + } + + FTPSClient ftpClient = new FTPSClient(); + + try { + ftpClient.connect(server, port); + ftpClient.login(user, pass); + ftpClient.enterLocalPassiveMode(); + + ftpClient.execPBSZ(0); + ftpClient.execPROT("P"); + + ftpClient.setFileType(FTP.BINARY_FILE_TYPE); + + sender.sendMessage("Ftp: Uploading backup [" + file.getName() + "] ..."); + + InputStream inputStream = new FileInputStream(file); + + boolean done = ftpClient.storeFile(file.getName(), inputStream); + inputStream.close(); + if (done) { + sender.sendMessage("Ftp: Upload successful. Backup stored on ftp server."); + + if (ServerBackup.getInstance().getConfig().getBoolean("Ftp.DeleteLocalBackup")) { + boolean exists = false; + for (FTPFile backup : ftpClient.listFiles()) { + if (backup.getName().equalsIgnoreCase(file.getName())) + exists = true; + } + + if (exists) { + file.delete(); + } else { + sender.sendMessage( + "Ftp: Local backup deletion failed because the uploaded file was not found on the ftp server. Try again."); + } + } + } else { + sender.sendMessage( + "Ftp: Error while uploading backup to ftp server. Check server details in config.yml (ip, port, user, password)."); + } + } catch (IOException e) { + sender.sendMessage("Ftp: Error while uploading backup to ftp server."); + e.printStackTrace(); + } finally { + try { + if (ftpClient.isConnected()) { + ftpClient.logout(); + ftpClient.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void downloadFileFromFtp(String filePath) { + File file = new File(filePath); + + FTPSClient ftpClient = new FTPSClient(); + + try { + ftpClient.connect(server, port); + ftpClient.login(user, pass); + ftpClient.enterLocalPassiveMode(); + + ftpClient.execPBSZ(0); + ftpClient.execPROT("P"); + + ftpClient.setFileType(FTP.BINARY_FILE_TYPE); + + boolean exists = false; + for (FTPFile backup : ftpClient.listFiles()) { + if (backup.getName().equalsIgnoreCase(file.getName())) + exists = true; + } + + if (!exists) { + sender.sendMessage("Ftp: ftp-backup '" + file.getName() + "' not found."); + + return; + } + + sender.sendMessage("Ftp: Downloading backup [" + file.getName() + "] ..."); + + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file)); + boolean success = ftpClient.retrieveFile(file.getName(), outputStream); + outputStream.close(); + + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File dFile = new File(ServerBackup.getInstance().backupDestination + "//" + file.getPath()); + + try { + FileUtils.copyFile(file, dFile); + } catch (IOException e) { + e.printStackTrace(); + } + + if (dFile.exists()) { + file.delete(); + } + }); + + if (success) { + sender.sendMessage("Ftp: Download successful. Backup downloaded from ftp server."); + } else { + sender.sendMessage( + "Ftp: Error while downloading backup from ftp server. Check server details in config.yml (ip, port, user, password)."); + } + } catch (IOException e) { + sender.sendMessage("Ftp: Error while downloading backup from ftp server."); + e.printStackTrace(); + } finally { + try { + if (ftpClient.isConnected()) { + ftpClient.logout(); + ftpClient.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public List getFtpBackupList() { + List backups = new ArrayList<>(); + + FTPSClient ftpClient = new FTPSClient(); + + try { + ftpClient.connect(server, port); + ftpClient.login(user, pass); + ftpClient.enterLocalPassiveMode(); + + ftpClient.execPBSZ(0); + ftpClient.execPROT("P"); + + FTPFile[] files = ftpClient.listFiles(); + + int c = 1; + + for (FTPFile file : files) { + double fileSize = (double) file.getSize() / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + backups.add("§7[" + c + "]§f " + file.getName() + " §7[" + fileSize + "MB]"); + + c++; + } + + } catch (IOException e) { + sender.sendMessage("Error while connecting to FTP server."); + e.printStackTrace(); + } finally { + try { + if (ftpClient.isConnected()) { + ftpClient.logout(); + ftpClient.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + return backups; + } + +} diff --git a/src/main/java/de/sebli/serverbackup/ServerBackup.java b/src/main/java/de/sebli/serverbackup/ServerBackup.java new file mode 100644 index 00000000..20de76a7 --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/ServerBackup.java @@ -0,0 +1,265 @@ +package de.sebli.serverbackup; + +import de.sebli.serverbackup.commands.SBCommand; +import de.sebli.serverbackup.utils.Metrics; +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.logging.Level; + +public class ServerBackup extends JavaPlugin implements Listener { + + private static ServerBackup sb; + public String backupDestination = "Backups//"; + + public static ServerBackup getInstance() { + return sb; + } + + @Override + public void onDisable() { + stopTimer(); + + for (BukkitTask task : Bukkit.getScheduler().getPendingTasks()) { + task.cancel(); + + this.getLogger().log(Level.WARNING, "WARNING - ServerBackup: Task [" + task.getTaskId() + + "] cancelled due to server shutdown. There might be some unfinished Backups."); + } + + this.getLogger().log(Level.INFO, "ServerBackup: Plugin disabled."); + } + + @Override + public void onEnable() { + sb = this; + + loadFiles(); + + getCommand("backup").setExecutor(new SBCommand()); + + Bukkit.getPluginManager().registerEvents(this, this); + + startTimer(); + + this.getLogger().log(Level.INFO, "ServerBackup: Plugin enabled."); + + if (getConfig().getBoolean("UpdateAvailableMessage")) { + checkVersion(); + } + + int mpid = 14673; + + Metrics metrics = new Metrics(this, mpid); + + metrics.addCustomChart(new Metrics.SimplePie("player_per_server", () -> String.valueOf(Bukkit.getOnlinePlayers().size()))); + + metrics.addCustomChart(new Metrics.SimplePie("using_ftp_server", () -> { + if (getConfig().getBoolean("Ftp.UploadBackup")) { + return "yes"; + } else { + return "no"; + } + })); + + metrics.addCustomChart(new Metrics.SingleLineChart("total_backup_space", () -> { + File file = new File(backupDestination); + + double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + return (int) fileSize; + })); + } + + private void checkVersion() { + this.getLogger().log(Level.INFO, "ServerBackup: Searching for updates..."); + + Bukkit.getScheduler().runTaskAsynchronously(this, () -> { + int resourceID = 79320; + try (InputStream inputStream = (new URL( + "https://api.spigotmc.org/legacy/update.php?resource=" + resourceID)).openStream(); + Scanner scanner = new Scanner(inputStream)) { + if (scanner.hasNext()) { + String latest = scanner.next(); + String current = getDescription().getVersion(); + + int late = Integer.parseInt(latest.replaceAll("\\.", "")); + int curr = Integer.parseInt(current.replaceAll("\\.", "")); + + if (curr >= late) { + this.getLogger().log(Level.INFO, + "ServerBackup: No updates found. The server is running the latest version."); + } else { + this.getLogger().log(Level.INFO, "\nServerBackup: There is a newer version available - " + + latest + ", you are on - " + current); + this.getLogger().log(Level.INFO, + "ServerBackup: Please download the latest version - https://www.spigotmc.org/resources/" + + resourceID + "\n"); + } + } + } catch (IOException exception) { + this.getLogger().log(Level.WARNING, + "ServerBackup: Cannot search for updates - " + exception.getMessage()); + } + }); + + } + + public void loadFiles() { + if (getConfig().contains("BackupDestination")) + backupDestination = getConfig().getString("BackupDestination"); + + if (!Files.exists(Paths.get(backupDestination))) { + try { + Files.createDirectories(Paths.get(backupDestination)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + File files = new File(backupDestination + "//Files"); + + if (!files.exists()) { + files.mkdir(); + } + + getConfig().options() + .header("BackupTimer = At what time should a Backup be created? The format is: 'hh-mm' e.g. '12-30'." + + "\nDeleteOldBackups = Deletes old backups automatically after a specific time (in days, standard = 7 days)" + + "\nDeleteOldBackups - Type '0' at DeleteOldBackups to disable the deletion of old backups." + + "\nBackupLimiter = Deletes old backups automatically if number of total backups is greater than this number (e.g. if you enter '5' - the oldest backup will be deleted if there are more than 5 backups, so you will always keep the latest 5 backups)" + + "\nBackupLimiter - Type '0' to disable this feature. If you don't type '0' the feature 'DeleteOldBackups' will be disabled and this feature ('BackupLimiter') will be enabled." + + "\nKeepUniqueBackups - Type 'true' to disable the deletion of unique backups. The plugin will keep the newest backup of all backed up worlds or folders, no matter how old it is." + + "\nCollectiveZipFile - Type 'true' if you want to have all backed up worlds in just one zip file.\n" + + "\nIMPORTANT FTP information [BETA feature]: Set 'UploadBackup' to 'true' if you want to store your backups on a ftp server (sftp does not work at the moment - if you host your own server (e.g. vps/root server) you need to set up a ftp server on it)." + + "\nIf you use ftp backups, you can set 'DeleteLocalBackup' to 'true' if you want the plugin to remove the created backup from your server once it has been uploaded to your ftp server." + + "\nContact me if you need help or have a question: https://www.spigotmc.org/conversations/add?to=SebliYT"); + getConfig().options().copyDefaults(true); + + getConfig().addDefault("AutomaticBackups", true); + + List days = new ArrayList<>(); + days.add("MONDAY"); + days.add("TUESDAY"); + days.add("WEDNESDAY"); + days.add("THURSDAY"); + days.add("FRIDAY"); + days.add("SATURDAY"); + days.add("SUNDAY"); + + List times = new ArrayList<>(); + times.add("00-00"); + + getConfig().addDefault("BackupTimer.Days", days); + getConfig().addDefault("BackupTimer.Times", times); + + List worlds = new ArrayList<>(); + worlds.add("world"); + worlds.add("world_nether"); + worlds.add("world_the_end"); + + getConfig().addDefault("BackupWorlds", worlds); + + getConfig().addDefault("DeleteOldBackups", 14); + getConfig().addDefault("BackupLimiter", 0); + + getConfig().addDefault("KeepUniqueBackups", false); + getConfig().addDefault("CollectiveZipFile", false); + getConfig().addDefault("UpdateAvailableMessage", true); + + if (getConfig().contains("ZipCompression")) { + getConfig().set("ZipCompression", null); + } + + if (getConfig().contains("BackupDestination")) { + if (getConfig().getString("BackupDestination") + .equalsIgnoreCase("- this feature will be available soon -")) { + getConfig().set("BackupDestination", null); + } + } + + getConfig().addDefault("BackupDestination", "Backups//"); + + getConfig().addDefault("Ftp.UploadBackup", false); + getConfig().addDefault("Ftp.DeleteLocalBackup", false); + getConfig().addDefault("Ftp.Server.IP", "127.0.0.1"); + getConfig().addDefault("Ftp.Server.Port", 21); + getConfig().addDefault("Ftp.Server.User", "username"); + getConfig().addDefault("Ftp.Server.Password", "password"); + + getConfig().addDefault("SendLogMessages", false); + + if (getConfig().contains("FirstStart")) { + getConfig().set("FirstStart", null); + } + + saveConfig(); + + backupDestination = getConfig().getString("BackupDestination"); + } + + public void startTimer() { + if (getConfig().getBoolean("AutomaticBackups")) { + Bukkit.getScheduler().runTaskTimerAsynchronously(this, new BackupTimer(), 20 * 60, 20 * 60); + } + } + + public void stopTimer() { + Bukkit.getScheduler().cancelTasks(this); + } + + // Events + @EventHandler + public void onJoin(PlayerJoinEvent e) { + Player p = e.getPlayer(); + + if (p.hasPermission("backup.admin")) { + if (getConfig().getBoolean("UpdateAvailableMessage")) { + Bukkit.getScheduler().runTaskAsynchronously(this, () -> { + int resourceID = 79320; + try (InputStream inputStream = (new URL( + "https://api.spigotmc.org/legacy/update.php?resource=" + resourceID)).openStream(); + Scanner scanner = new Scanner(inputStream)) { + if (scanner.hasNext()) { + String latest = scanner.next(); + String current = getDescription().getVersion(); + + int late = Integer.parseInt(latest.replaceAll("\\.", "")); + int curr = Integer.parseInt(current.replaceAll("\\.", "")); + + if (curr < late) { + p.sendMessage("§8=====§fServerBackup§8====="); + p.sendMessage(""); + p.sendMessage("§7There is a newer version available - §a" + latest + + "§7, you are on - §c" + current); + p.sendMessage( + "§7Please download the latest version - §4https://www.spigotmc.org/resources/" + + resourceID); + p.sendMessage(""); + p.sendMessage("§8=====§9Plugin by Seblii§8====="); + } + } + } catch (IOException ignored) { + } + }); + } + } + } + +} diff --git a/src/main/java/de/sebli/serverbackup/ZipManager.java b/src/main/java/de/sebli/serverbackup/ZipManager.java new file mode 100644 index 00000000..fba84d6b --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/ZipManager.java @@ -0,0 +1,181 @@ +package de.sebli.serverbackup; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.logging.Level; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +public class ZipManager { + + private final String sourceFilePath; + private final String targetFilePath; + private final CommandSender sender; + private final boolean sendDebugMsg; + private final boolean isSaving; + + public ZipManager(String sourceFilePath, String targetFilePath, CommandSender sender, boolean sendDebugMsg, + boolean isSaving) { + this.sourceFilePath = sourceFilePath; + this.targetFilePath = targetFilePath; + this.sender = sender; + this.sendDebugMsg = sendDebugMsg; + this.isSaving = isSaving; + } + + public void zip() { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + + long sTime = System.nanoTime(); + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Started zipping: " + sourceFilePath); + + Path p; + try { + p = Files.createFile(Paths.get(targetFilePath)); + } catch (IOException e) { + e.printStackTrace(); + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); + return; + } + + try (ZipOutputStream zs = new ZipOutputStream(Files.newOutputStream(p))) { + Path pp = Paths.get(sourceFilePath); + Files.walk(pp).filter(path -> !Files.isDirectory(path)).forEach(path -> { + ZipEntry zipEntry = new ZipEntry(pp.relativize(path).toString()); + try { + if (sendDebugMsg) { + if (ServerBackup.getInstance().getConfig().getBoolean("SendLogMessages")) { + ServerBackup.getInstance().getLogger().log(Level.INFO, "Zipping '" + path); + + if (Bukkit.getConsoleSender() != sender) { + sender.sendMessage("Zipping '" + path); + } + } + } + + zs.putNextEntry(zipEntry); + + if (!System.getProperty("os.name").startsWith("Windows") + || !path.toString().contains("session.lock")) { + try { + Files.copy(path, zs); + } catch (IOException e) { + e.printStackTrace(); + } + } + + zs.closeEntry(); + } catch (IOException e) { + e.printStackTrace(); + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); + } + }); + } catch (IOException e) { + e.printStackTrace(); + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while zipping files."); + return; + } + + long time = (System.nanoTime() - sTime) / 1000000; + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Files zipped. [" + time + "ms]"); + + if (!isSaving) { + File file = new File(sourceFilePath); + + try { + Files.delete(file.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + sender.sendMessage("Backup [" + sourceFilePath + "] zipped."); + sender.sendMessage("Backup [" + sourceFilePath + "] saved."); + + if (ServerBackup.getInstance().getConfig().getBoolean("Ftp.UploadBackup")) { + FtpManager ftpm = new FtpManager(sender); + ftpm.uploadFileToFtp(targetFilePath); + } + + for (Player all : Bukkit.getOnlinePlayers()) { + if (all.hasPermission("backup.notification")) { + all.sendMessage("Backup [" + sourceFilePath + "] saved."); + } + } + }); + } + + public void unzip() { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + + long sTime = System.nanoTime(); + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Started unzipping: " + sourceFilePath); + + byte[] buffer = new byte[1024]; + try { + File folder = new File(targetFilePath); + if (!folder.exists()) { + folder.mkdir(); + } + ZipInputStream zis = new ZipInputStream(new FileInputStream(sourceFilePath)); + ZipEntry ze = zis.getNextEntry(); + while (ze != null) { + String fileName = ze.getName(); + File newFile = new File(targetFilePath + File.separator + fileName); + + if (sendDebugMsg) { + if (ServerBackup.getInstance().getConfig().getBoolean("SendLogMessages")) { + ServerBackup.getInstance().getLogger().log(Level.INFO, "Unzipping '" + newFile.getPath()); + + if (Bukkit.getConsoleSender() != sender) { + sender.sendMessage("Unzipping '" + newFile.getPath()); + } + } + } + + new File(newFile.getParent()).mkdirs(); + if (!newFile.toPath().normalize().startsWith(targetFilePath)) { + throw new Exception("Bad zip entry"); + } + FileOutputStream fos = new FileOutputStream(newFile); + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + fos.close(); + ze = zis.getNextEntry(); + } + zis.closeEntry(); + zis.close(); + } catch (Exception e) { + e.printStackTrace(); + ServerBackup.getInstance().getLogger().log(Level.WARNING, "Error while unzipping files."); + return; + } + + long time = (System.nanoTime() - sTime) / 1000000; + + ServerBackup.getInstance().getLogger().log(Level.INFO, "ServerBackup | Files unzipped. [" + time + "ms]"); + + File file = new File(sourceFilePath); + + file.delete(); + + sender.sendMessage("Backup [" + sourceFilePath + "] unzipped."); + }); + } + +} diff --git a/src/main/java/de/sebli/serverbackup/commands/SBCommand.java b/src/main/java/de/sebli/serverbackup/commands/SBCommand.java new file mode 100644 index 00000000..feaaf21f --- /dev/null +++ b/src/main/java/de/sebli/serverbackup/commands/SBCommand.java @@ -0,0 +1,676 @@ +package de.sebli.serverbackup.commands; + +import com.google.common.io.Files; +import de.sebli.serverbackup.BackupManager; +import de.sebli.serverbackup.FtpManager; +import de.sebli.serverbackup.ServerBackup; +import de.sebli.serverbackup.ZipManager; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.bukkit.util.StringUtil; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; + +public class SBCommand implements CommandExecutor, TabCompleter { + + @SuppressWarnings("deprecation") + @Override + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (sender.hasPermission("backup.admin")) { + if (args.length == 1) { + if (args[0].equalsIgnoreCase("list")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + if (backups.length == 0) { + sender.sendMessage("No backups found."); + + return; + } + + Arrays.sort(backups); + + if (backups.length < 10) { + sender.sendMessage("----- Backup 1-" + backups.length + "/" + backups.length + " -----"); + } else { + sender.sendMessage("----- Backup 1-10/" + backups.length + " -----"); + } + sender.sendMessage(""); + + for (int i = 0; i < backups.length && i < 10; i++) { + double fileSize = (double) FileUtils.sizeOf(backups[i]) / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + if (sender instanceof Player) { + Player p = (Player) sender; + + TextComponent msg = new TextComponent("§7[" + (i + 1) + "] §r" + + backups[i].getName() + " §7[" + fileSize + "MB]"); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent( + new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, backups[i].getName())); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(backups[i].getName()); + } + } + + int maxPages = backups.length / 10; + + if (backups.length % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("-------- Page 1/" + maxPages + " --------"); + }); + } else if (args[0].equalsIgnoreCase("reload") || args[0].equalsIgnoreCase("rl")) { + ServerBackup.getInstance().reloadConfig(); + + ServerBackup.getInstance().stopTimer(); + ServerBackup.getInstance().startTimer(); + + String oldDes = ServerBackup.getInstance().backupDestination; + + if (!oldDes + .equalsIgnoreCase(ServerBackup.getInstance().getConfig().getString("BackupDestination"))) { + ServerBackup.getInstance().backupDestination = ServerBackup.getInstance().getConfig() + .getString("BackupDestination"); + + ServerBackup.getInstance().getLogger().log(Level.INFO, + "ServerBackup: Backup destination [" + oldDes + " >> " + + ServerBackup.getInstance().backupDestination + "] updated successfully."); + } + + ServerBackup.getInstance().loadFiles(); + + sender.sendMessage("Config reloaded."); + } else { + sendHelp(sender); + } + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("list")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + if (backups.length == 0) { + sender.sendMessage("No backups found."); + + return; + } + + Arrays.sort(backups); + + try { + int page = Integer.parseInt(args[1]); + + if (backups.length < page * 10 - 9) { + sender.sendMessage("Try a lower value."); + + return; + } + + if (backups.length <= page * 10 && backups.length >= page * 10 - 10) { + sender.sendMessage("----- Backup " + (page * 10 - 9) + "-" + + backups.length + "/" + backups.length + " -----"); + } else { + sender.sendMessage("----- Backup " + (page * 10 - 9) + "-" + + page * 10 + "/" + backups.length + " -----"); + } + sender.sendMessage(""); + + for (int i = page * 10 - 10; i < backups.length && i < page * 10; i++) { + double fileSize = (double) FileUtils.sizeOf(backups[i]) / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + if (sender instanceof Player) { + Player p = (Player) sender; + + TextComponent msg = new TextComponent("§7[" + (i + 1) + "] §r" + + backups[i].getName() + " §7[" + fileSize + "MB]"); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent( + new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, backups[i].getName())); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(backups[i].getName()); + } + } + + int maxPages = backups.length / 10; + + if (backups.length % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("-------- Page " + page + "/" + maxPages + " --------"); + } catch (Exception e) { + sender.sendMessage("'" + args[1] + "' is not a valid number."); + } + }); + } else if (args[0].equalsIgnoreCase("ftp")) { + if (args[1].equalsIgnoreCase("list")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + FtpManager ftpm = new FtpManager(sender); + + List backups = ftpm.getFtpBackupList(); + + if (backups.size() == 0) { + sender.sendMessage("No ftp backups found."); + + return; + } + + if (backups.size() < 10) { + sender.sendMessage( + "----- Ftp-Backup 1-" + backups.size() + "/" + backups.size() + " -----"); + } else { + sender.sendMessage("----- Ftp-Backup 1-10/" + backups.size() + " -----"); + } + sender.sendMessage(""); + + for (int i = 0; i < backups.size() && i < 10; i++) { + if (sender instanceof Player) { + Player p = (Player) sender; + TextComponent msg = new TextComponent(backups.get(i)); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + backups.get(i).split(" ")[1])); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(backups.get(i)); + } + } + + int maxPages = backups.size() / 10; + + if (backups.size() % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("--------- Page 1/" + maxPages + " ---------"); + }); + } + } else if (args[0].equalsIgnoreCase("zip")) { + String filePath = args[1]; + + if (args[1].contains(".zip")) { + sender.sendMessage("'" + args[1] + "' is already a ZIP file."); + return false; + } + + File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); + File newFile = new File(ServerBackup.getInstance().backupDestination + "//" + filePath + ".zip"); + + if (!newFile.exists()) { + sender.sendMessage("Zipping Backup..."); + sender.sendMessage(""); + + if (file.exists()) { + ZipManager zm = new ZipManager(file.getPath(), newFile.getPath(), sender, true, false); + + zm.zip(); + } else { + sender.sendMessage("No Backup named '" + args[1] + "' found."); + } + } else { + sender.sendMessage("There is already a folder named '" + args[1].replaceAll(".zip", "") + "'"); + } + } else if (args[0].equalsIgnoreCase("unzip")) { + String filePath = args[1]; + + if (!args[1].contains(".zip")) { + sender.sendMessage("'" + args[1] + "' is not a ZIP file."); + return false; + } + + File file = new File(ServerBackup.getInstance().backupDestination + "//" + filePath); + File newFile = new File( + ServerBackup.getInstance().backupDestination + "//" + filePath.replaceAll(".zip", "")); + + if (!newFile.exists()) { + sender.sendMessage("Unzipping Backup..."); + sender.sendMessage(""); + + if (file.exists()) { + ZipManager zm = new ZipManager(file.getPath(), + ServerBackup.getInstance().backupDestination + "//" + newFile.getName(), sender, + false, true); + + zm.unzip(); + } else { + sender.sendMessage("No Backup named '" + args[1] + "' found."); + } + } else { + sender.sendMessage("There is already a ZIP file named '" + args[1] + ".zip'"); + } + } else if (args[0].equalsIgnoreCase("delete") || args[0].equalsIgnoreCase("remove")) { + if (args[1].equalsIgnoreCase("Files")) { + sender.sendMessage("You can not delete the 'Files' backup folder."); + + return false; + } + + BackupManager bm = new BackupManager(args[1], sender); + + bm.removeBackup(); + } else if (args[0].equalsIgnoreCase("create")) { + File file = new File(args[1]); + if (!file.isDirectory()) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + try { + File des = new File(ServerBackup.getInstance().backupDestination + "//Files//" + + args[1].replaceAll("/", "-")); + + if (des.exists()) { + des = new File(des.getPath() + .replaceAll("." + FilenameUtils.getExtension(des.getName()), "") + " " + + System.currentTimeMillis() / 1000 + "." + + FilenameUtils.getExtension(file.getName())); + } + + Files.copy(file, des); + + sender.sendMessage("Backup [" + args[1] + "] saved."); + } catch (IOException e) { + sender.sendMessage("An error occured while saving Backup [" + args[1] + + "]. See console for more information."); + e.printStackTrace(); + } + }); + } else { + BackupManager bm = new BackupManager(args[1], sender); + + bm.createBackup(); + } + } else if (args[0].equalsIgnoreCase("search")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + if (backups.length == 0) { + sender.sendMessage("No backups found."); + + return; + } + + List backupsMatch = new ArrayList<>(); + + for (File backup : backups) { + if (backup.getName().contains(args[1])) { + backupsMatch.add(backup); + } + } + + if (backupsMatch.size() == 0) { + sender.sendMessage("No backups for search argument '" + args[1] + "' found."); + + return; + } + + Collections.sort(backupsMatch); + + int count = 1; + + if (backupsMatch.size() < 10) { + sender.sendMessage( + "----- Backup 1-" + backupsMatch.size() + "/" + backupsMatch.size() + " -----"); + } else { + sender.sendMessage("----- Backup 1-10/" + backupsMatch.size() + " -----"); + } + sender.sendMessage(""); + + for (File file : backupsMatch) { + if (count <= 10 && count <= backupsMatch.size()) { + double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + if (sender instanceof Player) { + Player p = (Player) sender; + + TextComponent msg = new TextComponent("§7[" + count + "] §r" + + file.getName() + " §7[" + fileSize + "MB]"); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + "/backup remove " + file.getName())); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(file.getName()); + } + } + count++; + } + + int maxPages = backupsMatch.size() / 10; + + if (backupsMatch.size() % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("-------- Page 1/" + maxPages + " --------"); + }); + } else { + sendHelp(sender); + } + } else if (args.length == 3) { + if (args[0].equalsIgnoreCase("search")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + if (backups.length == 0) { + sender.sendMessage("No backups found."); + + return; + } + + List backupsMatch = new ArrayList<>(); + + for (File backup : backups) { + if (backup.getName().contains(args[1])) { + backupsMatch.add(backup); + } + } + + if (backupsMatch.size() == 0) { + sender.sendMessage("No backups for search argument '" + args[1] + "' found."); + + return; + } + + Collections.sort(backupsMatch); + + try { + int page = Integer.parseInt(args[2]); + + if (backups.length < page * 10 - 9) { + sender.sendMessage("Try a lower value."); + + return; + } + + int count = page * 10 - 9; + + if (backupsMatch.size() <= page * 10 && backupsMatch.size() >= page * 10 - 10) { + sender.sendMessage("----- Backup " + (page * 10 - 9) + "-" + + backupsMatch.size() + "/" + backupsMatch.size() + " -----"); + } else { + sender.sendMessage("----- Backup " + (page * 10 - 9) + "-" + + page * 10 + "/" + backupsMatch.size() + " -----"); + } + sender.sendMessage(""); + + for (File file : backupsMatch) { + if (count <= page * 10 && count <= backupsMatch.size()) { + double fileSize = (double) FileUtils.sizeOf(file) / 1000 / 1000; + fileSize = Math.round(fileSize * 100.0) / 100.0; + + if (sender instanceof Player) { + Player p = (Player) sender; + + TextComponent msg = new TextComponent("§7[" + count + "] §r" + + file.getName() + " §7[" + fileSize + "MB]"); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + "/backup remove " + file.getName())); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(file.getName()); + } + } + count++; + } + + int maxPages = backupsMatch.size() / 10; + + if (backupsMatch.size() % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("-------- Page " + page + "/" + maxPages + " --------"); + } catch (Exception e) { + sender.sendMessage("'" + args[2] + "' is not a valid number."); + } + }); + } else if (args[0].equalsIgnoreCase("ftp")) { + if (args[1].equalsIgnoreCase("list")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + FtpManager ftpm = new FtpManager(sender); + + List backups = ftpm.getFtpBackupList(); + + if (backups.size() == 0) { + sender.sendMessage("No ftp backups found."); + + return; + } + + try { + int page = Integer.parseInt(args[2]); + + if (backups.size() < page * 10 - 9) { + sender.sendMessage("Try a lower value."); + + return; + } + + if (backups.size() <= page * 10 && backups.size() >= page * 10 - 10) { + sender.sendMessage("----- Ftp-Backup " + (page * 10 - 9) + "-" + + backups.size() + "/" + backups.size() + " -----"); + } else { + sender.sendMessage("----- Ftp-Backup " + (page * 10 - 9) + "-" + + page * 10 + "/" + backups.size() + " -----"); + } + sender.sendMessage(""); + + for (int i = page * 10 - 10; i < backups.size() && i < page * 10; i++) { + if (sender instanceof Player) { + Player p = (Player) sender; + + TextComponent msg = new TextComponent(backups.get(i)); + msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder("Click to get Backup name").create())); + msg.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + backups.get(i).split(" ")[1])); + + p.spigot().sendMessage(msg); + } else { + sender.sendMessage(backups.get(i)); + } + } + + int maxPages = backups.size() / 10; + + if (backups.size() % 10 != 0) { + maxPages++; + } + + sender.sendMessage(""); + sender.sendMessage("--------- Page " + page + "/" + maxPages + " ---------"); + } catch (Exception e) { + sender.sendMessage("'" + args[1] + "' is not a valid number."); + } + }); + } else if (args[1].equalsIgnoreCase("download")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + FtpManager ftpm = new FtpManager(sender); + + ftpm.downloadFileFromFtp(args[2]); + }); + } else if (args[1].equalsIgnoreCase("upload")) { + Bukkit.getScheduler().runTaskAsynchronously(ServerBackup.getInstance(), () -> { + FtpManager ftpm = new FtpManager(sender); + + ftpm.uploadFileToFtp(args[2]); + }); + } + } else { + sendHelp(sender); + } + } else { + sendHelp(sender); + } + } else { + sender.sendMessage("§cI'm sorry but you do not have permission to perform this command."); + } + + return false; + } + + private void sendHelp(CommandSender sender) { + sender.sendMessage("/backup reload - reloads the config"); + sender.sendMessage(""); + sender.sendMessage("/backup list - shows a list of 10 backups"); + sender.sendMessage(""); + sender.sendMessage( + "/backup search - shows a list of 10 backups that contain the given search argument"); + sender.sendMessage(""); + sender.sendMessage("/backup create - creates a new backup of a world"); + sender.sendMessage(""); + sender.sendMessage("/backup remove - removes an existing backup"); + sender.sendMessage(""); + sender.sendMessage("/backup zip - zipping folder"); + sender.sendMessage(""); + sender.sendMessage("/backup unzip - unzipping file"); + sender.sendMessage(""); + sender.sendMessage( + "/backup ftp - download, upload or list ftp backup files [BETA feature]"); + } + + @Override + public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { + List completions = new ArrayList<>(); + List commands = new ArrayList<>(); + + if (sender.hasPermission("backup.admin")) { + if (args.length == 1) { + commands.add("reload"); + commands.add("list"); + commands.add("search"); + commands.add("create"); + commands.add("remove"); + commands.add("zip"); + commands.add("unzip"); + commands.add("ftp"); + + StringUtil.copyPartialMatches(args[0], commands, completions); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("list")) { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + int maxPages = backups.length / 10; + + if (backups.length % 10 != 0) { + maxPages++; + } + + for (int i = 1; i < maxPages + 1; i++) { + commands.add(String.valueOf(i)); + } + } else if (args[0].equalsIgnoreCase("remove")) { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + for (File backup : backups) { + commands.add(backup.getName()); + } + } else if (args[0].equalsIgnoreCase("create")) { + for (World world : Bukkit.getWorlds()) { + commands.add(world.getName()); + } + } else if (args[0].equalsIgnoreCase("zip")) { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + for (File backup : backups) { + if (!backup.getName().endsWith(".zip")) { + commands.add(backup.getName()); + } + } + } else if (args[0].equalsIgnoreCase("unzip")) { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + for (File backup : backups) { + if (backup.getName().endsWith(".zip")) { + commands.add(backup.getName()); + } + } + } else if (args[0].equalsIgnoreCase("ftp")) { + commands.add("list"); + commands.add("download"); + commands.add("upload"); + } + + StringUtil.copyPartialMatches(args[1], commands, completions); + } else if (args.length == 3) { + if (args[0].equalsIgnoreCase("ftp")) { + if (args[1].equalsIgnoreCase("list")) { + FtpManager ftpm = new FtpManager(sender); + + List backups = ftpm.getFtpBackupList(); + + int maxPages = backups.size() / 10; + + if (backups.size() % 10 != 0) { + maxPages++; + } + + for (int i = 1; i < maxPages + 1; i++) { + commands.add(String.valueOf(i)); + } + } else if (args[1].equalsIgnoreCase("download")) { + FtpManager ftpm = new FtpManager(sender); + + List backups = ftpm.getFtpBackupList(); + + for (String backup : backups) { + commands.add(backup.split(" ")[1]); + } + } else if (args[1].equalsIgnoreCase("upload")) { + File[] backups = new File(ServerBackup.getInstance().backupDestination + "").listFiles(); + + for (File backup : backups) { + if (backup.getName().endsWith(".zip")) { + commands.add(backup.getName()); + } + } + } + } + + StringUtil.copyPartialMatches(args[2], commands, completions); + } + } + + Collections.sort(completions); + + return completions; + } + +} diff --git a/src/de/sebli/serverbackup/utils/Metrics.java b/src/main/java/de/sebli/serverbackup/utils/Metrics.java similarity index 95% rename from src/de/sebli/serverbackup/utils/Metrics.java rename to src/main/java/de/sebli/serverbackup/utils/Metrics.java index 64baf73a..65d7eed9 100644 --- a/src/de/sebli/serverbackup/utils/Metrics.java +++ b/src/main/java/de/sebli/serverbackup/utils/Metrics.java @@ -1,841 +1,830 @@ -package de.sebli.serverbackup.utils; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.lang.reflect.Method; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.zip.GZIPOutputStream; -import javax.net.ssl.HttpsURLConnection; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; - -public class Metrics { - - private final Plugin plugin; - - private final MetricsBase metricsBase; - - /** - * Creates a new Metrics instance. - * - * @param plugin Your plugin instance. - * @param serviceId The id of the service. It can be found at - * What is my - * plugin id? - */ - @SuppressWarnings("deprecation") - public Metrics(JavaPlugin plugin, int serviceId) { - this.plugin = plugin; - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - if (!config.isSet("serverUuid")) { - config.addDefault("enabled", true); - config.addDefault("serverUuid", UUID.randomUUID().toString()); - config.addDefault("logFailedRequests", false); - config.addDefault("logSentData", false); - config.addDefault("logResponseStatusText", false); - // Inform the server owners about bStats - config.options() - .header("bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" - + "many people use their plugin and their total player count. It's recommended to keep bStats\n" - + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" - + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" - + "anonymous.") - .copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { - } - } - // Load the data - boolean enabled = config.getBoolean("enabled", true); - String serverUUID = config.getString("serverUuid"); - boolean logErrors = config.getBoolean("logFailedRequests", false); - boolean logSentData = config.getBoolean("logSentData", false); - boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); - metricsBase = new MetricsBase("bukkit", serverUUID, serviceId, enabled, this::appendPlatformData, - this::appendServiceData, submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), - plugin::isEnabled, (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), - (message) -> this.plugin.getLogger().log(Level.INFO, message), logErrors, logSentData, - logResponseStatusText); - } - - /** - * Adds a custom chart. - * - * @param chart The chart to add. - */ - public void addCustomChart(CustomChart chart) { - metricsBase.addCustomChart(chart); - } - - private void appendPlatformData(JsonObjectBuilder builder) { - builder.appendField("playerAmount", getPlayerAmount()); - builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); - builder.appendField("bukkitVersion", Bukkit.getVersion()); - builder.appendField("bukkitName", Bukkit.getName()); - builder.appendField("javaVersion", System.getProperty("java.version")); - builder.appendField("osName", System.getProperty("os.name")); - builder.appendField("osArch", System.getProperty("os.arch")); - builder.appendField("osVersion", System.getProperty("os.version")); - builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); - } - - private void appendServiceData(JsonObjectBuilder builder) { - builder.appendField("pluginVersion", plugin.getDescription().getVersion()); - } - - private int getPlayerAmount() { - try { - // Around MC 1.8 the return type was changed from an array to a collection, - // This fixes java.lang.NoSuchMethodError: - // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; - Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); - return onlinePlayersMethod.getReturnType().equals(Collection.class) - ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() - : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; - } catch (Exception e) { - // Just use the new method if the reflection failed - return Bukkit.getOnlinePlayers().size(); - } - } - - public static class MetricsBase { - - /** The version of the Metrics class. */ - public static final String METRICS_VERSION = "3.0.0"; - - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, - task -> new Thread(task, "bStats-Metrics")); - - private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; - - private final String platform; - - private final String serverUuid; - - private final int serviceId; - - private final Consumer appendPlatformDataConsumer; - - private final Consumer appendServiceDataConsumer; - - private final Consumer submitTaskConsumer; - - private final Supplier checkServiceEnabledSupplier; - - private final BiConsumer errorLogger; - - private final Consumer infoLogger; - - private final boolean logErrors; - - private final boolean logSentData; - - private final boolean logResponseStatusText; - - private final Set customCharts = new HashSet<>(); - - private final boolean enabled; - - /** - * Creates a new MetricsBase class instance. - * - * @param platform The platform of the service. - * @param serviceId The id of the service. - * @param serverUuid The server uuid. - * @param enabled Whether or not data sending is enabled. - * @param appendPlatformDataConsumer A consumer that receives a - * {@code JsonObjectBuilder} and appends all - * platform-specific data. - * @param appendServiceDataConsumer A consumer that receives a - * {@code JsonObjectBuilder} and appends all - * service-specific data. - * @param submitTaskConsumer A consumer that takes a runnable with the - * submit task. This can be used to delegate - * the data collection to a another thread to - * prevent errors caused by concurrency. Can - * be {@code null}. - * @param checkServiceEnabledSupplier A supplier to check if the service is - * still enabled. - * @param errorLogger A consumer that accepts log message and an - * error. - * @param infoLogger A consumer that accepts info log messages. - * @param logErrors Whether or not errors should be logged. - * @param logSentData Whether or not the sent data should be - * logged. - * @param logResponseStatusText Whether or not the response status text - * should be logged. - */ - public MetricsBase(String platform, String serverUuid, int serviceId, boolean enabled, - Consumer appendPlatformDataConsumer, - Consumer appendServiceDataConsumer, Consumer submitTaskConsumer, - Supplier checkServiceEnabledSupplier, BiConsumer errorLogger, - Consumer infoLogger, boolean logErrors, boolean logSentData, boolean logResponseStatusText) { - this.platform = platform; - this.serverUuid = serverUuid; - this.serviceId = serviceId; - this.enabled = enabled; - this.appendPlatformDataConsumer = appendPlatformDataConsumer; - this.appendServiceDataConsumer = appendServiceDataConsumer; - this.submitTaskConsumer = submitTaskConsumer; - this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; - this.errorLogger = errorLogger; - this.infoLogger = infoLogger; - this.logErrors = logErrors; - this.logSentData = logSentData; - this.logResponseStatusText = logResponseStatusText; - checkRelocation(); - if (enabled) { - // WARNING: Removing the option to opt-out will get your plugin banned from - // bStats - startSubmitting(); - } - } - - public void addCustomChart(CustomChart chart) { - this.customCharts.add(chart); - } - - private void startSubmitting() { - final Runnable submitTask = () -> { - if (!enabled || !checkServiceEnabledSupplier.get()) { - // Submitting data or service is disabled - scheduler.shutdown(); - return; - } - if (submitTaskConsumer != null) { - submitTaskConsumer.accept(this::submitData); - } else { - this.submitData(); - } - }; - // Many servers tend to restart at a fixed time at xx:00 which causes an uneven - // distribution - // of requests on the - // bStats backend. To circumvent this problem, we introduce some randomness into - // the initial - // and second delay. - // WARNING: You must not modify and part of this Metrics class, including the - // submit delay or - // frequency! - // WARNING: Modifying this code will get your plugin banned on bStats. Just - // don't do it! - long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); - long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); - scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); - scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, - TimeUnit.MILLISECONDS); - } - - private void submitData() { - final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); - appendPlatformDataConsumer.accept(baseJsonBuilder); - final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); - appendServiceDataConsumer.accept(serviceJsonBuilder); - JsonObjectBuilder.JsonObject[] chartData = customCharts.stream() - .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) - .filter(Objects::nonNull).toArray(JsonObjectBuilder.JsonObject[]::new); - serviceJsonBuilder.appendField("id", serviceId); - serviceJsonBuilder.appendField("customCharts", chartData); - baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); - baseJsonBuilder.appendField("serverUUID", serverUuid); - baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); - JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); - scheduler.execute(() -> { - try { - // Send the data - sendData(data); - } catch (Exception e) { - // Something went wrong! :( - if (logErrors) { - errorLogger.accept("Could not submit bStats metrics data", e); - } - } - }); - } - - private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { - if (logSentData) { - infoLogger.accept("Sent bStats metrics data: " + data.toString()); - } - String url = String.format(REPORT_URL, platform); - HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("User-Agent", "Metrics-Service/1"); - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - } - StringBuilder builder = new StringBuilder(); - try (BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(connection.getInputStream()))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - if (logResponseStatusText) { - infoLogger.accept("Sent data to bStats and received response: " + builder); - } - } - - /** Checks that the class was properly relocated. */ - private void checkRelocation() { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null - || !System.getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this - // little - // "trick" ... :D - final String defaultPackage = new String( - new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' }); - final String examplePackage = new String( - new byte[] { 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e' }); - // We want to make sure no one just copy & pastes the example and uses the wrong - // package - // names - if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) - || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - /** - * Gzips the given string. - * - * @param str The string to gzip. - * @return The gzipped string. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - } - return outputStream.toByteArray(); - } - } - - public static class DrilldownPie extends CustomChart { - - private final Callable>> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public DrilldownPie(String chartId, Callable>> callable) { - super(chartId); - this.callable = callable; - } - - @Override - public JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map> map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean reallyAllSkipped = true; - for (Map.Entry> entryValues : map.entrySet()) { - JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); - boolean allSkipped = true; - for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { - valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); - allSkipped = false; - } - if (!allSkipped) { - reallyAllSkipped = false; - valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); - } - } - if (reallyAllSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class AdvancedPie extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedPie(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class MultiLineChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public MultiLineChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SimpleBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimpleBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - for (Map.Entry entry : map.entrySet()) { - valuesBuilder.appendField(entry.getKey(), new int[] { entry.getValue() }); - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public abstract static class CustomChart { - - private final String chartId; - - protected CustomChart(String chartId) { - if (chartId == null) { - throw new IllegalArgumentException("chartId must not be null"); - } - this.chartId = chartId; - } - - public JsonObjectBuilder.JsonObject getRequestJsonObject(BiConsumer errorLogger, - boolean logErrors) { - JsonObjectBuilder builder = new JsonObjectBuilder(); - builder.appendField("chartId", chartId); - try { - JsonObjectBuilder.JsonObject data = getChartData(); - if (data == null) { - // If the data is null we don't send the chart. - return null; - } - builder.appendField("data", data); - } catch (Throwable t) { - if (logErrors) { - errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); - } - return null; - } - return builder.build(); - } - - protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; - } - - public static class SimplePie extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SimplePie(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - String value = callable.call(); - if (value == null || value.isEmpty()) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - - public static class AdvancedBarChart extends CustomChart { - - private final Callable> callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public AdvancedBarChart(String chartId, Callable> callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); - Map map = callable.call(); - if (map == null || map.isEmpty()) { - // Null = skip the chart - return null; - } - boolean allSkipped = true; - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().length == 0) { - // Skip this invalid - continue; - } - allSkipped = false; - valuesBuilder.appendField(entry.getKey(), entry.getValue()); - } - if (allSkipped) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); - } - } - - public static class SingleLineChart extends CustomChart { - - private final Callable callable; - - /** - * Class constructor. - * - * @param chartId The id of the chart. - * @param callable The callable which is used to request the chart data. - */ - public SingleLineChart(String chartId, Callable callable) { - super(chartId); - this.callable = callable; - } - - @Override - protected JsonObjectBuilder.JsonObject getChartData() throws Exception { - int value = callable.call(); - if (value == 0) { - // Null = skip the chart - return null; - } - return new JsonObjectBuilder().appendField("value", value).build(); - } - } - - /** - * An extremely simple JSON builder. - * - *

- * While this class is neither feature-rich nor the most performant one, it's - * sufficient enough for its use-case. - */ - public static class JsonObjectBuilder { - - private StringBuilder builder = new StringBuilder(); - - private boolean hasAtLeastOneField = false; - - public JsonObjectBuilder() { - builder.append("{"); - } - - /** - * Appends a null field to the JSON. - * - * @param key The key of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendNull(String key) { - appendFieldUnescaped(key, "null"); - return this; - } - - /** - * Appends a string field to the JSON. - * - * @param key The key of the field. - * @param value The value of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, String value) { - if (value == null) { - throw new IllegalArgumentException("JSON value must not be null"); - } - appendFieldUnescaped(key, "\"" + escape(value) + "\""); - return this; - } - - /** - * Appends an integer field to the JSON. - * - * @param key The key of the field. - * @param value The value of the field. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, int value) { - appendFieldUnescaped(key, String.valueOf(value)); - return this; - } - - /** - * Appends an object to the JSON. - * - * @param key The key of the field. - * @param object The object. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, JsonObject object) { - if (object == null) { - throw new IllegalArgumentException("JSON object must not be null"); - } - appendFieldUnescaped(key, object.toString()); - return this; - } - - /** - * Appends a string array to the JSON. - * - * @param key The key of the field. - * @param values The string array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, String[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = Arrays.stream(values).map(value -> "\"" + escape(value) + "\"") - .collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends an integer array to the JSON. - * - * @param key The key of the field. - * @param values The integer array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, int[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends an object array to the JSON. - * - * @param key The key of the field. - * @param values The integer array. - * @return A reference to this object. - */ - public JsonObjectBuilder appendField(String key, JsonObject[] values) { - if (values == null) { - throw new IllegalArgumentException("JSON values must not be null"); - } - String escapedValues = Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); - appendFieldUnescaped(key, "[" + escapedValues + "]"); - return this; - } - - /** - * Appends a field to the object. - * - * @param key The key of the field. - * @param escapedValue The escaped value of the field. - */ - private void appendFieldUnescaped(String key, String escapedValue) { - if (builder == null) { - throw new IllegalStateException("JSON has already been built"); - } - if (key == null) { - throw new IllegalArgumentException("JSON key must not be null"); - } - if (hasAtLeastOneField) { - builder.append(","); - } - builder.append("\"").append(escape(key)).append("\":").append(escapedValue); - hasAtLeastOneField = true; - } - - /** - * Builds the JSON string and invalidates this builder. - * - * @return The built JSON string. - */ - public JsonObject build() { - if (builder == null) { - throw new IllegalStateException("JSON has already been built"); - } - JsonObject object = new JsonObject(builder.append("}").toString()); - builder = null; - return object; - } - - /** - * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. - * - *

- * This method escapes only the necessary characters '"', '\'. and '\u0000' - - * '\u001F'. Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and - * not as "\n"). - * - * @param value The value to escape. - * @return The escaped value. - */ - private static String escape(String value) { - final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - if (c == '"') { - builder.append("\\\""); - } else if (c == '\\') { - builder.append("\\\\"); - } else if (c <= '\u000F') { - builder.append("\\u000").append(Integer.toHexString(c)); - } else if (c <= '\u001F') { - builder.append("\\u00").append(Integer.toHexString(c)); - } else { - builder.append(c); - } - } - return builder.toString(); - } - - /** - * A super simple representation of a JSON object. - * - *

- * This class only exists to make methods of the {@link JsonObjectBuilder} - * type-safe and not allow a raw string inputs for methods like - * {@link JsonObjectBuilder#appendField(String, JsonObject)}. - */ - public static class JsonObject { - - private final String value; - - private JsonObject(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } - } +package de.sebli.serverbackup.utils; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class Metrics { + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at + * What is my + * plugin id? + */ + public Metrics(JavaPlugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config.options() + .header("bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + metricsBase = new MetricsBase("bukkit", serverUUID, serviceId, enabled, this::appendPlatformData, + this::appendServiceData, submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), logErrors, logSentData, + logResponseStatusText); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "3.0.0"; + + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, + task -> new Thread(task, "bStats-Metrics")); + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a + * {@code JsonObjectBuilder} and appends all + * platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a + * {@code JsonObjectBuilder} and appends all + * service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the + * submit task. This can be used to delegate + * the data collection to a another thread to + * prevent errors caused by concurrency. Can + * be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is + * still enabled. + * @param errorLogger A consumer that accepts log message and an + * error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be + * logged. + * @param logResponseStatusText Whether or not the response status text + * should be logged. + */ + public MetricsBase(String platform, String serverUuid, int serviceId, boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, BiConsumer errorLogger, + Consumer infoLogger, boolean logErrors, boolean logSentData, boolean logResponseStatusText) { + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + checkRelocation(); + if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from + // bStats + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven + // distribution + // of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into + // the initial + // and second delay. + // WARNING: You must not modify and part of this Metrics class, including the + // submit delay or + // frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just + // don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, + TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull).toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute(() -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this + // little + // "trick" ... :D + final String defaultPackage = new String( + new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' }); + final String examplePackage = new String( + new byte[] { 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e' }); + // We want to make sure no one just copy & pastes the example and uses the wrong + // package + // names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] { entry.getValue() }); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject(BiConsumer errorLogger, + boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

+ * While this class is neither feature-rich nor the most performant one, it's + * sufficient enough for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = Arrays.stream(values).map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

+ * This method escapes only the necessary characters '"', '\'. and '\u0000' - + * '\u001F'. Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and + * not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

+ * This class only exists to make methods of the {@link JsonObjectBuilder} + * type-safe and not allow a raw string inputs for methods like + * {@link JsonObjectBuilder#appendField(String, JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } } \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 00000000..017eee53 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,19 @@ +main: de.sebli.serverbackup.ServerBackup +name: ServerBackup +version: $version +description: A backup plugin for instant backup creation with little to no performance impact +load: STARTUP +authors: + - Seblii + - onetwoeight +website: https://github.com/128931/ServerBackup +api-version: 1.18 + +commands: + backup: + aliases: [ serverbackup ] + permission: backup.admin + +permissions: + backup.admin: + description: Permission for all backup commands \ No newline at end of file diff --git a/src/org/apache/commons/io/ByteOrderMark.java b/src/org/apache/commons/io/ByteOrderMark.java deleted file mode 100644 index 62b4c973..00000000 --- a/src/org/apache/commons/io/ByteOrderMark.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.Serializable; -import java.util.Locale; - -/** - * Byte Order Mark (BOM) representation - see {@link org.apache.commons.io.input.BOMInputStream}. - * - * @see org.apache.commons.io.input.BOMInputStream - * @see Wikipedia: Byte Order Mark - * @see W3C: Autodetection of Character Encodings - * (Non-Normative) - * @since 2.0 - */ -public class ByteOrderMark implements Serializable { - - private static final long serialVersionUID = 1L; - - /** UTF-8 BOM. */ - public static final ByteOrderMark UTF_8 = new ByteOrderMark("UTF-8", 0xEF, 0xBB, 0xBF); - - /** UTF-16BE BOM (Big-Endian). */ - public static final ByteOrderMark UTF_16BE = new ByteOrderMark("UTF-16BE", 0xFE, 0xFF); - - /** UTF-16LE BOM (Little-Endian). */ - public static final ByteOrderMark UTF_16LE = new ByteOrderMark("UTF-16LE", 0xFF, 0xFE); - - /** - * UTF-32BE BOM (Big-Endian). - * - * @since 2.2 - */ - public static final ByteOrderMark UTF_32BE = new ByteOrderMark("UTF-32BE", 0x00, 0x00, 0xFE, 0xFF); - - /** - * UTF-32LE BOM (Little-Endian). - * - * @since 2.2 - */ - public static final ByteOrderMark UTF_32LE = new ByteOrderMark("UTF-32LE", 0xFF, 0xFE, 0x00, 0x00); - - /** - * Unicode BOM character; external form depends on the encoding. - * - * @see Byte Order Mark (BOM) FAQ - * @since 2.5 - */ - public static final char UTF_BOM = '\uFEFF'; - - private final String charsetName; - private final int[] bytes; - - /** - * Constructs a new BOM. - * - * @param charsetName The name of the charset the BOM represents - * @param bytes The BOM's bytes - * @throws IllegalArgumentException if the charsetName is null or - * zero length - * @throws IllegalArgumentException if the bytes are null or zero - * length - */ - public ByteOrderMark(final String charsetName, final int... bytes) { - if (charsetName == null || charsetName.isEmpty()) { - throw new IllegalArgumentException("No charsetName specified"); - } - if (bytes == null || bytes.length == 0) { - throw new IllegalArgumentException("No bytes specified"); - } - this.charsetName = charsetName; - this.bytes = new int[bytes.length]; - System.arraycopy(bytes, 0, this.bytes, 0, bytes.length); - } - - /** - * Gets the name of the {@link java.nio.charset.Charset} the BOM represents. - * - * @return the character set name - */ - public String getCharsetName() { - return charsetName; - } - - /** - * Gets the length of the BOM's bytes. - * - * @return the length of the BOM's bytes - */ - public int length() { - return bytes.length; - } - - /** - * Gets the byte at the specified position. - * - * @param pos The position - * @return The specified byte - */ - public int get(final int pos) { - return bytes[pos]; - } - - /** - * Gets a copy of the BOM's bytes. - * - * @return a copy of the BOM's bytes - */ - public byte[] getBytes() { - final byte[] copy = IOUtils.byteArray(bytes.length); - for (int i = 0; i < bytes.length; i++) { - copy[i] = (byte)bytes[i]; - } - return copy; - } - - /** - * Indicates if this BOM's bytes equals another. - * - * @param obj The object to compare to - * @return true if the bom's bytes are equal, otherwise - * false - */ - @Override - public boolean equals(final Object obj) { - if (!(obj instanceof ByteOrderMark)) { - return false; - } - final ByteOrderMark bom = (ByteOrderMark)obj; - if (bytes.length != bom.length()) { - return false; - } - for (int i = 0; i < bytes.length; i++) { - if (bytes[i] != bom.get(i)) { - return false; - } - } - return true; - } - - /** - * Computes the hashcode for this BOM. - * - * @return the hashcode for this BOM. - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - int hashCode = getClass().hashCode(); - for (final int b : bytes) { - hashCode += b; - } - return hashCode; - } - - /** - * Converts this instance to a String representation of the BOM. - * - * @return the length of the BOM's bytes - */ - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append(getClass().getSimpleName()); - builder.append('['); - builder.append(charsetName); - builder.append(": "); - for (int i = 0; i < bytes.length; i++) { - if (i > 0) { - builder.append(","); - } - builder.append("0x"); - builder.append(Integer.toHexString(0xFF & bytes[i]).toUpperCase(Locale.ROOT)); - } - builder.append(']'); - return builder.toString(); - } - -} diff --git a/src/org/apache/commons/io/ByteOrderParser.java b/src/org/apache/commons/io/ByteOrderParser.java deleted file mode 100644 index a0124c0e..00000000 --- a/src/org/apache/commons/io/ByteOrderParser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.nio.ByteOrder; - -/** - * Converts Strings to {@link ByteOrder} instances. - * - * @since 2.6 - */ -public final class ByteOrderParser { - - /** - * ByteOrderUtils is a static utility class, so prevent construction with a private constructor. - */ - private ByteOrderParser() { - } - - /** - * Parses the String argument as a {@link ByteOrder}. - *

- * Returns {@code ByteOrder.LITTLE_ENDIAN} if the given value is {@code "LITTLE_ENDIAN"}. - *

- *

- * Returns {@code ByteOrder.BIG_ENDIAN} if the given value is {@code "BIG_ENDIAN"}. - *

- * Examples: - *
    - *
  • {@code ByteOrderParser.parseByteOrder("LITTLE_ENDIAN")} returns {@code ByteOrder.LITTLE_ENDIAN}
  • - *
  • {@code ByteOrderParser.parseByteOrder("BIG_ENDIAN")} returns {@code ByteOrder.BIG_ENDIAN}
  • - *
- * - * @param value - * the {@code String} containing the ByteOrder representation to be parsed - * @return the ByteOrder represented by the string argument - * @throws IllegalArgumentException - * if the {@code String} containing the ByteOrder representation to be parsed is unknown. - */ - public static ByteOrder parseByteOrder(final String value) { - if (ByteOrder.BIG_ENDIAN.toString().equals(value)) { - return ByteOrder.BIG_ENDIAN; - } - if (ByteOrder.LITTLE_ENDIAN.toString().equals(value)) { - return ByteOrder.LITTLE_ENDIAN; - } - throw new IllegalArgumentException("Unsupported byte order setting: " + value + ", expected one of " + ByteOrder.LITTLE_ENDIAN + - ", " + ByteOrder.BIG_ENDIAN); - } - -} diff --git a/src/org/apache/commons/io/Charsets.java b/src/org/apache/commons/io/Charsets.java deleted file mode 100644 index ce9b3472..00000000 --- a/src/org/apache/commons/io/Charsets.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.charset.UnsupportedCharsetException; -import java.util.Collections; -import java.util.SortedMap; -import java.util.TreeMap; - -/** - * Charsets required of every implementation of the Java platform. - * - * From the Java documentation - * Standard charsets: - *

- * Every implementation of the Java platform is required to support the following character encodings. Consult - * the release documentation for your implementation to see if any other encodings are supported. Consult the release - * documentation for your implementation to see if any other encodings are supported. - *

- * - *
    - *
  • {@code US-ASCII}
    - * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
  • - *
  • {@code ISO-8859-1}
    - * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
  • - *
  • {@code UTF-8}
    - * Eight-bit Unicode Transformation Format.
  • - *
  • {@code UTF-16BE}
    - * Sixteen-bit Unicode Transformation Format, big-endian byte order.
  • - *
  • {@code UTF-16LE}
    - * Sixteen-bit Unicode Transformation Format, little-endian byte order.
  • - *
  • {@code UTF-16}
    - * 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.)
  • - *
- * - * @see Standard charsets - * @since 2.3 - */ -public class Charsets { - - // - // This class should only contain Charset instances for required encodings. This guarantees that it will load - // correctly and without delay on all Java platforms. - // - - private static final SortedMap STANDARD_CHARSET_MAP; - - static { - final SortedMap standardCharsetMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - standardCharsetMap.put(StandardCharsets.ISO_8859_1.name(), StandardCharsets.ISO_8859_1); - standardCharsetMap.put(StandardCharsets.US_ASCII.name(), StandardCharsets.US_ASCII); - standardCharsetMap.put(StandardCharsets.UTF_16.name(), StandardCharsets.UTF_16); - standardCharsetMap.put(StandardCharsets.UTF_16BE.name(), StandardCharsets.UTF_16BE); - standardCharsetMap.put(StandardCharsets.UTF_16LE.name(), StandardCharsets.UTF_16LE); - standardCharsetMap.put(StandardCharsets.UTF_8.name(), StandardCharsets.UTF_8); - STANDARD_CHARSET_MAP = Collections.unmodifiableSortedMap(standardCharsetMap); - } - - /** - * Constructs a sorted map from canonical charset names to charset objects required of every implementation of the - * Java platform. - *

- * From the Java documentation - * Standard charsets: - *

- * - * @return An immutable, case-insensitive map from canonical charset names to charset objects. - * @see Charset#availableCharsets() - * @since 2.5 - */ - public static SortedMap requiredCharsets() { - return STANDARD_CHARSET_MAP; - } - - /** - * Returns the given Charset or the default Charset if the given Charset is null. - * - * @param charset - * A charset or null. - * @return the given Charset or the default Charset if the given Charset is null - */ - public static Charset toCharset(final Charset charset) { - return charset == null ? Charset.defaultCharset() : charset; - } - - /** - * Returns a Charset for the named charset. If the name is null, return the default Charset. - * - * @param charsetName The name of the requested charset, may be null. - * @return a Charset for the named charset. - * @throws UnsupportedCharsetException If the named charset is unavailable (unchecked exception). - */ - public static Charset toCharset(final String charsetName) throws UnsupportedCharsetException { - return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName); - } - - /** - * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1. - *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset ISO_8859_1 = StandardCharsets.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 Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset US_ASCII = StandardCharsets.US_ASCII; - - /** - *

- * Sixteen-bit Unicode Transformation Format, The 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 Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset UTF_16 = StandardCharsets.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 Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset UTF_16BE = StandardCharsets.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 Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset UTF_16LE = StandardCharsets.UTF_16LE; - - /** - *

- * Eight-bit Unicode Transformation Format. - *

- *

- * Every implementation of the Java platform is required to support this character encoding. - *

- * - * @see Standard charsets - * @deprecated Use Java 7's {@link java.nio.charset.StandardCharsets} - */ - @Deprecated - public static final Charset UTF_8 = StandardCharsets.UTF_8; -} diff --git a/src/org/apache/commons/io/CopyUtils.java b/src/org/apache/commons/io/CopyUtils.java deleted file mode 100644 index 0e1ab2f4..00000000 --- a/src/org/apache/commons/io/CopyUtils.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; -import java.nio.charset.Charset; - -/** - * This class provides static utility methods for buffered - * copying between sources ({@code InputStream}, {@code Reader}, - * {@code String} and {@code byte[]}) and destinations - * ({@code OutputStream}, {@code Writer}, {@code String} and - * {@code byte[]}). - *

- * Unless otherwise noted, these {@code 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' {@code 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 article. - *

- * For byte-to-char methods, a {@code copy} variant allows the encoding - * to be selected (otherwise the platform default is used). We would like to - * encourage you to always specify the encoding because relying on the platform - * default can lead to unexpected results. - *

- * We don't provide special variants for the {@code copy} methods that - * let you specify the buffer size because in modern VMs the impact on speed - * seems to be minimal. We're using a default buffer size of 4 KB. - *

- * The {@code copy} methods use an internal buffer when copying. It is - * therefore advisable not to deliberately wrap the stream arguments - * to the {@code copy} methods in {@code 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 fill an internal buffer, from which further - * {@code read} requests can inexpensively get their data (until the buffer - * runs out). - *

- * However, the {@code copy} methods do the same thing, keeping an - * internal buffer, populated by - * {@link InputStream#read(byte[] b, int off, int len)} requests. Having two - * buffers (or three if the destination stream is also buffered) is pointless, - * and the unnecessary buffer management hurts performance slightly (about 3%, - * according to some simple experiments). - *

- * Behold, intrepid explorers; a map of this class: - *

- *       Method      Input               Output          Dependency
- *       ------      -----               ------          -------
- * 1     copy        InputStream         OutputStream    (primitive)
- * 2     copy        Reader              Writer          (primitive)
- *
- * 3     copy        InputStream         Writer          2
- *
- * 4     copy        Reader              OutputStream    2
- *
- * 5     copy        String              OutputStream    2
- * 6     copy        String              Writer          (trivial)
- *
- * 7     copy        byte[]              Writer          3
- * 8     copy        byte[]              OutputStream    (trivial)
- * 
- *

- * Note that only the first two methods shuffle bytes; the rest use these - * two, or (if possible) copy using native Java copy methods. As there are - * method variants to specify the encoding, each row may - * correspond to up to 2 methods. - *

- * Origin of code: Excalibur. - * - * @deprecated Use IOUtils. Will be removed in 3.0. - * Methods renamed to IOUtils.write() or IOUtils.copy(). - * Null handling behavior changed in IOUtils (null data does not - * throw NullPointerException). - */ -@Deprecated -public class CopyUtils { - - /** - * Instances should NOT be constructed in standard programming. - */ - public CopyUtils() { } - - /** - * Copies bytes from a {@code byte[]} to an {@code OutputStream}. - * @param input the byte array to read from - * @param output the {@code OutputStream} to write to - * @throws IOException In case of an I/O problem - */ - public static void copy(final byte[] input, final OutputStream output) throws IOException { - output.write(input); - } - - /** - * Copies and convert bytes from a {@code byte[]} to chars on a - * {@code Writer}. - * The platform's default encoding is used for the byte-to-char conversion. - * @param input the byte array to read from - * @param output the {@code Writer} to write to - * @throws IOException In case of an I/O problem - * @deprecated 2.5 use {@link #copy(byte[], Writer, String)} instead - */ - @Deprecated - public static void copy(final byte[] input, final Writer output) throws IOException { - final ByteArrayInputStream inputStream = new ByteArrayInputStream(input); - copy(inputStream, output); - } - - /** - * Copies and convert bytes from a {@code byte[]} to chars on a - * {@code Writer}, using the specified encoding. - * @param input the byte array to read from - * @param output the {@code 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 an I/O problem - */ - public static void copy(final byte[] input, final Writer output, final String encoding) throws IOException { - final ByteArrayInputStream inputStream = new ByteArrayInputStream(input); - copy(inputStream, output, encoding); - } - - /** - * Copies bytes from an {@code InputStream} to an - * {@code OutputStream}. - * @param input the {@code InputStream} to read from - * @param output the {@code OutputStream} to write to - * @return the number of bytes copied - * @throws IOException In case of an I/O problem - */ - public static int copy(final InputStream input, final OutputStream output) throws IOException { - final byte[] buffer = IOUtils.byteArray(); - int count = 0; - int n; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - // ---------------------------------------------------------------- - // Reader -> Writer - // ---------------------------------------------------------------- - - /** - * Copies chars from a {@code Reader} to a {@code Writer}. - * @param input the {@code Reader} to read from - * @param output the {@code Writer} to write to - * @return the number of characters copied - * @throws IOException In case of an I/O problem - */ - public static int copy( - final Reader input, - final Writer output) - throws IOException { - final char[] buffer = IOUtils.getCharArray(); - int count = 0; - int n; - while (EOF != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - // ---------------------------------------------------------------- - // InputStream -> Writer - // ---------------------------------------------------------------- - - /** - * Copies and convert bytes from an {@code InputStream} to chars on a - * {@code Writer}. - * The platform's default encoding is used for the byte-to-char conversion. - * @param input the {@code InputStream} to read from - * @param output the {@code Writer} to write to - * @throws IOException In case of an I/O problem - * @deprecated 2.5 use {@link #copy(InputStream, Writer, String)} instead - */ - @Deprecated - public static void copy( - final InputStream input, - final Writer output) - throws IOException { - // make explicit the dependency on the default encoding - final InputStreamReader in = new InputStreamReader(input, Charset.defaultCharset()); - copy(in, output); - } - - /** - * Copies and convert bytes from an {@code InputStream} to chars on a - * {@code Writer}, using the specified encoding. - * @param input the {@code InputStream} to read from - * @param output the {@code 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 an I/O problem - */ - public static void copy( - final InputStream input, - final Writer output, - final String encoding) - throws IOException { - final InputStreamReader in = new InputStreamReader(input, encoding); - copy(in, output); - } - - - // ---------------------------------------------------------------- - // Reader -> OutputStream - // ---------------------------------------------------------------- - - /** - * Serialize chars from a {@code Reader} to bytes on an - * {@code OutputStream}, and flush the {@code OutputStream}. - * Uses the default platform encoding. - * @param input the {@code Reader} to read from - * @param output the {@code OutputStream} to write to - * @throws IOException In case of an I/O problem - * @deprecated 2.5 use {@link #copy(Reader, OutputStream, String)} instead - */ - @Deprecated - public static void copy( - final Reader input, - final OutputStream output) - throws IOException { - // make explicit the dependency on the default encoding - final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset()); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - /** - * Serialize chars from a {@code Reader} to bytes on an - * {@code OutputStream}, and flush the {@code OutputStream}. - * @param input the {@code Reader} to read from - * @param output the {@code OutputStream} 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 an I/O problem - * @since 2.5 - */ - public static void copy( - final Reader input, - final OutputStream output, - final String encoding) - throws IOException { - final OutputStreamWriter out = new OutputStreamWriter(output, encoding); - copy(input, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - // ---------------------------------------------------------------- - // String -> OutputStream - // ---------------------------------------------------------------- - - /** - * Serialize chars from a {@code String} to bytes on an - * {@code OutputStream}, and - * flush the {@code OutputStream}. - * Uses the platform default encoding. - * @param input the {@code String} to read from - * @param output the {@code OutputStream} to write to - * @throws IOException In case of an I/O problem - * @deprecated 2.5 use {@link #copy(String, OutputStream, String)} instead - */ - @Deprecated - public static void copy( - final String input, - final OutputStream output) - throws IOException { - final StringReader in = new StringReader(input); - // make explicit the dependency on the default encoding - final OutputStreamWriter out = new OutputStreamWriter(output, Charset.defaultCharset()); - copy(in, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - /** - * Serialize chars from a {@code String} to bytes on an - * {@code OutputStream}, and - * flush the {@code OutputStream}. - * @param input the {@code String} to read from - * @param output the {@code OutputStream} 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 an I/O problem - * @since 2.5 - */ - public static void copy( - final String input, - final OutputStream output, - final String encoding) - throws IOException { - final StringReader in = new StringReader(input); - final OutputStreamWriter out = new OutputStreamWriter(output, encoding); - copy(in, out); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, we - // have to flush here. - out.flush(); - } - - // ---------------------------------------------------------------- - // String -> Writer - // ---------------------------------------------------------------- - - /** - * Copies chars from a {@code String} to a {@code Writer}. - * @param input the {@code String} to read from - * @param output the {@code Writer} to write to - * @throws IOException In case of an I/O problem - */ - public static void copy(final String input, final Writer output) - throws IOException { - output.write(input); - } - -} diff --git a/src/org/apache/commons/io/DirectoryWalker.java b/src/org/apache/commons/io/DirectoryWalker.java deleted file mode 100644 index d199e117..00000000 --- a/src/org/apache/commons/io/DirectoryWalker.java +++ /dev/null @@ -1,667 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Collection; -import java.util.Objects; - -import org.apache.commons.io.file.PathUtils; -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; - -/** - * Abstract class that walks through a directory hierarchy and provides subclasses with convenient hooks to add specific - * behavior. - *

- * This class operates with a {@link FileFilter} and maximum depth to limit the files and directories visited. Commons - * IO supplies many common filter implementations in the filefilter - * package. - *

- *

- * The following sections describe: - *

- * - * - *

1. Example Implementation

- * - * There are many possible extensions, for example, to delete all files and '.svn' directories, and return a list of - * deleted files: - * - *
- * public class FileCleaner extends DirectoryWalker {
- *
- *     public FileCleaner() {
- *         super();
- *     }
- *
- *     public List clean(File startDirectory) {
- *         List results = new ArrayList();
- *         walk(startDirectory, results);
- *         return results;
- *     }
- *
- *     protected boolean handleDirectory(File directory, int depth, Collection results) {
- *         // delete svn directories and then skip
- *         if (".svn".equals(directory.getName())) {
- *             directory.delete();
- *             return false;
- *         } else {
- *             return true;
- *         }
- *
- *     }
- *
- *     protected void handleFile(File file, int depth, Collection results) {
- *         // delete file and add to list of deleted
- *         file.delete();
- *         results.add(file);
- *     }
- * }
- * 
- * - *

2. Filter Example

- * - *

- * Choosing which directories and files to process can be a key aspect of using this class. This information can be - * setup in three ways, via three different constructors. - *

- *

- * The first option is to visit all directories and files. This is achieved via the no-args constructor. - *

- *

- * The second constructor option is to supply a single {@link FileFilter} that describes the files and directories to - * visit. Care must be taken with this option as the same filter is used for both directories and files. - *

- *

- * For example, if you wanted all directories which are not hidden and files which end in ".txt": - *

- * - *
- * public class FooDirectoryWalker extends DirectoryWalker {
- *     public FooDirectoryWalker(FileFilter filter) {
- *         super(filter, -1);
- *     }
- * }
- *
- * // Build up the filters and create the walker
- * // Create a filter for Non-hidden directories
- * IOFileFilter fooDirFilter = FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter,
- *     HiddenFileFilter.VISIBLE);
- *
- * // Create a filter for Files ending in ".txt"
- * IOFileFilter fooFileFilter = FileFilterUtils.andFileFilter(FileFilterUtils.fileFileFilter,
- *     FileFilterUtils.suffixFileFilter(".txt"));
- *
- * // Combine the directory and file filters using an OR condition
- * java.io.FileFilter fooFilter = FileFilterUtils.orFileFilter(fooDirFilter, fooFileFilter);
- *
- * // Use the filter to construct a DirectoryWalker implementation
- * FooDirectoryWalker walker = new FooDirectoryWalker(fooFilter);
- * 
- *

- * The third constructor option is to specify separate filters, one for directories and one for files. These are - * combined internally to form the correct {@code FileFilter}, something which is very easy to get wrong when - * attempted manually, particularly when trying to express constructs like 'any file in directories named docs'. - *

- *

- * For example, if you wanted all directories which are not hidden and files which end in ".txt": - *

- * - *
- *  public class FooDirectoryWalker extends DirectoryWalker {
- *    public FooDirectoryWalker(IOFileFilter dirFilter, IOFileFilter fileFilter) {
- *      super(dirFilter, fileFilter, -1);
- *    }
- *  }
- *
- *  // Use the filters to construct the walker
- *  FooDirectoryWalker walker = new FooDirectoryWalker(
- *    HiddenFileFilter.VISIBLE,
- *    FileFilterUtils.suffixFileFilter(".txt"),
- *  );
- * 
- *

- * This is much simpler than the previous example, and is why it is the preferred option for filtering. - *

- * - *

3. Cancellation

- * - *

- * The DirectoryWalker contains some of the logic required for cancel processing. Subclasses must complete the - * implementation. - *

- *

- * What {@code DirectoryWalker} does provide for cancellation is: - *

- *
    - *
  • {@link CancelException} which can be thrown in any of the lifecycle methods to stop processing.
  • - *
  • The {@code walk()} method traps thrown {@link CancelException} and calls the {@code handleCancelled()} - * method, providing a place for custom cancel processing.
  • - *
- *

- * Implementations need to provide: - *

- *
    - *
  • The decision logic on whether to cancel processing or not.
  • - *
  • Constructing and throwing a {@link CancelException}.
  • - *
  • Custom cancel processing in the {@code handleCancelled()} method. - *
- *

- * Two possible scenarios are envisaged for cancellation: - *

- *
    - *
  • 3.1 External / Multi-threaded - cancellation being decided/initiated by an external - * process.
  • - *
  • 3.2 Internal - cancellation being decided/initiated from within a DirectoryWalker - * implementation.
  • - *
- *

- * The following sections provide example implementations for these two different scenarios. - *

- * - *

3.1 External / Multi-threaded

- * - *

- * This example provides a public {@code cancel()} method that can be called by another thread to stop the - * processing. A typical example use-case would be a cancel button on a GUI. Calling this method sets a - * volatile flag to ensure - * it will work properly in a multi-threaded environment. The flag is returned by the {@code handleIsCancelled()} - * method, which will cause the walk to stop immediately. The {@code handleCancelled()} method will be the next, - * and last, callback method received once cancellation has occurred. - *

- * - *
- * public class FooDirectoryWalker extends DirectoryWalker {
- *
- *     private volatile boolean cancelled = false;
- *
- *     public void cancel() {
- *         cancelled = true;
- *     }
- *
- *     protected boolean handleIsCancelled(File file, int depth, Collection results) {
- *         return cancelled;
- *     }
- *
- *     protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
- *         // implement processing required when a cancellation occurs
- *     }
- * }
- * 
- * - *

3.2 Internal

- * - *

- * This shows an example of how internal cancellation processing could be implemented. Note the decision logic - * and throwing a {@link CancelException} could be implemented in any of the lifecycle methods. - *

- * - *
- * public class BarDirectoryWalker extends DirectoryWalker {
- *
- *     protected boolean handleDirectory(File directory, int depth, Collection results) throws IOException {
- *         // cancel if hidden directory
- *         if (directory.isHidden()) {
- *             throw new CancelException(file, depth);
- *         }
- *         return true;
- *     }
- *
- *     protected void handleFile(File file, int depth, Collection results) throws IOException {
- *         // cancel if read-only file
- *         if (!file.canWrite()) {
- *             throw new CancelException(file, depth);
- *         }
- *         results.add(file);
- *     }
- *
- *     protected void handleCancelled(File startDirectory, Collection results, CancelException cancel) {
- *         // implement processing required when a cancellation occurs
- *     }
- * }
- * 
- * - * @param The result type, like {@link File}. - * @since 1.3 - * @deprecated Apache Commons IO no longer uses this class. Instead, use - * {@link PathUtils#walk(java.nio.file.Path, org.apache.commons.io.file.PathFilter, int, boolean, java.nio.file.FileVisitOption...)} - * or {@link Files#walkFileTree(java.nio.file.Path, java.util.Set, int, java.nio.file.FileVisitor)}, and - * friends. - */ -@Deprecated -public abstract class DirectoryWalker { - - /** - * The file filter to use to filter files and directories. - */ - private final FileFilter filter; - /** - * The limit on the directory depth to walk. - */ - private final int depthLimit; - - /** - * Construct an instance with no filtering and unlimited depth. - */ - protected DirectoryWalker() { - this(null, -1); - } - - /** - * Constructs an instance with a filter and limit the depth navigated to. - *

- * The filter controls which files and directories will be navigated to as - * part of the walk. The {@link FileFilterUtils} class is useful for combining - * various filters together. A {@code null} filter means that no - * filtering should occur and all files and directories will be visited. - *

- * - * @param filter the filter to apply, null means visit all files - * @param depthLimit controls how deep the hierarchy is - * navigated to (less than 0 means unlimited) - */ - protected DirectoryWalker(final FileFilter filter, final int depthLimit) { - this.filter = filter; - this.depthLimit = depthLimit; - } - - /** - * Constructs an instance with a directory and a file filter and an optional - * limit on the depth navigated to. - *

- * The filters control which files and directories will be navigated to as part - * of the walk. This constructor uses {@link FileFilterUtils#makeDirectoryOnly(IOFileFilter)} - * and {@link FileFilterUtils#makeFileOnly(IOFileFilter)} internally to combine the filters. - * A {@code null} filter means that no filtering should occur. - *

- * - * @param directoryFilter the filter to apply to directories, null means visit all directories - * @param fileFilter the filter to apply to files, null means visit all files - * @param depthLimit controls how deep the hierarchy is - * navigated to (less than 0 means unlimited) - */ - protected DirectoryWalker(IOFileFilter directoryFilter, IOFileFilter fileFilter, final int depthLimit) { - if (directoryFilter == null && fileFilter == null) { - this.filter = null; - } else { - directoryFilter = directoryFilter != null ? directoryFilter : TrueFileFilter.TRUE; - fileFilter = fileFilter != null ? fileFilter : TrueFileFilter.TRUE; - directoryFilter = FileFilterUtils.makeDirectoryOnly(directoryFilter); - fileFilter = FileFilterUtils.makeFileOnly(fileFilter); - this.filter = directoryFilter.or(fileFilter); - } - this.depthLimit = depthLimit; - } - - /** - * Internal method that walks the directory hierarchy in a depth-first manner. - *

- * Users of this class do not need to call this method. This method will - * be called automatically by another (public) method on the specific subclass. - *

- *

- * Writers of subclasses should call this method to start the directory walk. - * Once called, this method will emit events as it walks the hierarchy. - * The event methods have the prefix {@code handle}. - *

- * - * @param startDirectory the directory to start from, not null - * @param results the collection of result objects, may be updated - * @throws NullPointerException if the start directory is null - * @throws IOException if an I/O Error occurs - */ - protected final void walk(final File startDirectory, final Collection results) throws IOException { - Objects.requireNonNull(startDirectory, "startDirectory"); - try { - handleStart(startDirectory, results); - walk(startDirectory, 0, results); - handleEnd(results); - } catch(final CancelException cancel) { - handleCancelled(startDirectory, results, cancel); - } - } - - /** - * Main recursive method to examine the directory hierarchy. - * - * @param directory the directory to examine, not null - * @param depth the directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - private void walk(final File directory, final int depth, final Collection results) throws IOException { - checkIfCancelled(directory, depth, results); - if (handleDirectory(directory, depth, results)) { - handleDirectoryStart(directory, depth, results); - final int childDepth = depth + 1; - if (depthLimit < 0 || childDepth <= depthLimit) { - checkIfCancelled(directory, depth, results); - File[] childFiles = filter == null ? directory.listFiles() : directory.listFiles(filter); - childFiles = filterDirectoryContents(directory, depth, childFiles); - if (childFiles == null) { - handleRestricted(directory, childDepth, results); - } else { - for (final File childFile : childFiles) { - if (childFile.isDirectory()) { - walk(childFile, childDepth, results); - } else { - checkIfCancelled(childFile, childDepth, results); - handleFile(childFile, childDepth, results); - checkIfCancelled(childFile, childDepth, results); - } - } - } - } - handleDirectoryEnd(directory, depth, results); - } - checkIfCancelled(directory, depth, results); - } - - /** - * Checks whether the walk has been cancelled by calling {@link #handleIsCancelled}, - * throwing a {@code CancelException} if it has. - *

- * Writers of subclasses should not normally call this method as it is called - * automatically by the walk of the tree. However, sometimes a single method, - * typically {@link #handleFile}, may take a long time to run. In that case, - * you may wish to check for cancellation by calling this method. - *

- * - * @param file the current file being processed - * @param depth the current file level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - protected final void checkIfCancelled(final File file, final int depth, final Collection results) throws - IOException { - if (handleIsCancelled(file, depth, results)) { - throw new CancelException(file, depth); - } - } - - /** - * Overridable callback method invoked to determine if the entire walk - * operation should be immediately cancelled. - *

- * This method should be implemented by those subclasses that want to - * provide a public {@code cancel()} method available from another - * thread. The design pattern for the subclass should be as follows: - *

- *
-     *  public class FooDirectoryWalker extends DirectoryWalker {
-     *    private volatile boolean cancelled = false;
-     *
-     *    public void cancel() {
-     *        cancelled = true;
-     *    }
-     *    private void handleIsCancelled(File file, int depth, Collection results) {
-     *        return cancelled;
-     *    }
-     *    protected void handleCancelled(File startDirectory,
-     *              Collection results, CancelException cancel) {
-     *        // implement processing required when a cancellation occurs
-     *    }
-     *  }
-     * 
- *

- * If this method returns true, then the directory walk is immediately - * cancelled. The next callback method will be {@link #handleCancelled}. - *

- *

- * This implementation returns false. - *

- * - * @param file the file or directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @return true if the walk has been cancelled - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected boolean handleIsCancelled( - final File file, final int depth, final Collection results) throws IOException { - // do nothing - overridable by subclass - return false; // not cancelled - } - - /** - * Overridable callback method invoked when the operation is cancelled. - * The file being processed when the cancellation occurred can be - * obtained from the exception. - *

- * This implementation just re-throws the {@link CancelException}. - *

- * - * @param startDirectory the directory that the walk started from - * @param results the collection of result objects, may be updated - * @param cancel the exception throw to cancel further processing - * containing details at the point of cancellation. - * @throws IOException if an I/O Error occurs - */ - protected void handleCancelled(final File startDirectory, final Collection results, - final CancelException cancel) throws IOException { - // re-throw exception - overridable by subclass - throw cancel; - } - - /** - * Overridable callback method invoked at the start of processing. - *

- * This implementation does nothing. - *

- * - * @param startDirectory the directory to start from - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleStart(final File startDirectory, final Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked to determine if a directory should be processed. - *

- * This method returns a boolean to indicate if the directory should be examined or not. - * If you return false, the entire directory and any subdirectories will be skipped. - * Note that this functionality is in addition to the filtering by file filter. - *

- *

- * This implementation does nothing and returns true. - *

- * - * @param directory the current directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @return true to process this directory, false to skip this directory - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected boolean handleDirectory(final File directory, final int depth, final Collection results) throws - IOException { - // do nothing - overridable by subclass - return true; // process directory - } - - /** - * Overridable callback method invoked at the start of processing each directory. - *

- * This implementation does nothing. - *

- * - * @param directory the current directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleDirectoryStart(final File directory, final int depth, final Collection results) throws - IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked with the contents of each directory. - *

- * This implementation returns the files unchanged - *

- * - * @param directory the current directory being processed - * @param depth the current directory level (starting directory = 0) - * @param files the files (possibly filtered) in the directory, may be {@code null} - * @return the filtered list of files - * @throws IOException if an I/O Error occurs - * @since 2.0 - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected File[] filterDirectoryContents(final File directory, final int depth, final File... files) throws - IOException { - return files; - } - - /** - * Overridable callback method invoked for each (non-directory) file. - *

- * This implementation does nothing. - *

- * - * @param file the current file being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleFile(final File file, final int depth, final Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked for each restricted directory. - *

- * This implementation does nothing. - *

- * - * @param directory the restricted directory - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleRestricted(final File directory, final int depth, final Collection results) throws - IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked at the end of processing each directory. - *

- * This implementation does nothing. - *

- * - * @param directory the directory being processed - * @param depth the current directory level (starting directory = 0) - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) throws - IOException { - // do nothing - overridable by subclass - } - - /** - * Overridable callback method invoked at the end of processing. - *

- * This implementation does nothing. - *

- * - * @param results the collection of result objects, may be updated - * @throws IOException if an I/O Error occurs - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void handleEnd(final Collection results) throws IOException { - // do nothing - overridable by subclass - } - - /** - * CancelException is thrown in DirectoryWalker to cancel the current - * processing. - */ - public static class CancelException extends IOException { - - /** Serialization id. */ - private static final long serialVersionUID = 1347339620135041008L; - - /** The file being processed when the exception was thrown. */ - private final File file; - /** The file depth when the exception was thrown. */ - private final int depth; - - /** - * Constructs a {@code CancelException} with - * the file and depth when cancellation occurred. - * - * @param file the file when the operation was cancelled, may be null - * @param depth the depth when the operation was cancelled, may be null - */ - public CancelException(final File file, final int depth) { - this("Operation Cancelled", file, depth); - } - - /** - * Constructs a {@code CancelException} with - * an appropriate message and the file and depth when - * cancellation occurred. - * - * @param message the detail message - * @param file the file when the operation was cancelled - * @param depth the depth when the operation was cancelled - */ - public CancelException(final String message, final File file, final int depth) { - super(message); - this.file = file; - this.depth = depth; - } - - /** - * Returns the file when the operation was cancelled. - * - * @return the file when the operation was cancelled - */ - public File getFile() { - return file; - } - - /** - * Returns the depth when the operation was cancelled. - * - * @return the depth when the operation was cancelled - */ - public int getDepth() { - return depth; - } - } -} diff --git a/src/org/apache/commons/io/EndianUtils.java b/src/org/apache/commons/io/EndianUtils.java deleted file mode 100644 index 849f86ba..00000000 --- a/src/org/apache/commons/io/EndianUtils.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Utility code for dealing with different endian systems. - *

- * Different computer architectures adopt different conventions for - * byte ordering. In so-called "Little Endian" architectures (eg Intel), - * the low-order byte is stored in memory at the lowest address, and - * subsequent bytes at higher addresses. For "Big Endian" architectures - * (eg Motorola), the situation is reversed. - * This class helps you solve this incompatibility. - *

- * Origin of code: Excalibur - * - * @see org.apache.commons.io.input.SwappedDataInputStream - */ -public class EndianUtils { - - /** - * Instances should NOT be constructed in standard programming. - */ - public EndianUtils() { - } - - // ========================================== Swapping routines - - /** - * Converts a "short" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static short swapShort(final short value) { - return (short) ( ( ( ( value >> 0 ) & 0xff ) << 8 ) + - ( ( ( value >> 8 ) & 0xff ) << 0 ) ); - } - - /** - * Converts a "int" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static int swapInteger(final int value) { - return - ( ( ( value >> 0 ) & 0xff ) << 24 ) + - ( ( ( value >> 8 ) & 0xff ) << 16 ) + - ( ( ( value >> 16 ) & 0xff ) << 8 ) + - ( ( ( value >> 24 ) & 0xff ) << 0 ); - } - - /** - * Converts a "long" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static long swapLong(final long value) { - return - ( ( ( value >> 0 ) & 0xff ) << 56 ) + - ( ( ( value >> 8 ) & 0xff ) << 48 ) + - ( ( ( value >> 16 ) & 0xff ) << 40 ) + - ( ( ( value >> 24 ) & 0xff ) << 32 ) + - ( ( ( value >> 32 ) & 0xff ) << 24 ) + - ( ( ( value >> 40 ) & 0xff ) << 16 ) + - ( ( ( value >> 48 ) & 0xff ) << 8 ) + - ( ( ( value >> 56 ) & 0xff ) << 0 ); - } - - /** - * Converts a "float" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static float swapFloat(final float value) { - return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) ); - } - - /** - * Converts a "double" value between endian systems. - * @param value value to convert - * @return the converted value - */ - public static double swapDouble(final double value) { - return Double.longBitsToDouble( swapLong( Double.doubleToLongBits( value ) ) ); - } - - // ========================================== Swapping read/write routines - - /** - * Writes a "short" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedShort(final byte[] data, final int offset, final short value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - } - - /** - * Reads a "short" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static short readSwappedShort(final byte[] data, final int offset) { - return (short)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) ); - } - - /** - * Reads an unsigned short (16-bit) value from a byte array at a given - * offset. The value is converted to the opposed endian system while - * reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static int readSwappedUnsignedShort(final byte[] data, final int offset) { - return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) ); - } - - /** - * Writes a "int" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedInteger(final byte[] data, final int offset, final int value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff ); - data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff ); - } - - /** - * Reads a "int" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static int readSwappedInteger(final byte[] data, final int offset) { - return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) + - ( ( data[ offset + 2 ] & 0xff ) << 16 ) + - ( ( data[ offset + 3 ] & 0xff ) << 24 ) ); - } - - /** - * Reads an unsigned integer (32-bit) value from a byte array at a given - * offset. The value is converted to the opposed endian system while - * reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static long readSwappedUnsignedInteger(final byte[] data, final int offset) { - final long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + - ( ( data[ offset + 1 ] & 0xff ) << 8 ) + - ( ( data[ offset + 2 ] & 0xff ) << 16 ) ); - - final long high = data[ offset + 3 ] & 0xff; - - return (high << 24) + (0xffffffffL & low); - } - - /** - * Writes a "long" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedLong(final byte[] data, final int offset, final long value) { - data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff ); - data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff ); - data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff ); - data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff ); - data[ offset + 4 ] = (byte)( ( value >> 32 ) & 0xff ); - data[ offset + 5 ] = (byte)( ( value >> 40 ) & 0xff ); - data[ offset + 6 ] = (byte)( ( value >> 48 ) & 0xff ); - data[ offset + 7 ] = (byte)( ( value >> 56 ) & 0xff ); - } - - /** - * Reads a "long" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static long readSwappedLong(final byte[] data, final int offset) { - final long low = readSwappedInteger(data, offset); - final long high = readSwappedInteger(data, offset + 4); - return (high << 32) + (0xffffffffL & low); - } - - /** - * Writes a "float" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedFloat(final byte[] data, final int offset, final float value) { - writeSwappedInteger( data, offset, Float.floatToIntBits( value ) ); - } - - /** - * Reads a "float" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static float readSwappedFloat(final byte[] data, final int offset) { - return Float.intBitsToFloat( readSwappedInteger( data, offset ) ); - } - - /** - * Writes a "double" value to a byte array at a given offset. The value is - * converted to the opposed endian system while writing. - * @param data target byte array - * @param offset starting offset in the byte array - * @param value value to write - */ - public static void writeSwappedDouble(final byte[] data, final int offset, final double value) { - writeSwappedLong( data, offset, Double.doubleToLongBits( value ) ); - } - - /** - * Reads a "double" value from a byte array at a given offset. The value is - * converted to the opposed endian system while reading. - * @param data source byte array - * @param offset starting offset in the byte array - * @return the value read - */ - public static double readSwappedDouble(final byte[] data, final int offset) { - return Double.longBitsToDouble( readSwappedLong( data, offset ) ); - } - - /** - * Writes a "short" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedShort(final OutputStream output, final short value) throws IOException { - output.write((byte) ((value >> 0) & 0xff)); - output.write((byte) ((value >> 8) & 0xff)); - } - - /** - * Reads a "short" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static short readSwappedShort(final InputStream input) throws IOException { - return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8)); - } - - /** - * Reads a unsigned short (16-bit) from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static int readSwappedUnsignedShort(final InputStream input) throws IOException { - final int value1 = read(input); - final int value2 = read(input); - - return (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8)); - } - - /** - * Writes a "int" value to an OutputStream. The value is converted to the opposed endian system while writing. - * - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException { - output.write((byte) ((value >> 0) & 0xff)); - output.write((byte) ((value >> 8) & 0xff)); - output.write((byte) ((value >> 16) & 0xff)); - output.write((byte) ((value >> 24) & 0xff)); - } - - /** - * Reads a "int" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static int readSwappedInteger(final InputStream input) throws IOException { - final int value1 = read(input); - final int value2 = read(input); - final int value3 = read(input); - final int value4 = read(input); - - return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24); - } - - /** - * Reads a unsigned integer (32-bit) from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static long readSwappedUnsignedInteger(final InputStream input) throws IOException { - final int value1 = read(input); - final int value2 = read(input); - final int value3 = read(input); - final int value4 = read(input); - - final long low = (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16)); - - final long high = value4 & 0xff; - - return (high << 24) + (0xffffffffL & low); - } - - /** - * Writes a "long" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedLong(final OutputStream output, final long value) throws IOException { - output.write((byte) ((value >> 0) & 0xff)); - output.write((byte) ((value >> 8) & 0xff)); - output.write((byte) ((value >> 16) & 0xff)); - output.write((byte) ((value >> 24) & 0xff)); - output.write((byte) ((value >> 32) & 0xff)); - output.write((byte) ((value >> 40) & 0xff)); - output.write((byte) ((value >> 48) & 0xff)); - output.write((byte) ((value >> 56) & 0xff)); - } - - /** - * Reads a "long" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static long readSwappedLong(final InputStream input) throws IOException { - final byte[] bytes = new byte[8]; - for (int i = 0; i < 8; i++) { - bytes[i] = (byte) read(input); - } - return readSwappedLong(bytes, 0); - } - - /** - * Writes a "float" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedFloat(final OutputStream output, final float value) throws IOException { - writeSwappedInteger(output, Float.floatToIntBits(value)); - } - - /** - * Reads a "float" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static float readSwappedFloat(final InputStream input) throws IOException { - return Float.intBitsToFloat(readSwappedInteger(input)); - } - - /** - * Writes a "double" value to an OutputStream. The value is - * converted to the opposed endian system while writing. - * @param output target OutputStream - * @param value value to write - * @throws IOException in case of an I/O problem - */ - public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException { - writeSwappedLong(output, Double.doubleToLongBits(value)); - } - - /** - * Reads a "double" value from an InputStream. The value is - * converted to the opposed endian system while reading. - * @param input source InputStream - * @return the value just read - * @throws IOException in case of an I/O problem - */ - public static double readSwappedDouble(final InputStream input) throws IOException { - return Double.longBitsToDouble(readSwappedLong(input)); - } - - /** - * Reads the next byte from the input stream. - * @param input the stream - * @return the byte - * @throws IOException if the end of file is reached - */ - private static int read(final InputStream input) throws IOException { - final int value = input.read(); - - if (EOF == value) { - throw new EOFException("Unexpected EOF reached"); - } - - return value; - } -} diff --git a/src/org/apache/commons/io/FileCleaner.java b/src/org/apache/commons/io/FileCleaner.java deleted file mode 100644 index 43c3cf2f..00000000 --- a/src/org/apache/commons/io/FileCleaner.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; - -/** - * Keeps track of files awaiting deletion, and deletes them when an associated - * marker object is reclaimed by the garbage collector. - *

- * This utility creates a background thread to handle file deletion. - * Each file to be deleted is registered with a handler object. - * When the handler object is garbage collected, the file is deleted. - *

- * In an environment with multiple class loaders (a servlet container, for - * example), you should consider stopping the background thread if it is no - * longer needed. This is done by invoking the method - * {@link #exitWhenFinished}, typically in - * {@code javax.servlet.ServletContextListener.contextDestroyed(javax.servlet.ServletContextEvent)} or similar. - * - * @deprecated Use {@link FileCleaningTracker} - */ -@Deprecated -public class FileCleaner { - /** - * The instance to use for the deprecated, static methods. - */ - static final FileCleaningTracker theInstance = new FileCleaningTracker(); - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the file is null - * @deprecated Use {@link FileCleaningTracker#track(File, Object)}. - */ - @Deprecated - public static void track(final File file, final Object marker) { - theInstance.track(file, marker); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The specified deletion strategy is used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the file is null - * @deprecated Use {@link FileCleaningTracker#track(File, Object, FileDeleteStrategy)}. - */ - @Deprecated - public static void track(final File file, final Object marker, final FileDeleteStrategy deleteStrategy) { - theInstance.track(file, marker, deleteStrategy); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the path is null - * @deprecated Use {@link FileCleaningTracker#track(String, Object)}. - */ - @Deprecated - public static void track(final String path, final Object marker) { - theInstance.track(path, marker); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The specified deletion strategy is used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the path is null - * @deprecated Use {@link FileCleaningTracker#track(String, Object, FileDeleteStrategy)}. - */ - @Deprecated - public static void track(final String path, final Object marker, final FileDeleteStrategy deleteStrategy) { - theInstance.track(path, marker, deleteStrategy); - } - - /** - * Retrieve the number of files currently being tracked, and therefore - * awaiting deletion. - * - * @return the number of files being tracked - * @deprecated Use {@link FileCleaningTracker#getTrackCount()}. - */ - @Deprecated - public static int getTrackCount() { - return theInstance.getTrackCount(); - } - - /** - * Call this method to cause the file cleaner thread to terminate when - * there are no more objects being tracked for deletion. - *

- * In a simple environment, you don't need this method as the file cleaner - * thread will simply exit when the JVM exits. In a more complex environment, - * with multiple class loaders (such as an application server), you should be - * aware that the file cleaner thread will continue running even if the class - * loader it was started from terminates. This can constitute a memory leak. - *

- * For example, suppose that you have developed a web application, which - * contains the commons-io jar file in your WEB-INF/lib directory. In other - * words, the FileCleaner class is loaded through the class loader of your - * web application. If the web application is terminated, but the servlet - * container is still running, then the file cleaner thread will still exist, - * posing a memory leak. - *

- * This method allows the thread to be terminated. Simply call this method - * in the resource cleanup code, such as - * {@code javax.servlet.ServletContextListener.contextDestroyed(javax.servlet.ServletContextEvent)}. - * One called, no new objects can be tracked by the file cleaner. - * @deprecated Use {@link FileCleaningTracker#exitWhenFinished()}. - */ - @Deprecated - public static synchronized void exitWhenFinished() { - theInstance.exitWhenFinished(); - } - - /** - * Returns the singleton instance, which is used by the deprecated, static methods. - * This is mainly useful for code, which wants to support the new - * {@link FileCleaningTracker} class while maintain compatibility with the - * deprecated {@link FileCleaner}. - * - * @return the singleton instance - */ - public static FileCleaningTracker getInstance() { - return theInstance; - } -} diff --git a/src/org/apache/commons/io/FileCleaningTracker.java b/src/org/apache/commons/io/FileCleaningTracker.java deleted file mode 100644 index 70fedb85..00000000 --- a/src/org/apache/commons/io/FileCleaningTracker.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.lang.ref.PhantomReference; -import java.lang.ref.ReferenceQueue; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; - -/** - * Keeps track of files awaiting deletion, and deletes them when an associated - * marker object is reclaimed by the garbage collector. - *

- * This utility creates a background thread to handle file deletion. - * Each file to be deleted is registered with a handler object. - * When the handler object is garbage collected, the file is deleted. - *

- * In an environment with multiple class loaders (a servlet container, for - * example), you should consider stopping the background thread if it is no - * longer needed. This is done by invoking the method - * {@link #exitWhenFinished}, typically in - * {@code javax.servlet.ServletContextListener.contextDestroyed(javax.servlet.ServletContextEvent)} or similar. - * - */ -public class FileCleaningTracker { - - // Note: fields are package protected to allow use by test cases - - /** - * Queue of {@code Tracker} instances being watched. - */ - ReferenceQueue q = new ReferenceQueue<>(); - /** - * Collection of {@code Tracker} instances in existence. - */ - final Collection trackers = Collections.synchronizedSet(new HashSet<>()); // synchronized - /** - * Collection of File paths that failed to delete. - */ - final List deleteFailures = Collections.synchronizedList(new ArrayList<>()); - /** - * Whether to terminate the thread when the tracking is complete. - */ - volatile boolean exitWhenFinished; - /** - * The thread that will clean up registered files. - */ - Thread reaper; - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the file is null - */ - public void track(final File file, final Object marker) { - track(file, marker, null); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The specified deletion strategy is used. - * - * @param file the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the file is null - */ - public void track(final File file, final Object marker, final FileDeleteStrategy deleteStrategy) { - Objects.requireNonNull(file, "file"); - addTracker(file.getPath(), marker, deleteStrategy); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @throws NullPointerException if the path is null - */ - public void track(final String path, final Object marker) { - track(path, marker, null); - } - - /** - * Track the specified file, using the provided marker, deleting the file - * when the marker instance is garbage collected. - * The specified deletion strategy is used. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @throws NullPointerException if the path is null - */ - public void track(final String path, final Object marker, final FileDeleteStrategy deleteStrategy) { - Objects.requireNonNull(path, "path"); - addTracker(path, marker, deleteStrategy); - } - - /** - * Adds a tracker to the list of trackers. - * - * @param path the full path to the file to be tracked, not null - * @param marker the marker object used to track the file, not null - * @param deleteStrategy the strategy to delete the file, null means normal - */ - private synchronized void addTracker(final String path, final Object marker, final FileDeleteStrategy - deleteStrategy) { - // synchronized block protects reaper - if (exitWhenFinished) { - throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called"); - } - if (reaper == null) { - reaper = new Reaper(); - reaper.start(); - } - trackers.add(new Tracker(path, deleteStrategy, marker, q)); - } - - /** - * Retrieve the number of files currently being tracked, and therefore - * awaiting deletion. - * - * @return the number of files being tracked - */ - public int getTrackCount() { - return trackers.size(); - } - - /** - * Return the file paths that failed to delete. - * - * @return the file paths that failed to delete - * @since 2.0 - */ - public List getDeleteFailures() { - return deleteFailures; - } - - /** - * Call this method to cause the file cleaner thread to terminate when - * there are no more objects being tracked for deletion. - *

- * In a simple environment, you don't need this method as the file cleaner - * thread will simply exit when the JVM exits. In a more complex environment, - * with multiple class loaders (such as an application server), you should be - * aware that the file cleaner thread will continue running even if the class - * loader it was started from terminates. This can constitute a memory leak. - *

- * For example, suppose that you have developed a web application, which - * contains the commons-io jar file in your WEB-INF/lib directory. In other - * words, the FileCleaner class is loaded through the class loader of your - * web application. If the web application is terminated, but the servlet - * container is still running, then the file cleaner thread will still exist, - * posing a memory leak. - *

- * This method allows the thread to be terminated. Simply call this method - * in the resource cleanup code, such as - * {@code javax.servlet.ServletContextListener.contextDestroyed(javax.servlet.ServletContextEvent)}. - * Once called, no new objects can be tracked by the file cleaner. - */ - public synchronized void exitWhenFinished() { - // synchronized block protects reaper - exitWhenFinished = true; - if (reaper != null) { - synchronized (reaper) { - reaper.interrupt(); - } - } - } - - /** - * The reaper thread. - */ - private final class Reaper extends Thread { - /** Construct a new Reaper */ - Reaper() { - super("File Reaper"); - setPriority(Thread.MAX_PRIORITY); - setDaemon(true); - } - - /** - * Run the reaper thread that will delete files as their associated - * marker objects are reclaimed by the garbage collector. - */ - @Override - public void run() { - // thread exits when exitWhenFinished is true and there are no more tracked objects - while (!exitWhenFinished || !trackers.isEmpty()) { - try { - // Wait for a tracker to remove. - final Tracker tracker = (Tracker) q.remove(); // cannot return null - trackers.remove(tracker); - if (!tracker.delete()) { - deleteFailures.add(tracker.getPath()); - } - tracker.clear(); - } catch (final InterruptedException e) { - continue; - } - } - } - } - - /** - * Inner class which acts as the reference for a file pending deletion. - */ - private static final class Tracker extends PhantomReference { - - /** - * The full path to the file being tracked. - */ - private final String path; - /** - * The strategy for deleting files. - */ - private final FileDeleteStrategy deleteStrategy; - - /** - * Constructs an instance of this class from the supplied parameters. - * - * @param path the full path to the file to be tracked, not null - * @param deleteStrategy the strategy to delete the file, null means normal - * @param marker the marker object used to track the file, not null - * @param queue the queue on to which the tracker will be pushed, not null - */ - Tracker(final String path, final FileDeleteStrategy deleteStrategy, final Object marker, - final ReferenceQueue queue) { - super(marker, queue); - this.path = path; - this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy; - } - - /** - * Return the path. - * - * @return the path - */ - public String getPath() { - return path; - } - - /** - * Deletes the file associated with this tracker instance. - * - * @return {@code true} if the file was deleted successfully; - * {@code false} otherwise. - */ - public boolean delete() { - return deleteStrategy.deleteQuietly(new File(path)); - } - } - -} diff --git a/src/org/apache/commons/io/FileDeleteStrategy.java b/src/org/apache/commons/io/FileDeleteStrategy.java deleted file mode 100644 index 7a072780..00000000 --- a/src/org/apache/commons/io/FileDeleteStrategy.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.IOException; - -/** - * Strategy for deleting files. - *

- * There is more than one way to delete a file. - * You may want to limit access to certain directories, to only delete - * directories if they are empty, or maybe to force deletion. - *

- *

- * This class captures the strategy to use and is designed for user subclassing. - *

- * - * @since 1.3 - */ -public class FileDeleteStrategy { - - /** - * Force file deletion strategy. - */ - static class ForceFileDeleteStrategy extends FileDeleteStrategy { - /** Default Constructor */ - ForceFileDeleteStrategy() { - super("Force"); - } - - /** - * Deletes the file object. - *

- * This implementation uses {@code FileUtils.forceDelete()} - * if the file exists. - *

- * - * @param fileToDelete the file to delete, not null - * @return Always returns {@code true} - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - @Override - protected boolean doDelete(final File fileToDelete) throws IOException { - FileUtils.forceDelete(fileToDelete); - return true; - } - } - - /** - * The singleton instance for normal file deletion, which does not permit - * the deletion of directories that are not empty. - */ - public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal"); - - /** - * The singleton instance for forced file deletion, which always deletes, - * even if the file represents a non-empty directory. - */ - public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy(); - - /** The name of the strategy. */ - private final String name; - - /** - * Restricted constructor. - * - * @param name the name by which the strategy is known - */ - protected FileDeleteStrategy(final String name) { - this.name = name; - } - - /** - * Deletes the file object, which may be a file or a directory. - * If the file does not exist, the method just returns. - *

- * Subclass writers should override {@link #doDelete(File)}, not this method. - *

- * - * @param fileToDelete the file to delete, not null - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - public void delete(final File fileToDelete) throws IOException { - if (fileToDelete.exists() && !doDelete(fileToDelete)) { - throw new IOException("Deletion failed: " + fileToDelete); - } - } - - /** - * Deletes the file object, which may be a file or a directory. - * All {@code IOException}s are caught and false returned instead. - * If the file does not exist or is null, true is returned. - *

- * Subclass writers should override {@link #doDelete(File)}, not this method. - *

- * - * @param fileToDelete the file to delete, null returns true - * @return true if the file was deleted, or there was no such file - */ - public boolean deleteQuietly(final File fileToDelete) { - if (fileToDelete == null || !fileToDelete.exists()) { - return true; - } - try { - return doDelete(fileToDelete); - } catch (final IOException ex) { - return false; - } - } - - /** - * Actually deletes the file object, which may be a file or a directory. - *

- * This method is designed for subclasses to override. - * The implementation may return either false or an {@code IOException} - * when deletion fails. The {@link #delete(File)} and {@link #deleteQuietly(File)} - * methods will handle either response appropriately. - * A check has been made to ensure that the file will exist. - *

- *

- * This implementation uses {@link FileUtils#delete(File)}. - *

- * - * @param file the file to delete, exists, not null - * @return true if the file was deleted - * @throws NullPointerException if the file is null - * @throws IOException if an error occurs during file deletion - */ - protected boolean doDelete(final File file) throws IOException { - FileUtils.delete(file); - return true; - } - - /** - * Gets a string describing the delete strategy. - * - * @return a string describing the delete strategy - */ - @Override - public String toString() { - return "FileDeleteStrategy[" + name + "]"; - } - -} diff --git a/src/org/apache/commons/io/FileExistsException.java b/src/org/apache/commons/io/FileExistsException.java deleted file mode 100644 index ef95eaf2..00000000 --- a/src/org/apache/commons/io/FileExistsException.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.io.IOException; - -/** - * Indicates that a file already exists. - * - * @since 2.0 - */ -public class FileExistsException extends IOException { - - /** - * Defines the serial version UID. - */ - private static final long serialVersionUID = 1L; - - /** - * Default Constructor. - */ - public FileExistsException() { - } - - /** - * Construct an instance with the specified message. - * - * @param message The error message - */ - public FileExistsException(final String message) { - super(message); - } - - /** - * Construct an instance with the specified file. - * - * @param file The file that exists - */ - public FileExistsException(final File file) { - super("File " + file + " exists"); - } - -} diff --git a/src/org/apache/commons/io/FileSystem.java b/src/org/apache/commons/io/FileSystem.java deleted file mode 100644 index dadf7192..00000000 --- a/src/org/apache/commons/io/FileSystem.java +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.util.Arrays; -import java.util.Locale; -import java.util.Objects; - -/** - * Abstracts an OS' file system details, currently supporting the single use case of converting a file name String to a - * legal file name with {@link #toLegalFileName(String, char)}. - *

- * The starting point of any operation is {@link #getCurrent()} which gets you the enum for the file system that matches - * the OS hosting the running JVM. - *

- * - * @since 2.7 - */ -public enum FileSystem { - - /** - * Generic file system. - */ - GENERIC(false, false, Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] { 0 }, new String[] {}, false), - - /** - * Linux file system. - */ - LINUX(true, true, 255, 4096, new char[] { - // KEEP THIS ARRAY SORTED! - // @formatter:off - // ASCII NUL - 0, - '/' - // @formatter:on - }, new String[] {}, false), - - /** - * MacOS file system. - */ - MAC_OSX(true, true, 255, 1024, new char[] { - // KEEP THIS ARRAY SORTED! - // @formatter:off - // ASCII NUL - 0, - '/', - ':' - // @formatter:on - }, new String[] {}, false), - - /** - * Windows file system. - *

- * The reserved characters are defined in the - * Naming Conventions - * (microsoft.com). - *

- * - * @see Naming Conventions - * (microsoft.com) - */ - WINDOWS(false, true, 255, - 32000, new char[] { - // KEEP THIS ARRAY SORTED! - // @formatter:off - // ASCII NUL - 0, - // 1-31 may be allowed in file streams - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, - '"', '*', '/', ':', '<', '>', '?', '\\', '|' - // @formatter:on - }, // KEEP THIS ARRAY SORTED! - new String[] { "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "CON", "LPT1", - "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "NUL", "PRN" }, true); - - /** - *

- * Is {@code true} if this is Linux. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- */ - private static final boolean IS_OS_LINUX = getOsMatchesName("Linux"); - - /** - *

- * Is {@code true} if this is Mac. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- */ - private static final boolean IS_OS_MAC = getOsMatchesName("Mac"); - - /** - * The prefix String for all Windows OS. - */ - private static final String OS_NAME_WINDOWS_PREFIX = "Windows"; - - /** - *

- * Is {@code true} if this is Windows. - *

- *

- * The field will return {@code false} if {@code OS_NAME} is {@code null}. - *

- */ - private static final boolean IS_OS_WINDOWS = getOsMatchesName(OS_NAME_WINDOWS_PREFIX); - - /** - * Gets the current file system. - * - * @return the current file system - */ - public static FileSystem getCurrent() { - if (IS_OS_LINUX) { - return LINUX; - } - if (IS_OS_MAC) { - return FileSystem.MAC_OSX; - } - if (IS_OS_WINDOWS) { - return FileSystem.WINDOWS; - } - return GENERIC; - } - - /** - * Decides if the operating system matches. - * - * @param osNamePrefix - * the prefix for the os name - * @return true if matches, or false if not or can't determine - */ - private static boolean getOsMatchesName(final String osNamePrefix) { - return isOsNameMatch(getSystemProperty("os.name"), osNamePrefix); - } - - /** - *

- * Gets a System property, defaulting to {@code null} if the property cannot be read. - *

- *

- * If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to - * {@code System.err}. - *

- * - * @param property - * the system property name - * @return the system property value or {@code null} if a security problem occurs - */ - private static String getSystemProperty(final String property) { - try { - return System.getProperty(property); - } catch (final SecurityException ex) { - // we are not allowed to look at this property - System.err.println("Caught a SecurityException reading the system property '" + property - + "'; the SystemUtils property value will default to null."); - return null; - } - } - - /** - * Decides if the operating system matches. - *

- * This method is package private instead of private to support unit test invocation. - *

- * - * @param osName - * the actual OS name - * @param osNamePrefix - * the prefix for the expected OS name - * @return true if matches, or false if not or can't determine - */ - private static boolean isOsNameMatch(final String osName, final String osNamePrefix) { - if (osName == null) { - return false; - } - return osName.toUpperCase(Locale.ROOT).startsWith(osNamePrefix.toUpperCase(Locale.ROOT)); - } - - private final boolean casePreserving; - private final boolean caseSensitive; - private final char[] illegalFileNameChars; - private final int maxFileNameLength; - private final int maxPathLength; - private final String[] reservedFileNames; - private final boolean supportsDriveLetter; - - /** - * Constructs a new instance. - * - * @param caseSensitive Whether this file system is case sensitive. - * @param casePreserving Whether this file system is case preserving. - * @param maxFileLength The maximum length for file names. The file name does not include folders. - * @param maxPathLength The maximum length of the path to a file. This can include folders. - * @param illegalFileNameChars Illegal characters for this file system. - * @param reservedFileNames The reserved file names. - * @param supportsDriveLetter Whether this file system support driver letters. - */ - FileSystem(final boolean caseSensitive, final boolean casePreserving, final int maxFileLength, - final int maxPathLength, final char[] illegalFileNameChars, final String[] reservedFileNames, - final boolean supportsDriveLetter) { - this.maxFileNameLength = maxFileLength; - this.maxPathLength = maxPathLength; - this.illegalFileNameChars = Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars"); - this.reservedFileNames = Objects.requireNonNull(reservedFileNames, "reservedFileNames"); - this.caseSensitive = caseSensitive; - this.casePreserving = casePreserving; - this.supportsDriveLetter = supportsDriveLetter; - } - - /** - * Gets a cloned copy of the illegal characters for this file system. - * - * @return the illegal characters for this file system. - */ - public char[] getIllegalFileNameChars() { - return this.illegalFileNameChars.clone(); - } - - /** - * Gets the maximum length for file names. The file name does not include folders. - * - * @return the maximum length for file names. - */ - public int getMaxFileNameLength() { - return maxFileNameLength; - } - - /** - * Gets the maximum length of the path to a file. This can include folders. - * - * @return the maximum length of the path to a file. - */ - public int getMaxPathLength() { - return maxPathLength; - } - - /** - * Gets a cloned copy of the reserved file names. - * - * @return the reserved file names. - */ - public String[] getReservedFileNames() { - return reservedFileNames.clone(); - } - - /** - * Whether this file system preserves case. - * - * @return Whether this file system preserves case. - */ - public boolean isCasePreserving() { - return casePreserving; - } - - /** - * Whether this file system is case-sensitive. - * - * @return Whether this file system is case-sensitive. - */ - public boolean isCaseSensitive() { - return caseSensitive; - } - - /** - * Returns {@code true} if the given character is illegal in a file name, {@code false} otherwise. - * - * @param c - * the character to test - * @return {@code true} if the given character is illegal in a file name, {@code false} otherwise. - */ - private boolean isIllegalFileNameChar(final char c) { - return Arrays.binarySearch(illegalFileNameChars, c) >= 0; - } - - /** - * Checks if a candidate file name (without a path) such as {@code "filename.ext"} or {@code "filename"} is a - * potentially legal file name. If the file name length exceeds {@link #getMaxFileNameLength()}, or if it contains - * an illegal character then the check fails. - * - * @param candidate - * a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"} - * @return {@code true} if the candidate name is legal - */ - public boolean isLegalFileName(final CharSequence candidate) { - if (candidate == null || candidate.length() == 0 || candidate.length() > maxFileNameLength) { - return false; - } - if (isReservedFileName(candidate)) { - return false; - } - for (int i = 0; i < candidate.length(); i++) { - if (isIllegalFileNameChar(candidate.charAt(i))) { - return false; - } - } - return true; - } - - /** - * Returns whether the given string is a reserved file name. - * - * @param candidate - * the string to test - * @return {@code true} if the given string is a reserved file name. - */ - public boolean isReservedFileName(final CharSequence candidate) { - return Arrays.binarySearch(reservedFileNames, candidate) >= 0; - } - - /** - * Tests whether this file system support driver letters. - *

- * Windows supports driver letters as do other operating systems. Whether these other OS's still support Java like - * OS/2, is a different matter. - *

- * - * @return whether this file system support driver letters. - * @since 2.9.0 - * @see Operating systems that use drive letter - * assignment - */ - public boolean supportsDriveLetter() { - return supportsDriveLetter; - } - - /** - * Converts a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"} to a legal file - * name. Illegal characters in the candidate name are replaced by the {@code replacement} character. If the file - * name length exceeds {@link #getMaxFileNameLength()}, then the name is truncated to - * {@link #getMaxFileNameLength()}. - * - * @param candidate - * a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"} - * @param replacement - * Illegal characters in the candidate name are replaced by this character - * @return a String without illegal characters - */ - public String toLegalFileName(final String candidate, final char replacement) { - if (isIllegalFileNameChar(replacement)) { - throw new IllegalArgumentException( - String.format("The replacement character '%s' cannot be one of the %s illegal characters: %s", - // %s does not work properly with NUL - replacement == '\0' ? "\\0" : replacement, name(), Arrays.toString(illegalFileNameChars))); - } - final String truncated = candidate.length() > maxFileNameLength ? candidate.substring(0, maxFileNameLength) - : candidate; - boolean changed = false; - final char[] charArray = truncated.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - if (isIllegalFileNameChar(charArray[i])) { - charArray[i] = replacement; - changed = true; - } - } - return changed ? String.valueOf(charArray) : truncated; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/io/FileSystemUtils.java b/src/org/apache/commons/io/FileSystemUtils.java deleted file mode 100644 index 53b0e48b..00000000 --- a/src/org/apache/commons/io/FileSystemUtils.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; - -/** - * General File System utilities. - *

- * This class provides static utility methods for general file system - * functions not provided via the JDK {@link java.io.File File} class. - *

- * The current functions provided are: - *

    - *
  • Get the free space on a drive - *
- * - * @since 1.1 - * @deprecated As of 2.6 deprecated without replacement. Use equivalent - * methods in {@link java.nio.file.FileStore} instead, e.g. - * {@code Files.getFileStore(Paths.get("/home")).getUsableSpace()} - * or iterate over {@code FileSystems.getDefault().getFileStores()} - */ -@Deprecated -public class FileSystemUtils { - - /** Singleton instance, used mainly for testing. */ - private static final FileSystemUtils INSTANCE = new FileSystemUtils(); - - /** Operating system state flag for error. */ - private static final int INIT_PROBLEM = -1; - /** Operating system state flag for neither Unix nor Windows. */ - private static final int OTHER = 0; - /** Operating system state flag for Windows. */ - private static final int WINDOWS = 1; - /** Operating system state flag for Unix. */ - private static final int UNIX = 2; - /** Operating system state flag for Posix flavour Unix. */ - private static final int POSIX_UNIX = 3; - - /** The operating system flag. */ - private static final int OS; - - /** The path to df */ - private static final String DF; - - static { - int os = OTHER; - String dfPath = "df"; - try { - String osName = System.getProperty("os.name"); - if (osName == null) { - throw new IOException("os.name not found"); - } - osName = osName.toLowerCase(Locale.ENGLISH); - // match - if (osName.contains("windows")) { - os = WINDOWS; - } else if (osName.contains("linux") || - osName.contains("mpe/ix") || - osName.contains("freebsd") || - osName.contains("openbsd") || - osName.contains("irix") || - osName.contains("digital unix") || - osName.contains("unix") || - osName.contains("mac os x")) { - os = UNIX; - } else if (osName.contains("sun os") || - osName.contains("sunos") || - osName.contains("solaris")) { - os = POSIX_UNIX; - dfPath = "/usr/xpg4/bin/df"; - } else if (osName.contains("hp-ux") || - osName.contains("aix")) { - os = POSIX_UNIX; - } - - } catch (final Exception ex) { - os = INIT_PROBLEM; - } - OS = os; - DF = dfPath; - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public FileSystemUtils() { - } - - /** - * Returns the free space on a drive or volume by invoking - * the command line. - * This method does not normalize the result, and typically returns - * bytes on Windows, 512 byte units on OS X and kilobytes on Unix. - * As this is not very useful, this method is deprecated in favour - * of {@link #freeSpaceKb(String)} which returns a result in kilobytes. - *

- * Note that some OS's are NOT currently supported, including OS/390, - * OpenVMS. - *

-     * FileSystemUtils.freeSpace("C:");       // Windows
-     * FileSystemUtils.freeSpace("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows and 'df' on *nix. - * - * @param path the path to get free space for, not null, not empty on Unix - * @return the amount of free drive space on the drive or volume - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since 1.1, enhanced OS support in 1.2 and 1.3 - * @deprecated Use freeSpaceKb(String) - * Deprecated from 1.3, may be removed in 2.0 - */ - @Deprecated - public static long freeSpace(final String path) throws IOException { - return INSTANCE.freeSpaceOS(path, OS, false, Duration.ofMillis(-1)); - } - - /** - * Returns the free space on a drive or volume in kibibytes (1024 bytes) - * by invoking the command line. - *
-     * FileSystemUtils.freeSpaceKb("C:");       // Windows
-     * FileSystemUtils.freeSpaceKb("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix. - *

- * In order to work, you must be running Windows, or have a implementation of - * Unix df that supports GNU format when passed -k (or -kP). If you are going - * to rely on this code, please check that it works on your OS by running - * some simple tests to compare the command line with the output from this class. - * If your operating system isn't supported, please raise a JIRA call detailing - * the exact result from df -k and as much other detail as possible, thanks. - * - * @param path the path to get free space for, not null, not empty on Unix - * @return the amount of free drive space on the drive or volume in kilobytes - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since 1.2, enhanced OS support in 1.3 - * @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}. - */ - @Deprecated - public static long freeSpaceKb(final String path) throws IOException { - return freeSpaceKb(path, -1); - } - /** - * Returns the free space on a drive or volume in kibibytes (1024 bytes) - * by invoking the command line. - *

-     * FileSystemUtils.freeSpaceKb("C:");       // Windows
-     * FileSystemUtils.freeSpaceKb("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix. - *

- * In order to work, you must be running Windows, or have a implementation of - * Unix df that supports GNU format when passed -k (or -kP). If you are going - * to rely on this code, please check that it works on your OS by running - * some simple tests to compare the command line with the output from this class. - * If your operating system isn't supported, please raise a JIRA call detailing - * the exact result from df -k and as much other detail as possible, thanks. - * - * @param path the path to get free space for, not null, not empty on Unix - * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the amount of free drive space on the drive or volume in kilobytes - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since 2.0 - * @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}. - */ - @Deprecated - public static long freeSpaceKb(final String path, final long timeout) throws IOException { - return INSTANCE.freeSpaceOS(path, OS, true, Duration.ofMillis(timeout)); - } - - /** - * Returns the free space for the working directory - * in kibibytes (1024 bytes) by invoking the command line. - *

- * Identical to: - *

-     * freeSpaceKb(new File(".").getAbsolutePath())
-     * 
- * @return the amount of free drive space on the drive or volume in kilobytes - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since 2.0 - * @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}. - */ - @Deprecated - public static long freeSpaceKb() throws IOException { - return freeSpaceKb(-1); - } - - /** - * Returns the free space for the working directory - * in kibibytes (1024 bytes) by invoking the command line. - *

- * Identical to: - *

-     * freeSpaceKb(new File(".").getAbsolutePath())
-     * 
- * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the amount of free drive space on the drive or volume in kilobytes - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - * @since 2.0 - * @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}. - */ - @Deprecated - public static long freeSpaceKb(final long timeout) throws IOException { - return freeSpaceKb(new File(".").getAbsolutePath(), timeout); - } - - /** - * Returns the free space on a drive or volume in a cross-platform manner. - * Note that some OS's are NOT currently supported, including OS/390. - *
-     * FileSystemUtils.freeSpace("C:");  // Windows
-     * FileSystemUtils.freeSpace("/volume");  // *nix
-     * 
- * The free space is calculated via the command line. - * It uses 'dir /-c' on Windows and 'df' on *nix. - * - * @param path the path to get free space for, not null, not empty on Unix - * @param os the operating system code - * @param kb whether to normalize to kilobytes - * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the amount of free drive space on the drive or volume - * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialisation - * @throws IOException if an error occurs when finding the free space - */ - long freeSpaceOS(final String path, final int os, final boolean kb, final Duration timeout) throws IOException { - if (path == null) { - throw new IllegalArgumentException("Path must not be null"); - } - switch (os) { - case WINDOWS: - return kb ? freeSpaceWindows(path, timeout) / FileUtils.ONE_KB : freeSpaceWindows(path, timeout); - case UNIX: - return freeSpaceUnix(path, kb, false, timeout); - case POSIX_UNIX: - return freeSpaceUnix(path, kb, true, timeout); - case OTHER: - throw new IllegalStateException("Unsupported operating system"); - default: - throw new IllegalStateException( - "Exception caught when determining operating system"); - } - } - - /** - * Find free space on the Windows platform using the 'dir' command. - * - * @param path the path to get free space for, including the colon - * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the amount of free drive space on the drive - * @throws IOException if an error occurs - */ - long freeSpaceWindows(final String path, final Duration timeout) throws IOException { - String normPath = FilenameUtils.normalize(path, false); - if (normPath == null) { - throw new IllegalArgumentException(path); - } - if (!normPath.isEmpty() && normPath.charAt(0) != '"') { - normPath = "\"" + normPath + "\""; - } - - // build and run the 'dir' command - final String[] cmdAttribs = {"cmd.exe", "/C", "dir /a /-c " + normPath}; - - // read in the output of the command to an ArrayList - final List lines = performCommand(cmdAttribs, Integer.MAX_VALUE, timeout); - - // now iterate over the lines we just read and find the LAST - // non-empty line (the free space bytes should be in the last element - // of the ArrayList anyway, but this will ensure it works even if it's - // not, still assuming it is on the last non-blank line) - for (int i = lines.size() - 1; i >= 0; i--) { - final String line = lines.get(i); - if (!line.isEmpty()) { - return parseDir(line, normPath); - } - } - // all lines are blank - throw new IOException( - "Command line 'dir /-c' did not return any info " + - "for path '" + normPath + "'"); - } - - /** - * Parses the Windows dir response last line - * - * @param line the line to parse - * @param path the path that was sent - * @return the number of bytes - * @throws IOException if an error occurs - */ - long parseDir(final String line, final String path) throws IOException { - // read from the end of the line to find the last numeric - // character on the line, then continue until we find the first - // non-numeric character, and everything between that and the last - // numeric character inclusive is our free space bytes count - int bytesStart = 0; - int bytesEnd = 0; - int j = line.length() - 1; - innerLoop1: while (j >= 0) { - final char c = line.charAt(j); - if (Character.isDigit(c)) { - // found the last numeric character, this is the end of - // the free space bytes count - bytesEnd = j + 1; - break innerLoop1; - } - j--; - } - innerLoop2: while (j >= 0) { - final char c = line.charAt(j); - if (!Character.isDigit(c) && c != ',' && c != '.') { - // found the next non-numeric character, this is the - // beginning of the free space bytes count - bytesStart = j + 1; - break innerLoop2; - } - j--; - } - if (j < 0) { - throw new IOException( - "Command line 'dir /-c' did not return valid info " + - "for path '" + path + "'"); - } - - // remove commas and dots in the bytes count - final StringBuilder buf = new StringBuilder(line.substring(bytesStart, bytesEnd)); - for (int k = 0; k < buf.length(); k++) { - if (buf.charAt(k) == ',' || buf.charAt(k) == '.') { - buf.deleteCharAt(k--); - } - } - return parseBytes(buf.toString(), path); - } - - /** - * Find free space on the *nix platform using the 'df' command. - * - * @param path the path to get free space for - * @param kb whether to normalize to kilobytes - * @param posix whether to use the POSIX standard format flag - * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the amount of free drive space on the volume - * @throws IOException if an error occurs - */ - long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) - throws IOException { - if (path.isEmpty()) { - throw new IllegalArgumentException("Path must not be empty"); - } - - // build and run the 'dir' command - String flags = "-"; - if (kb) { - flags += "k"; - } - if (posix) { - flags += "P"; - } - final String[] cmdAttribs = - flags.length() > 1 ? new String[] {DF, flags, path} : new String[] {DF, path}; - - // perform the command, asking for up to 3 lines (header, interesting, overflow) - final List lines = performCommand(cmdAttribs, 3, timeout); - if (lines.size() < 2) { - // unknown problem, throw exception - throw new IOException( - "Command line '" + DF + "' did not return info as expected " + - "for path '" + path + "'- response was " + lines); - } - final String line2 = lines.get(1); // the line we're interested in - - // Now, we tokenize the string. The fourth element is what we want. - StringTokenizer tok = new StringTokenizer(line2, " "); - if (tok.countTokens() < 4) { - // could be long Filesystem, thus data on third line - if ((tok.countTokens() != 1) || (lines.size() < 3)) { - throw new IOException( - "Command line '" + DF + "' did not return data as expected " + - "for path '" + path + "'- check path is valid"); - } - final String line3 = lines.get(2); // the line may be interested in - tok = new StringTokenizer(line3, " "); - } else { - tok.nextToken(); // Ignore Filesystem - } - tok.nextToken(); // Ignore 1K-blocks - tok.nextToken(); // Ignore Used - final String freeSpace = tok.nextToken(); - return parseBytes(freeSpace, path); - } - - /** - * Parses the bytes from a string. - * - * @param freeSpace the free space string - * @param path the path - * @return the number of bytes - * @throws IOException if an error occurs - */ - long parseBytes(final String freeSpace, final String path) throws IOException { - try { - final long bytes = Long.parseLong(freeSpace); - if (bytes < 0) { - throw new IOException( - "Command line '" + DF + "' did not find free space in response " + - "for path '" + path + "'- check path is valid"); - } - return bytes; - - } catch (final NumberFormatException ex) { - throw new IOException( - "Command line '" + DF + "' did not return numeric data as expected " + - "for path '" + path + "'- check path is valid", ex); - } - } - - /** - * Performs an OS command. - * - * @param cmdAttribs the command line parameters - * @param max The maximum limit for the lines returned - * @param timeout The timeout amount in milliseconds or no timeout if the value - * is zero or less - * @return the lines returned by the command, converted to lower-case - * @throws IOException if an error occurs - */ - List performCommand(final String[] cmdAttribs, final int max, final Duration timeout) throws IOException { - // this method does what it can to avoid the 'Too many open files' error - // based on trial and error and these links: - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4784692 - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4801027 - // http://forum.java.sun.com/thread.jspa?threadID=533029&messageID=2572018 - // however, its still not perfect as the JDK support is so poor - // (see commons-exec or Ant for a better multi-threaded multi-os solution) - - final List lines = new ArrayList<>(20); - Process proc = null; - InputStream in = null; - OutputStream out = null; - InputStream err = null; - BufferedReader inr = null; - try { - - final Thread monitor = ThreadMonitor.start(timeout); - - proc = openProcess(cmdAttribs); - in = proc.getInputStream(); - out = proc.getOutputStream(); - err = proc.getErrorStream(); - // default charset is most likely appropriate here - inr = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset())); - String line = inr.readLine(); - while (line != null && lines.size() < max) { - line = line.toLowerCase(Locale.ENGLISH).trim(); - lines.add(line); - line = inr.readLine(); - } - - proc.waitFor(); - - ThreadMonitor.stop(monitor); - - if (proc.exitValue() != 0) { - // os command problem, throw exception - throw new IOException( - "Command line returned OS error code '" + proc.exitValue() + - "' for command " + Arrays.asList(cmdAttribs)); - } - if (lines.isEmpty()) { - // unknown problem, throw exception - throw new IOException( - "Command line did not return any info " + - "for command " + Arrays.asList(cmdAttribs)); - } - - inr.close(); - inr = null; - - in.close(); - in = null; - - if (out != null) { - out.close(); - out = null; - } - - if (err != null) { - err.close(); - err = null; - } - - return lines; - - } catch (final InterruptedException ex) { - throw new IOException( - "Command line threw an InterruptedException " + - "for command " + Arrays.asList(cmdAttribs) + " timeout=" + timeout, ex); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - IOUtils.closeQuietly(err); - IOUtils.closeQuietly(inr); - if (proc != null) { - proc.destroy(); - } - } - } - - /** - * Opens the process to the operating system. - * - * @param cmdAttribs the command line parameters - * @return the process - * @throws IOException if an error occurs - */ - Process openProcess(final String[] cmdAttribs) throws IOException { - return Runtime.getRuntime().exec(cmdAttribs); - } - -} diff --git a/src/org/apache/commons/io/FileUtils.java b/src/org/apache/commons/io/FileUtils.java deleted file mode 100644 index 0e76e3af..00000000 --- a/src/org/apache/commons/io/FileUtils.java +++ /dev/null @@ -1,3588 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.UncheckedIOException; -import java.math.BigInteger; -import java.net.URL; -import java.net.URLConnection; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.charset.UnsupportedCharsetException; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitOption; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.NotDirectoryException; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.time.Instant; -import java.time.LocalTime; -import java.time.ZoneId; -import java.time.chrono.ChronoLocalDate; -import java.time.chrono.ChronoLocalDateTime; -import java.time.chrono.ChronoZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.zip.CRC32; -import java.util.zip.CheckedInputStream; -import java.util.zip.Checksum; - -import org.apache.commons.io.file.AccumulatorPathVisitor; -import org.apache.commons.io.file.Counters; -import org.apache.commons.io.file.PathFilter; -import org.apache.commons.io.file.PathUtils; -import org.apache.commons.io.file.StandardDeleteOption; -import org.apache.commons.io.filefilter.FileEqualsFileFilter; -import org.apache.commons.io.filefilter.FileFileFilter; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.SuffixFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; - -/** - * General file manipulation utilities. - *

- * Facilities are provided in the following areas: - *

- *
    - *
  • writing to a file - *
  • reading from a file - *
  • make a directory including parent directories - *
  • copying files and directories - *
  • deleting files and directories - *
  • converting to and from a URL - *
  • listing files and directories by filter and extension - *
  • comparing file content - *
  • file last changed date - *
  • calculating a checksum - *
- *

- * Note that a specific charset should be specified whenever possible. Relying on the platform default means that the - * code is Locale-dependent. Only use the default if the files are known to always use the platform default. - *

- *

- * {@link SecurityException} are not documented in the Javadoc. - *

- *

- * Origin of code: Excalibur, Alexandria, Commons-Utils - *

- */ -public class FileUtils { - /** - * The number of bytes in a kilobyte. - */ - public static final long ONE_KB = 1024; - - /** - * The number of bytes in a kilobyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_KB_BI = BigInteger.valueOf(ONE_KB); - - /** - * The number of bytes in a megabyte. - */ - public static final long ONE_MB = ONE_KB * ONE_KB; - - /** - * The number of bytes in a megabyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_MB_BI = ONE_KB_BI.multiply(ONE_KB_BI); - - /** - * The number of bytes in a gigabyte. - */ - public static final long ONE_GB = ONE_KB * ONE_MB; - - /** - * The number of bytes in a gigabyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_GB_BI = ONE_KB_BI.multiply(ONE_MB_BI); - - /** - * The number of bytes in a terabyte. - */ - public static final long ONE_TB = ONE_KB * ONE_GB; - - /** - * The number of bytes in a terabyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_TB_BI = ONE_KB_BI.multiply(ONE_GB_BI); - - /** - * The number of bytes in a petabyte. - */ - public static final long ONE_PB = ONE_KB * ONE_TB; - - /** - * The number of bytes in a petabyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_PB_BI = ONE_KB_BI.multiply(ONE_TB_BI); - - /** - * The number of bytes in an exabyte. - */ - public static final long ONE_EB = ONE_KB * ONE_PB; - - /** - * The number of bytes in an exabyte. - * - * @since 2.4 - */ - public static final BigInteger ONE_EB_BI = ONE_KB_BI.multiply(ONE_PB_BI); - - /** - * The number of bytes in a zettabyte. - */ - public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB)); - - /** - * The number of bytes in a yottabyte. - */ - public static final BigInteger ONE_YB = ONE_KB_BI.multiply(ONE_ZB); - - /** - * An empty array of type {@code File}. - */ - public static final File[] EMPTY_FILE_ARRAY = {}; - - /** - * Copies the given array and adds StandardCopyOption.COPY_ATTRIBUTES. - * - * @param copyOptions sorted copy options. - * @return a new array. - */ - private static CopyOption[] addCopyAttributes(final CopyOption... copyOptions) { - // Make a copy first since we don't want to sort the call site's version. - final CopyOption[] actual = Arrays.copyOf(copyOptions, copyOptions.length + 1); - Arrays.sort(actual, 0, copyOptions.length); - if (Arrays.binarySearch(copyOptions, 0, copyOptions.length, StandardCopyOption.COPY_ATTRIBUTES) >= 0) { - return copyOptions; - } - actual[actual.length - 1] = StandardCopyOption.COPY_ATTRIBUTES; - return actual; - } - - /** - * Returns a human-readable version of the file size, where the input represents a specific number of bytes. - *

- * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the - * nearest GB boundary. - *

- *

- * Similarly for the 1MB and 1KB boundaries. - *

- * - * @param size the number of bytes - * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) - * @throws NullPointerException if the given {@code BigInteger} is {@code null}. - * @see IO-226 - should the rounding be changed? - * @since 2.4 - */ - // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? - public static String byteCountToDisplaySize(final BigInteger size) { - Objects.requireNonNull(size, "size"); - final String displaySize; - - if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_EB_BI) + " EB"; - } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_PB_BI) + " PB"; - } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_TB_BI) + " TB"; - } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_GB_BI) + " GB"; - } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_MB_BI) + " MB"; - } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { - displaySize = size.divide(ONE_KB_BI) + " KB"; - } else { - displaySize = size + " bytes"; - } - return displaySize; - } - - /** - * Returns a human-readable version of the file size, where the input represents a specific number of bytes. - *

- * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the - * nearest GB boundary. - *

- *

- * Similarly for the 1MB and 1KB boundaries. - *

- * - * @param size the number of bytes - * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) - * @see IO-226 - should the rounding be changed? - */ - // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? - public static String byteCountToDisplaySize(final long size) { - return byteCountToDisplaySize(BigInteger.valueOf(size)); - } - - /** - * Computes the checksum of a file using the specified checksum object. Multiple files may be checked using one - * {@code Checksum} instance if desired simply by reusing the same checksum object. For example: - * - *
-     * long checksum = FileUtils.checksum(file, new CRC32()).getValue();
-     * 
- * - * @param file the file to checksum, must not be {@code null} - * @param checksum the checksum object to be used, must not be {@code null} - * @return the checksum specified, updated with the content of the file - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws NullPointerException if the given {@code Checksum} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a file. - * @throws IOException if an IO error occurs reading the file. - * @since 1.3 - */ - public static Checksum checksum(final File file, final Checksum checksum) throws IOException { - requireExistsChecked(file, "file"); - requireFile(file, "file"); - Objects.requireNonNull(checksum, "checksum"); - try (InputStream inputStream = new CheckedInputStream(Files.newInputStream(file.toPath()), checksum)) { - IOUtils.consume(inputStream); - } - return checksum; - } - - /** - * Computes the checksum of a file using the CRC32 checksum routine. - * The value of the checksum is returned. - * - * @param file the file to checksum, must not be {@code null} - * @return the checksum value - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a file. - * @throws IOException if an IO error occurs reading the file. - * @since 1.3 - */ - public static long checksumCRC32(final File file) throws IOException { - return checksum(file, new CRC32()).getValue(); - } - - /** - * Cleans a directory without deleting it. - * - * @param directory directory to clean - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if directory does not exist or is not a directory. - * @throws IOException if an I/O error occurs. - * @see #forceDelete(File) - */ - public static void cleanDirectory(final File directory) throws IOException { - final File[] files = listFiles(directory, null); - - final List causeList = new ArrayList<>(); - for (final File file : files) { - try { - forceDelete(file); - } catch (final IOException ioe) { - causeList.add(ioe); - } - } - - if (!causeList.isEmpty()) { - throw new IOExceptionList(directory.toString(), causeList); - } - } - - /** - * Cleans a directory without deleting it. - * - * @param directory directory to clean, must not be {@code null} - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if directory does not exist or is not a directory. - * @throws IOException if an I/O error occurs. - * @see #forceDeleteOnExit(File) - */ - private static void cleanDirectoryOnExit(final File directory) throws IOException { - final File[] files = listFiles(directory, null); - - final List causeList = new ArrayList<>(); - for (final File file : files) { - try { - forceDeleteOnExit(file); - } catch (final IOException ioe) { - causeList.add(ioe); - } - } - - if (!causeList.isEmpty()) { - throw new IOExceptionList(causeList); - } - } - - /** - * Tests whether the contents of two files are equal. - *

- * This method checks to see if the two files are different lengths or if they point to the same file, before - * resorting to byte-by-byte comparison of the contents. - *

- *

- * Code origin: Avalon - *

- * - * @param file1 the first file - * @param file2 the second file - * @return true if the content of the files are equal or they both don't exist, false otherwise - * @throws IllegalArgumentException when an input is not a file. - * @throws IOException If an I/O error occurs. - * @see org.apache.commons.io.file.PathUtils#fileContentEquals(Path,Path,java.nio.file.LinkOption[],java.nio.file.OpenOption...) - */ - public static boolean contentEquals(final File file1, final File file2) throws IOException { - if (file1 == null && file2 == null) { - return true; - } - if (file1 == null || file2 == null) { - return false; - } - final boolean file1Exists = file1.exists(); - if (file1Exists != file2.exists()) { - return false; - } - - if (!file1Exists) { - // two not existing files are equal - return true; - } - - requireFile(file1, "file1"); - requireFile(file2, "file2"); - - if (file1.length() != file2.length()) { - // lengths differ, cannot be equal - return false; - } - - if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { - // same file - return true; - } - - try (InputStream input1 = Files.newInputStream(file1.toPath()); InputStream input2 = Files.newInputStream(file2.toPath())) { - return IOUtils.contentEquals(input1, input2); - } - } - - /** - * Compares the contents of two files to determine if they are equal or not. - *

- * This method checks to see if the two files point to the same file, - * before resorting to line-by-line comparison of the contents. - *

- * - * @param file1 the first file - * @param file2 the second file - * @param charsetName the name of the requested charset. - * May be null, in which case the platform default is used - * @return true if the content of the files are equal or neither exists, - * false otherwise - * @throws IllegalArgumentException when an input is not a file. - * @throws IOException in case of an I/O error. - * @throws UnsupportedCharsetException If the named charset is unavailable (unchecked exception). - * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader) - * @since 2.2 - */ - public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName) - throws IOException { - if (file1 == null && file2 == null) { - return true; - } - if (file1 == null || file2 == null) { - return false; - } - final boolean file1Exists = file1.exists(); - if (file1Exists != file2.exists()) { - return false; - } - - if (!file1Exists) { - // two not existing files are equal - return true; - } - - requireFile(file1, "file1"); - requireFile(file2, "file2"); - - if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { - // same file - return true; - } - - final Charset charset = Charsets.toCharset(charsetName); - try (Reader input1 = new InputStreamReader(Files.newInputStream(file1.toPath()), charset); - Reader input2 = new InputStreamReader(Files.newInputStream(file2.toPath()), charset)) { - return IOUtils.contentEqualsIgnoreEOL(input1, input2); - } - } - - /** - * Converts a Collection containing java.io.File instanced into array - * representation. This is to account for the difference between - * File.listFiles() and FileUtils.listFiles(). - * - * @param files a Collection containing java.io.File instances - * @return an array of java.io.File - */ - public static File[] convertFileCollectionToFileArray(final Collection files) { - return files.toArray(EMPTY_FILE_ARRAY); - } - - /** - * Copies a whole directory to a new location preserving the file dates. - *

- * This method copies the specified directory and all its child directories and files to the specified destination. - * The destination is the new location and name of the directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: This method tries to preserve the files' last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * - * @param srcDir an existing directory to copy, must not be {@code null}. - * @param destDir the new directory, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.1 - */ - public static void copyDirectory(final File srcDir, final File destDir) throws IOException { - copyDirectory(srcDir, destDir, true); - } - - /** - * Copies a whole directory to a new location. - *

- * This method copies the contents of the specified source directory to within the specified destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * - * @param srcDir an existing directory to copy, must not be {@code null}. - * @param destDir the new directory, must not be {@code null}. - * @param preserveFileDate true if the file date of the copy should be the same as the original. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.1 - */ - public static void copyDirectory(final File srcDir, final File destDir, final boolean preserveFileDate) - throws IOException { - copyDirectory(srcDir, destDir, null, preserveFileDate); - } - - /** - * Copies a filtered directory to a new location preserving the file dates. - *

- * This method copies the contents of the specified source directory to within the specified destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: This method tries to preserve the files' last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * Example: Copy directories only - * - *
-     * // only copy the directory structure
-     * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
-     * 
- * - * Example: Copy directories and txt files - * - *
-     * // Create a filter for ".txt" files
-     * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
-     * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
-     *
-     * // Create a filter for either directories or ".txt" files
-     * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
-     *
-     * // Copy using the filter
-     * FileUtils.copyDirectory(srcDir, destDir, filter);
-     * 
- * - * @param srcDir an existing directory to copy, must not be {@code null}. - * @param destDir the new directory, must not be {@code null}. - * @param filter the filter to apply, null means copy all directories and files should be the same as the original. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter) - throws IOException { - copyDirectory(srcDir, destDir, filter, true); - } - - /** - * Copies a filtered directory to a new location. - *

- * This method copies the contents of the specified source directory to within the specified destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * Example: Copy directories only - * - *
-     * // only copy the directory structure
-     * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
-     * 
- * - * Example: Copy directories and txt files - * - *
-     * // Create a filter for ".txt" files
-     * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
-     * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
-     *
-     * // Create a filter for either directories or ".txt" files
-     * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
-     *
-     * // Copy using the filter
-     * FileUtils.copyDirectory(srcDir, destDir, filter, false);
-     * 
- * - * @param srcDir an existing directory to copy, must not be {@code null}. - * @param destDir the new directory, must not be {@code null}. - * @param filter the filter to apply, null means copy all directories and files. - * @param preserveFileDate true if the file date of the copy should be the same as the original. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter, - final boolean preserveFileDate) throws IOException { - copyDirectory(srcDir, destDir, filter, preserveFileDate, StandardCopyOption.REPLACE_EXISTING); - } - - /** - * Copies a filtered directory to a new location. - *

- * This method copies the contents of the specified source directory to within the specified destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * Example: Copy directories only - * - *
-     * // only copy the directory structure
-     * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
-     * 
- * - * Example: Copy directories and txt files - * - *
-     * // Create a filter for ".txt" files
-     * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
-     * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
-     *
-     * // Create a filter for either directories or ".txt" files
-     * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
-     *
-     * // Copy using the filter
-     * FileUtils.copyDirectory(srcDir, destDir, filter, false);
-     * 
- * - * @param srcDir an existing directory to copy, must not be {@code null} - * @param destDir the new directory, must not be {@code null} - * @param fileFilter the filter to apply, null means copy all directories and files - * @param preserveFileDate true if the file date of the copy should be the same as the original - * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 2.8.0 - */ - public static void copyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, - final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException { - requireFileCopy(srcDir, destDir); - requireDirectory(srcDir, "srcDir"); - requireCanonicalPathsNotEquals(srcDir, destDir); - - // Cater for destination being directory within the source directory (see IO-141) - List exclusionList = null; - final String srcDirCanonicalPath = srcDir.getCanonicalPath(); - final String destDirCanonicalPath = destDir.getCanonicalPath(); - if (destDirCanonicalPath.startsWith(srcDirCanonicalPath)) { - final File[] srcFiles = listFiles(srcDir, fileFilter); - if (srcFiles.length > 0) { - exclusionList = new ArrayList<>(srcFiles.length); - for (final File srcFile : srcFiles) { - final File copiedFile = new File(destDir, srcFile.getName()); - exclusionList.add(copiedFile.getCanonicalPath()); - } - } - } - doCopyDirectory(srcDir, destDir, fileFilter, exclusionList, - preserveFileDate, preserveFileDate ? addCopyAttributes(copyOptions) : copyOptions); - } - - /** - * Copies a directory to within another directory preserving the file dates. - *

- * This method copies the source directory and all its contents to a directory of the same name in the specified - * destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: This method tries to preserve the files' last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * - * @param sourceDir an existing directory to copy, must not be {@code null}. - * @param destinationDir the directory to place the copy in, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.2 - */ - public static void copyDirectoryToDirectory(final File sourceDir, final File destinationDir) throws IOException { - requireDirectoryIfExists(sourceDir, "sourceDir"); - requireDirectoryIfExists(destinationDir, "destinationDir"); - copyDirectory(sourceDir, new File(destinationDir, sourceDir.getName()), true); - } - - /** - * Copies a file to a new location preserving the file date. - *

- * This method copies the contents of the specified source file to the specified destination file. The directory - * holding the destination file is created if it does not exist. If the destination file exists, then this method - * will overwrite it. - *

- *

- * Note: This method tries to preserve the file's last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that the operation will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * - * @param srcFile an existing file to copy, must not be {@code null}. - * @param destFile the new file, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @throws IOException if the output file length is not the same as the input file length after the copy completes. - * @see #copyFileToDirectory(File, File) - * @see #copyFile(File, File, boolean) - */ - public static void copyFile(final File srcFile, final File destFile) throws IOException { - copyFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); - } - - /** - * Copies an existing file to a new file location. - *

- * This method copies the contents of the specified source file to the specified destination file. The directory - * holding the destination file is created if it does not exist. If the destination file exists, then this method - * will overwrite it. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * - * @param srcFile an existing file to copy, must not be {@code null}. - * @param destFile the new file, must not be {@code null}. - * @param preserveFileDate true if the file date of the copy should be the same as the original. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @throws IOException if the output file length is not the same as the input file length after the copy completes - * @see #copyFile(File, File, boolean, CopyOption...) - */ - public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate) - throws IOException { - copyFile(srcFile, destFile, - preserveFileDate - ? new CopyOption[] {StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING} - : new CopyOption[] {StandardCopyOption.REPLACE_EXISTING}); - } - - /** - * Copies a file to a new location. - *

- * This method copies the contents of the specified source file to the specified destination file. The directory - * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite - * it with {@link StandardCopyOption#REPLACE_EXISTING}. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * - * @param srcFile an existing file to copy, must not be {@code null}. - * @param destFile the new file, must not be {@code null}. - * @param preserveFileDate true if the file date of the copy should be the same as the original. - * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileNotFoundException if the source does not exist. - * @throws IllegalArgumentException if source is not a file. - * @throws IOException if the output file length is not the same as the input file length after the copy completes. - * @throws IOException if an I/O error occurs, or setting the last-modified time didn't succeeded. - * @see #copyFileToDirectory(File, File, boolean) - * @since 2.8.0 - */ - public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions) - throws IOException { - copyFile(srcFile, destFile, preserveFileDate ? addCopyAttributes(copyOptions) : copyOptions); - } - - /** - * Copies a file to a new location. - *

- * This method copies the contents of the specified source file to the specified destination file. The directory - * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite - * it if you use {@link StandardCopyOption#REPLACE_EXISTING}. - *

- * - * @param srcFile an existing file to copy, must not be {@code null}. - * @param destFile the new file, must not be {@code null}. - * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileNotFoundException if the source does not exist. - * @throws IllegalArgumentException if source is not a file. - * @throws IOException if the output file length is not the same as the input file length after the copy completes. - * @throws IOException if an I/O error occurs. - * @see StandardCopyOption - * @since 2.9.0 - */ - public static void copyFile(final File srcFile, final File destFile, final CopyOption... copyOptions) - throws IOException { - requireFileCopy(srcFile, destFile); - requireFile(srcFile, "srcFile"); - requireCanonicalPathsNotEquals(srcFile, destFile); - createParentDirectories(destFile); - requireFileIfExists(destFile, "destFile"); - if (destFile.exists()) { - requireCanWrite(destFile, "destFile"); - } - - // On Windows, the last modified time is copied by default. - Files.copy(srcFile.toPath(), destFile.toPath(), copyOptions); - - // TODO IO-386: Do we still need this check? - requireEqualSizes(srcFile, destFile, srcFile.length(), destFile.length()); - } - - /** - * Copies bytes from a {@code File} to an {@code OutputStream}. - *

- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - *

- * - * @param input the {@code File} to read. - * @param output the {@code OutputStream} to write. - * @return the number of bytes copied - * @throws NullPointerException if the File is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.1 - */ - public static long copyFile(final File input, final OutputStream output) throws IOException { - try (InputStream fis = Files.newInputStream(input.toPath())) { - return IOUtils.copyLarge(fis, output); - } - } - - /** - * Copies a file to a directory preserving the file date. - *

- * This method copies the contents of the specified source file to a file of the same name in the specified - * destination directory. The destination directory is created if it does not exist. If the destination file exists, - * then this method will overwrite it. - *

- *

- * Note: This method tries to preserve the file's last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that the operation will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * - * @param srcFile an existing file to copy, must not be {@code null}. - * @param destDir the directory to place the copy in, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @see #copyFile(File, File, boolean) - */ - public static void copyFileToDirectory(final File srcFile, final File destDir) throws IOException { - copyFileToDirectory(srcFile, destDir, true); - } - - /** - * Copies a file to a directory optionally preserving the file date. - *

- * This method copies the contents of the specified source file to a file of the same name in the specified - * destination directory. The destination directory is created if it does not exist. If the destination file exists, - * then this method will overwrite it. - *

- *

- * Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last - * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation - * will succeed. If the modification operation fails, the methods throws IOException. - *

- * - * @param sourceFile an existing file to copy, must not be {@code null}. - * @param destinationDir the directory to place the copy in, must not be {@code null}. - * @param preserveFileDate true if the file date of the copy should be the same as the original. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @throws IOException if the output file length is not the same as the input file length after the copy completes. - * @see #copyFile(File, File, CopyOption...) - * @since 1.3 - */ - public static void copyFileToDirectory(final File sourceFile, final File destinationDir, final boolean preserveFileDate) - throws IOException { - Objects.requireNonNull(sourceFile, "sourceFile"); - requireDirectoryIfExists(destinationDir, "destinationDir"); - copyFile(sourceFile, new File(destinationDir, sourceFile.getName()), preserveFileDate); - } - - /** - * Copies bytes from an {@link InputStream} {@code source} to a file - * {@code destination}. The directories up to {@code destination} - * will be created if they don't already exist. {@code destination} - * will be overwritten if it already exists. - *

- * The {@code source} stream is closed. - *

- *

- * See {@link #copyToFile(InputStream, File)} for a method that does not close the input stream. - *

- * - * @param source the {@code InputStream} to copy bytes from, must not be {@code null}, will be closed - * @param destination the non-directory {@code File} to write bytes to - * (possibly overwriting), must not be {@code null} - * @throws IOException if {@code destination} is a directory - * @throws IOException if {@code destination} cannot be written - * @throws IOException if {@code destination} needs creating but can't be - * @throws IOException if an IO error occurs during copying - * @since 2.0 - */ - public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException { - try (InputStream inputStream = source) { - copyToFile(inputStream, destination); - } - } - - /** - * Copies a file or directory to within another directory preserving the file dates. - *

- * This method copies the source file or directory, along all its contents, to a directory of the same name in the - * specified destination directory. - *

- *

- * The destination directory is created if it does not exist. If the destination directory did exist, then this - * method merges the source with the destination, with the source taking precedence. - *

- *

- * Note: This method tries to preserve the files' last modified date/times using - * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the - * modification operation fails, the methods throws IOException. - *

- * - * @param sourceFile an existing file or directory to copy, must not be {@code null}. - * @param destinationDir the directory to place the copy in, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @see #copyDirectoryToDirectory(File, File) - * @see #copyFileToDirectory(File, File) - * @since 2.6 - */ - public static void copyToDirectory(final File sourceFile, final File destinationDir) throws IOException { - Objects.requireNonNull(sourceFile, "sourceFile"); - if (sourceFile.isFile()) { - copyFileToDirectory(sourceFile, destinationDir); - } else if (sourceFile.isDirectory()) { - copyDirectoryToDirectory(sourceFile, destinationDir); - } else { - throw new FileNotFoundException("The source " + sourceFile + " does not exist"); - } - } - - /** - * Copies a files to a directory preserving each file's date. - *

- * This method copies the contents of the specified source files - * to a file of the same name in the specified destination directory. - * The destination directory is created if it does not exist. - * If the destination file exists, then this method will overwrite it. - *

- *

- * Note: This method tries to preserve the file's last - * modified date/times using {@link File#setLastModified(long)}, however - * it is not guaranteed that the operation will succeed. - * If the modification operation fails, the methods throws IOException. - *

- * - * @param sourceIterable a existing files to copy, must not be {@code null}. - * @param destinationDir the directory to place the copy in, must not be {@code null}. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @see #copyFileToDirectory(File, File) - * @since 2.6 - */ - public static void copyToDirectory(final Iterable sourceIterable, final File destinationDir) throws IOException { - Objects.requireNonNull(sourceIterable, "sourceIterable"); - for (final File src : sourceIterable) { - copyFileToDirectory(src, destinationDir); - } - } - - /** - * Copies bytes from an {@link InputStream} source to a {@link File} destination. The directories - * up to {@code destination} will be created if they don't already exist. {@code destination} will be - * overwritten if it already exists. The {@code source} stream is left open, e.g. for use with - * {@link java.util.zip.ZipInputStream ZipInputStream}. See {@link #copyInputStreamToFile(InputStream, File)} for a - * method that closes the input stream. - * - * @param inputStream the {@code InputStream} to copy bytes from, must not be {@code null} - * @param file the non-directory {@code File} to write bytes to (possibly overwriting), must not be - * {@code null} - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the File is {@code null}. - * @throws IllegalArgumentException if the file object is a directory. - * @throws IllegalArgumentException if the file is not writable. - * @throws IOException if the directories could not be created. - * @throws IOException if an IO error occurs during copying. - * @since 2.5 - */ - public static void copyToFile(final InputStream inputStream, final File file) throws IOException { - try (OutputStream out = openOutputStream(file)) { - IOUtils.copy(inputStream, out); - } - } - - /** - * Copies bytes from the URL {@code source} to a file - * {@code destination}. The directories up to {@code destination} - * will be created if they don't already exist. {@code destination} - * will be overwritten if it already exists. - *

- * Warning: this method does not set a connection or read timeout and thus - * might block forever. Use {@link #copyURLToFile(URL, File, int, int)} - * with reasonable timeouts to prevent this. - *

- * - * @param source the {@code URL} to copy bytes from, must not be {@code null} - * @param destination the non-directory {@code File} to write bytes to - * (possibly overwriting), must not be {@code null} - * @throws IOException if {@code source} URL cannot be opened - * @throws IOException if {@code destination} is a directory - * @throws IOException if {@code destination} cannot be written - * @throws IOException if {@code destination} needs creating but can't be - * @throws IOException if an IO error occurs during copying - */ - public static void copyURLToFile(final URL source, final File destination) throws IOException { - try (final InputStream stream = source.openStream()) { - copyInputStreamToFile(stream, destination); - } - } - - /** - * Copies bytes from the URL {@code source} to a file {@code destination}. The directories up to - * {@code destination} will be created if they don't already exist. {@code destination} will be - * overwritten if it already exists. - * - * @param source the {@code URL} to copy bytes from, must not be {@code null} - * @param destination the non-directory {@code File} to write bytes to (possibly overwriting), must not be - * {@code null} - * @param connectionTimeoutMillis the number of milliseconds until this method will timeout if no connection could - * be established to the {@code source} - * @param readTimeoutMillis the number of milliseconds until this method will timeout if no data could be read from - * the {@code source} - * @throws IOException if {@code source} URL cannot be opened - * @throws IOException if {@code destination} is a directory - * @throws IOException if {@code destination} cannot be written - * @throws IOException if {@code destination} needs creating but can't be - * @throws IOException if an IO error occurs during copying - * @since 2.0 - */ - public static void copyURLToFile(final URL source, final File destination, - final int connectionTimeoutMillis, final int readTimeoutMillis) throws IOException { - final URLConnection connection = source.openConnection(); - connection.setConnectTimeout(connectionTimeoutMillis); - connection.setReadTimeout(readTimeoutMillis); - try (final InputStream stream = connection.getInputStream()) { - copyInputStreamToFile(stream, destination); - } - } - - - /** - * Creates all parent directories for a File object. - * - * @param file the File that may need parents, may be null. - * @return The parent directory, or {@code null} if the given file does not name a parent - * @throws IOException if the directory was not created along with all its parent directories. - * @throws IOException if the given file object is not null and not a directory. - * @since 2.9.0 - */ - public static File createParentDirectories(final File file) throws IOException { - return mkdirs(getParentFile(file)); - } - - /** - * Decodes the specified URL as per RFC 3986, i.e. transforms - * percent-encoded octets to characters by decoding with the UTF-8 character - * set. This function is primarily intended for usage with - * {@link java.net.URL} which unfortunately does not enforce proper URLs. As - * such, this method will leniently accept invalid characters or malformed - * percent-encoded octets and simply pass them literally through to the - * result string. Except for rare edge cases, this will make unencoded URLs - * pass through unaltered. - * - * @param url The URL to decode, may be {@code null}. - * @return The decoded URL or {@code null} if the input was - * {@code null}. - */ - static String decodeUrl(final String url) { - String decoded = url; - if (url != null && url.indexOf('%') >= 0) { - final int n = url.length(); - final StringBuilder buffer = new StringBuilder(); - final ByteBuffer bytes = ByteBuffer.allocate(n); - for (int i = 0; i < n; ) { - if (url.charAt(i) == '%') { - try { - do { - final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16); - bytes.put(octet); - i += 3; - } while (i < n && url.charAt(i) == '%'); - continue; - } catch (final RuntimeException e) { - // malformed percent-encoded octet, fall through and - // append characters literally - } finally { - if (bytes.position() > 0) { - bytes.flip(); - buffer.append(StandardCharsets.UTF_8.decode(bytes).toString()); - bytes.clear(); - } - } - } - buffer.append(url.charAt(i++)); - } - decoded = buffer.toString(); - } - return decoded; - } - - /** - * Deletes the given File but throws an IOException if it cannot, unlike {@link File#delete()} which returns a - * boolean. - * - * @param file The file to delete. - * @return the given file. - * @throws IOException if the file cannot be deleted. - * @see File#delete() - * @since 2.9.0 - */ - public static File delete(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - Files.delete(file.toPath()); - return file; - } - - /** - * Deletes a directory recursively. - * - * @param directory directory to delete - * @throws IOException in case deletion is unsuccessful - * @throws IllegalArgumentException if {@code directory} is not a directory - */ - public static void deleteDirectory(final File directory) throws IOException { - Objects.requireNonNull(directory, "directory"); - if (!directory.exists()) { - return; - } - if (!isSymlink(directory)) { - cleanDirectory(directory); - } - delete(directory); - } - - /** - * Schedules a directory recursively for deletion on JVM exit. - * - * @param directory directory to delete, must not be {@code null} - * @throws NullPointerException if the directory is {@code null} - * @throws IOException in case deletion is unsuccessful - */ - private static void deleteDirectoryOnExit(final File directory) throws IOException { - if (!directory.exists()) { - return; - } - directory.deleteOnExit(); - if (!isSymlink(directory)) { - cleanDirectoryOnExit(directory); - } - } - - /** - * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

- *
    - *
  • A directory to be deleted does not have to be empty.
  • - *
  • No exceptions are thrown when a file or directory cannot be deleted.
  • - *
- * - * @param file file or directory to delete, can be {@code null} - * @return {@code true} if the file or directory was deleted, otherwise - * {@code false} - * - * @since 1.4 - */ - public static boolean deleteQuietly(final File file) { - if (file == null) { - return false; - } - try { - if (file.isDirectory()) { - cleanDirectory(file); - } - } catch (final Exception ignored) { - // ignore - } - - try { - return file.delete(); - } catch (final Exception ignored) { - return false; - } - } - - /** - * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory). - *

- * Files are normalized before comparison. - *

- * - * Edge cases: - *
    - *
  • A {@code directory} must not be null: if null, throw IllegalArgumentException
  • - *
  • A {@code directory} must be a directory: if not a directory, throw IllegalArgumentException
  • - *
  • A directory does not contain itself: return false
  • - *
  • A null child file is not contained in any parent: return false
  • - *
- * - * @param directory the file to consider as the parent. - * @param child the file to consider as the child. - * @return true is the candidate leaf is under by the specified composite. False otherwise. - * @throws IOException if an IO error occurs while checking the files. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory. - * @see FilenameUtils#directoryContains(String, String) - * @since 2.2 - */ - public static boolean directoryContains(final File directory, final File child) throws IOException { - requireDirectoryExists(directory, "directory"); - - if (child == null) { - return false; - } - - if (!directory.exists() || !child.exists()) { - return false; - } - - // Canonicalize paths (normalizes relative paths) - return FilenameUtils.directoryContains(directory.getCanonicalPath(), child.getCanonicalPath()); - } - - /** - * Internal copy directory method. - * - * @param srcDir the validated source directory, must not be {@code null}. - * @param destDir the validated destination directory, must not be {@code null}. - * @param fileFilter the filter to apply, null means copy all directories and files. - * @param exclusionList List of files and directories to exclude from the copy, may be null. - * @param preserveDirDate preserve the directories last modified dates. - * @param copyOptions options specifying how the copy should be done, see {@link StandardCopyOption}. - * @throws IOException if the directory was not created along with all its parent directories. - * @throws IOException if the given file object is not a directory. - */ - private static void doCopyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, - final List exclusionList, final boolean preserveDirDate, final CopyOption... copyOptions) throws IOException { - // recurse dirs, copy files. - final File[] srcFiles = listFiles(srcDir, fileFilter); - requireDirectoryIfExists(destDir, "destDir"); - mkdirs(destDir); - requireCanWrite(destDir, "destDir"); - for (final File srcFile : srcFiles) { - final File dstFile = new File(destDir, srcFile.getName()); - if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) { - if (srcFile.isDirectory()) { - doCopyDirectory(srcFile, dstFile, fileFilter, exclusionList, preserveDirDate, copyOptions); - } else { - copyFile(srcFile, dstFile, copyOptions); - } - } - } - // Do this last, as the above has probably affected directory metadata - if (preserveDirDate) { - setLastModified(srcDir, destDir); - } - } - - /** - * Deletes a file or directory. For a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

- *
    - *
  • The directory does not have to be empty.
  • - *
  • You get an exception when a file or directory cannot be deleted.
  • - *
- * - * @param file file or directory to delete, must not be {@code null}. - * @throws NullPointerException if the file is {@code null}. - * @throws FileNotFoundException if the file was not found. - * @throws IOException in case deletion is unsuccessful. - */ - public static void forceDelete(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - final Counters.PathCounters deleteCounters; - try { - deleteCounters = PathUtils.delete(file.toPath(), PathUtils.EMPTY_LINK_OPTION_ARRAY, - StandardDeleteOption.OVERRIDE_READ_ONLY); - } catch (final IOException e) { - throw new IOException("Cannot delete file: " + file, e); - } - - if (deleteCounters.getFileCounter().get() < 1 && deleteCounters.getDirectoryCounter().get() < 1) { - // didn't find a file to delete. - throw new FileNotFoundException("File does not exist: " + file); - } - } - - /** - * Schedules a file to be deleted when JVM exits. - * If file is directory delete it and all sub-directories. - * - * @param file file or directory to delete, must not be {@code null}. - * @throws NullPointerException if the file is {@code null}. - * @throws IOException in case deletion is unsuccessful. - */ - public static void forceDeleteOnExit(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - if (file.isDirectory()) { - deleteDirectoryOnExit(file); - } else { - file.deleteOnExit(); - } - } - - /** - * Makes a directory, including any necessary but nonexistent parent - * directories. If a file already exists with specified name but it is - * not a directory then an IOException is thrown. - * If the directory cannot be created (or the file already exists but is not a directory) - * then an IOException is thrown. - * - * @param directory directory to create, must not be {@code null}. - * @throws IOException if the directory was not created along with all its parent directories. - * @throws IOException if the given file object is not a directory. - * @throws SecurityException See {@link File#mkdirs()}. - */ - public static void forceMkdir(final File directory) throws IOException { - mkdirs(directory); - } - - /** - * Makes any necessary but nonexistent parent directories for a given File. If the parent directory cannot be - * created then an IOException is thrown. - * - * @param file file with parent to create, must not be {@code null}. - * @throws NullPointerException if the file is {@code null}. - * @throws IOException if the parent directory cannot be created. - * @since 2.5 - */ - public static void forceMkdirParent(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - final File parent = getParentFile(file); - if (parent == null) { - return; - } - forceMkdir(parent); - } - - /** - * Construct a file from the set of name elements. - * - * @param directory the parent directory. - * @param names the name elements. - * @return the new file. - * @since 2.1 - */ - public static File getFile(final File directory, final String... names) { - Objects.requireNonNull(directory, "directory"); - Objects.requireNonNull(names, "names"); - File file = directory; - for (final String name : names) { - file = new File(file, name); - } - return file; - } - - /** - * Construct a file from the set of name elements. - * - * @param names the name elements. - * @return the file. - * @since 2.1 - */ - public static File getFile(final String... names) { - Objects.requireNonNull(names, "names"); - File file = null; - for (final String name : names) { - if (file == null) { - file = new File(name); - } else { - file = new File(file, name); - } - } - return file; - } - - /** - * Gets the parent of the given file. The given file may be bull and a file's parent may as well be null. - * - * @param file The file to query. - * @return The parent file or {@code null}. - */ - private static File getParentFile(final File file) { - return file == null ? null : file.getParentFile(); - } - - /** - * Returns a {@link File} representing the system temporary directory. - * - * @return the system temporary directory. - * - * @since 2.0 - */ - public static File getTempDirectory() { - return new File(getTempDirectoryPath()); - } - - /** - * Returns the path to the system temporary directory. - * - * @return the path to the system temporary directory. - * - * @since 2.0 - */ - public static String getTempDirectoryPath() { - return System.getProperty("java.io.tmpdir"); - } - - /** - * Returns a {@link File} representing the user's home directory. - * - * @return the user's home directory. - * - * @since 2.0 - */ - public static File getUserDirectory() { - return new File(getUserDirectoryPath()); - } - - /** - * Returns the path to the user's home directory. - * - * @return the path to the user's home directory. - * - * @since 2.0 - */ - public static String getUserDirectoryPath() { - return System.getProperty("user.home"); - } - - /** - * Tests whether the specified {@code File} is a directory or not. Implemented as a - * null-safe delegate to {@code Files.isDirectory(Path path, LinkOption... options)}. - * - * @param file the path to the file. - * @param options options indicating how symbolic links are handled - * @return {@code true} if the file is a directory; {@code false} if - * the path is null, the file does not exist, is not a directory, or it cannot - * be determined if the file is a directory or not. - * @throws SecurityException In the case of the default provider, and a security manager is installed, the - * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read - * access to the directory. - * @since 2.9.0 - */ - public static boolean isDirectory(final File file, final LinkOption... options) { - return file != null && Files.isDirectory(file.toPath(), options); - } - - /** - * Tests whether the directory is empty. - * - * @param directory the directory to query. - * @return whether the directory is empty. - * @throws IOException if an I/O error occurs. - * @throws NotDirectoryException if the file could not otherwise be opened because it is not a directory - * (optional specific exception). - * @since 2.9.0 - */ - public static boolean isEmptyDirectory(final File directory) throws IOException { - return PathUtils.isEmptyDirectory(directory.toPath()); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDate} - * at the current time. - * - *

Note: The input date is assumed to be in the system default time-zone with the time - * part set to the current time. To use a non-default time-zone use the method - * {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) - * isFileNewer(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where - * {@code zoneId} is a valid {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDate the date reference. - * @return true if the {@code File} exists and has been modified after the given - * {@code ChronoLocalDate} at the current time. - * @throws NullPointerException if the file or local date is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate) { - return isFileNewer(file, chronoLocalDate, LocalTime.now()); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDate} - * at the specified time. - * - *

Note: The input date and time are assumed to be in the system default time-zone. To use a - * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) - * isFileNewer(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid - * {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDate the date reference. - * @param localTime the time reference. - * @return true if the {@code File} exists and has been modified after the given - * {@code ChronoLocalDate} at the given time. - * @throws NullPointerException if the file, local date or zone ID is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { - Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); - Objects.requireNonNull(localTime, "localTime"); - return isFileNewer(file, chronoLocalDate.atTime(localTime)); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDateTime} - * at the system-default time zone. - * - *

Note: The input date and time is assumed to be in the system default time-zone. To use a - * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) - * isFileNewer(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid - * {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDateTime the date reference. - * @return true if the {@code File} exists and has been modified after the given - * {@code ChronoLocalDateTime} at the system-default time zone. - * @throws NullPointerException if the file or local date time is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final ChronoLocalDateTime chronoLocalDateTime) { - return isFileNewer(file, chronoLocalDateTime, ZoneId.systemDefault()); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDateTime} - * at the specified {@code ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDateTime the date reference. - * @param zoneId the time zone. - * @return true if the {@code File} exists and has been modified after the given - * {@code ChronoLocalDateTime} at the given {@code ZoneId}. - * @throws NullPointerException if the file, local date time or zone ID is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final ChronoLocalDateTime chronoLocalDateTime, final ZoneId zoneId) { - Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); - Objects.requireNonNull(zoneId, "zoneId"); - return isFileNewer(file, chronoLocalDateTime.atZone(zoneId)); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code ChronoZonedDateTime}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoZonedDateTime the date reference. - * @return true if the {@code File} exists and has been modified after the given - * {@code ChronoZonedDateTime}. - * @throws NullPointerException if the file or zoned date time is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final ChronoZonedDateTime chronoZonedDateTime) { - Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); - return isFileNewer(file, chronoZonedDateTime.toInstant()); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code Date}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param date the date reference. - * @return true if the {@code File} exists and has been modified - * after the given {@code Date}. - * @throws NullPointerException if the file or date is {@code null}. - */ - public static boolean isFileNewer(final File file, final Date date) { - Objects.requireNonNull(date, "date"); - return isFileNewer(file, date.getTime()); - } - - /** - * Tests if the specified {@code File} is newer than the reference {@code File}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param reference the {@code File} of which the modification date is used. - * @return true if the {@code File} exists and has been modified more - * recently than the reference {@code File}. - * @throws NullPointerException if the file or reference file is {@code null}. - * @throws IllegalArgumentException if the reference file doesn't exist. - */ - public static boolean isFileNewer(final File file, final File reference) { - requireExists(reference, "reference"); - return isFileNewer(file, lastModifiedUnchecked(reference)); - } - - /** - * Tests if the specified {@code File} is newer than the specified {@code Instant}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param instant the date reference. - * @return true if the {@code File} exists and has been modified after the given {@code Instant}. - * @throws NullPointerException if the file or instant is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileNewer(final File file, final Instant instant) { - Objects.requireNonNull(instant, "instant"); - return isFileNewer(file, instant.toEpochMilli()); - } - - /** - * Tests if the specified {@code File} is newer than the specified time reference. - * - * @param file the {@code File} of which the modification date must be compared. - * @param timeMillis the time reference measured in milliseconds since the - * epoch (00:00:00 GMT, January 1, 1970). - * @return true if the {@code File} exists and has been modified after the given time reference. - * @throws NullPointerException if the file is {@code null}. - */ - public static boolean isFileNewer(final File file, final long timeMillis) { - Objects.requireNonNull(file, "file"); - return file.exists() && lastModifiedUnchecked(file) > timeMillis; - } - - /** - * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDate} - * at the current time. - * - *

Note: The input date is assumed to be in the system default time-zone with the time - * part set to the current time. To use a non-default time-zone use the method - * {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) - * isFileOlder(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where - * {@code zoneId} is a valid {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDate the date reference. - * @return true if the {@code File} exists and has been modified before the given - * {@code ChronoLocalDate} at the current time. - * @throws NullPointerException if the file or local date is {@code null}. - * @see ZoneId#systemDefault() - * @see LocalTime#now() - * - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate) { - return isFileOlder(file, chronoLocalDate, LocalTime.now()); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDate} - * at the specified {@code LocalTime}. - * - *

Note: The input date and time are assumed to be in the system default time-zone. To use a - * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) - * isFileOlder(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid - * {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDate the date reference. - * @param localTime the time reference. - * @return true if the {@code File} exists and has been modified before the - * given {@code ChronoLocalDate} at the specified time. - * @throws NullPointerException if the file, local date or local time is {@code null}. - * @see ZoneId#systemDefault() - * - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { - Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); - Objects.requireNonNull(localTime, "localTime"); - return isFileOlder(file, chronoLocalDate.atTime(localTime)); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDateTime} - * at the system-default time zone. - * - *

Note: The input date and time is assumed to be in the system default time-zone. To use a - * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) - * isFileOlder(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid - * {@link ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDateTime the date reference. - * @return true if the {@code File} exists and has been modified before the given - * {@code ChronoLocalDateTime} at the system-default time zone. - * @throws NullPointerException if the file or local date time is {@code null}. - * @see ZoneId#systemDefault() - * - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final ChronoLocalDateTime chronoLocalDateTime) { - return isFileOlder(file, chronoLocalDateTime, ZoneId.systemDefault()); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDateTime} - * at the specified {@code ZoneId}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoLocalDateTime the date reference. - * @param zoneId the time zone. - * @return true if the {@code File} exists and has been modified before the given - * {@code ChronoLocalDateTime} at the given {@code ZoneId}. - * @throws NullPointerException if the file, local date time or zone ID is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final ChronoLocalDateTime chronoLocalDateTime, final ZoneId zoneId) { - Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); - Objects.requireNonNull(zoneId, "zoneId"); - return isFileOlder(file, chronoLocalDateTime.atZone(zoneId)); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code ChronoZonedDateTime}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param chronoZonedDateTime the date reference. - * @return true if the {@code File} exists and has been modified before the given - * {@code ChronoZonedDateTime}. - * @throws NullPointerException if the file or zoned date time is {@code null}. - * - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final ChronoZonedDateTime chronoZonedDateTime) { - Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); - return isFileOlder(file, chronoZonedDateTime.toInstant()); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code Date}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param date the date reference. - * @return true if the {@code File} exists and has been modified before the given {@code Date}. - * @throws NullPointerException if the file or date is {@code null}. - */ - public static boolean isFileOlder(final File file, final Date date) { - Objects.requireNonNull(date, "date"); - return isFileOlder(file, date.getTime()); - } - - /** - * Tests if the specified {@code File} is older than the reference {@code File}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param reference the {@code File} of which the modification date is used. - * @return true if the {@code File} exists and has been modified before the reference {@code File}. - * @throws NullPointerException if the file or reference file is {@code null}. - * @throws IllegalArgumentException if the reference file doesn't exist. - */ - public static boolean isFileOlder(final File file, final File reference) { - requireExists(reference, "reference"); - return isFileOlder(file, lastModifiedUnchecked(reference)); - } - - /** - * Tests if the specified {@code File} is older than the specified {@code Instant}. - * - * @param file the {@code File} of which the modification date must be compared. - * @param instant the date reference. - * @return true if the {@code File} exists and has been modified before the given {@code Instant}. - * @throws NullPointerException if the file or instant is {@code null}. - * @since 2.8.0 - */ - public static boolean isFileOlder(final File file, final Instant instant) { - Objects.requireNonNull(instant, "instant"); - return isFileOlder(file, instant.toEpochMilli()); - } - - /** - * Tests if the specified {@code File} is older than the specified time reference. - * - * @param file the {@code File} of which the modification date must be compared. - * @param timeMillis the time reference measured in milliseconds since the - * epoch (00:00:00 GMT, January 1, 1970). - * @return true if the {@code File} exists and has been modified before the given time reference. - * @throws NullPointerException if the file is {@code null}. - */ - public static boolean isFileOlder(final File file, final long timeMillis) { - Objects.requireNonNull(file, "file"); - return file.exists() && lastModifiedUnchecked(file) < timeMillis; - } - - /** - * Tests whether the specified {@code File} is a regular file or not. Implemented as a - * null-safe delegate to {@code Files.isRegularFile(Path path, LinkOption... options)}. - * - * @param file the path to the file. - * @param options options indicating how symbolic links are handled - * @return {@code true} if the file is a regular file; {@code false} if - * the path is null, the file does not exist, is not a directory, or it cannot - * be determined if the file is a regular file or not. - * @throws SecurityException In the case of the default provider, and a security manager is installed, the - * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read - * access to the directory. - * @since 2.9.0 - */ - public static boolean isRegularFile(final File file, final LinkOption... options) { - return file != null && Files.isRegularFile(file.toPath(), options); - } - - /** - * Tests whether the specified file is a symbolic link rather than an actual file. - *

- * This method delegates to {@link Files#isSymbolicLink(Path path)} - *

- * - * @param file the file to test. - * @return true if the file is a symbolic link, see {@link Files#isSymbolicLink(Path path)}. - * @since 2.0 - * @see Files#isSymbolicLink(Path) - */ - public static boolean isSymlink(final File file) { - return file != null && Files.isSymbolicLink(file.toPath()); - } - - /** - * Iterates over the files in given directory (and optionally - * its subdirectories). - *

- * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. - *

- *

- * All files found are filtered by an IOFileFilter. - *

- * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is {@code null}, subdirectories will not be included in the - * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - * @since 1.2 - */ - public static Iterator iterateFiles(final File directory, final IOFileFilter fileFilter, - final IOFileFilter dirFilter) { - return listFiles(directory, fileFilter, dirFilter).iterator(); - } - - /** - * Iterates over the files in a given directory (and optionally - * its subdirectories) which match an array of extensions. - *

- * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. - *

- *

- * - * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is {@code null}, all files are returned. - * @param recursive if true all subdirectories are searched as well - * @return an iterator of java.io.File with the matching files - * @since 1.2 - */ - public static Iterator iterateFiles(final File directory, final String[] extensions, - final boolean recursive) { - try { - return StreamIterator.iterator(streamFiles(directory, recursive, extensions)); - } catch (final IOException e) { - throw new UncheckedIOException(directory.toString(), e); - } - } - - /** - * Iterates over the files in given directory (and optionally - * its subdirectories). - *

- * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. - *

- *

- * All files found are filtered by an IOFileFilter. - *

- *

- * The resulting iterator includes the subdirectories themselves. - *

- * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is {@code null}, subdirectories will not be included in the - * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - * @since 2.2 - */ - public static Iterator iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, - final IOFileFilter dirFilter) { - return listFilesAndDirs(directory, fileFilter, dirFilter).iterator(); - } - - /** - * Returns the last modification time in milliseconds via - * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. - *

- * Use this method to avoid issues with {@link File#lastModified()} like - * JDK-8177809 where {@link File#lastModified()} is - * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10. - *

- * - * @param file The File to query. - * @return See {@link java.nio.file.attribute.FileTime#toMillis()}. - * @throws IOException if an I/O error occurs. - * @since 2.9.0 - */ - public static long lastModified(final File file) throws IOException { - // https://bugs.openjdk.java.net/browse/JDK-8177809 - // File.lastModified() is losing milliseconds (always ends in 000) - // This bug is in OpenJDK 8 and 9, and fixed in 10. - return Files.getLastModifiedTime(Objects.requireNonNull(file.toPath(), "file")).toMillis(); - } - - /** - * Returns the last modification time in milliseconds via - * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. - *

- * Use this method to avoid issues with {@link File#lastModified()} like - * JDK-8177809 where {@link File#lastModified()} is - * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10. - *

- * - * @param file The File to query. - * @return See {@link java.nio.file.attribute.FileTime#toMillis()}. - * @throws UncheckedIOException if an I/O error occurs. - * @since 2.9.0 - */ - public static long lastModifiedUnchecked(final File file) { - // https://bugs.openjdk.java.net/browse/JDK-8177809 - // File.lastModified() is losing milliseconds (always ends in 000) - // This bug is in OpenJDK 8 and 9, and fixed in 10. - try { - return lastModified(file); - } catch (final IOException e) { - throw new UncheckedIOException(file.toString(), e); - } - } - - /** - * Returns an Iterator for the lines in a {@code File} using the default encoding for the VM. - * - * @param file the file to open for input, must not be {@code null} - * @return an Iterator of the lines in the file, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @see #lineIterator(File, String) - * @since 1.3 - */ - public static LineIterator lineIterator(final File file) throws IOException { - return lineIterator(file, null); - } - - /** - * Returns an Iterator for the lines in a {@code File}. - *

- * This method opens an {@code InputStream} for the file. - * When you have finished with the iterator you should close the stream - * to free internal resources. This can be done by calling the - * {@link LineIterator#close()} or - * {@link LineIterator#closeQuietly(LineIterator)} method. - *

- *

- * The recommended usage pattern is: - *

- *
-     * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
-     * try {
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   LineIterator.closeQuietly(iterator);
-     * }
-     * 
- *

- * If an exception occurs during the creation of the iterator, the - * underlying stream is closed. - *

- * - * @param file the file to open for input, must not be {@code null} - * @param charsetName the name of the requested charset, {@code null} means platform default - * @return an Iterator of the lines in the file, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 1.2 - */ - public static LineIterator lineIterator(final File file, final String charsetName) throws IOException { - InputStream inputStream = null; - try { - inputStream = openInputStream(file); - return IOUtils.lineIterator(inputStream, charsetName); - } catch (final IOException | RuntimeException ex) { - IOUtils.closeQuietly(inputStream, ex::addSuppressed); - throw ex; - } - } - - private static AccumulatorPathVisitor listAccumulate(final File directory, final IOFileFilter fileFilter, - final IOFileFilter dirFilter) throws IOException { - final boolean isDirFilterSet = dirFilter != null; - final FileEqualsFileFilter rootDirFilter = new FileEqualsFileFilter(directory); - final PathFilter dirPathFilter = isDirFilterSet ? rootDirFilter.or(dirFilter) : rootDirFilter; - final AccumulatorPathVisitor visitor = new AccumulatorPathVisitor(Counters.noopPathCounters(), fileFilter, - dirPathFilter); - Files.walkFileTree(directory.toPath(), Collections.emptySet(), toMaxDepth(isDirFilterSet), visitor); - return visitor; - } - - /** - * Lists files in a directory, asserting that the supplied directory exists and is a directory. - * - * @param directory The directory to list - * @param fileFilter Optional file filter, may be null. - * @return The files in the directory, never {@code null}. - * @throws NullPointerException if directory is {@code null}. - * @throws IllegalArgumentException if directory does not exist or is not a directory. - * @throws IOException if an I/O error occurs. - */ - private static File[] listFiles(final File directory, final FileFilter fileFilter) throws IOException { - requireDirectoryExists(directory, "directory"); - final File[] files = fileFilter == null ? directory.listFiles() : directory.listFiles(fileFilter); - if (files == null) { - // null if the directory does not denote a directory, or if an I/O error occurs. - throw new IOException("Unknown I/O error listing contents of directory: " + directory); - } - return files; - } - - /** - * Finds files within a given directory (and optionally its - * subdirectories). All files found are filtered by an IOFileFilter. - *

- * If your search should recurse into subdirectories you can pass in - * an IOFileFilter for directories. You don't need to bind a - * DirectoryFileFilter (via logical AND) to this filter. This method does - * that for you. - *

- *

- * An example: If you want to search through all directories called - * "temp" you pass in {@code FileFilterUtils.NameFileFilter("temp")} - *

- *

- * Another common usage of this method is find files in a directory - * tree but ignoring the directories generated CVS. You can simply pass - * in {@code FileFilterUtils.makeCVSAware(null)}. - *

- * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. Must not be {@code null}, - * use {@link TrueFileFilter#INSTANCE} to match all files in selected directories. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is {@code null}, subdirectories will not be included in the - * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. - * @return a collection of java.io.File with the matching files - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - */ - public static Collection listFiles( - final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { - try { - final AccumulatorPathVisitor visitor = listAccumulate(directory, fileFilter, dirFilter); - return visitor.getFileList().stream().map(Path::toFile).collect(Collectors.toList()); - } catch (final IOException e) { - throw new UncheckedIOException(directory.toString(), e); - } - } - - /** - * Finds files within a given directory (and optionally its subdirectories) - * which match an array of extensions. - * - * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is {@code null}, all files are returned. - * @param recursive if true all subdirectories are searched as well - * @return a collection of java.io.File with the matching files - */ - public static Collection listFiles(final File directory, final String[] extensions, final boolean recursive) { - try { - return toList(streamFiles(directory, recursive, extensions)); - } catch (final IOException e) { - throw new UncheckedIOException(directory.toString(), e); - } - } - - /** - * Finds files within a given directory (and optionally its - * subdirectories). All files found are filtered by an IOFileFilter. - *

- * The resulting collection includes the starting directory and - * any subdirectories that match the directory filter. - *

- * - * @param directory the directory to search in - * @param fileFilter filter to apply when finding files. - * @param dirFilter optional filter to apply when finding subdirectories. - * If this parameter is {@code null}, subdirectories will not be included in the - * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return a collection of java.io.File with the matching files - * @see org.apache.commons.io.FileUtils#listFiles - * @see org.apache.commons.io.filefilter.FileFilterUtils - * @see org.apache.commons.io.filefilter.NameFileFilter - * @since 2.2 - */ - public static Collection listFilesAndDirs( - final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { - try { - final AccumulatorPathVisitor visitor = listAccumulate(directory, fileFilter, dirFilter); - final List list = visitor.getFileList(); - list.addAll(visitor.getDirList()); - return list.stream().map(Path::toFile).collect(Collectors.toList()); - } catch (final IOException e) { - throw new UncheckedIOException(directory.toString(), e); - } - } - - /** - * Calls {@link File#mkdirs()} and throws an exception on failure. - * - * @param directory the receiver for {@code mkdirs()}, may be null. - * @return the given file, may be null. - * @throws IOException if the directory was not created along with all its parent directories. - * @throws IOException if the given file object is not a directory. - * @throws SecurityException See {@link File#mkdirs()}. - * @see File#mkdirs() - */ - private static File mkdirs(final File directory) throws IOException { - if ((directory != null) && (!directory.mkdirs() && !directory.isDirectory())) { - throw new IOException("Cannot create directory '" + directory + "'."); - } - return directory; - } - - /** - * Moves a directory. - *

- * When the destination directory is on another file system, do a "copy and delete". - *

- * - * @param srcDir the directory to be moved. - * @param destDir the destination directory. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void moveDirectory(final File srcDir, final File destDir) throws IOException { - validateMoveParameters(srcDir, destDir); - requireDirectory(srcDir, "srcDir"); - requireAbsent(destDir, "destDir"); - if (!srcDir.renameTo(destDir)) { - if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) { - throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir); - } - copyDirectory(srcDir, destDir); - deleteDirectory(srcDir); - if (srcDir.exists()) { - throw new IOException("Failed to delete original directory '" + srcDir + - "' after copy to '" + destDir + "'"); - } - } - } - - /** - * Moves a directory to another directory. - * - * @param src the file to be moved. - * @param destDir the destination file. - * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an - * IOException. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws IllegalArgumentException if the source or destination is invalid. - * @throws FileNotFoundException if the source does not exist. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void moveDirectoryToDirectory(final File src, final File destDir, final boolean createDestDir) - throws IOException { - validateMoveParameters(src, destDir); - if (!destDir.isDirectory()) { - if (destDir.exists()) { - throw new IOException("Destination '" + destDir + "' is not a directory"); - } - if (!createDestDir) { - throw new FileNotFoundException("Destination directory '" + destDir + - "' does not exist [createDestDir=" + false + "]"); - } - mkdirs(destDir); - } - moveDirectory(src, new File(destDir, src.getName())); - } - - /** - * Moves a file preserving attributes. - *

- * Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}. - *

- *

- * When the destination file is on another file system, do a "copy and delete". - *

- * - * @param srcFile the file to be moved. - * @param destFile the destination file. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileExistsException if the destination file exists. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs. - * @since 1.4 - */ - public static void moveFile(final File srcFile, final File destFile) throws IOException { - moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES); - } - - /** - * Moves a file. - *

- * When the destination file is on another file system, do a "copy and delete". - *

- * - * @param srcFile the file to be moved. - * @param destFile the destination file. - * @param copyOptions Copy options. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileExistsException if the destination file exists. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 2.9.0 - */ - public static void moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions) - throws IOException { - validateMoveParameters(srcFile, destFile); - requireFile(srcFile, "srcFile"); - requireAbsent(destFile, null); - final boolean rename = srcFile.renameTo(destFile); - if (!rename) { - copyFile(srcFile, destFile, copyOptions); - if (!srcFile.delete()) { - FileUtils.deleteQuietly(destFile); - throw new IOException("Failed to delete original file '" + srcFile + - "' after copy to '" + destFile + "'"); - } - } - } - - /** - * Moves a file to a directory. - * - * @param srcFile the file to be moved. - * @param destDir the destination file. - * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an - * IOException. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileExistsException if the destination file exists. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) - throws IOException { - validateMoveParameters(srcFile, destDir); - if (!destDir.exists() && createDestDir) { - mkdirs(destDir); - } - requireExistsChecked(destDir, "destDir"); - requireDirectory(destDir, "destDir"); - moveFile(srcFile, new File(destDir, srcFile.getName())); - } - - /** - * Moves a file or directory to the destination directory. - *

- * When the destination is on another file system, do a "copy and delete". - *

- * - * @param src the file or directory to be moved. - * @param destDir the destination directory. - * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an - * IOException. - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileExistsException if the directory or file exists in the destination directory. - * @throws IOException if source or destination is invalid. - * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. - * @since 1.4 - */ - public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) - throws IOException { - validateMoveParameters(src, destDir); - if (src.isDirectory()) { - moveDirectoryToDirectory(src, destDir, createDestDir); - } else { - moveFileToDirectory(src, destDir, createDestDir); - } - } - - /** - * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling - * {@code new FileInputStream(file)}. - *

- * At the end of the method either the stream will be successfully opened, or an exception will have been thrown. - *

- *

- * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a - * directory. An exception is thrown if the file exists but cannot be read. - *

- * - * @param file the file to open for input, must not be {@code null} - * @return a new {@link FileInputStream} for the specified file - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException See FileNotFoundException above, FileNotFoundException is a subclass of IOException. - * @since 1.3 - */ - public static FileInputStream openInputStream(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - return new FileInputStream(file); - } - - /** - * Opens a {@link FileOutputStream} for the specified file, checking and - * creating the parent directory if it does not exist. - *

- * At the end of the method either the stream will be successfully opened, - * or an exception will have been thrown. - *

- *

- * The parent directory will be created if it does not exist. - * The file will be created if it does not exist. - * An exception is thrown if the file object exists but is a directory. - * An exception is thrown if the file exists but cannot be written to. - * An exception is thrown if the parent directory cannot be created. - *

- * - * @param file the file to open for output, must not be {@code null} - * @return a new {@link FileOutputStream} for the specified file - * @throws NullPointerException if the file object is {@code null}. - * @throws IllegalArgumentException if the file object is a directory - * @throws IllegalArgumentException if the file is not writable. - * @throws IOException if the directories could not be created. - * @since 1.3 - */ - public static FileOutputStream openOutputStream(final File file) throws IOException { - return openOutputStream(file, false); - } - - /** - * Opens a {@link FileOutputStream} for the specified file, checking and - * creating the parent directory if it does not exist. - *

- * At the end of the method either the stream will be successfully opened, - * or an exception will have been thrown. - *

- *

- * The parent directory will be created if it does not exist. - * The file will be created if it does not exist. - * An exception is thrown if the file object exists but is a directory. - * An exception is thrown if the file exists but cannot be written to. - * An exception is thrown if the parent directory cannot be created. - *

- * - * @param file the file to open for output, must not be {@code null} - * @param append if {@code true}, then bytes will be added to the - * end of the file rather than overwriting - * @return a new {@link FileOutputStream} for the specified file - * @throws NullPointerException if the file object is {@code null}. - * @throws IllegalArgumentException if the file object is a directory - * @throws IllegalArgumentException if the file is not writable. - * @throws IOException if the directories could not be created. - * @since 2.1 - */ - public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException { - Objects.requireNonNull(file, "file"); - if (file.exists()) { - requireFile(file, "file"); - requireCanWrite(file, "file"); - } else { - createParentDirectories(file); - } - return new FileOutputStream(file, append); - } - - /** - * Reads the contents of a file into a byte array. - * The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @return the file contents, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 1.1 - */ - public static byte[] readFileToByteArray(final File file) throws IOException { - try (InputStream inputStream = openInputStream(file)) { - final long fileLength = file.length(); - // file.length() may return 0 for system-dependent entities, treat 0 as unknown length - see IO-453 - return fileLength > 0 ? IOUtils.toByteArray(inputStream, fileLength) : IOUtils.toByteArray(inputStream); - } - } - - /** - * Reads the contents of a file into a String using the default encoding for the VM. - * The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @return the file contents, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 1.3.1 - * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static String readFileToString(final File file) throws IOException { - return readFileToString(file, Charset.defaultCharset()); - } - - /** - * Reads the contents of a file into a String. - * The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @param charsetName the name of the requested charset, {@code null} means platform default - * @return the file contents, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 2.3 - */ - public static String readFileToString(final File file, final Charset charsetName) throws IOException { - try (InputStream inputStream = openInputStream(file)) { - return IOUtils.toString(inputStream, Charsets.toCharset(charsetName)); - } - } - - /** - * Reads the contents of a file into a String. The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @param charsetName the name of the requested charset, {@code null} means platform default - * @return the file contents, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. - * @since 2.3 - */ - public static String readFileToString(final File file, final String charsetName) throws IOException { - return readFileToString(file, Charsets.toCharset(charsetName)); - } - - /** - * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. - * The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @return the list of Strings representing each line in the file, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 1.3 - * @deprecated 2.5 use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static List readLines(final File file) throws IOException { - return readLines(file, Charset.defaultCharset()); - } - - /** - * Reads the contents of a file line by line to a List of Strings. - * The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @param charset the charset to use, {@code null} means platform default - * @return the list of Strings representing each line in the file, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @since 2.3 - */ - public static List readLines(final File file, final Charset charset) throws IOException { - try (InputStream inputStream = openInputStream(file)) { - return IOUtils.readLines(inputStream, Charsets.toCharset(charset)); - } - } - - /** - * Reads the contents of a file line by line to a List of Strings. The file is always closed. - * - * @param file the file to read, must not be {@code null} - * @param charsetName the name of the requested charset, {@code null} means platform default - * @return the list of Strings representing each line in the file, never {@code null} - * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. - * @since 1.1 - */ - public static List readLines(final File file, final String charsetName) throws IOException { - return readLines(file, Charsets.toCharset(charsetName)); - } - - private static void requireAbsent(final File file, final String name) throws FileExistsException { - if (file.exists()) { - throw new FileExistsException( - String.format("File element in parameter '%s' already exists: '%s'", name, file)); - } - } - - - /** - * Throws IllegalArgumentException if the given files' canonical representations are equal. - * - * @param file1 The first file to compare. - * @param file2 The second file to compare. - * @throws IllegalArgumentException if the given files' canonical representations are equal. - */ - private static void requireCanonicalPathsNotEquals(final File file1, final File file2) throws IOException { - final String canonicalPath = file1.getCanonicalPath(); - if (canonicalPath.equals(file2.getCanonicalPath())) { - throw new IllegalArgumentException(String - .format("File canonical paths are equal: '%s' (file1='%s', file2='%s')", canonicalPath, file1, file2)); - } - } - - /** - * Throws an {@link IllegalArgumentException} if the file is not writable. This provides a more precise exception - * message than a plain access denied. - * - * @param file The file to test. - * @param name The parameter name to use in the exception message. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the file is not writable. - */ - private static void requireCanWrite(final File file, final String name) { - Objects.requireNonNull(file, "file"); - if (!file.canWrite()) { - throw new IllegalArgumentException("File parameter '" + name + " is not writable: '" + file + "'"); - } - } - - /** - * Requires that the given {@code File} is a directory. - * - * @param directory The {@code File} to check. - * @param name The parameter name to use in the exception message in case of null input or if the file is not a directory. - * @return the given directory. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory. - */ - private static File requireDirectory(final File directory, final String name) { - Objects.requireNonNull(directory, name); - if (!directory.isDirectory()) { - throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'"); - } - return directory; - } - - /** - * Requires that the given {@code File} exists and is a directory. - * - * @param directory The {@code File} to check. - * @param name The parameter name to use in the exception message in case of null input. - * @return the given directory. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory. - */ - private static File requireDirectoryExists(final File directory, final String name) { - requireExists(directory, name); - requireDirectory(directory, name); - return directory; - } - - /** - * Requires that the given {@code File} is a directory if it exists. - * - * @param directory The {@code File} to check. - * @param name The parameter name to use in the exception message in case of null input. - * @return the given directory. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} exists but is not a directory. - */ - private static File requireDirectoryIfExists(final File directory, final String name) { - Objects.requireNonNull(directory, name); - if (directory.exists()) { - requireDirectory(directory, name); - } - return directory; - } - - /** - * Requires that two file lengths are equal. - * - * @param srcFile Source file. - * @param destFile Destination file. - * @param srcLen Source file length. - * @param dstLen Destination file length - * @throws IOException Thrown when the given sizes are not equal. - */ - private static void requireEqualSizes(final File srcFile, final File destFile, final long srcLen, final long dstLen) - throws IOException { - if (srcLen != dstLen) { - throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile - + "' Expected length: " + srcLen + " Actual: " + dstLen); - } - } - - /** - * Requires that the given {@code File} exists and throws an {@link IllegalArgumentException} if it doesn't. - * - * @param file The {@code File} to check. - * @param fileParamName The parameter name to use in the exception message in case of {@code null} input. - * @return the given file. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist. - */ - private static File requireExists(final File file, final String fileParamName) { - Objects.requireNonNull(file, fileParamName); - if (!file.exists()) { - throw new IllegalArgumentException( - "File system element for parameter '" + fileParamName + "' does not exist: '" + file + "'"); - } - return file; - } - - /** - * Requires that the given {@code File} exists and throws an {@link FileNotFoundException} if it doesn't. - * - * @param file The {@code File} to check. - * @param fileParamName The parameter name to use in the exception message in case of {@code null} input. - * @return the given file. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws FileNotFoundException if the given {@code File} does not exist. - */ - private static File requireExistsChecked(final File file, final String fileParamName) throws FileNotFoundException { - Objects.requireNonNull(file, fileParamName); - if (!file.exists()) { - throw new FileNotFoundException( - "File system element for parameter '" + fileParamName + "' does not exist: '" + file + "'"); - } - return file; - } - - /** - * Requires that the given {@code File} is a file. - * - * @param file The {@code File} to check. - * @param name The parameter name to use in the exception message. - * @return the given file. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory. - */ - private static File requireFile(final File file, final String name) { - Objects.requireNonNull(file, name); - if (!file.isFile()) { - throw new IllegalArgumentException("Parameter '" + name + "' is not a file: " + file); - } - return file; - } - - /** - * Requires parameter attributes for a file copy operation. - * - * @param source the source file - * @param destination the destination - * @throws NullPointerException if any of the given {@code File}s are {@code null}. - * @throws FileNotFoundException if the source does not exist. - */ - private static void requireFileCopy(final File source, final File destination) throws FileNotFoundException { - requireExistsChecked(source, "source"); - Objects.requireNonNull(destination, "destination"); - } - - /** - * Requires that the given {@code File} is a file if it exists. - * - * @param file The {@code File} to check. - * @param name The parameter name to use in the exception message in case of null input. - * @return the given directory. - * @throws NullPointerException if the given {@code File} is {@code null}. - * @throws IllegalArgumentException if the given {@code File} does exists but is not a directory. - */ - private static File requireFileIfExists(final File file, final String name) { - Objects.requireNonNull(file, name); - return file.exists() ? requireFile(file, name) : file; - } - - /** - * Sets the given {@code targetFile}'s last modified date to the value from {@code sourceFile}. - * - * @param sourceFile The source file to query. - * @param targetFile The target file to set. - * @throws NullPointerException if sourceFile is {@code null}. - * @throws NullPointerException if targetFile is {@code null}. - * @throws IOException if setting the last-modified time failed. - */ - private static void setLastModified(final File sourceFile, final File targetFile) throws IOException { - Objects.requireNonNull(sourceFile, "sourceFile"); - setLastModified(targetFile, lastModified(sourceFile)); - } - - /** - * Sets the given {@code targetFile}'s last modified date to the given value. - * - * @param file The source file to query. - * @param timeMillis The new last-modified time, measured in milliseconds since the epoch 01-01-1970 GMT. - * @throws NullPointerException if file is {@code null}. - * @throws IOException if setting the last-modified time failed. - */ - private static void setLastModified(final File file, final long timeMillis) throws IOException { - Objects.requireNonNull(file, "file"); - if (!file.setLastModified(timeMillis)) { - throw new IOException(String.format("Failed setLastModified(%s) on '%s'", timeMillis, file)); - } - } - - /** - * Returns the size of the specified file or directory. If the provided - * {@link File} is a regular file, then the file's length is returned. - * If the argument is a directory, then the size of the directory is - * calculated recursively. If a directory or subdirectory is security - * restricted, its size will not be included. - *

- * Note that overflow is not detected, and the return value may be negative if - * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative - * method that does not overflow. - *

- * - * @param file the regular file or directory to return the size - * of (must not be {@code null}). - * - * @return the length of the file, or recursive size of the directory, - * provided (in bytes). - * - * @throws NullPointerException if the file is {@code null}. - * @throws IllegalArgumentException if the file does not exist. - * - * @since 2.0 - */ - public static long sizeOf(final File file) { - requireExists(file, "file"); - return file.isDirectory() ? sizeOfDirectory0(file) : file.length(); - } - - /** - * Gets the size of a file. - * - * @param file the file to check. - * @return the size of the file. - * @throws NullPointerException if the file is {@code null}. - */ - private static long sizeOf0(final File file) { - Objects.requireNonNull(file, "file"); - if (file.isDirectory()) { - return sizeOfDirectory0(file); - } - return file.length(); // will be 0 if file does not exist - } - - /** - * Returns the size of the specified file or directory. If the provided - * {@link File} is a regular file, then the file's length is returned. - * If the argument is a directory, then the size of the directory is - * calculated recursively. If a directory or subdirectory is security - * restricted, its size will not be included. - * - * @param file the regular file or directory to return the size - * of (must not be {@code null}). - * - * @return the length of the file, or recursive size of the directory, - * provided (in bytes). - * - * @throws NullPointerException if the file is {@code null}. - * @throws IllegalArgumentException if the file does not exist. - * - * @since 2.4 - */ - public static BigInteger sizeOfAsBigInteger(final File file) { - requireExists(file, "file"); - return file.isDirectory() ? sizeOfDirectoryBig0(file) : BigInteger.valueOf(file.length()); - } - - /** - * Returns the size of a file or directory. - * - * @param file The file or directory. - * @return the size - */ - private static BigInteger sizeOfBig0(final File file) { - Objects.requireNonNull(file, "fileOrDir"); - return file.isDirectory() ? sizeOfDirectoryBig0(file) : BigInteger.valueOf(file.length()); - } - - /** - * Counts the size of a directory recursively (sum of the length of all files). - *

- * Note that overflow is not detected, and the return value may be negative if - * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative - * method that does not overflow. - *

- * - * @param directory directory to inspect, must not be {@code null}. - * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total - * is greater than {@link Long#MAX_VALUE}. - * @throws NullPointerException if the directory is {@code null}. - */ - public static long sizeOfDirectory(final File directory) { - return sizeOfDirectory0(requireDirectoryExists(directory, "directory")); - } - - /** - * Gets the size of a directory. - * - * @param directory the directory to check - * @return the size - * @throws NullPointerException if the directory is {@code null}. - */ - private static long sizeOfDirectory0(final File directory) { - Objects.requireNonNull(directory, "directory"); - final File[] files = directory.listFiles(); - if (files == null) { // null if security restricted - return 0L; - } - long size = 0; - - for (final File file : files) { - if (!isSymlink(file)) { - size += sizeOf0(file); - if (size < 0) { - break; - } - } - } - - return size; - } - - /** - * Counts the size of a directory recursively (sum of the length of all files). - * - * @param directory directory to inspect, must not be {@code null}. - * @return size of directory in bytes, 0 if directory is security restricted. - * @throws NullPointerException if the directory is {@code null}. - * @since 2.4 - */ - public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) { - return sizeOfDirectoryBig0(requireDirectoryExists(directory, "directory")); - } - - /** - * Computes the size of a directory. - * - * @param directory The directory. - * @return the size. - */ - private static BigInteger sizeOfDirectoryBig0(final File directory) { - Objects.requireNonNull(directory, "directory"); - final File[] files = directory.listFiles(); - if (files == null) { - // null if security restricted - return BigInteger.ZERO; - } - BigInteger size = BigInteger.ZERO; - - for (final File file : files) { - if (!isSymlink(file)) { - size = size.add(sizeOfBig0(file)); - } - } - - return size; - } - - /** - * Streams over the files in a given directory (and optionally - * its subdirectories) which match an array of extensions. - * - * @param directory the directory to search in - * @param recursive if true all subdirectories are searched as well - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is {@code null}, all files are returned. - * @return an iterator of java.io.File with the matching files - * @throws IOException if an I/O error is thrown when accessing the starting file. - * @since 2.9.0 - */ - public static Stream streamFiles(final File directory, final boolean recursive, final String... extensions) - throws IOException { - final IOFileFilter filter = extensions == null ? FileFileFilter.INSTANCE - : FileFileFilter.INSTANCE.and(new SuffixFileFilter(toSuffixes(extensions))); - return PathUtils.walk(directory.toPath(), filter, toMaxDepth(recursive), false, FileVisitOption.FOLLOW_LINKS) - .map(Path::toFile); - } - - /** - * Converts from a {@code URL} to a {@code File}. - *

- * From version 1.1 this method will decode the URL. - * Syntax such as {@code file:///my%20docs/file.txt} will be - * correctly decoded to {@code /my docs/file.txt}. Starting with version - * 1.5, this method uses UTF-8 to decode percent-encoded octets to characters. - * Additionally, malformed percent-encoded octets are handled leniently by - * passing them through literally. - *

- * - * @param url the file URL to convert, {@code null} returns {@code null} - * @return the equivalent {@code File} object, or {@code null} - * if the URL's protocol is not {@code file} - */ - public static File toFile(final URL url) { - if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { - return null; - } - final String filename = url.getFile().replace('/', File.separatorChar); - return new File(decodeUrl(filename)); - } - - /** - * Converts each of an array of {@code URL} to a {@code File}. - *

- * Returns an array of the same size as the input. - * If the input is {@code null}, an empty array is returned. - * If the input contains {@code null}, the output array contains {@code null} at the same - * index. - *

- *

- * This method will decode the URL. - * Syntax such as {@code file:///my%20docs/file.txt} will be - * correctly decoded to {@code /my docs/file.txt}. - *

- * - * @param urls the file URLs to convert, {@code null} returns empty array - * @return a non-{@code null} array of Files matching the input, with a {@code null} item - * if there was a {@code null} at that index in the input array - * @throws IllegalArgumentException if any file is not a URL file - * @throws IllegalArgumentException if any file is incorrectly encoded - * @since 1.1 - */ - public static File[] toFiles(final URL... urls) { - if (IOUtils.length(urls) == 0) { - return EMPTY_FILE_ARRAY; - } - final File[] files = new File[urls.length]; - for (int i = 0; i < urls.length; i++) { - final URL url = urls[i]; - if (url != null) { - if (!"file".equalsIgnoreCase(url.getProtocol())) { - throw new IllegalArgumentException("Can only convert file URL to a File: " + url); - } - files[i] = toFile(url); - } - } - return files; - } - - private static List toList(final Stream stream) { - return stream.collect(Collectors.toList()); - } - - /** - * Converts whether or not to recurse into a recursion max depth. - * - * @param recursive whether or not to recurse - * @return the recursion depth - */ - private static int toMaxDepth(final boolean recursive) { - return recursive ? Integer.MAX_VALUE : 1; - } - - /** - * Converts an array of file extensions to suffixes. - * - * @param extensions an array of extensions. Format: {"java", "xml"} - * @return an array of suffixes. Format: {".java", ".xml"} - * @throws NullPointerException if the parameter is null - */ - private static String[] toSuffixes(final String... extensions) { - Objects.requireNonNull(extensions, "extensions"); - final String[] suffixes = new String[extensions.length]; - for (int i = 0; i < extensions.length; i++) { - suffixes[i] = "." + extensions[i]; - } - return suffixes; - } - - /** - * Implements the same behavior as the "touch" utility on Unix. It creates - * a new file with size 0 or, if the file exists already, it is opened and - * closed without modifying it, but updating the file date and time. - *

- * NOTE: As from v1.3, this method throws an IOException if the last - * modified date of the file cannot be set. Also, as from v1.3 this method - * creates parent directories if they do not exist. - *

- * - * @param file the File to touch. - * @throws IOException if an I/O problem occurs. - * @throws IOException if setting the last-modified time failed. - */ - public static void touch(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - if (!file.exists()) { - openOutputStream(file).close(); - } - setLastModified(file, System.currentTimeMillis()); - } - - /** - * Converts each of an array of {@code File} to a {@code URL}. - *

- * Returns an array of the same size as the input. - *

- * - * @param files the files to convert, must not be {@code null} - * @return an array of URLs matching the input - * @throws IOException if a file cannot be converted - * @throws NullPointerException if the parameter is null - */ - public static URL[] toURLs(final File... files) throws IOException { - Objects.requireNonNull(files, "files"); - final URL[] urls = new URL[files.length]; - for (int i = 0; i < urls.length; i++) { - urls[i] = files[i].toURI().toURL(); - } - return urls; - } - - /** - * Validates the given arguments. - *
    - *
  • Throws {@link NullPointerException} if {@code source} is null
  • - *
  • Throws {@link NullPointerException} if {@code destination} is null
  • - *
  • Throws {@link FileNotFoundException} if {@code source} does not exist
  • - *
- * - * @param source the file or directory to be moved - * @param destination the destination file or directory - * @throws FileNotFoundException if {@code source} file does not exist - */ - private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException { - Objects.requireNonNull(source, "source"); - Objects.requireNonNull(destination, "destination"); - if (!source.exists()) { - throw new FileNotFoundException("Source '" + source + "' does not exist"); - } - } - - /** - * Waits for NFS to propagate a file creation, imposing a timeout. - *

- * This method repeatedly tests {@link File#exists()} until it returns - * true up to the maximum time specified in seconds. - *

- * - * @param file the file to check, must not be {@code null} - * @param seconds the maximum time in seconds to wait - * @return true if file exists - * @throws NullPointerException if the file is {@code null} - */ - public static boolean waitFor(final File file, final int seconds) { - Objects.requireNonNull(file, "file"); - final long finishAtMillis = System.currentTimeMillis() + (seconds * 1000L); - boolean wasInterrupted = false; - try { - while (!file.exists()) { - final long remainingMillis = finishAtMillis - System.currentTimeMillis(); - if (remainingMillis < 0){ - return false; - } - try { - Thread.sleep(Math.min(100, remainingMillis)); - } catch (final InterruptedException ignore) { - wasInterrupted = true; - } catch (final Exception ex) { - break; - } - } - } finally { - if (wasInterrupted) { - Thread.currentThread().interrupt(); - } - } - return true; - } - - /** - * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. - * - * @param file the file to write - * @param data the content to write to the file - * @throws IOException in case of an I/O error - * @since 2.0 - * @deprecated 2.5 use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static void write(final File file, final CharSequence data) throws IOException { - write(file, data, Charset.defaultCharset(), false); - } - - /** - * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. - * - * @param file the file to write - * @param data the content to write to the file - * @param append if {@code true}, then the data will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.1 - * @deprecated 2.5 use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static void write(final File file, final CharSequence data, final boolean append) throws IOException { - write(file, data, Charset.defaultCharset(), append); - } - - /** - * Writes a CharSequence to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charset the name of the requested charset, {@code null} means platform default - * @throws IOException in case of an I/O error - * @since 2.3 - */ - public static void write(final File file, final CharSequence data, final Charset charset) throws IOException { - write(file, data, charset, false); - } - - /** - * Writes a CharSequence to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charset the charset to use, {@code null} means platform default - * @param append if {@code true}, then the data will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.3 - */ - public static void write(final File file, final CharSequence data, final Charset charset, final boolean append) - throws IOException { - writeStringToFile(file, Objects.toString(data, null), charset, append); - } - - // Private method, must be invoked will a directory parameter - - /** - * Writes a CharSequence to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charsetName the name of the requested charset, {@code null} means platform default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 2.0 - */ - public static void write(final File file, final CharSequence data, final String charsetName) throws IOException { - write(file, data, charsetName, false); - } - - /** - * Writes a CharSequence to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param append if {@code true}, then the data will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM - * @since 2.1 - */ - public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) - throws IOException { - write(file, data, Charsets.toCharset(charsetName), append); - } - - /** - * Writes a byte array to a file creating the file if it does not exist. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - *

- * - * @param file the file to write to - * @param data the content to write to the file - * @throws IOException in case of an I/O error - * @since 1.1 - */ - public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException { - writeByteArrayToFile(file, data, false); - } - - // Must be called with a directory - - /** - * Writes a byte array to a file creating the file if it does not exist. - * - * @param file the file to write to - * @param data the content to write to the file - * @param append if {@code true}, then bytes will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.1 - */ - public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) - throws IOException { - writeByteArrayToFile(file, data, 0, data.length, append); - } - - /** - * Writes {@code len} bytes from the specified byte array starting - * at offset {@code off} to a file, creating the file if it does - * not exist. - * - * @param file the file to write to - * @param data the content to write to the file - * @param off the start offset in the data - * @param len the number of bytes to write - * @throws IOException in case of an I/O error - * @since 2.5 - */ - public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) - throws IOException { - writeByteArrayToFile(file, data, off, len, false); - } - - /** - * Writes {@code len} bytes from the specified byte array starting - * at offset {@code off} to a file, creating the file if it does - * not exist. - * - * @param file the file to write to - * @param data the content to write to the file - * @param off the start offset in the data - * @param len the number of bytes to write - * @param append if {@code true}, then bytes will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.5 - */ - public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, - final boolean append) throws IOException { - try (OutputStream out = openOutputStream(file, append)) { - out.write(data, off, len); - } - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The default VM encoding and the default line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, {@code null} entries produce blank lines - * @throws IOException in case of an I/O error - * @since 1.3 - */ - public static void writeLines(final File file, final Collection lines) throws IOException { - writeLines(file, null, lines, null, false); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The default VM encoding and the default line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, {@code null} entries produce blank lines - * @param append if {@code true}, then the lines will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.1 - */ - public static void writeLines(final File file, final Collection lines, final boolean append) throws IOException { - writeLines(file, null, lines, null, append); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The default VM encoding and the specified line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, {@code null} entries produce blank lines - * @param lineEnding the line separator to use, {@code null} is system default - * @throws IOException in case of an I/O error - * @since 1.3 - */ - public static void writeLines(final File file, final Collection lines, final String lineEnding) - throws IOException { - writeLines(file, null, lines, lineEnding, false); - } - - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The default VM encoding and the specified line ending will be used. - * - * @param file the file to write to - * @param lines the lines to write, {@code null} entries produce blank lines - * @param lineEnding the line separator to use, {@code null} is system default - * @param append if {@code true}, then the lines will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.1 - */ - public static void writeLines(final File file, final Collection lines, final String lineEnding, - final boolean append) throws IOException { - writeLines(file, null, lines, lineEnding, append); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The specified character encoding and the default line ending will be used. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - *

- * - * @param file the file to write to - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param lines the lines to write, {@code null} entries produce blank lines - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 1.1 - */ - public static void writeLines(final File file, final String charsetName, final Collection lines) - throws IOException { - writeLines(file, charsetName, lines, null, false); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line, optionally appending. - * The specified character encoding and the default line ending will be used. - * - * @param file the file to write to - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param lines the lines to write, {@code null} entries produce blank lines - * @param append if {@code true}, then the lines will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 2.1 - */ - public static void writeLines(final File file, final String charsetName, final Collection lines, - final boolean append) throws IOException { - writeLines(file, charsetName, lines, null, append); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The specified character encoding and the line ending will be used. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - *

- * - * @param file the file to write to - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param lines the lines to write, {@code null} entries produce blank lines - * @param lineEnding the line separator to use, {@code null} is system default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 1.1 - */ - public static void writeLines(final File file, final String charsetName, final Collection lines, - final String lineEnding) throws IOException { - writeLines(file, charsetName, lines, lineEnding, false); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * the specified {@code File} line by line. - * The specified character encoding and the line ending will be used. - * - * @param file the file to write to - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param lines the lines to write, {@code null} entries produce blank lines - * @param lineEnding the line separator to use, {@code null} is system default - * @param append if {@code true}, then the lines will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 2.1 - */ - public static void writeLines(final File file, final String charsetName, final Collection lines, - final String lineEnding, final boolean append) throws IOException { - try (OutputStream out = new BufferedOutputStream(openOutputStream(file, append))) { - IOUtils.writeLines(lines, lineEnding, out, charsetName); - } - } - - /** - * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. - * - * @param file the file to write - * @param data the content to write to the file - * @throws IOException in case of an I/O error - * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static void writeStringToFile(final File file, final String data) throws IOException { - writeStringToFile(file, data, Charset.defaultCharset(), false); - } - - /** - * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. - * - * @param file the file to write - * @param data the content to write to the file - * @param append if {@code true}, then the String will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.1 - * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding) - */ - @Deprecated - public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException { - writeStringToFile(file, data, Charset.defaultCharset(), append); - } - - /** - * Writes a String to a file creating the file if it does not exist. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - *

- * - * @param file the file to write - * @param data the content to write to the file - * @param charset the charset to use, {@code null} means platform default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - * @since 2.4 - */ - public static void writeStringToFile(final File file, final String data, final Charset charset) - throws IOException { - writeStringToFile(file, data, charset, false); - } - - /** - * Writes a String to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charset the charset to use, {@code null} means platform default - * @param append if {@code true}, then the String will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @since 2.3 - */ - public static void writeStringToFile(final File file, final String data, final Charset charset, - final boolean append) throws IOException { - try (OutputStream out = openOutputStream(file, append)) { - IOUtils.write(data, out, charset); - } - } - - /** - * Writes a String to a file creating the file if it does not exist. - *

- * NOTE: As from v1.3, the parent directories of the file will be created - * if they do not exist. - *

- * - * @param file the file to write - * @param data the content to write to the file - * @param charsetName the name of the requested charset, {@code null} means platform default - * @throws IOException in case of an I/O error - * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM - */ - public static void writeStringToFile(final File file, final String data, final String charsetName) throws IOException { - writeStringToFile(file, data, charsetName, false); - } - - /** - * Writes a String to a file creating the file if it does not exist. - * - * @param file the file to write - * @param data the content to write to the file - * @param charsetName the name of the requested charset, {@code null} means platform default - * @param append if {@code true}, then the String will be added to the - * end of the file rather than overwriting - * @throws IOException in case of an I/O error - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM - * @since 2.1 - */ - public static void writeStringToFile(final File file, final String data, final String charsetName, - final boolean append) throws IOException { - writeStringToFile(file, data, Charsets.toCharset(charsetName), append); - } - - /** - * Instances should NOT be constructed in standard programming. - * @deprecated Will be private in 3.0. - */ - @Deprecated - public FileUtils() { //NOSONAR - - } -} diff --git a/src/org/apache/commons/io/FilenameUtils.java b/src/org/apache/commons/io/FilenameUtils.java deleted file mode 100644 index 7ef31ccb..00000000 --- a/src/org/apache/commons/io/FilenameUtils.java +++ /dev/null @@ -1,1631 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.File; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Deque; -import java.util.List; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * General file name and file path manipulation utilities. - *

- * When dealing with file names you can hit problems when moving from a Windows - * based development machine to a Unix based production machine. - * This class aims to help avoid those problems. - *

- * NOTE: You may be able to avoid using this class entirely simply by - * using JDK {@link java.io.File File} objects and the two argument constructor - * {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}. - *

- * Most methods on this class are designed to work the same on both Unix and Windows. - * Those that don't include 'System', 'Unix' or 'Windows' in their name. - *

- * Most methods recognize both separators (forward and back), and both - * sets of prefixes. See the Javadoc of each method for details. - *

- * This class defines six components within a file name - * (example C:\dev\project\file.txt): - *

    - *
  • the prefix - C:\
  • - *
  • the path - dev\project\
  • - *
  • the full path - C:\dev\project\
  • - *
  • the name - file.txt
  • - *
  • the base name - file
  • - *
  • the extension - txt
  • - *
- * Note that this class works best if directory file names end with a separator. - * If you omit the last separator, it is impossible to determine if the file name - * corresponds to a file or a directory. As a result, we have chosen to say - * it corresponds to a file. - *

- * This class only supports Unix and Windows style names. - * Prefixes are matched as follows: - *

- * Windows:
- * a\b\c.txt           --> ""          --> relative
- * \a\b\c.txt          --> "\"         --> current drive absolute
- * C:a\b\c.txt         --> "C:"        --> drive relative
- * C:\a\b\c.txt        --> "C:\"       --> absolute
- * \\server\a\b\c.txt  --> "\\server\" --> UNC
- *
- * Unix:
- * a/b/c.txt           --> ""          --> relative
- * /a/b/c.txt          --> "/"         --> absolute
- * ~/a/b/c.txt         --> "~/"        --> current user
- * ~                   --> "~/"        --> current user (slash added)
- * ~user/a/b/c.txt     --> "~user/"    --> named user
- * ~user               --> "~user/"    --> named user (slash added)
- * 
- * Both prefix styles are matched always, irrespective of the machine that you are - * currently running on. - *

- * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. - * - * @since 1.1 - */ -public class FilenameUtils { - - private static final String[] EMPTY_STRING_ARRAY = {}; - - private static final String EMPTY_STRING = ""; - - private static final int NOT_FOUND = -1; - - /** - * The extension separator character. - * @since 1.4 - */ - public static final char EXTENSION_SEPARATOR = '.'; - - /** - * The extension separator String. - * @since 1.4 - */ - public static final String EXTENSION_SEPARATOR_STR = Character.toString(EXTENSION_SEPARATOR); - - /** - * The Unix separator character. - */ - private static final char UNIX_SEPARATOR = '/'; - - /** - * The Windows separator character. - */ - private static final char WINDOWS_SEPARATOR = '\\'; - - /** - * The system separator character. - */ - private static final char SYSTEM_SEPARATOR = File.separatorChar; - - /** - * The separator character that is the opposite of the system separator. - */ - private static final char OTHER_SEPARATOR; - static { - if (isSystemWindows()) { - OTHER_SEPARATOR = UNIX_SEPARATOR; - } else { - OTHER_SEPARATOR = WINDOWS_SEPARATOR; - } - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public FilenameUtils() { - } - - /** - * Determines if Windows file system is in use. - * - * @return true if the system is Windows - */ - static boolean isSystemWindows() { - return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR; - } - - /** - * Checks if the character is a separator. - * - * @param ch the character to check - * @return true if it is a separator character - */ - private static boolean isSeparator(final char ch) { - return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR; - } - - /** - * Normalizes a path, removing double and single dot path steps. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *

- * A trailing slash will be retained. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo//               -->   /foo/
-     * /foo/./              -->   /foo/
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar/
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo/
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar/
-     * ~/../bar             -->   null
-     * 
- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param fileName the fileName to normalize, null returns null - * @return the normalized fileName, or null if invalid. Null bytes inside string will be removed - */ - public static String normalize(final String fileName) { - return doNormalize(fileName, SYSTEM_SEPARATOR, true); - } - /** - * Normalizes a path, removing double and single dot path steps. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format specified. - *

- * A trailing slash will be retained. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo//               -->   /foo/
-     * /foo/./              -->   /foo/
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar/
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo/
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar/
-     * ~/../bar             -->   null
-     * 
- * The output will be the same on both Unix and Windows including - * the separator character. - * - * @param fileName the fileName to normalize, null returns null - * @param unixSeparator {@code true} if a unix separator should - * be used or {@code false} if a windows separator should be used. - * @return the normalized fileName, or null if invalid. Null bytes inside string will be removed - * @since 2.0 - */ - public static String normalize(final String fileName, final boolean unixSeparator) { - final char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; - return doNormalize(fileName, separator, true); - } - - /** - * Normalizes a path, removing double and single dot path steps, - * and removing any final directory separator. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *

- * A trailing slash will be removed. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo//               -->   /foo
-     * /foo/./              -->   /foo
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar
-     * ~/../bar             -->   null
-     * 
- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param fileName the fileName to normalize, null returns null - * @return the normalized fileName, or null if invalid. Null bytes inside string will be removed - */ - public static String normalizeNoEndSeparator(final String fileName) { - return doNormalize(fileName, SYSTEM_SEPARATOR, false); - } - - /** - * Normalizes a path, removing double and single dot path steps, - * and removing any final directory separator. - *

- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format specified. - *

- * A trailing slash will be removed. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *

- * The output will be the same on both Unix and Windows including - * the separator character. - *

-     * /foo//               -->   /foo
-     * /foo/./              -->   /foo
-     * /foo/../bar          -->   /bar
-     * /foo/../bar/         -->   /bar
-     * /foo/../bar/../baz   -->   /baz
-     * //foo//./bar         -->   /foo/bar
-     * /../                 -->   null
-     * ../foo               -->   null
-     * foo/bar/..           -->   foo
-     * foo/../../bar        -->   null
-     * foo/../bar           -->   bar
-     * //server/foo/../bar  -->   //server/bar
-     * //server/../bar      -->   null
-     * C:\foo\..\bar        -->   C:\bar
-     * C:\..\bar            -->   null
-     * ~/foo/../bar/        -->   ~/bar
-     * ~/../bar             -->   null
-     * 
- * - * @param fileName the fileName to normalize, null returns null - * @param unixSeparator {@code true} if a unix separator should - * be used or {@code false} if a windows separator should be used. - * @return the normalized fileName, or null if invalid. Null bytes inside string will be removed - * @since 2.0 - */ - public static String normalizeNoEndSeparator(final String fileName, final boolean unixSeparator) { - final char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; - return doNormalize(fileName, separator, false); - } - - /** - * Internal method to perform the normalization. - * - * @param fileName the fileName - * @param separator The separator character to use - * @param keepSeparator true to keep the final separator - * @return the normalized fileName. Null bytes inside string will be removed. - */ - private static String doNormalize(final String fileName, final char separator, final boolean keepSeparator) { - if (fileName == null) { - return null; - } - - requireNonNullChars(fileName); - - int size = fileName.length(); - if (size == 0) { - return fileName; - } - final int prefix = getPrefixLength(fileName); - if (prefix < 0) { - return null; - } - - final char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy - fileName.getChars(0, fileName.length(), array, 0); - - // fix separators throughout - final char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR; - for (int i = 0; i < array.length; i++) { - if (array[i] == otherSeparator) { - array[i] = separator; - } - } - - // add extra separator on the end to simplify code below - boolean lastIsDirectory = true; - if (array[size - 1] != separator) { - array[size++] = separator; - lastIsDirectory = false; - } - - // adjoining slashes - // If we get here, prefix can only be 0 or greater, size 1 or greater - // If prefix is 0, set loop start to 1 to prevent index errors - for (int i = (prefix != 0) ? prefix : 1; i < size; i++) { - if (array[i] == separator && array[i - 1] == separator) { - System.arraycopy(array, i, array, i - 1, size - i); - size--; - i--; - } - } - - // dot slash - for (int i = prefix + 1; i < size; i++) { - if (array[i] == separator && array[i - 1] == '.' && - (i == prefix + 1 || array[i - 2] == separator)) { - if (i == size - 1) { - lastIsDirectory = true; - } - System.arraycopy(array, i + 1, array, i - 1, size - i); - size -=2; - i--; - } - } - - // double dot slash - outer: - for (int i = prefix + 2; i < size; i++) { - if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' && - (i == prefix + 2 || array[i - 3] == separator)) { - if (i == prefix + 2) { - return null; - } - if (i == size - 1) { - lastIsDirectory = true; - } - int j; - for (j = i - 4 ; j >= prefix; j--) { - if (array[j] == separator) { - // remove b/../ from a/b/../c - System.arraycopy(array, i + 1, array, j + 1, size - i); - size -= i - j; - i = j + 1; - continue outer; - } - } - // remove a/../ from a/../c - System.arraycopy(array, i + 1, array, prefix, size - i); - size -= i + 1 - prefix; - i = prefix + 1; - } - } - - if (size <= 0) { // should never be less than 0 - return EMPTY_STRING; - } - if (size <= prefix) { // should never be less than prefix - return new String(array, 0, size); - } - if (lastIsDirectory && keepSeparator) { - return new String(array, 0, size); // keep trailing separator - } - return new String(array, 0, size - 1); // lose trailing separator - } - - /** - * Concatenates a fileName to a base path using normal command line style rules. - *

- * The effect is equivalent to resultant directory after changing - * directory to the first argument, followed by changing directory to - * the second argument. - *

- * The first argument is the base path, the second is the path to concatenate. - * The returned path is always normalized via {@link #normalize(String)}, - * thus {@code ..} is handled. - *

- * If {@code pathToAdd} is absolute (has an absolute prefix), then - * it will be normalized and returned. - * Otherwise, the paths will be joined, normalized and returned. - *

- * The output will be the same on both Unix and Windows except - * for the separator character. - *

-     * /foo/      + bar        -->  /foo/bar
-     * /foo       + bar        -->  /foo/bar
-     * /foo       + /bar       -->  /bar
-     * /foo       + C:/bar     -->  C:/bar
-     * /foo       + C:bar      -->  C:bar (*)
-     * /foo/a/    + ../bar     -->  /foo/bar
-     * /foo/      + ../../bar  -->  null
-     * /foo/      + /bar       -->  /bar
-     * /foo/..    + /bar       -->  /bar
-     * /foo       + bar/c.txt  -->  /foo/bar/c.txt
-     * /foo/c.txt + bar        -->  /foo/c.txt/bar (!)
-     * 
- * (*) Note that the Windows relative drive prefix is unreliable when - * used with this method. - * (!) Note that the first parameter must be a path. If it ends with a name, then - * the name will be built into the concatenated path. If this might be a problem, - * use {@link #getFullPath(String)} on the base path argument. - * - * @param basePath the base path to attach to, always treated as a path - * @param fullFileNameToAdd the fileName (or path) to attach to the base - * @return the concatenated path, or null if invalid. Null bytes inside string will be removed - */ - public static String concat(final String basePath, final String fullFileNameToAdd) { - final int prefix = getPrefixLength(fullFileNameToAdd); - if (prefix < 0) { - return null; - } - if (prefix > 0) { - return normalize(fullFileNameToAdd); - } - if (basePath == null) { - return null; - } - final int len = basePath.length(); - if (len == 0) { - return normalize(fullFileNameToAdd); - } - final char ch = basePath.charAt(len - 1); - if (isSeparator(ch)) { - return normalize(basePath + fullFileNameToAdd); - } - return normalize(basePath + '/' + fullFileNameToAdd); - } - - /** - * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory). - *

- * The files names are expected to be normalized. - *

- * - * Edge cases: - *
    - *
  • A {@code directory} must not be null: if null, throw IllegalArgumentException
  • - *
  • A directory does not contain itself: return false
  • - *
  • A null child file is not contained in any parent: return false
  • - *
- * - * @param canonicalParent - * the file to consider as the parent. - * @param canonicalChild - * the file to consider as the child. - * @return true is the candidate leaf is under by the specified composite. False otherwise. - * @since 2.2 - * @see FileUtils#directoryContains(File, File) - */ - public static boolean directoryContains(final String canonicalParent, final String canonicalChild) { - Objects.requireNonNull(canonicalParent, "canonicalParent"); - - if (canonicalChild == null) { - return false; - } - - if (IOCase.SYSTEM.checkEquals(canonicalParent, canonicalChild)) { - return false; - } - - return IOCase.SYSTEM.checkStartsWith(canonicalChild, canonicalParent); - } - - /** - * Converts all separators to the Unix separator of forward slash. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToUnix(final String path) { - if (path == null || path.indexOf(WINDOWS_SEPARATOR) == NOT_FOUND) { - return path; - } - return path.replace(WINDOWS_SEPARATOR, UNIX_SEPARATOR); - } - - /** - * Converts all separators to the Windows separator of backslash. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToWindows(final String path) { - if (path == null || path.indexOf(UNIX_SEPARATOR) == NOT_FOUND) { - return path; - } - return path.replace(UNIX_SEPARATOR, WINDOWS_SEPARATOR); - } - - /** - * Converts all separators to the system separator. - * - * @param path the path to be changed, null ignored - * @return the updated path - */ - public static String separatorsToSystem(final String path) { - if (path == null) { - return null; - } - return isSystemWindows() ? separatorsToWindows(path) : separatorsToUnix(path); - } - - /** - * Returns the length of the fileName prefix, such as {@code C:/} or {@code ~/}. - *

- * This method will handle a file in either Unix or Windows format. - *

- * The prefix length includes the first slash in the full fileName - * if applicable. Thus, it is possible that the length returned is greater - * than the length of the input string. - *

-     * Windows:
-     * a\b\c.txt           --> 0           --> relative
-     * \a\b\c.txt          --> 1           --> current drive absolute
-     * C:a\b\c.txt         --> 2           --> drive relative
-     * C:\a\b\c.txt        --> 3           --> absolute
-     * \\server\a\b\c.txt  --> 9           --> UNC
-     * \\\a\b\c.txt        --> -1          --> error
-     *
-     * Unix:
-     * a/b/c.txt           --> 0           --> relative
-     * /a/b/c.txt          --> 1           --> absolute
-     * ~/a/b/c.txt         --> 2           --> current user
-     * ~                   --> 2           --> current user (slash added)
-     * ~user/a/b/c.txt     --> 6           --> named user
-     * ~user               --> 6           --> named user (slash added)
-     * //server/a/b/c.txt  --> 9
-     * ///a/b/c.txt        --> -1          --> error
-     * C:                  --> 0           --> valid filename as only null byte and / are reserved characters
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * Note that a leading // (or \\) is used to indicate a UNC name on Windows. - * These must be followed by a server name, so double-slashes are not collapsed - * to a single slash at the start of the fileName. - * - * @param fileName the fileName to find the prefix in, null returns -1 - * @return the length of the prefix, -1 if invalid or null - */ - public static int getPrefixLength(final String fileName) { - if (fileName == null) { - return NOT_FOUND; - } - final int len = fileName.length(); - if (len == 0) { - return 0; - } - char ch0 = fileName.charAt(0); - if (ch0 == ':') { - return NOT_FOUND; - } - if (len == 1) { - if (ch0 == '~') { - return 2; // return a length greater than the input - } - return isSeparator(ch0) ? 1 : 0; - } - if (ch0 == '~') { - int posUnix = fileName.indexOf(UNIX_SEPARATOR, 1); - int posWin = fileName.indexOf(WINDOWS_SEPARATOR, 1); - if (posUnix == NOT_FOUND && posWin == NOT_FOUND) { - return len + 1; // return a length greater than the input - } - posUnix = posUnix == NOT_FOUND ? posWin : posUnix; - posWin = posWin == NOT_FOUND ? posUnix : posWin; - return Math.min(posUnix, posWin) + 1; - } - final char ch1 = fileName.charAt(1); - if (ch1 == ':') { - ch0 = Character.toUpperCase(ch0); - if (ch0 >= 'A' && ch0 <= 'Z') { - if (len == 2 && !FileSystem.getCurrent().supportsDriveLetter()) { - return 0; - } - if (len == 2 || !isSeparator(fileName.charAt(2))) { - return 2; - } - return 3; - } - if (ch0 == UNIX_SEPARATOR) { - return 1; - } - return NOT_FOUND; - - } - if (!isSeparator(ch0) || !isSeparator(ch1)) { - return isSeparator(ch0) ? 1 : 0; - } - int posUnix = fileName.indexOf(UNIX_SEPARATOR, 2); - int posWin = fileName.indexOf(WINDOWS_SEPARATOR, 2); - if (posUnix == NOT_FOUND && posWin == NOT_FOUND || posUnix == 2 || posWin == 2) { - return NOT_FOUND; - } - posUnix = posUnix == NOT_FOUND ? posWin : posUnix; - posWin = posWin == NOT_FOUND ? posUnix : posWin; - final int pos = Math.min(posUnix, posWin) + 1; - final String hostnamePart = fileName.substring(2, pos - 1); - return isValidHostName(hostnamePart) ? pos : NOT_FOUND; - } - - /** - * Returns the index of the last directory separator character. - *

- * This method will handle a file in either Unix or Windows format. - * The position of the last forward or backslash is returned. - *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to find the last path separator in, null returns -1 - * @return the index of the last separator character, or -1 if there - * is no such character - */ - public static int indexOfLastSeparator(final String fileName) { - if (fileName == null) { - return NOT_FOUND; - } - final int lastUnixPos = fileName.lastIndexOf(UNIX_SEPARATOR); - final int lastWindowsPos = fileName.lastIndexOf(WINDOWS_SEPARATOR); - return Math.max(lastUnixPos, lastWindowsPos); - } - - /** - * Returns the index of the last extension separator character, which is a dot. - *

- * This method also checks that there is no directory separator after the last dot. To do this it uses - * {@link #indexOfLastSeparator(String)} which will handle a file in either Unix or Windows format. - *

- *

- * The output will be the same irrespective of the machine that the code is running on, with the - * exception of a possible {@link IllegalArgumentException} on Windows (see below). - *

- * Note: This method used to have a hidden problem for names like "foo.exe:bar.txt". - * In this case, the name wouldn't be the name of a file, but the identifier of an - * alternate data stream (bar.txt) on the file foo.exe. The method used to return - * ".txt" here, which would be misleading. Commons IO 2.7, and later versions, are throwing - * an {@link IllegalArgumentException} for names like this. - * - * @param fileName - * the fileName to find the last extension separator in, null returns -1 - * @return the index of the last extension separator character, or -1 if there is no such character - * @throws IllegalArgumentException Windows only: The fileName parameter is, in fact, - * the identifier of an Alternate Data Stream, for example "foo.exe:bar.txt". - */ - public static int indexOfExtension(final String fileName) throws IllegalArgumentException { - if (fileName == null) { - return NOT_FOUND; - } - if (isSystemWindows()) { - // Special handling for NTFS ADS: Don't accept colon in the fileName. - final int offset = fileName.indexOf(':', getAdsCriticalOffset(fileName)); - if (offset != -1) { - throw new IllegalArgumentException("NTFS ADS separator (':') in file name is forbidden."); - } - } - final int extensionPos = fileName.lastIndexOf(EXTENSION_SEPARATOR); - final int lastSeparator = indexOfLastSeparator(fileName); - return lastSeparator > extensionPos ? NOT_FOUND : extensionPos; - } - - /** - * Gets the prefix from a full fileName, such as {@code C:/} - * or {@code ~/}. - *

- * This method will handle a file in either Unix or Windows format. - * The prefix includes the first slash in the full fileName where applicable. - *

-     * Windows:
-     * a\b\c.txt           --> ""          --> relative
-     * \a\b\c.txt          --> "\"         --> current drive absolute
-     * C:a\b\c.txt         --> "C:"        --> drive relative
-     * C:\a\b\c.txt        --> "C:\"       --> absolute
-     * \\server\a\b\c.txt  --> "\\server\" --> UNC
-     *
-     * Unix:
-     * a/b/c.txt           --> ""          --> relative
-     * /a/b/c.txt          --> "/"         --> absolute
-     * ~/a/b/c.txt         --> "~/"        --> current user
-     * ~                   --> "~/"        --> current user (slash added)
-     * ~user/a/b/c.txt     --> "~user/"    --> named user
-     * ~user               --> "~user/"    --> named user (slash added)
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * @param fileName the fileName to query, null returns null - * @return the prefix of the file, null if invalid. Null bytes inside string will be removed - */ - public static String getPrefix(final String fileName) { - if (fileName == null) { - return null; - } - final int len = getPrefixLength(fileName); - if (len < 0) { - return null; - } - if (len > fileName.length()) { - requireNonNullChars(fileName + UNIX_SEPARATOR); - return fileName + UNIX_SEPARATOR; - } - final String path = fileName.substring(0, len); - requireNonNullChars(path); - return path; - } - - /** - * Gets the path from a full fileName, which excludes the prefix. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *

-     * C:\a\b\c.txt --> a\b\
-     * ~/a/b/c.txt  --> a/b/
-     * a.txt        --> ""
-     * a/b/c        --> a/b/
-     * a/b/c/       --> a/b/c/
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - *

- * This method drops the prefix from the result. - * See {@link #getFullPath(String)} for the method that retains the prefix. - * - * @param fileName the fileName to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid. - * Null bytes inside string will be removed - */ - public static String getPath(final String fileName) { - return doGetPath(fileName, 1); - } - - /** - * Gets the path from a full fileName, which excludes the prefix, and - * also excluding the final directory separator. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *

-     * C:\a\b\c.txt --> a\b
-     * ~/a/b/c.txt  --> a/b
-     * a.txt        --> ""
-     * a/b/c        --> a/b
-     * a/b/c/       --> a/b/c
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - *

- * This method drops the prefix from the result. - * See {@link #getFullPathNoEndSeparator(String)} for the method that retains the prefix. - * - * @param fileName the fileName to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid. - * Null bytes inside string will be removed - */ - public static String getPathNoEndSeparator(final String fileName) { - return doGetPath(fileName, 0); - } - - /** - * Does the work of getting the path. - * - * @param fileName the fileName - * @param separatorAdd 0 to omit the end separator, 1 to return it - * @return the path. Null bytes inside string will be removed - */ - private static String doGetPath(final String fileName, final int separatorAdd) { - if (fileName == null) { - return null; - } - final int prefix = getPrefixLength(fileName); - if (prefix < 0) { - return null; - } - final int index = indexOfLastSeparator(fileName); - final int endIndex = index+separatorAdd; - if (prefix >= fileName.length() || index < 0 || prefix >= endIndex) { - return EMPTY_STRING; - } - final String path = fileName.substring(prefix, endIndex); - requireNonNullChars(path); - return path; - } - - /** - * Gets the full path from a full fileName, which is the prefix + path. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *

-     * C:\a\b\c.txt --> C:\a\b\
-     * ~/a/b/c.txt  --> ~/a/b/
-     * a.txt        --> ""
-     * a/b/c        --> a/b/
-     * a/b/c/       --> a/b/c/
-     * C:           --> C:
-     * C:\          --> C:\
-     * ~            --> ~/
-     * ~/           --> ~/
-     * ~user        --> ~user/
-     * ~user/       --> ~user/
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPath(final String fileName) { - return doGetFullPath(fileName, true); - } - - /** - * Gets the full path from a full fileName, which is the prefix + path, - * and also excluding the final directory separator. - *

- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *

-     * C:\a\b\c.txt --> C:\a\b
-     * ~/a/b/c.txt  --> ~/a/b
-     * a.txt        --> ""
-     * a/b/c        --> a/b
-     * a/b/c/       --> a/b/c
-     * C:           --> C:
-     * C:\          --> C:\
-     * ~            --> ~
-     * ~/           --> ~
-     * ~user        --> ~user
-     * ~user/       --> ~user
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPathNoEndSeparator(final String fileName) { - return doGetFullPath(fileName, false); - } - - /** - * Does the work of getting the path. - * - * @param fileName the fileName - * @param includeSeparator true to include the end separator - * @return the path - */ - private static String doGetFullPath(final String fileName, final boolean includeSeparator) { - if (fileName == null) { - return null; - } - final int prefix = getPrefixLength(fileName); - if (prefix < 0) { - return null; - } - if (prefix >= fileName.length()) { - if (includeSeparator) { - return getPrefix(fileName); // add end slash if necessary - } - return fileName; - } - final int index = indexOfLastSeparator(fileName); - if (index < 0) { - return fileName.substring(0, prefix); - } - int end = index + (includeSeparator ? 1 : 0); - if (end == 0) { - end++; - } - return fileName.substring(0, end); - } - - /** - * Gets the name minus the path from a full fileName. - *

- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash is returned. - *

-     * a/b/c.txt --> c.txt
-     * a.txt     --> a.txt
-     * a/b/c     --> c
-     * a/b/c/    --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to query, null returns null - * @return the name of the file without the path, or an empty string if none exists. - * Null bytes inside string will be removed - */ - public static String getName(final String fileName) { - if (fileName == null) { - return null; - } - requireNonNullChars(fileName); - final int index = indexOfLastSeparator(fileName); - return fileName.substring(index + 1); - } - - /** - * Checks the input for null bytes, a sign of unsanitized data being passed to to file level functions. - * - * This may be used for poison byte attacks. - * - * @param path the path to check - */ - private static void requireNonNullChars(final String path) { - if (path.indexOf(0) >= 0) { - throw new IllegalArgumentException("Null byte present in file/path name. There are no " - + "known legitimate use cases for such data, but several injection attacks may use it"); - } - } - - /** - * Gets the base name, minus the full path and extension, from a full fileName. - *

- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash and before the last dot is returned. - *

-     * a/b/c.txt --> c
-     * a.txt     --> a
-     * a/b/c     --> c
-     * a/b/c/    --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to query, null returns null - * @return the name of the file without the path, or an empty string if none exists. Null bytes inside string - * will be removed - */ - public static String getBaseName(final String fileName) { - return removeExtension(getName(fileName)); - } - - /** - * Gets the extension of a fileName. - *

- * This method returns the textual part of the fileName after the last dot. - * There must be no directory separator after the dot. - *

-     * foo.txt      --> "txt"
-     * a/b/c.jpg    --> "jpg"
-     * a/b.txt/c    --> ""
-     * a/b/c        --> ""
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on, with the - * exception of a possible {@link IllegalArgumentException} on Windows (see below). - *

- *

- * Note: This method used to have a hidden problem for names like "foo.exe:bar.txt". - * In this case, the name wouldn't be the name of a file, but the identifier of an - * alternate data stream (bar.txt) on the file foo.exe. The method used to return - * ".txt" here, which would be misleading. Commons IO 2.7, and later versions, are throwing - * an {@link IllegalArgumentException} for names like this. - * - * @param fileName the fileName to retrieve the extension of. - * @return the extension of the file or an empty string if none exists or {@code null} - * if the fileName is {@code null}. - * @throws IllegalArgumentException Windows only: The fileName parameter is, in fact, - * the identifier of an Alternate Data Stream, for example "foo.exe:bar.txt". - */ - public static String getExtension(final String fileName) throws IllegalArgumentException { - if (fileName == null) { - return null; - } - final int index = indexOfExtension(fileName); - if (index == NOT_FOUND) { - return EMPTY_STRING; - } - return fileName.substring(index + 1); - } - - /** - * Special handling for NTFS ADS: Don't accept colon in the fileName. - * - * @param fileName a file name - * @return ADS offsets. - */ - private static int getAdsCriticalOffset(final String fileName) { - // Step 1: Remove leading path segments. - final int offset1 = fileName.lastIndexOf(SYSTEM_SEPARATOR); - final int offset2 = fileName.lastIndexOf(OTHER_SEPARATOR); - if (offset1 == -1) { - if (offset2 == -1) { - return 0; - } - return offset2 + 1; - } - if (offset2 == -1) { - return offset1 + 1; - } - return Math.max(offset1, offset2) + 1; - } - - /** - * Removes the extension from a fileName. - *

- * This method returns the textual part of the fileName before the last dot. - * There must be no directory separator after the dot. - *

-     * foo.txt    --> foo
-     * a\b\c.jpg  --> a\b\c
-     * a\b\c      --> a\b\c
-     * a.b\c      --> a.b\c
-     * 
- *

- * The output will be the same irrespective of the machine that the code is running on. - * - * @param fileName the fileName to query, null returns null - * @return the fileName minus the extension - */ - public static String removeExtension(final String fileName) { - if (fileName == null) { - return null; - } - requireNonNullChars(fileName); - - final int index = indexOfExtension(fileName); - if (index == NOT_FOUND) { - return fileName; - } - return fileName.substring(0, index); - } - - /** - * Checks whether two fileNames are equal exactly. - *

- * No processing is performed on the fileNames other than comparison, - * thus this is merely a null-safe case-sensitive equals. - * - * @param fileName1 the first fileName to query, may be null - * @param fileName2 the second fileName to query, may be null - * @return true if the fileNames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equals(final String fileName1, final String fileName2) { - return equals(fileName1, fileName2, false, IOCase.SENSITIVE); - } - - /** - * Checks whether two fileNames are equal using the case rules of the system. - *

- * No processing is performed on the fileNames other than comparison. - * The check is case-sensitive on Unix and case-insensitive on Windows. - * - * @param fileName1 the first fileName to query, may be null - * @param fileName2 the second fileName to query, may be null - * @return true if the fileNames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsOnSystem(final String fileName1, final String fileName2) { - return equals(fileName1, fileName2, false, IOCase.SYSTEM); - } - - /** - * Checks whether two fileNames are equal after both have been normalized. - *

- * Both fileNames are first passed to {@link #normalize(String)}. - * The check is then performed in a case-sensitive manner. - * - * @param fileName1 the first fileName to query, may be null - * @param fileName2 the second fileName to query, may be null - * @return true if the fileNames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equalsNormalized(final String fileName1, final String fileName2) { - return equals(fileName1, fileName2, true, IOCase.SENSITIVE); - } - - /** - * Checks whether two fileNames are equal after both have been normalized - * and using the case rules of the system. - *

- * Both fileNames are first passed to {@link #normalize(String)}. - * The check is then performed case-sensitive on Unix and - * case-insensitive on Windows. - * - * @param fileName1 the first fileName to query, may be null - * @param fileName2 the second fileName to query, may be null - * @return true if the fileNames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsNormalizedOnSystem(final String fileName1, final String fileName2) { - return equals(fileName1, fileName2, true, IOCase.SYSTEM); - } - - /** - * Checks whether two fileNames are equal, optionally normalizing and providing - * control over the case-sensitivity. - * - * @param fileName1 the first fileName to query, may be null - * @param fileName2 the second fileName to query, may be null - * @param normalized whether to normalize the fileNames - * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive - * @return true if the fileNames are equal, null equals null - * @since 1.3 - */ - public static boolean equals( - String fileName1, String fileName2, - final boolean normalized, IOCase caseSensitivity) { - - if (fileName1 == null || fileName2 == null) { - return fileName1 == null && fileName2 == null; - } - if (normalized) { - fileName1 = normalize(fileName1); - if (fileName1 == null) { - return false; - } - fileName2 = normalize(fileName2); - if (fileName2 == null) { - return false; - } - } - if (caseSensitivity == null) { - caseSensitivity = IOCase.SENSITIVE; - } - return caseSensitivity.checkEquals(fileName1, fileName2); - } - - /** - * Checks whether the extension of the fileName is that specified. - *

- * This method obtains the extension as the textual part of the fileName - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param fileName the fileName to query, null returns false - * @param extension the extension to check for, null or empty checks for no extension - * @return true if the fileName has the specified extension - * @throws java.lang.IllegalArgumentException if the supplied fileName contains null bytes - */ - public static boolean isExtension(final String fileName, final String extension) { - if (fileName == null) { - return false; - } - requireNonNullChars(fileName); - - if (extension == null || extension.isEmpty()) { - return indexOfExtension(fileName) == NOT_FOUND; - } - final String fileExt = getExtension(fileName); - return fileExt.equals(extension); - } - - /** - * Checks whether the extension of the fileName is one of those specified. - *

- * This method obtains the extension as the textual part of the fileName - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param fileName the fileName to query, null returns false - * @param extensions the extensions to check for, null checks for no extension - * @return true if the fileName is one of the extensions - * @throws java.lang.IllegalArgumentException if the supplied fileName contains null bytes - */ - public static boolean isExtension(final String fileName, final String... extensions) { - if (fileName == null) { - return false; - } - requireNonNullChars(fileName); - - if (extensions == null || extensions.length == 0) { - return indexOfExtension(fileName) == NOT_FOUND; - } - final String fileExt = getExtension(fileName); - for (final String extension : extensions) { - if (fileExt.equals(extension)) { - return true; - } - } - return false; - } - - /** - * Checks whether the extension of the fileName is one of those specified. - *

- * This method obtains the extension as the textual part of the fileName - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param fileName the fileName to query, null returns false - * @param extensions the extensions to check for, null checks for no extension - * @return true if the fileName is one of the extensions - * @throws java.lang.IllegalArgumentException if the supplied fileName contains null bytes - */ - public static boolean isExtension(final String fileName, final Collection extensions) { - if (fileName == null) { - return false; - } - requireNonNullChars(fileName); - - if (extensions == null || extensions.isEmpty()) { - return indexOfExtension(fileName) == NOT_FOUND; - } - final String fileExt = getExtension(fileName); - for (final String extension : extensions) { - if (fileExt.equals(extension)) { - return true; - } - } - return false; - } - - /** - * Checks a fileName to see if it matches the specified wildcard matcher, - * always testing case-sensitive. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple (zero or more) wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The check is case-sensitive always. - *

-     * wildcardMatch("c.txt", "*.txt")      --> true
-     * wildcardMatch("c.txt", "*.jpg")      --> false
-     * wildcardMatch("a/b/c.txt", "a/b/*")  --> true
-     * wildcardMatch("c.txt", "*.???")      --> true
-     * wildcardMatch("c.txt", "*.????")     --> false
-     * 
- * N.B. the sequence "*?" does not work properly at present in match strings. - * - * @param fileName the fileName to match on - * @param wildcardMatcher the wildcard string to match against - * @return true if the fileName matches the wildcard string - * @see IOCase#SENSITIVE - */ - public static boolean wildcardMatch(final String fileName, final String wildcardMatcher) { - return wildcardMatch(fileName, wildcardMatcher, IOCase.SENSITIVE); - } - - /** - * Checks a fileName to see if it matches the specified wildcard matcher - * using the case rules of the system. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple (zero or more) wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The check is case-sensitive on Unix and case-insensitive on Windows. - *

-     * wildcardMatch("c.txt", "*.txt")      --> true
-     * wildcardMatch("c.txt", "*.jpg")      --> false
-     * wildcardMatch("a/b/c.txt", "a/b/*")  --> true
-     * wildcardMatch("c.txt", "*.???")      --> true
-     * wildcardMatch("c.txt", "*.????")     --> false
-     * 
- * N.B. the sequence "*?" does not work properly at present in match strings. - * - * @param fileName the fileName to match on - * @param wildcardMatcher the wildcard string to match against - * @return true if the fileName matches the wildcard string - * @see IOCase#SYSTEM - */ - public static boolean wildcardMatchOnSystem(final String fileName, final String wildcardMatcher) { - return wildcardMatch(fileName, wildcardMatcher, IOCase.SYSTEM); - } - - /** - * Checks a fileName to see if it matches the specified wildcard matcher - * allowing control over case-sensitivity. - *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple (zero or more) wildcard characters. - * N.B. the sequence "*?" does not work properly at present in match strings. - * - * @param fileName the fileName to match on - * @param wildcardMatcher the wildcard string to match against - * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive - * @return true if the fileName matches the wildcard string - * @since 1.3 - */ - public static boolean wildcardMatch(final String fileName, final String wildcardMatcher, IOCase caseSensitivity) { - if (fileName == null && wildcardMatcher == null) { - return true; - } - if (fileName == null || wildcardMatcher == null) { - return false; - } - if (caseSensitivity == null) { - caseSensitivity = IOCase.SENSITIVE; - } - final String[] wcs = splitOnTokens(wildcardMatcher); - boolean anyChars = false; - int textIdx = 0; - int wcsIdx = 0; - final Deque backtrack = new ArrayDeque<>(wcs.length); - - // loop around a backtrack stack, to handle complex * matching - do { - if (!backtrack.isEmpty()) { - final int[] array = backtrack.pop(); - wcsIdx = array[0]; - textIdx = array[1]; - anyChars = true; - } - - // loop whilst tokens and text left to process - while (wcsIdx < wcs.length) { - - if (wcs[wcsIdx].equals("?")) { - // ? so move to next text char - textIdx++; - if (textIdx > fileName.length()) { - break; - } - anyChars = false; - - } else if (wcs[wcsIdx].equals("*")) { - // set any chars status - anyChars = true; - if (wcsIdx == wcs.length - 1) { - textIdx = fileName.length(); - } - - } else { - // matching text token - if (anyChars) { - // any chars then try to locate text token - textIdx = caseSensitivity.checkIndexOf(fileName, textIdx, wcs[wcsIdx]); - if (textIdx == NOT_FOUND) { - // token not found - break; - } - final int repeat = caseSensitivity.checkIndexOf(fileName, textIdx + 1, wcs[wcsIdx]); - if (repeat >= 0) { - backtrack.push(new int[] {wcsIdx, repeat}); - } - } else if (!caseSensitivity.checkRegionMatches(fileName, textIdx, wcs[wcsIdx])) { - // matching from current position - // couldn't match token - break; - } - - // matched text token, move text index to end of matched token - textIdx += wcs[wcsIdx].length(); - anyChars = false; - } - - wcsIdx++; - } - - // full match - if (wcsIdx == wcs.length && textIdx == fileName.length()) { - return true; - } - - } while (!backtrack.isEmpty()); - - return false; - } - - /** - * Splits a string into a number of tokens. - * The text is split by '?' and '*'. - * Where multiple '*' occur consecutively they are collapsed into a single '*'. - * - * @param text the text to split - * @return the array of tokens, never null - */ - static String[] splitOnTokens(final String text) { - // used by wildcardMatch - // package level so a unit test may run on this - - if (text.indexOf('?') == NOT_FOUND && text.indexOf('*') == NOT_FOUND) { - return new String[] { text }; - } - - final char[] array = text.toCharArray(); - final ArrayList list = new ArrayList<>(); - final StringBuilder buffer = new StringBuilder(); - char prevChar = 0; - for (final char ch : array) { - if (ch == '?' || ch == '*') { - if (buffer.length() != 0) { - list.add(buffer.toString()); - buffer.setLength(0); - } - if (ch == '?') { - list.add("?"); - } else if (prevChar != '*') {// ch == '*' here; check if previous char was '*' - list.add("*"); - } - } else { - buffer.append(ch); - } - prevChar = ch; - } - if (buffer.length() != 0) { - list.add(buffer.toString()); - } - - return list.toArray(EMPTY_STRING_ARRAY); - } - - /** - * Checks whether a given string is a valid host name according to - * RFC 3986. - * - *

Accepted are IP addresses (v4 and v6) as well as what the - * RFC calls a "reg-name". Percent encoded names don't seem to be - * valid names in UNC paths.

- * - * @see "https://tools.ietf.org/html/rfc3986#section-3.2.2" - * @param name the hostname to validate - * @return true if the given name is a valid host name - */ - private static boolean isValidHostName(final String name) { - return isIPv6Address(name) || isRFC3986HostName(name); - } - - private static final Pattern IPV4_PATTERN = - Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"); - private static final int IPV4_MAX_OCTET_VALUE = 255; - - /** - * Checks whether a given string represents a valid IPv4 address. - * - * @param name the name to validate - * @return true if the given name is a valid IPv4 address - */ - // mostly copied from org.apache.commons.validator.routines.InetAddressValidator#isValidInet4Address - private static boolean isIPv4Address(final String name) { - final Matcher m = IPV4_PATTERN.matcher(name); - if (!m.matches() || m.groupCount() != 4) { - return false; - } - - // verify that address subgroups are legal - for (int i = 1; i <= 4; i++) { - final String ipSegment = m.group(i); - final int iIpSegment = Integer.parseInt(ipSegment); - if (iIpSegment > IPV4_MAX_OCTET_VALUE) { - return false; - } - - if (ipSegment.length() > 1 && ipSegment.startsWith("0")) { - return false; - } - - } - - return true; - } - - private static final int IPV6_MAX_HEX_GROUPS = 8; - private static final int IPV6_MAX_HEX_DIGITS_PER_GROUP = 4; - private static final int MAX_UNSIGNED_SHORT = 0xffff; - private static final int BASE_16 = 16; - - // copied from org.apache.commons.validator.routines.InetAddressValidator#isValidInet6Address - /** - * Checks whether a given string represents a valid IPv6 address. - * - * @param inet6Address the name to validate - * @return true if the given name is a valid IPv6 address - */ - private static boolean isIPv6Address(final String inet6Address) { - final boolean containsCompressedZeroes = inet6Address.contains("::"); - if (containsCompressedZeroes && (inet6Address.indexOf("::") != inet6Address.lastIndexOf("::"))) { - return false; - } - if ((inet6Address.startsWith(":") && !inet6Address.startsWith("::")) - || (inet6Address.endsWith(":") && !inet6Address.endsWith("::"))) { - return false; - } - String[] octets = inet6Address.split(":"); - if (containsCompressedZeroes) { - final List octetList = new ArrayList<>(Arrays.asList(octets)); - if (inet6Address.endsWith("::")) { - // String.split() drops ending empty segments - octetList.add(""); - } else if (inet6Address.startsWith("::") && !octetList.isEmpty()) { - octetList.remove(0); - } - octets = octetList.toArray(EMPTY_STRING_ARRAY); - } - if (octets.length > IPV6_MAX_HEX_GROUPS) { - return false; - } - int validOctets = 0; - int emptyOctets = 0; // consecutive empty chunks - for (int index = 0; index < octets.length; index++) { - final String octet = octets[index]; - if (octet.isEmpty()) { - emptyOctets++; - if (emptyOctets > 1) { - return false; - } - } else { - emptyOctets = 0; - // Is last chunk an IPv4 address? - if (index == octets.length - 1 && octet.contains(".")) { - if (!isIPv4Address(octet)) { - return false; - } - validOctets += 2; - continue; - } - if (octet.length() > IPV6_MAX_HEX_DIGITS_PER_GROUP) { - return false; - } - final int octetInt; - try { - octetInt = Integer.parseInt(octet, BASE_16); - } catch (final NumberFormatException e) { - return false; - } - if (octetInt < 0 || octetInt > MAX_UNSIGNED_SHORT) { - return false; - } - } - validOctets++; - } - return validOctets <= IPV6_MAX_HEX_GROUPS && (validOctets >= IPV6_MAX_HEX_GROUPS || containsCompressedZeroes); - } - - private static final Pattern REG_NAME_PART_PATTERN = Pattern.compile("^[a-zA-Z0-9][a-zA-Z0-9-]*$"); - - /** - * Checks whether a given string is a valid host name according to - * RFC 3986 - not accepting IP addresses. - * - * @see "https://tools.ietf.org/html/rfc3986#section-3.2.2" - * @param name the hostname to validate - * @return true if the given name is a valid host name - */ - private static boolean isRFC3986HostName(final String name) { - final String[] parts = name.split("\\.", -1); - for (int i = 0; i < parts.length; i++) { - if (parts[i].isEmpty()) { - // trailing dot is legal, otherwise we've hit a .. sequence - return i == parts.length - 1; - } - if (!REG_NAME_PART_PATTERN.matcher(parts[i]).matches()) { - return false; - } - } - return true; - } -} diff --git a/src/org/apache/commons/io/HexDump.java b/src/org/apache/commons/io/HexDump.java deleted file mode 100644 index 86b49b63..00000000 --- a/src/org/apache/commons/io/HexDump.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.Charset; - -/** - * Dumps data in hexadecimal format. - *

- * Provides a single function to take an array of bytes and display it - * in hexadecimal form. - *

- * Origin of code: POI. - * - */ -public class HexDump { - - /** - * Instances should NOT be constructed in standard programming. - */ - public HexDump() { - } - - /** - * Dump an array of bytes to an OutputStream. The output is formatted - * for human inspection, with a hexadecimal offset followed by the - * hexadecimal values of the next 16 bytes of data and the printable ASCII - * characters (if any) that those bytes represent printed per each line - * of output. - *

- * The offset argument specifies the start offset of the data array - * within a larger entity like a file or an incoming stream. For example, - * if the data array contains the third kibibyte of a file, then the - * offset argument should be set to 2048. The offset value printed - * at the beginning of each line indicates where in that larger entity - * the first byte on that line is located. - *

- * All bytes between the given index (inclusive) and the end of the - * data array are dumped. - * - * @param data the byte array to be dumped - * @param offset offset of the byte array within a larger entity - * @param stream the OutputStream to which the data is to be - * written - * @param index initial index into the byte array - * - * @throws IOException is thrown if anything goes wrong writing - * the data to stream - * @throws ArrayIndexOutOfBoundsException if the index is - * outside the data array's bounds - * @throws IllegalArgumentException if the output stream is null - */ - - public static void dump(final byte[] data, final long offset, - final OutputStream stream, final int index) - throws IOException, ArrayIndexOutOfBoundsException, - IllegalArgumentException { - - if (index < 0 || index >= data.length) { - throw new ArrayIndexOutOfBoundsException( - "illegal index: " + index + " into array of length " - + data.length); - } - if (stream == null) { - throw new IllegalArgumentException("cannot write to nullstream"); - } - long display_offset = offset + index; - final StringBuilder buffer = new StringBuilder(74); - - for (int j = index; j < data.length; j += 16) { - int chars_read = data.length - j; - - if (chars_read > 16) { - chars_read = 16; - } - dump(buffer, display_offset).append(' '); - for (int k = 0; k < 16; k++) { - if (k < chars_read) { - dump(buffer, data[k + j]); - } else { - buffer.append(" "); - } - buffer.append(' '); - } - for (int k = 0; k < chars_read; k++) { - if (data[k + j] >= ' ' && data[k + j] < 127) { - buffer.append((char) data[k + j]); - } else { - buffer.append('.'); - } - } - buffer.append(EOL); - // make explicit the dependency on the default encoding - stream.write(buffer.toString().getBytes(Charset.defaultCharset())); - stream.flush(); - buffer.setLength(0); - display_offset += chars_read; - } - } - - /** - * The line-separator (initializes to "line.separator" system property. - */ - public static final String EOL = - System.getProperty("line.separator"); - private static final char[] _hexcodes = - { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' - }; - private static final int[] _shifts = - { - 28, 24, 20, 16, 12, 8, 4, 0 - }; - - /** - * Dump a long value into a StringBuilder. - * - * @param _lbuffer the StringBuilder to dump the value in - * @param value the long value to be dumped - * @return StringBuilder containing the dumped value. - */ - private static StringBuilder dump(final StringBuilder _lbuffer, final long value) { - for (int j = 0; j < 8; j++) { - _lbuffer - .append(_hexcodes[(int) (value >> _shifts[j]) & 15]); - } - return _lbuffer; - } - - /** - * Dump a byte value into a StringBuilder. - * - * @param _cbuffer the StringBuilder to dump the value in - * @param value the byte value to be dumped - * @return StringBuilder containing the dumped value. - */ - private static StringBuilder dump(final StringBuilder _cbuffer, final byte value) { - for (int j = 0; j < 2; j++) { - _cbuffer.append(_hexcodes[value >> _shifts[j + 6] & 15]); - } - return _cbuffer; - } - -} diff --git a/src/org/apache/commons/io/IOCase.java b/src/org/apache/commons/io/IOCase.java deleted file mode 100644 index aba8075d..00000000 --- a/src/org/apache/commons/io/IOCase.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.util.Objects; - -/** - * Enumeration of IO case sensitivity. - *

- * Different filing systems have different rules for case-sensitivity. - * Windows is case-insensitive, Unix is case-sensitive. - *

- *

- * This class captures that difference, providing an enumeration to - * control how file name comparisons should be performed. It also provides - * methods that use the enumeration to perform comparisons. - *

- *

- * Wherever possible, you should use the {@code check} methods in this - * class to compare file names. - *

- * - * @since 1.3 - */ -public enum IOCase { - - /** - * The constant for case sensitive regardless of operating system. - */ - SENSITIVE("Sensitive", true), - - /** - * The constant for case insensitive regardless of operating system. - */ - INSENSITIVE("Insensitive", false), - - /** - * The constant for case sensitivity determined by the current operating system. - * Windows is case-insensitive when comparing file names, Unix is case-sensitive. - *

- * Note: This only caters for Windows and Unix. Other operating - * systems (e.g. OSX and OpenVMS) are treated as case sensitive if they use the - * Unix file separator and case-insensitive if they use the Windows file separator - * (see {@link java.io.File#separatorChar}). - *

- *

- * If you serialize this constant on Windows, and deserialize on Unix, or vice - * versa, then the value of the case-sensitivity flag will change. - *

- */ - SYSTEM("System", !FilenameUtils.isSystemWindows()); - - /** - * Tests for cases sensitivity in a null-safe manner. - * - * @param caseSensitivity an IOCase. - * @return true if the input is non-null and {@link #isCaseSensitive()}. - * @since 2.10.0 - */ - public static boolean isCaseSensitive(final IOCase caseSensitivity) { - return caseSensitivity != null && !caseSensitivity.isCaseSensitive(); - } - - /** Serialization version. */ - private static final long serialVersionUID = -6343169151696340687L; - - /** The enumeration name. */ - private final String name; - - /** The sensitivity flag. */ - private final transient boolean sensitive; - - /** - * Factory method to create an IOCase from a name. - * - * @param name the name to find - * @return the IOCase object - * @throws IllegalArgumentException if the name is invalid - */ - public static IOCase forName(final String name) { - for (final IOCase ioCase : IOCase.values()) { - if (ioCase.getName().equals(name)) { - return ioCase; - } - } - throw new IllegalArgumentException("Invalid IOCase name: " + name); - } - - /** - * Constructs a new instance. - * - * @param name the name - * @param sensitive the sensitivity - */ - IOCase(final String name, final boolean sensitive) { - this.name = name; - this.sensitive = sensitive; - } - - /** - * Replaces the enumeration from the stream with a real one. - * This ensures that the correct flag is set for SYSTEM. - * - * @return the resolved object - */ - private Object readResolve() { - return forName(name); - } - - /** - * Gets the name of the constant. - * - * @return the name of the constant - */ - public String getName() { - return name; - } - - /** - * Does the object represent case sensitive comparison. - * - * @return true if case sensitive - */ - public boolean isCaseSensitive() { - return sensitive; - } - - /** - * Compares two strings using the case-sensitivity rule. - *

- * This method mimics {@link String#compareTo} but takes case-sensitivity - * into account. - *

- * - * @param str1 the first string to compare, not null - * @param str2 the second string to compare, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public int checkCompareTo(final String str1, final String str2) { - Objects.requireNonNull(str1, "str1"); - Objects.requireNonNull(str2, "str2"); - return sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2); - } - - /** - * Compares two strings using the case-sensitivity rule. - *

- * This method mimics {@link String#equals} but takes case-sensitivity - * into account. - *

- * - * @param str1 the first string to compare, not null - * @param str2 the second string to compare, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkEquals(final String str1, final String str2) { - Objects.requireNonNull(str1, "str1"); - Objects.requireNonNull(str2, "str2"); - return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2); - } - - /** - * Checks if one string starts with another using the case-sensitivity rule. - *

- * This method mimics {@link String#startsWith(String)} but takes case-sensitivity - * into account. - *

- * - * @param str the string to check - * @param start the start to compare against - * @return true if equal using the case rules, false if either input is null - */ - public boolean checkStartsWith(final String str, final String start) { - return str != null && start != null && str.regionMatches(!sensitive, 0, start, 0, start.length()); - } - - /** - * Checks if one string ends with another using the case-sensitivity rule. - *

- * This method mimics {@link String#endsWith} but takes case-sensitivity - * into account. - *

- * - * @param str the string to check - * @param end the end to compare against - * @return true if equal using the case rules, false if either input is null - */ - public boolean checkEndsWith(final String str, final String end) { - if (str == null || end == null) { - return false; - } - final int endLen = end.length(); - return str.regionMatches(!sensitive, str.length() - endLen, end, 0, endLen); - } - - /** - * Checks if one string contains another starting at a specific index using the - * case-sensitivity rule. - *

- * This method mimics parts of {@link String#indexOf(String, int)} - * but takes case-sensitivity into account. - *

- * - * @param str the string to check, not null - * @param strStartIndex the index to start at in str - * @param search the start to search for, not null - * @return the first index of the search String, - * -1 if no match or {@code null} string input - * @throws NullPointerException if either string is null - * @since 2.0 - */ - public int checkIndexOf(final String str, final int strStartIndex, final String search) { - final int endIndex = str.length() - search.length(); - if (endIndex >= strStartIndex) { - for (int i = strStartIndex; i <= endIndex; i++) { - if (checkRegionMatches(str, i, search)) { - return i; - } - } - } - return -1; - } - - /** - * Checks if one string contains another at a specific index using the case-sensitivity rule. - *

- * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)} - * but takes case-sensitivity into account. - *

- * - * @param str the string to check, not null - * @param strStartIndex the index to start at in str - * @param search the start to search for, not null - * @return true if equal using the case rules - * @throws NullPointerException if either string is null - */ - public boolean checkRegionMatches(final String str, final int strStartIndex, final String search) { - return str.regionMatches(!sensitive, strStartIndex, search, 0, search.length()); - } - - /** - * Gets a string describing the sensitivity. - * - * @return a string describing the sensitivity - */ - @Override - public String toString() { - return name; - } - -} diff --git a/src/org/apache/commons/io/IOExceptionList.java b/src/org/apache/commons/io/IOExceptionList.java deleted file mode 100644 index 45e0c70e..00000000 --- a/src/org/apache/commons/io/IOExceptionList.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -/** - * A IOException based on a list of Throwable causes. - *

- * The first exception in the list is used as this exception's cause and is accessible with the usual - * {@link #getCause()} while the complete list is accessible with {@link #getCauseList()}. - *

- * - * @since 2.7 - */ -public class IOExceptionList extends IOException { - - private static final long serialVersionUID = 1L; - private final List causeList; - - /** - * Creates a new exception caused by a list of exceptions. - * - * @param causeList a list of cause exceptions. - */ - public IOExceptionList(final List causeList) { - this(String.format("%,d exceptions: %s", causeList == null ? 0 : causeList.size(), causeList), causeList); - } - - /** - * Creates a new exception caused by a list of exceptions. - * - * @param message The detail message, see {@link #getMessage()}. - * @param causeList a list of cause exceptions. - * @since 2.9.0 - */ - public IOExceptionList(final String message, final List causeList) { - super(message, causeList == null || causeList.isEmpty() ? null : causeList.get(0)); - this.causeList = causeList == null ? Collections.emptyList() : causeList; - } - - /** - * Gets the cause exception at the given index. - * - * @param type of exception to return. - * @param index index in the cause list. - * @return The list of causes. - */ - @SuppressWarnings("unchecked") - public T getCause(final int index) { - return (T) causeList.get(index); - } - - /** - * Gets the cause exception at the given index. - * - * @param type of exception to return. - * @param index index in the cause list. - * @param clazz type of exception to return. - * @return The list of causes. - */ - public T getCause(final int index, final Class clazz) { - return clazz.cast(causeList.get(index)); - } - - /** - * Gets the cause list. - * - * @param type of exception to return. - * @return The list of causes. - */ - @SuppressWarnings("unchecked") - public List getCauseList() { - return (List) causeList; - } - - /** - * Works around Throwable and Generics, may fail at runtime depending on the argument value. - * - * @param type of exception to return. - * @param clazz the target type - * @return The list of causes. - */ - @SuppressWarnings("unchecked") - public List getCauseList(final Class clazz) { - return (List) causeList; - } - -} diff --git a/src/org/apache/commons/io/IOExceptionWithCause.java b/src/org/apache/commons/io/IOExceptionWithCause.java deleted file mode 100644 index cd72dcd9..00000000 --- a/src/org/apache/commons/io/IOExceptionWithCause.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.io.IOException; - -/** - * Subclasses IOException with the {@link Throwable} constructors missing before Java 6. - * - * @since 1.4 - * @deprecated (since 2.5) use {@link IOException} instead - */ -@Deprecated -public class IOExceptionWithCause extends IOException { - - /** - * Defines the serial version UID. - */ - private static final long serialVersionUID = 1L; - - /** - * Constructs a new instance with the given message and cause. - *

- * As specified in {@link Throwable}, the message in the given {@code cause} is not used in this instance's - * message. - *

- * - * @param message - * the message (see {@link #getMessage()}) - * @param cause - * the cause (see {@link #getCause()}). A {@code null} value is allowed. - */ - public IOExceptionWithCause(final String message, final Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new instance with the given cause. - *

- * The message is set to {@code cause==null ? null : cause.toString()}, which by default contains the class - * and message of {@code cause}. This constructor is useful for call sites that just wrap another throwable. - *

- * - * @param cause - * the cause (see {@link #getCause()}). A {@code null} value is allowed. - */ - public IOExceptionWithCause(final Throwable cause) { - super(cause); - } - -} diff --git a/src/org/apache/commons/io/IOIndexedException.java b/src/org/apache/commons/io/IOIndexedException.java deleted file mode 100644 index ce455215..00000000 --- a/src/org/apache/commons/io/IOIndexedException.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.io.IOException; - -/** - * A IOException associated with a source index. - * - * @since 2.7 - */ -public class IOIndexedException extends IOException { - - private static final long serialVersionUID = 1L; - private final int index; - - /** - * Creates a new exception. - * - * @param index index of this exception. - * @param cause cause exceptions. - */ - public IOIndexedException(final int index, final Throwable cause) { - super(toMessage(index, cause), cause); - this.index = index; - } - - /** - * Converts input to a suitable String for exception message. - * - * @param index An index into a source collection. - * @param cause A cause. - * @return A message. - */ - protected static String toMessage(final int index, final Throwable cause) { - // Letting index be any int - final String unspecified = "Null"; - final String name = cause == null ? unspecified : cause.getClass().getSimpleName(); - final String msg = cause == null ? unspecified : cause.getMessage(); - return String.format("%s #%,d: %s", name, index, msg); - } - - /** - * The index of this exception. - * - * @return index of this exception. - */ - public int getIndex() { - return index; - } - -} diff --git a/src/org/apache/commons/io/IOUtils.java b/src/org/apache/commons/io/IOUtils.java deleted file mode 100644 index 1bfdf693..00000000 --- a/src/org/apache/commons/io/IOUtils.java +++ /dev/null @@ -1,3536 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.CharArrayWriter; -import java.io.Closeable; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.HttpURLConnection; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.Selector; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.function.Consumer; - -import org.apache.commons.io.function.IOConsumer; -import org.apache.commons.io.output.AppendableWriter; -import org.apache.commons.io.output.ByteArrayOutputStream; -import org.apache.commons.io.output.NullOutputStream; -import org.apache.commons.io.output.StringBuilderWriter; -import org.apache.commons.io.output.ThresholdingOutputStream; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; - -/** - * General IO stream manipulation utilities. - *

- * This class provides static utility methods for input/output operations. - *

    - *
  • [Deprecated] closeQuietly - these methods close a stream ignoring nulls and exceptions - *
  • toXxx/read - these methods read data from a stream - *
  • write - these methods write data to a stream - *
  • copy - these methods copy all the data from one stream to another - *
  • contentEquals - these methods compare the content of two streams - *
- *

- * The byte-to-char methods and char-to-byte methods involve a conversion step. - * Two methods are provided in each case, one that uses the platform default - * encoding and the other which allows you to specify an encoding. You are - * encouraged to always specify an encoding because relying on the platform - * default can lead to unexpected results, for example when moving from - * development to production. - *

- * All the methods in this class that read a stream are buffered internally. - * This means that there is no cause to use a {@code BufferedInputStream} - * or {@code BufferedReader}. The default buffer size of 4K has been shown - * to be efficient in tests. - *

- * The various copy methods all delegate the actual copying to one of the following methods: - *

    - *
  • {@link #copyLarge(InputStream, OutputStream, byte[])}
  • - *
  • {@link #copyLarge(InputStream, OutputStream, long, long, byte[])}
  • - *
  • {@link #copyLarge(Reader, Writer, char[])}
  • - *
  • {@link #copyLarge(Reader, Writer, long, long, char[])}
  • - *
- * For example, {@link #copy(InputStream, OutputStream)} calls {@link #copyLarge(InputStream, OutputStream)} - * which calls {@link #copy(InputStream, OutputStream, int)} which creates the buffer and calls - * {@link #copyLarge(InputStream, OutputStream, byte[])}. - *

- * Applications can re-use buffers by using the underlying methods directly. - * This may improve performance for applications that need to do a lot of copying. - *

- * Wherever possible, the methods in this class do not flush or close - * the stream. This is to avoid making non-portable assumptions about the - * streams' origin and further use. Thus the caller is still responsible for - * closing streams after use. - *

- * Origin of code: Excalibur. - */ -public class IOUtils { - // NOTE: This class is focused on InputStream, OutputStream, Reader and - // Writer. Each method should take at least one of these as a parameter, - // or return one of them. - - /** - * CR char. - * - * @since 2.9.0 - */ - public static final int CR = '\r'; - - /** - * The default buffer size ({@value}) to use in copy methods. - */ - public static final int DEFAULT_BUFFER_SIZE = 8192; - - /** - * The system directory separator character. - */ - public static final char DIR_SEPARATOR = File.separatorChar; - - /** - * The Unix directory separator character. - */ - public static final char DIR_SEPARATOR_UNIX = '/'; - - /** - * The Windows directory separator character. - */ - public static final char DIR_SEPARATOR_WINDOWS = '\\'; - - /** - * A singleton empty byte array. - * - * @since 2.9.0 - */ - public static final byte[] EMPTY_BYTE_ARRAY = {}; - - /** - * Represents the end-of-file (or stream). - * @since 2.5 (made public) - */ - public static final int EOF = -1; - - /** - * LF char. - * - * @since 2.9.0 - */ - public static final int LF = '\n'; - - /** - * The system line separator string. - * - * @deprecated Use {@link System#lineSeparator()}. - */ - @Deprecated - public static final String LINE_SEPARATOR = System.lineSeparator(); - - /** - * The Unix line separator string. - * - * @see StandardLineSeparator#LF - */ - public static final String LINE_SEPARATOR_UNIX = StandardLineSeparator.LF.getString(); - - /** - * The Windows line separator string. - * - * @see StandardLineSeparator#CRLF - */ - public static final String LINE_SEPARATOR_WINDOWS = StandardLineSeparator.CRLF.getString(); - - /** - * Internal byte array buffer. - */ - private static final ThreadLocal SKIP_BYTE_BUFFER = ThreadLocal.withInitial(IOUtils::byteArray); - - /** - * Internal byte array buffer. - */ - private static final ThreadLocal SKIP_CHAR_BUFFER = ThreadLocal.withInitial(IOUtils::charArray); - - /** - * Returns the given InputStream if it is already a {@link BufferedInputStream}, otherwise creates a - * BufferedInputStream from the given InputStream. - * - * @param inputStream the InputStream to wrap or return (not null) - * @return the given InputStream or a new {@link BufferedInputStream} for the given InputStream - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - @SuppressWarnings("resource") // parameter null check - public static BufferedInputStream buffer(final InputStream inputStream) { - // reject null early on rather than waiting for IO operation to fail - // not checked by BufferedInputStream - Objects.requireNonNull(inputStream, "inputStream"); - return inputStream instanceof BufferedInputStream ? - (BufferedInputStream) inputStream : new BufferedInputStream(inputStream); - } - - /** - * Returns the given InputStream if it is already a {@link BufferedInputStream}, otherwise creates a - * BufferedInputStream from the given InputStream. - * - * @param inputStream the InputStream to wrap or return (not null) - * @param size the buffer size, if a new BufferedInputStream is created. - * @return the given InputStream or a new {@link BufferedInputStream} for the given InputStream - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - @SuppressWarnings("resource") // parameter null check - public static BufferedInputStream buffer(final InputStream inputStream, final int size) { - // reject null early on rather than waiting for IO operation to fail - // not checked by BufferedInputStream - Objects.requireNonNull(inputStream, "inputStream"); - return inputStream instanceof BufferedInputStream ? - (BufferedInputStream) inputStream : new BufferedInputStream(inputStream, size); - } - - /** - * Returns the given OutputStream if it is already a {@link BufferedOutputStream}, otherwise creates a - * BufferedOutputStream from the given OutputStream. - * - * @param outputStream the OutputStream to wrap or return (not null) - * @return the given OutputStream or a new {@link BufferedOutputStream} for the given OutputStream - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - @SuppressWarnings("resource") // parameter null check - public static BufferedOutputStream buffer(final OutputStream outputStream) { - // reject null early on rather than waiting for IO operation to fail - // not checked by BufferedInputStream - Objects.requireNonNull(outputStream, "outputStream"); - return outputStream instanceof BufferedOutputStream ? - (BufferedOutputStream) outputStream : new BufferedOutputStream(outputStream); - } - - /** - * Returns the given OutputStream if it is already a {@link BufferedOutputStream}, otherwise creates a - * BufferedOutputStream from the given OutputStream. - * - * @param outputStream the OutputStream to wrap or return (not null) - * @param size the buffer size, if a new BufferedOutputStream is created. - * @return the given OutputStream or a new {@link BufferedOutputStream} for the given OutputStream - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - @SuppressWarnings("resource") // parameter null check - public static BufferedOutputStream buffer(final OutputStream outputStream, final int size) { - // reject null early on rather than waiting for IO operation to fail - // not checked by BufferedInputStream - Objects.requireNonNull(outputStream, "outputStream"); - return outputStream instanceof BufferedOutputStream ? - (BufferedOutputStream) outputStream : new BufferedOutputStream(outputStream, size); - } - - /** - * Returns the given reader if it is already a {@link BufferedReader}, otherwise creates a BufferedReader from - * the given reader. - * - * @param reader the reader to wrap or return (not null) - * @return the given reader or a new {@link BufferedReader} for the given reader - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - public static BufferedReader buffer(final Reader reader) { - return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); - } - - /** - * Returns the given reader if it is already a {@link BufferedReader}, otherwise creates a BufferedReader from the - * given reader. - * - * @param reader the reader to wrap or return (not null) - * @param size the buffer size, if a new BufferedReader is created. - * @return the given reader or a new {@link BufferedReader} for the given reader - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - public static BufferedReader buffer(final Reader reader, final int size) { - return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader, size); - } - - /** - * Returns the given Writer if it is already a {@link BufferedWriter}, otherwise creates a BufferedWriter from the - * given Writer. - * - * @param writer the Writer to wrap or return (not null) - * @return the given Writer or a new {@link BufferedWriter} for the given Writer - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - public static BufferedWriter buffer(final Writer writer) { - return writer instanceof BufferedWriter ? (BufferedWriter) writer : new BufferedWriter(writer); - } - - /** - * Returns the given Writer if it is already a {@link BufferedWriter}, otherwise creates a BufferedWriter from the - * given Writer. - * - * @param writer the Writer to wrap or return (not null) - * @param size the buffer size, if a new BufferedWriter is created. - * @return the given Writer or a new {@link BufferedWriter} for the given Writer - * @throws NullPointerException if the input parameter is null - * @since 2.5 - */ - public static BufferedWriter buffer(final Writer writer, final int size) { - return writer instanceof BufferedWriter ? (BufferedWriter) writer : new BufferedWriter(writer, size); - } - - /** - * Returns a new byte array of size {@link #DEFAULT_BUFFER_SIZE}. - * - * @return a new byte array of size {@link #DEFAULT_BUFFER_SIZE}. - * @since 2.9.0 - */ - public static byte[] byteArray() { - return byteArray(DEFAULT_BUFFER_SIZE); - } - - /** - * Returns a new byte array of the given size. - * - * TODO Consider guarding or warning against large allocations... - * - * @param size array size. - * @return a new byte array of the given size. - * @since 2.9.0 - */ - public static byte[] byteArray(final int size) { - return new byte[size]; - } - - /** - * Returns a new char array of size {@link #DEFAULT_BUFFER_SIZE}. - * - * @return a new char array of size {@link #DEFAULT_BUFFER_SIZE}. - * @since 2.9.0 - */ - private static char[] charArray() { - return charArray(DEFAULT_BUFFER_SIZE); - } - - /** - * Returns a new char array of the given size. - * - * TODO Consider guarding or warning against large allocations... - * - * @param size array size. - * @return a new char array of the given size. - * @since 2.9.0 - */ - private static char[] charArray(final int size) { - return new char[size]; - } - - /** - * Closes the given {@link Closeable} as a null-safe operation. - * - * @param closeable The resource to close, may be null. - * @throws IOException if an I/O error occurs. - * @since 2.7 - */ - public static void close(final Closeable closeable) throws IOException { - if (closeable != null) { - closeable.close(); - } - } - - /** - * Closes the given {@link Closeable} as a null-safe operation. - * - * @param closeables The resource(s) to close, may be null. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public static void close(final Closeable... closeables) throws IOException { - if (closeables != null) { - for (final Closeable closeable : closeables) { - close(closeable); - } - } - } - - /** - * Closes the given {@link Closeable} as a null-safe operation. - * - * @param closeable The resource to close, may be null. - * @param consumer Consume the IOException thrown by {@link Closeable#close()}. - * @throws IOException if an I/O error occurs. - * @since 2.7 - */ - public static void close(final Closeable closeable, final IOConsumer consumer) throws IOException { - if (closeable != null) { - try { - closeable.close(); - } catch (final IOException e) { - if (consumer != null) { - consumer.accept(e); - } - } - } - } - - /** - * Closes a URLConnection. - * - * @param conn the connection to close. - * @since 2.4 - */ - public static void close(final URLConnection conn) { - if (conn instanceof HttpURLConnection) { - ((HttpURLConnection) conn).disconnect(); - } - } - - /** - * Closes a {@code Closeable} unconditionally. - * - *

- * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in - * finally blocks. - *

- * Example code: - *

- *
-     * Closeable closeable = null;
-     * try {
-     *     closeable = new FileReader("foo.txt");
-     *     // process closeable
-     *     closeable.close();
-     * } catch (Exception e) {
-     *     // error handling
-     * } finally {
-     *     IOUtils.closeQuietly(closeable);
-     * }
-     * 
- *

- * Closing all streams: - *

- *
-     * try {
-     *     return IOUtils.copy(inputStream, outputStream);
-     * } finally {
-     *     IOUtils.closeQuietly(inputStream);
-     *     IOUtils.closeQuietly(outputStream);
-     * }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param closeable the objects to close, may be null or already closed - * @since 2.0 - * - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Closeable closeable) { - closeQuietly(closeable, (Consumer) null); - } - - /** - * Closes a {@code Closeable} unconditionally. - *

- * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. - *

- * This is typically used in finally blocks to ensure that the closeable is closed - * even if an Exception was thrown before the normal close statement was reached. - *
- * It should not be used to replace the close statement(s) - * which should be present for the non-exceptional case. - *
- * It is only intended to simplify tidying up where normal processing has already failed - * and reporting close failure as well is not necessary or useful. - *

- * Example code: - *

- *
-     * Closeable closeable = null;
-     * try {
-     *     closeable = new FileReader("foo.txt");
-     *     // processing using the closeable; may throw an Exception
-     *     closeable.close(); // Normal close - exceptions not ignored
-     * } catch (Exception e) {
-     *     // error handling
-     * } finally {
-     *     IOUtils.closeQuietly(closeable); // In case normal close was skipped due to Exception
-     * }
-     * 
- *

- * Closing all streams: - *
- *

-     * try {
-     *     return IOUtils.copy(inputStream, outputStream);
-     * } finally {
-     *     IOUtils.closeQuietly(inputStream, outputStream);
-     * }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * @param closeables the objects to close, may be null or already closed - * @see #closeQuietly(Closeable) - * @since 2.5 - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Closeable... closeables) { - if (closeables == null) { - return; - } - for (final Closeable closeable : closeables) { - closeQuietly(closeable); - } - } - - /** - * Closes the given {@link Closeable} as a null-safe operation while consuming IOException by the given {@code consumer}. - * - * @param closeable The resource to close, may be null. - * @param consumer Consumes the IOException thrown by {@link Closeable#close()}. - * @since 2.7 - */ - public static void closeQuietly(final Closeable closeable, final Consumer consumer) { - if (closeable != null) { - try { - closeable.close(); - } catch (final IOException e) { - if (consumer != null) { - consumer.accept(e); - } - } - } - } - - /** - * Closes an {@code InputStream} unconditionally. - *

- * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   byte[] data = new byte[1024];
-     *   InputStream in = null;
-     *   try {
-     *       in = new FileInputStream("foo.txt");
-     *       in.read(data);
-     *       in.close(); //close errors are handled
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(in);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param input the InputStream to close, may be null or already closed - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final InputStream input) { - closeQuietly((Closeable) input); - } - - /** - * Closes an {@code OutputStream} unconditionally. - *

- * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     * byte[] data = "Hello, World".getBytes();
-     *
-     * OutputStream out = null;
-     * try {
-     *     out = new FileOutputStream("foo.txt");
-     *     out.write(data);
-     *     out.close(); //close errors are handled
-     * } catch (IOException e) {
-     *     // error handling
-     * } finally {
-     *     IOUtils.closeQuietly(out);
-     * }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param output the OutputStream to close, may be null or already closed - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final OutputStream output) { - closeQuietly((Closeable) output); - } - - /** - * Closes an {@code Reader} unconditionally. - *

- * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   char[] data = new char[1024];
-     *   Reader in = null;
-     *   try {
-     *       in = new FileReader("foo.txt");
-     *       in.read(data);
-     *       in.close(); //close errors are handled
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(in);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param reader the Reader to close, may be null or already closed - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Reader reader) { - closeQuietly((Closeable) reader); - } - - /** - * Closes a {@code Selector} unconditionally. - *

- * Equivalent to {@link Selector#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   Selector selector = null;
-     *   try {
-     *       selector = Selector.open();
-     *       // process socket
-     *
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(selector);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param selector the Selector to close, may be null or already closed - * @since 2.2 - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Selector selector) { - closeQuietly((Closeable) selector); - } - - /** - * Closes a {@code ServerSocket} unconditionally. - *

- * Equivalent to {@link ServerSocket#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   ServerSocket socket = null;
-     *   try {
-     *       socket = new ServerSocket();
-     *       // process socket
-     *       socket.close();
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(socket);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param serverSocket the ServerSocket to close, may be null or already closed - * @since 2.2 - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final ServerSocket serverSocket) { - closeQuietly((Closeable) serverSocket); - } - - /** - * Closes a {@code Socket} unconditionally. - *

- * Equivalent to {@link Socket#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   Socket socket = null;
-     *   try {
-     *       socket = new Socket("http://www.foo.com/", 80);
-     *       // process socket
-     *       socket.close();
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(socket);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param socket the Socket to close, may be null or already closed - * @since 2.0 - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Socket socket) { - closeQuietly((Closeable) socket); - } - - /** - * Closes an {@code Writer} unconditionally. - *

- * Equivalent to {@link Writer#close()}, except any exceptions will be ignored. - * This is typically used in finally blocks. - *

- * Example code: - *

-     *   Writer out = null;
-     *   try {
-     *       out = new StringWriter();
-     *       out.write("Hello World");
-     *       out.close(); //close errors are handled
-     *   } catch (Exception e) {
-     *       // error handling
-     *   } finally {
-     *       IOUtils.closeQuietly(out);
-     *   }
-     * 
- *

- * Also consider using a try-with-resources statement where appropriate. - *

- * - * @param writer the Writer to close, may be null or already closed - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - public static void closeQuietly(final Writer writer) { - closeQuietly((Closeable) writer); - } - - /** - * Consumes bytes from a {@code InputStream} and ignores them. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - *

- * - * @param input the {@code InputStream} to read. - * @return the number of bytes copied. or {@code 0} if {@code input is null}. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public static long consume(final InputStream input) - throws IOException { - return copyLarge(input, NullOutputStream.NULL_OUTPUT_STREAM, getByteArray()); - } - - /** - * Compares the contents of two Streams to determine if they are equal or - * not. - *

- * This method buffers the input internally using - * {@code BufferedInputStream} if they are not already buffered. - *

- * - * @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 NullPointerException if either input is null - * @throws IOException if an I/O error occurs - */ - public static boolean contentEquals(final InputStream input1, final InputStream input2) throws IOException { - // Before making any changes, please test with - // org.apache.commons.io.jmh.IOUtilsContentEqualsInputStreamsBenchmark - if (input1 == input2) { - return true; - } - if (input1 == null || input2 == null) { - return false; - } - - // reuse one - final byte[] array1 = getByteArray(); - // allocate another - final byte[] array2 = byteArray(); - int pos1; - int pos2; - int count1; - int count2; - while (true) { - pos1 = 0; - pos2 = 0; - for (int index = 0; index < DEFAULT_BUFFER_SIZE; index++) { - if (pos1 == index) { - do { - count1 = input1.read(array1, pos1, DEFAULT_BUFFER_SIZE - pos1); - } while (count1 == 0); - if (count1 == EOF) { - return pos2 == index && input2.read() == EOF; - } - pos1 += count1; - } - if (pos2 == index) { - do { - count2 = input2.read(array2, pos2, DEFAULT_BUFFER_SIZE - pos2); - } while (count2 == 0); - if (count2 == EOF) { - return pos1 == index && input1.read() == EOF; - } - pos2 += count2; - } - if (array1[index] != array2[index]) { - return false; - } - } - } - } - - /** - * Compares the contents of two Readers to determine if they are equal or not. - *

- * This method buffers the input internally using {@code BufferedReader} if they are not already buffered. - *

- * - * @param input1 the first reader - * @param input2 the second reader - * @return true if the content of the readers are equal or they both don't exist, false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static boolean contentEquals(final Reader input1, final Reader input2) throws IOException { - if (input1 == input2) { - return true; - } - if (input1 == null || input2 == null) { - return false; - } - - // reuse one - final char[] array1 = getCharArray(); - // but allocate another - final char[] array2 = charArray(); - int pos1; - int pos2; - int count1; - int count2; - while (true) { - pos1 = 0; - pos2 = 0; - for (int index = 0; index < DEFAULT_BUFFER_SIZE; index++) { - if (pos1 == index) { - do { - count1 = input1.read(array1, pos1, DEFAULT_BUFFER_SIZE - pos1); - } while (count1 == 0); - if (count1 == EOF) { - return pos2 == index && input2.read() == EOF; - } - pos1 += count1; - } - if (pos2 == index) { - do { - count2 = input2.read(array2, pos2, DEFAULT_BUFFER_SIZE - pos2); - } while (count2 == 0); - if (count2 == EOF) { - return pos1 == index && input1.read() == EOF; - } - pos2 += count2; - } - if (array1[index] != array2[index]) { - return false; - } - } - } - } - - /** - * Compares the contents of two Readers to determine if they are equal or - * not, ignoring EOL characters. - *

- * This method buffers the input internally using - * {@code BufferedReader} if they are not already buffered. - * - * @param reader1 the first reader - * @param reader2 the second reader - * @return true if the content of the readers are equal (ignoring EOL differences), false otherwise - * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - @SuppressWarnings("resource") - public static boolean contentEqualsIgnoreEOL(final Reader reader1, final Reader reader2) - throws IOException { - if (reader1 == reader2) { - return true; - } - if (reader1 == null ^ reader2 == null) { - return false; - } - final BufferedReader br1 = toBufferedReader(reader1); - final BufferedReader br2 = toBufferedReader(reader2); - - String line1 = br1.readLine(); - String line2 = br2.readLine(); - while (line1 != null && line1.equals(line2)) { - line1 = br1.readLine(); - line2 = br2.readLine(); - } - return Objects.equals(line1, line2); - } - - /** - * Copies bytes from an {@code InputStream} to an {@code OutputStream}. - *

- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - *

- *

- * Large streams (over 2GB) will return a bytes copied value of {@code -1} after the copy has completed since - * the correct number of bytes cannot be returned as an int. For large streams use the - * {@code copyLarge(InputStream, OutputStream)} method. - *

- * - * @param inputStream the {@code InputStream} to read. - * @param outputStream the {@code OutputStream} to write. - * @return the number of bytes copied, or -1 if greater than {@link Integer#MAX_VALUE}. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 1.1 - */ - public static int copy(final InputStream inputStream, final OutputStream outputStream) throws IOException { - final long count = copyLarge(inputStream, outputStream); - if (count > Integer.MAX_VALUE) { - return EOF; - } - return (int) count; - } - - /** - * Copies bytes from an {@code InputStream} to an {@code OutputStream} using an internal buffer of the - * given size. - *

- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - *

- * - * @param inputStream the {@code InputStream} to read. - * @param outputStream the {@code OutputStream} to write to - * @param bufferSize the bufferSize used to copy from the input to the output - * @return the number of bytes copied. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.5 - */ - public static long copy(final InputStream inputStream, final OutputStream outputStream, final int bufferSize) - throws IOException { - return copyLarge(inputStream, outputStream, IOUtils.byteArray(bufferSize)); - } - - /** - * Copies bytes from an {@code InputStream} to chars on a - * {@code Writer} using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the {@code InputStream} to read from - * @param writer the {@code Writer} to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #copy(InputStream, Writer, Charset)} instead - */ - @Deprecated - public static void copy(final InputStream input, final Writer writer) - throws IOException { - copy(input, writer, Charset.defaultCharset()); - } - - /** - * Copies bytes from an {@code InputStream} to chars on a - * {@code Writer} using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the {@code InputStream} to read from - * @param writer the {@code Writer} to write to - * @param inputCharset the charset to use for the input stream, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void copy(final InputStream input, final Writer writer, final Charset inputCharset) - throws IOException { - final InputStreamReader reader = new InputStreamReader(input, Charsets.toCharset(inputCharset)); - copy(reader, writer); - } - - /** - * Copies bytes from an {@code InputStream} to chars on a - * {@code Writer} using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the {@code InputStream} to read from - * @param writer the {@code Writer} to write to - * @param inputCharsetName the name of the requested charset for the InputStream, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static void copy(final InputStream input, final Writer writer, final String inputCharsetName) - throws IOException { - copy(input, writer, Charsets.toCharset(inputCharsetName)); - } - - /** - * Copies chars from a {@code Reader} to a {@code Appendable}. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * Large streams (over 2GB) will return a chars copied value of - * {@code -1} after the copy has completed since the correct - * number of chars cannot be returned as an int. For large streams - * use the {@code copyLarge(Reader, Writer)} method. - * - * @param reader the {@code Reader} to read from - * @param output the {@code Appendable} to write to - * @return the number of characters copied, or -1 if > Integer.MAX_VALUE - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.7 - */ - public static long copy(final Reader reader, final Appendable output) throws IOException { - return copy(reader, output, CharBuffer.allocate(DEFAULT_BUFFER_SIZE)); - } - - /** - * Copies chars from a {@code Reader} to an {@code Appendable}. - *

- * This method uses the provided buffer, so there is no need to use a - * {@code BufferedReader}. - *

- * - * @param reader the {@code Reader} to read from - * @param output the {@code Appendable} to write to - * @param buffer the buffer to be used for the copy - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.7 - */ - public static long copy(final Reader reader, final Appendable output, final CharBuffer buffer) throws IOException { - long count = 0; - int n; - while (EOF != (n = reader.read(buffer))) { - buffer.flip(); - output.append(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copies chars from a {@code Reader} to bytes on an - * {@code OutputStream} using the default character encoding of the - * platform, and calling flush. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - *

- * This method uses {@link OutputStreamWriter}. - * - * @param reader the {@code Reader} to read from - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #copy(Reader, OutputStream, Charset)} instead - */ - @Deprecated - public static void copy(final Reader reader, final OutputStream output) - throws IOException { - copy(reader, output, Charset.defaultCharset()); - } - - /** - * Copies chars from a {@code Reader} to bytes on an - * {@code OutputStream} using the specified character encoding, and - * calling flush. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- *

- * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - *

- *

- * This method uses {@link OutputStreamWriter}. - *

- * - * @param reader the {@code Reader} to read from - * @param output the {@code OutputStream} to write to - * @param outputCharset the charset to use for the OutputStream, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void copy(final Reader reader, final OutputStream output, final Charset outputCharset) - throws IOException { - final OutputStreamWriter writer = new OutputStreamWriter(output, Charsets.toCharset(outputCharset)); - copy(reader, writer); - // XXX Unless anyone is planning on rewriting OutputStreamWriter, - // we have to flush here. - writer.flush(); - } - - /** - * Copies chars from a {@code Reader} to bytes on an - * {@code OutputStream} using the specified character encoding, and - * calling flush. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * Character encoding names can be found at - * IANA. - *

- * Due to the implementation of OutputStreamWriter, this method performs a - * flush. - *

- * This method uses {@link OutputStreamWriter}. - * - * @param reader the {@code Reader} to read from - * @param output the {@code OutputStream} to write to - * @param outputCharsetName the name of the requested charset for the OutputStream, null means platform default - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static void copy(final Reader reader, final OutputStream output, final String outputCharsetName) - throws IOException { - copy(reader, output, Charsets.toCharset(outputCharsetName)); - } - - /** - * Copies chars from a {@code Reader} to a {@code Writer}. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * Large streams (over 2GB) will return a chars copied value of - * {@code -1} after the copy has completed since the correct - * number of chars cannot be returned as an int. For large streams - * use the {@code copyLarge(Reader, Writer)} method. - * - * @param reader the {@code Reader} to read. - * @param writer the {@code Writer} to write. - * @return the number of characters copied, or -1 if > Integer.MAX_VALUE - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static int copy(final Reader reader, final Writer writer) throws IOException { - final long count = copyLarge(reader, writer); - if (count > Integer.MAX_VALUE) { - return EOF; - } - return (int) count; - } - - /** - * Copies bytes from a {@code URL} to an {@code OutputStream}. - *

- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - *

- *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - *

- * - * @param url the {@code URL} to read. - * @param file the {@code OutputStream} to write. - * @return the number of bytes copied. - * @throws NullPointerException if the URL is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.9.0 - */ - public static long copy(final URL url, final File file) throws IOException { - try (OutputStream outputStream = Files.newOutputStream(Objects.requireNonNull(file, "file").toPath())) { - return copy(url, outputStream); - } - } - - /** - * Copies bytes from a {@code URL} to an {@code OutputStream}. - *

- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - *

- *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - *

- * - * @param url the {@code URL} to read. - * @param outputStream the {@code OutputStream} to write. - * @return the number of bytes copied. - * @throws NullPointerException if the URL is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.9.0 - */ - public static long copy(final URL url, final OutputStream outputStream) throws IOException { - try (InputStream inputStream = Objects.requireNonNull(url, "url").openStream()) { - return copyLarge(inputStream, outputStream); - } - } - - /** - * Copies bytes from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - *

- * - * @param inputStream the {@code InputStream} to read. - * @param outputStream the {@code OutputStream} to write. - * @return the number of bytes copied. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 1.3 - */ - public static long copyLarge(final InputStream inputStream, final OutputStream outputStream) - throws IOException { - return copy(inputStream, outputStream, DEFAULT_BUFFER_SIZE); - } - - /** - * Copies bytes from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}. - *

- * This method uses the provided buffer, so there is no need to use a - * {@code BufferedInputStream}. - *

- * - * @param inputStream the {@code InputStream} to read. - * @param outputStream the {@code OutputStream} to write. - * @param buffer the buffer to use for the copy - * @return the number of bytes copied. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if an I/O error occurs. - * @since 2.2 - */ - @SuppressWarnings("resource") // streams are closed by the caller. - public static long copyLarge(final InputStream inputStream, final OutputStream outputStream, final byte[] buffer) - throws IOException { - Objects.requireNonNull(inputStream, "inputStream"); - Objects.requireNonNull(outputStream, "outputStream"); - long count = 0; - int n; - while (EOF != (n = inputStream.read(buffer))) { - outputStream.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copies some or all bytes from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}, optionally skipping input bytes. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- *

- * Note that the implementation uses {@link #skip(InputStream, long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of characters are skipped. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - * - * @param input the {@code InputStream} to read from - * @param output the {@code OutputStream} to write to - * @param inputOffset : number of bytes to skip from input before copying - * -ve values are ignored - * @param length : number of bytes to copy. -ve means all - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final InputStream input, final OutputStream output, final long inputOffset, - final long length) throws IOException { - return copyLarge(input, output, inputOffset, length, getByteArray()); - } - - /** - * Copies some or all bytes from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}, optionally skipping input bytes. - *

- * This method uses the provided buffer, so there is no need to use a - * {@code BufferedInputStream}. - *

- *

- * Note that the implementation uses {@link #skip(InputStream, long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of characters are skipped. - *

- * - * @param input the {@code InputStream} to read from - * @param output the {@code OutputStream} to write to - * @param inputOffset : number of bytes to skip from input before copying - * -ve values are ignored - * @param length : number of bytes to copy. -ve means all - * @param buffer the buffer to use for the copy - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final InputStream input, final OutputStream output, - final long inputOffset, final long length, final byte[] buffer) throws IOException { - if (inputOffset > 0) { - skipFully(input, inputOffset); - } - if (length == 0) { - return 0; - } - final int bufferLength = buffer.length; - int bytesToRead = bufferLength; - if (length > 0 && length < bufferLength) { - bytesToRead = (int) length; - } - int read; - long totalRead = 0; - while (bytesToRead > 0 && EOF != (read = input.read(buffer, 0, bytesToRead))) { - output.write(buffer, 0, read); - totalRead += read; - if (length > 0) { // only adjust length if not reading to the end - // Note the cast must work because buffer.length is an integer - bytesToRead = (int) Math.min(length - totalRead, bufferLength); - } - } - return totalRead; - } - - /** - * Copies chars from a large (over 2GB) {@code Reader} to a {@code Writer}. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - * - * @param reader the {@code Reader} to source. - * @param writer the {@code Writer} to target. - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 1.3 - */ - public static long copyLarge(final Reader reader, final Writer writer) throws IOException { - return copyLarge(reader, writer, getCharArray()); - } - - /** - * Copies chars from a large (over 2GB) {@code Reader} to a {@code Writer}. - *

- * This method uses the provided buffer, so there is no need to use a - * {@code BufferedReader}. - *

- * - * @param reader the {@code Reader} to source. - * @param writer the {@code Writer} to target. - * @param buffer the buffer to be used for the copy - * @return the number of characters copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final Reader reader, final Writer writer, final char[] buffer) throws IOException { - long count = 0; - int n; - while (EOF != (n = reader.read(buffer))) { - writer.write(buffer, 0, n); - count += n; - } - return count; - } - - /** - * Copies some or all chars from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}, optionally skipping input chars. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - *

- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. - * - * @param reader the {@code Reader} to read from - * @param writer the {@code Writer} to write to - * @param inputOffset : number of chars to skip from input before copying - * -ve values are ignored - * @param length : number of chars to copy. -ve means all - * @return the number of chars copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final Reader reader, final Writer writer, final long inputOffset, final long length) - throws IOException { - return copyLarge(reader, writer, inputOffset, length, getCharArray()); - } - - /** - * Copies some or all chars from a large (over 2GB) {@code InputStream} to an - * {@code OutputStream}, optionally skipping input chars. - *

- * This method uses the provided buffer, so there is no need to use a - * {@code BufferedReader}. - *

- * - * @param reader the {@code Reader} to read from - * @param writer the {@code Writer} to write to - * @param inputOffset : number of chars to skip from input before copying - * -ve values are ignored - * @param length : number of chars to copy. -ve means all - * @param buffer the buffer to be used for the copy - * @return the number of chars copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since 2.2 - */ - public static long copyLarge(final Reader reader, final Writer writer, final long inputOffset, final long length, - final char[] buffer) - throws IOException { - if (inputOffset > 0) { - skipFully(reader, inputOffset); - } - if (length == 0) { - return 0; - } - int bytesToRead = buffer.length; - if (length > 0 && length < buffer.length) { - bytesToRead = (int) length; - } - int read; - long totalRead = 0; - while (bytesToRead > 0 && EOF != (read = reader.read(buffer, 0, bytesToRead))) { - writer.write(buffer, 0, read); - totalRead += read; - if (length > 0) { // only adjust length if not reading to the end - // Note the cast must work because buffer.length is an integer - bytesToRead = (int) Math.min(length - totalRead, buffer.length); - } - } - return totalRead; - } - - /** - * Gets the thread local byte array. - * - * @return the thread local byte array. - */ - static byte[] getByteArray() { - return SKIP_BYTE_BUFFER.get(); - } - - /** - * Gets the thread local char array. - * - * @return the thread local char array. - */ - static char[] getCharArray() { - return SKIP_CHAR_BUFFER.get(); - } - - /** - * Returns the length of the given array in a null-safe manner. - * - * @param array an array or null - * @return the array length -- or 0 if the given array is null. - * @since 2.7 - */ - public static int length(final byte[] array) { - return array == null ? 0 : array.length; - } - - /** - * Returns the length of the given array in a null-safe manner. - * - * @param array an array or null - * @return the array length -- or 0 if the given array is null. - * @since 2.7 - */ - public static int length(final char[] array) { - return array == null ? 0 : array.length; - } - - /** - * Returns the length of the given CharSequence in a null-safe manner. - * - * @param csq a CharSequence or null - * @return the CharSequence length -- or 0 if the given CharSequence is null. - * @since 2.7 - */ - public static int length(final CharSequence csq) { - return csq == null ? 0 : csq.length(); - } - - /** - * Returns the length of the given array in a null-safe manner. - * - * @param array an array or null - * @return the array length -- or 0 if the given array is null. - * @since 2.7 - */ - public static int length(final Object[] array) { - return array == null ? 0 : array.length; - } - - /** - * Returns an Iterator for the lines in an {@code InputStream}, using - * the character encoding specified (or default encoding if null). - *

- * {@code LineIterator} holds a reference to the open - * {@code InputStream} specified here. When you have finished with - * the iterator you should close the stream to free internal resources. - * This can be done by closing the stream directly, or by calling - * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. - *

- * The recommended usage pattern is: - *

-     * try {
-     *   LineIterator it = IOUtils.lineIterator(stream, charset);
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   IOUtils.closeQuietly(stream);
-     * }
-     * 
- * - * @param input the {@code InputStream} to read from, not null - * @param charset the charset to use, null means platform default - * @return an Iterator of the lines in the reader, never null - * @throws IllegalArgumentException if the input is null - * @since 2.3 - */ - public static LineIterator lineIterator(final InputStream input, final Charset charset) { - return new LineIterator(new InputStreamReader(input, Charsets.toCharset(charset))); - } - - /** - * Returns an Iterator for the lines in an {@code InputStream}, using - * the character encoding specified (or default encoding if null). - *

- * {@code LineIterator} holds a reference to the open - * {@code InputStream} specified here. When you have finished with - * the iterator you should close the stream to free internal resources. - * This can be done by closing the stream directly, or by calling - * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. - *

- * The recommended usage pattern is: - *

-     * try {
-     *   LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   IOUtils.closeQuietly(stream);
-     * }
-     * 
- * - * @param input the {@code InputStream} to read from, not null - * @param charsetName the encoding to use, null means platform default - * @return an Iterator of the lines in the reader, never null - * @throws IllegalArgumentException if the input is null - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.2 - */ - public static LineIterator lineIterator(final InputStream input, final String charsetName) { - return lineIterator(input, Charsets.toCharset(charsetName)); - } - - /** - * Returns an Iterator for the lines in a {@code Reader}. - *

- * {@code LineIterator} holds a reference to the open - * {@code Reader} specified here. When you have finished with the - * iterator you should close the reader to free internal resources. - * This can be done by closing the reader directly, or by calling - * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. - *

- * The recommended usage pattern is: - *

-     * try {
-     *   LineIterator it = IOUtils.lineIterator(reader);
-     *   while (it.hasNext()) {
-     *     String line = it.nextLine();
-     *     /// do something with line
-     *   }
-     * } finally {
-     *   IOUtils.closeQuietly(reader);
-     * }
-     * 
- * - * @param reader the {@code Reader} to read from, not null - * @return an Iterator of the lines in the reader, never null - * @throws IllegalArgumentException if the reader is null - * @since 1.2 - */ - public static LineIterator lineIterator(final Reader reader) { - return new LineIterator(reader); - } - - /** - * Reads bytes from an input stream. - * This implementation guarantees that it will read as many bytes - * as possible before giving up; this may not always be the case for - * subclasses of {@link InputStream}. - * - * @param input where to read input from - * @param buffer destination - * @return actual length read; may be less than requested if EOF was reached - * @throws IOException if a read error occurs - * @since 2.2 - */ - public static int read(final InputStream input, final byte[] buffer) throws IOException { - return read(input, buffer, 0, buffer.length); - } - - /** - * Reads bytes from an input stream. - * This implementation guarantees that it will read as many bytes - * as possible before giving up; this may not always be the case for - * subclasses of {@link InputStream}. - * - * @param input where to read input from - * @param buffer destination - * @param offset initial offset into buffer - * @param length length to read, must be >= 0 - * @return actual length read; may be less than requested if EOF was reached - * @throws IOException if a read error occurs - * @since 2.2 - */ - public static int read(final InputStream input, final byte[] buffer, final int offset, final int length) - throws IOException { - if (length < 0) { - throw new IllegalArgumentException("Length must not be negative: " + length); - } - int remaining = length; - while (remaining > 0) { - final int location = length - remaining; - final int count = input.read(buffer, offset + location, remaining); - if (EOF == count) { // EOF - break; - } - remaining -= count; - } - return length - remaining; - } - - /** - * Reads bytes from a ReadableByteChannel. - *

- * This implementation guarantees that it will read as many bytes - * as possible before giving up; this may not always be the case for - * subclasses of {@link ReadableByteChannel}. - * - * @param input the byte channel to read - * @param buffer byte buffer destination - * @return the actual length read; may be less than requested if EOF was reached - * @throws IOException if a read error occurs - * @since 2.5 - */ - public static int read(final ReadableByteChannel input, final ByteBuffer buffer) throws IOException { - final int length = buffer.remaining(); - while (buffer.remaining() > 0) { - final int count = input.read(buffer); - if (EOF == count) { // EOF - break; - } - } - return length - buffer.remaining(); - } - - /** - * Reads characters from an input character stream. - * This implementation guarantees that it will read as many characters - * as possible before giving up; this may not always be the case for - * subclasses of {@link Reader}. - * - * @param reader where to read input from - * @param buffer destination - * @return actual length read; may be less than requested if EOF was reached - * @throws IOException if a read error occurs - * @since 2.2 - */ - public static int read(final Reader reader, final char[] buffer) throws IOException { - return read(reader, buffer, 0, buffer.length); - } - - /** - * Reads characters from an input character stream. - * This implementation guarantees that it will read as many characters - * as possible before giving up; this may not always be the case for - * subclasses of {@link Reader}. - * - * @param reader where to read input from - * @param buffer destination - * @param offset initial offset into buffer - * @param length length to read, must be >= 0 - * @return actual length read; may be less than requested if EOF was reached - * @throws IOException if a read error occurs - * @since 2.2 - */ - public static int read(final Reader reader, final char[] buffer, final int offset, final int length) - throws IOException { - if (length < 0) { - throw new IllegalArgumentException("Length must not be negative: " + length); - } - int remaining = length; - while (remaining > 0) { - final int location = length - remaining; - final int count = reader.read(buffer, offset + location, remaining); - if (EOF == count) { // EOF - break; - } - remaining -= count; - } - return length - remaining; - } - - /** - * Reads the requested number of bytes or fail if there are not enough left. - *

- * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may - * not read as many bytes as requested (most likely because of reaching EOF). - * - * @param input where to read input from - * @param buffer destination - * - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if length is negative - * @throws EOFException if the number of bytes read was incorrect - * @since 2.2 - */ - public static void readFully(final InputStream input, final byte[] buffer) throws IOException { - readFully(input, buffer, 0, buffer.length); - } - - /** - * Reads the requested number of bytes or fail if there are not enough left. - *

- * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may - * not read as many bytes as requested (most likely because of reaching EOF). - * - * @param input where to read input from - * @param buffer destination - * @param offset initial offset into buffer - * @param length length to read, must be >= 0 - * - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if length is negative - * @throws EOFException if the number of bytes read was incorrect - * @since 2.2 - */ - public static void readFully(final InputStream input, final byte[] buffer, final int offset, final int length) - throws IOException { - final int actual = read(input, buffer, offset, length); - if (actual != length) { - throw new EOFException("Length to read: " + length + " actual: " + actual); - } - } - - /** - * Reads the requested number of bytes or fail if there are not enough left. - *

- * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may - * not read as many bytes as requested (most likely because of reaching EOF). - * - * @param input where to read input from - * @param length length to read, must be >= 0 - * @return the bytes read from input - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if length is negative - * @throws EOFException if the number of bytes read was incorrect - * @since 2.5 - */ - public static byte[] readFully(final InputStream input, final int length) throws IOException { - final byte[] buffer = IOUtils.byteArray(length); - readFully(input, buffer, 0, buffer.length); - return buffer; - } - - /** - * Reads the requested number of bytes or fail if there are not enough left. - *

- * This allows for the possibility that {@link ReadableByteChannel#read(ByteBuffer)} may - * not read as many bytes as requested (most likely because of reaching EOF). - * - * @param input the byte channel to read - * @param buffer byte buffer destination - * @throws IOException if there is a problem reading the file - * @throws EOFException if the number of bytes read was incorrect - * @since 2.5 - */ - public static void readFully(final ReadableByteChannel input, final ByteBuffer buffer) throws IOException { - final int expected = buffer.remaining(); - final int actual = read(input, buffer); - if (actual != expected) { - throw new EOFException("Length to read: " + expected + " actual: " + actual); - } - } - - /** - * Reads the requested number of characters or fail if there are not enough left. - *

- * This allows for the possibility that {@link Reader#read(char[], int, int)} may - * not read as many characters as requested (most likely because of reaching EOF). - * - * @param reader where to read input from - * @param buffer destination - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if length is negative - * @throws EOFException if the number of characters read was incorrect - * @since 2.2 - */ - public static void readFully(final Reader reader, final char[] buffer) throws IOException { - readFully(reader, buffer, 0, buffer.length); - } - - /** - * Reads the requested number of characters or fail if there are not enough left. - *

- * This allows for the possibility that {@link Reader#read(char[], int, int)} may - * not read as many characters as requested (most likely because of reaching EOF). - * - * @param reader where to read input from - * @param buffer destination - * @param offset initial offset into buffer - * @param length length to read, must be >= 0 - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if length is negative - * @throws EOFException if the number of characters read was incorrect - * @since 2.2 - */ - public static void readFully(final Reader reader, final char[] buffer, final int offset, final int length) - throws IOException { - final int actual = read(reader, buffer, offset, length); - if (actual != length) { - throw new EOFException("Length to read: " + length + " actual: " + actual); - } - } - - /** - * Gets the contents of an {@code InputStream} as a list of Strings, - * one entry per line, using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input the {@code InputStream} to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #readLines(InputStream, Charset)} instead - */ - @Deprecated - public static List readLines(final InputStream input) throws IOException { - return readLines(input, Charset.defaultCharset()); - } - - /** - * Gets the contents of an {@code InputStream} as a list of Strings, - * one entry per line, using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input the {@code InputStream} to read from, not null - * @param charset the charset to use, null means platform default - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static List readLines(final InputStream input, final Charset charset) throws IOException { - final InputStreamReader reader = new InputStreamReader(input, Charsets.toCharset(charset)); - return readLines(reader); - } - - /** - * Gets the contents of an {@code InputStream} as a list of Strings, - * one entry per line, using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input the {@code InputStream} to read from, not null - * @param charsetName the name of the requested charset, null means platform default - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static List readLines(final InputStream input, final String charsetName) throws IOException { - return readLines(input, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents of a {@code Reader} as a list of Strings, - * one entry per line. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from, not null - * @return the list of Strings, never null - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - @SuppressWarnings("resource") // reader wraps input and is the responsibility of the caller. - public static List readLines(final Reader reader) throws IOException { - final BufferedReader bufReader = toBufferedReader(reader); - final List list = new ArrayList<>(); - String line; - while ((line = bufReader.readLine()) != null) { - list.add(line); - } - return list; - } - - /** - * Gets the contents of a classpath resource as a byte array. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @return the requested byte array - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static byte[] resourceToByteArray(final String name) throws IOException { - return resourceToByteArray(name, null); - } - - /** - * Gets the contents of a classpath resource as a byte array. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @param classLoader the class loader that the resolution of the resource is delegated to - * @return the requested byte array - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static byte[] resourceToByteArray(final String name, final ClassLoader classLoader) throws IOException { - return toByteArray(resourceToURL(name, classLoader)); - } - - /** - * Gets the contents of a classpath resource as a String using the - * specified character encoding. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @param charset the charset to use, null means platform default - * @return the requested String - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static String resourceToString(final String name, final Charset charset) throws IOException { - return resourceToString(name, charset, null); - } - - /** - * Gets the contents of a classpath resource as a String using the - * specified character encoding. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @param charset the charset to use, null means platform default - * @param classLoader the class loader that the resolution of the resource is delegated to - * @return the requested String - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static String resourceToString(final String name, final Charset charset, final ClassLoader classLoader) throws IOException { - return toString(resourceToURL(name, classLoader), charset); - } - - /** - * Gets a URL pointing to the given classpath resource. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @return the requested URL - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static URL resourceToURL(final String name) throws IOException { - return resourceToURL(name, null); - } - - /** - * Gets a URL pointing to the given classpath resource. - * - *

- * It is expected the given {@code name} to be absolute. The - * behavior is not well-defined otherwise. - *

- * - * @param name name of the desired resource - * @param classLoader the class loader that the resolution of the resource is delegated to - * @return the requested URL - * @throws IOException if an I/O error occurs. - * - * @since 2.6 - */ - public static URL resourceToURL(final String name, final ClassLoader classLoader) throws IOException { - // What about the thread context class loader? - // What about the system class loader? - final URL resource = classLoader == null ? IOUtils.class.getResource(name) : classLoader.getResource(name); - - if (resource == null) { - throw new IOException("Resource not found: " + name); - } - - return resource; - } - - /** - * Skips bytes from an input byte stream. - * This implementation guarantees that it will read as many bytes - * as possible before giving up; this may not always be the case for - * skip() implementations in subclasses of {@link InputStream}. - *

- * Note that the implementation uses {@link InputStream#read(byte[], int, int)} rather - * than delegating to {@link InputStream#skip(long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of bytes are skipped. - *

- * - * @param input byte stream to skip - * @param toSkip number of bytes to skip. - * @return number of bytes actually skipped. - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if toSkip is negative - * @see InputStream#skip(long) - * @see IO-203 - Add skipFully() method for InputStreams - * @since 2.0 - */ - public static long skip(final InputStream input, final long toSkip) throws IOException { - if (toSkip < 0) { - throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip); - } - /* - * N.B. no need to synchronize access to SKIP_BYTE_BUFFER: - we don't care if the buffer is created multiple - * times (the data is ignored) - we always use the same size buffer, so if it it is recreated it will still be - * OK (if the buffer size were variable, we would need to synch. to ensure some other thread did not create a - * smaller one) - */ - long remain = toSkip; - while (remain > 0) { - // See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip() - final byte[] byteArray = getByteArray(); - final long n = input.read(byteArray, 0, (int) Math.min(remain, byteArray.length)); - if (n < 0) { // EOF - break; - } - remain -= n; - } - return toSkip - remain; - } - - /** - * Skips bytes from a ReadableByteChannel. - * This implementation guarantees that it will read as many bytes - * as possible before giving up. - * - * @param input ReadableByteChannel to skip - * @param toSkip number of bytes to skip. - * @return number of bytes actually skipped. - * @throws IOException if there is a problem reading the ReadableByteChannel - * @throws IllegalArgumentException if toSkip is negative - * @since 2.5 - */ - public static long skip(final ReadableByteChannel input, final long toSkip) throws IOException { - if (toSkip < 0) { - throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip); - } - final ByteBuffer skipByteBuffer = ByteBuffer.allocate((int) Math.min(toSkip, DEFAULT_BUFFER_SIZE)); - long remain = toSkip; - while (remain > 0) { - skipByteBuffer.position(0); - skipByteBuffer.limit((int) Math.min(remain, DEFAULT_BUFFER_SIZE)); - final int n = input.read(skipByteBuffer); - if (n == EOF) { - break; - } - remain -= n; - } - return toSkip - remain; - } - - /** - * Skips characters from an input character stream. - * This implementation guarantees that it will read as many characters - * as possible before giving up; this may not always be the case for - * skip() implementations in subclasses of {@link Reader}. - *

- * Note that the implementation uses {@link Reader#read(char[], int, int)} rather - * than delegating to {@link Reader#skip(long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of characters are skipped. - *

- * - * @param reader character stream to skip - * @param toSkip number of characters to skip. - * @return number of characters actually skipped. - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if toSkip is negative - * @see Reader#skip(long) - * @see IO-203 - Add skipFully() method for InputStreams - * @since 2.0 - */ - public static long skip(final Reader reader, final long toSkip) throws IOException { - if (toSkip < 0) { - throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip); - } - long remain = toSkip; - while (remain > 0) { - // See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip() - final char[] charArray = getCharArray(); - final long n = reader.read(charArray, 0, (int) Math.min(remain, charArray.length)); - if (n < 0) { // EOF - break; - } - remain -= n; - } - return toSkip - remain; - } - - /** - * Skips the requested number of bytes or fail if there are not enough left. - *

- * This allows for the possibility that {@link InputStream#skip(long)} may - * not skip as many bytes as requested (most likely because of reaching EOF). - *

- * Note that the implementation uses {@link #skip(InputStream, long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of characters are skipped. - *

- * - * @param input stream to skip - * @param toSkip the number of bytes to skip - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if toSkip is negative - * @throws EOFException if the number of bytes skipped was incorrect - * @see InputStream#skip(long) - * @since 2.0 - */ - public static void skipFully(final InputStream input, final long toSkip) throws IOException { - if (toSkip < 0) { - throw new IllegalArgumentException("Bytes to skip must not be negative: " + toSkip); - } - final long skipped = skip(input, toSkip); - if (skipped != toSkip) { - throw new EOFException("Bytes to skip: " + toSkip + " actual: " + skipped); - } - } - - /** - * Skips the requested number of bytes or fail if there are not enough left. - * - * @param input ReadableByteChannel to skip - * @param toSkip the number of bytes to skip - * @throws IOException if there is a problem reading the ReadableByteChannel - * @throws IllegalArgumentException if toSkip is negative - * @throws EOFException if the number of bytes skipped was incorrect - * @since 2.5 - */ - public static void skipFully(final ReadableByteChannel input, final long toSkip) throws IOException { - if (toSkip < 0) { - throw new IllegalArgumentException("Bytes to skip must not be negative: " + toSkip); - } - final long skipped = skip(input, toSkip); - if (skipped != toSkip) { - throw new EOFException("Bytes to skip: " + toSkip + " actual: " + skipped); - } - } - - /** - * Skips the requested number of characters or fail if there are not enough left. - *

- * This allows for the possibility that {@link Reader#skip(long)} may - * not skip as many characters as requested (most likely because of reaching EOF). - *

- * Note that the implementation uses {@link #skip(Reader, long)}. - * This means that the method may be considerably less efficient than using the actual skip implementation, - * this is done to guarantee that the correct number of characters are skipped. - *

- * - * @param reader stream to skip - * @param toSkip the number of characters to skip - * @throws IOException if there is a problem reading the file - * @throws IllegalArgumentException if toSkip is negative - * @throws EOFException if the number of characters skipped was incorrect - * @see Reader#skip(long) - * @since 2.0 - */ - public static void skipFully(final Reader reader, final long toSkip) throws IOException { - final long skipped = skip(reader, toSkip); - if (skipped != toSkip) { - throw new EOFException("Chars to skip: " + toSkip + " actual: " + skipped); - } - } - - /** - * Fetches entire contents of an {@code InputStream} and represent - * same data as result InputStream. - *

- * This method is useful where, - *

    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for - * long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray(InputStream)}, since it - * avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - public static InputStream toBufferedInputStream(final InputStream input) throws IOException { - return ByteArrayOutputStream.toBufferedInputStream(input); - } - - /** - * Fetches entire contents of an {@code InputStream} and represent - * same data as result InputStream. - *

- * This method is useful where, - *

    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for - * long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray(InputStream)}, since it - * avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @param size the initial buffer size - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - * @since 2.5 - */ - public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException { - return ByteArrayOutputStream.toBufferedInputStream(input, size); - } - - /** - * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given - * reader. - * - * @param reader the reader to wrap or return (not null) - * @return the given reader or a new {@link BufferedReader} for the given reader - * @throws NullPointerException if the input parameter is null - * @see #buffer(Reader) - * @since 2.2 - */ - public static BufferedReader toBufferedReader(final Reader reader) { - return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); - } - - /** - * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given - * reader. - * - * @param reader the reader to wrap or return (not null) - * @param size the buffer size, if a new BufferedReader is created. - * @return the given reader or a new {@link BufferedReader} for the given reader - * @throws NullPointerException if the input parameter is null - * @see #buffer(Reader) - * @since 2.5 - */ - public static BufferedReader toBufferedReader(final Reader reader, final int size) { - return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader, size); - } - - /** - * Gets the contents of an {@code InputStream} as a {@code byte[]}. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- * - * @param inputStream the {@code InputStream} to read. - * @return the requested byte array. - * @throws NullPointerException if the InputStream is {@code null}. - * @throws IOException if an I/O error occurs or reading more than {@link Integer#MAX_VALUE} occurs. - */ - public static byte[] toByteArray(final InputStream inputStream) throws IOException { - // We use a ThresholdingOutputStream to avoid reading AND writing more than Integer.MAX_VALUE. - try (final UnsynchronizedByteArrayOutputStream ubaOutput = new UnsynchronizedByteArrayOutputStream(); - final ThresholdingOutputStream thresholdOuput = new ThresholdingOutputStream(Integer.MAX_VALUE, os -> { - throw new IllegalArgumentException( - String.format("Cannot read more than %,d into a byte array", Integer.MAX_VALUE)); - }, os -> ubaOutput)) { - copy(inputStream, thresholdOuput); - return ubaOutput.toByteArray(); - } - } - - /** - * Gets the contents of an {@code InputStream} as a {@code byte[]}. Use this method instead of - * {@code toByteArray(InputStream)} when {@code InputStream} size is known - * - * @param input the {@code InputStream} to read. - * @param size the size of {@code InputStream}. - * @return the requested byte array. - * @throws IOException if an I/O error occurs or {@code InputStream} size differ from parameter size. - * @throws IllegalArgumentException if size is less than zero. - * @since 2.1 - */ - public static byte[] toByteArray(final InputStream input, final int size) throws IOException { - - if (size < 0) { - throw new IllegalArgumentException("Size must be equal or greater than zero: " + size); - } - - if (size == 0) { - return EMPTY_BYTE_ARRAY; - } - - final byte[] data = IOUtils.byteArray(size); - int offset = 0; - int read; - - while (offset < size && (read = input.read(data, offset, size - offset)) != EOF) { - offset += read; - } - - if (offset != size) { - throw new IOException("Unexpected read size, current: " + offset + ", expected: " + size); - } - - return data; - } - - /** - * Gets contents of an {@code InputStream} as a {@code byte[]}. - * Use this method instead of {@code toByteArray(InputStream)} - * when {@code InputStream} size is known. - * NOTE: the method checks that the length can safely be cast to an int without truncation - * before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array. - * (Arrays can have no more than Integer.MAX_VALUE entries anyway) - * - * @param input the {@code InputStream} to read from - * @param size the size of {@code InputStream} - * @return the requested byte array - * @throws IOException if an I/O error occurs or {@code InputStream} size differ from parameter - * size - * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE - * @see IOUtils#toByteArray(java.io.InputStream, int) - * @since 2.1 - */ - public static byte[] toByteArray(final InputStream input, final long size) throws IOException { - - if (size > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size); - } - - return toByteArray(input, (int) size); - } - - /** - * Gets the contents of a {@code Reader} as a {@code byte[]} - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @deprecated 2.5 use {@link #toByteArray(Reader, Charset)} instead - */ - @Deprecated - public static byte[] toByteArray(final Reader reader) throws IOException { - return toByteArray(reader, Charset.defaultCharset()); - } - - /** - * Gets the contents of a {@code Reader} as a {@code byte[]} - * using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from - * @param charset the charset to use, null means platform default - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static byte[] toByteArray(final Reader reader, final Charset charset) throws IOException { - try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) { - copy(reader, output, charset); - return output.toByteArray(); - } - } - - /** - * Gets the contents of a {@code Reader} as a {@code byte[]} - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from - * @param charsetName the name of the requested charset, null means platform default - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static byte[] toByteArray(final Reader reader, final String charsetName) throws IOException { - return toByteArray(reader, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents of a {@code String} as a {@code byte[]} - * using the default character encoding of the platform. - *

- * This is the same as {@link String#getBytes()}. - * - * @param input the {@code String} to convert - * @return the requested byte array - * @throws NullPointerException if the input is null - * @deprecated 2.5 Use {@link String#getBytes()} instead - */ - @Deprecated - public static byte[] toByteArray(final String input) { - // make explicit the use of the default charset - return input.getBytes(Charset.defaultCharset()); - } - - /** - * Gets the contents of a {@code URI} as a {@code byte[]}. - * - * @param uri the {@code URI} to read - * @return the requested byte array - * @throws NullPointerException if the uri is null - * @throws IOException if an I/O exception occurs - * @since 2.4 - */ - public static byte[] toByteArray(final URI uri) throws IOException { - return IOUtils.toByteArray(uri.toURL()); - } - - /** - * Gets the contents of a {@code URL} as a {@code byte[]}. - * - * @param url the {@code URL} to read - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O exception occurs - * @since 2.4 - */ - public static byte[] toByteArray(final URL url) throws IOException { - final URLConnection conn = url.openConnection(); - try { - return IOUtils.toByteArray(conn); - } finally { - close(conn); - } - } - - /** - * Gets the contents of a {@code URLConnection} as a {@code byte[]}. - * - * @param urlConn the {@code URLConnection} to read. - * @return the requested byte array. - * @throws NullPointerException if the urlConn is null. - * @throws IOException if an I/O exception occurs. - * @since 2.4 - */ - public static byte[] toByteArray(final URLConnection urlConn) throws IOException { - try (InputStream inputStream = urlConn.getInputStream()) { - return IOUtils.toByteArray(inputStream); - } - } - - /** - * Gets the contents of an {@code InputStream} as a character array - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param inputStream the {@code InputStream} to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #toCharArray(InputStream, Charset)} instead - */ - @Deprecated - public static char[] toCharArray(final InputStream inputStream) throws IOException { - return toCharArray(inputStream, Charset.defaultCharset()); - } - - /** - * Gets the contents of an {@code InputStream} as a character array - * using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param inputStream the {@code InputStream} to read from - * @param charset the charset to use, null means platform default - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static char[] toCharArray(final InputStream inputStream, final Charset charset) - throws IOException { - final CharArrayWriter writer = new CharArrayWriter(); - copy(inputStream, writer, charset); - return writer.toCharArray(); - } - - /** - * Gets the contents of an {@code InputStream} as a character array - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param inputStream the {@code InputStream} to read from - * @param charsetName the name of the requested charset, null means platform default - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static char[] toCharArray(final InputStream inputStream, final String charsetName) throws IOException { - return toCharArray(inputStream, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents of a {@code Reader} as a character array. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from - * @return the requested character array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static char[] toCharArray(final Reader reader) throws IOException { - final CharArrayWriter sw = new CharArrayWriter(); - copy(reader, sw); - return sw.toCharArray(); - } - - /** - * Converts the specified CharSequence to an input stream, encoded as bytes - * using the default character encoding of the platform. - * - * @param input the CharSequence to convert - * @return an input stream - * @since 2.0 - * @deprecated 2.5 use {@link #toInputStream(CharSequence, Charset)} instead - */ - @Deprecated - public static InputStream toInputStream(final CharSequence input) { - return toInputStream(input, Charset.defaultCharset()); - } - - /** - * Converts the specified CharSequence to an input stream, encoded as bytes - * using the specified character encoding. - * - * @param input the CharSequence to convert - * @param charset the charset to use, null means platform default - * @return an input stream - * @since 2.3 - */ - public static InputStream toInputStream(final CharSequence input, final Charset charset) { - return toInputStream(input.toString(), charset); - } - - /** - * Converts the specified CharSequence to an input stream, encoded as bytes - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - * - * @param input the CharSequence to convert - * @param charsetName the name of the requested charset, null means platform default - * @return an input stream - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 2.0 - */ - public static InputStream toInputStream(final CharSequence input, final String charsetName) { - return toInputStream(input, Charsets.toCharset(charsetName)); - } - - /** - * Converts the specified string to an input stream, encoded as bytes - * using the default character encoding of the platform. - * - * @param input the string to convert - * @return an input stream - * @since 1.1 - * @deprecated 2.5 use {@link #toInputStream(String, Charset)} instead - */ - @Deprecated - public static InputStream toInputStream(final String input) { - return toInputStream(input, Charset.defaultCharset()); - } - - /** - * Converts the specified string to an input stream, encoded as bytes - * using the specified character encoding. - * - * @param input the string to convert - * @param charset the charset to use, null means platform default - * @return an input stream - * @since 2.3 - */ - public static InputStream toInputStream(final String input, final Charset charset) { - return new ByteArrayInputStream(input.getBytes(Charsets.toCharset(charset))); - } - - /** - * Converts the specified string to an input stream, encoded as bytes - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - * - * @param input the string to convert - * @param charsetName the name of the requested charset, null means platform default - * @return an input stream - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static InputStream toInputStream(final String input, final String charsetName) { - final byte[] bytes = input.getBytes(Charsets.toCharset(charsetName)); - return new ByteArrayInputStream(bytes); - } - - /** - * Gets the contents of a {@code byte[]} as a String - * using the default character encoding of the platform. - * - * @param input the byte array to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @deprecated 2.5 Use {@link String#String(byte[])} instead - */ - @Deprecated - public static String toString(final byte[] input) { - // make explicit the use of the default charset - return new String(input, Charset.defaultCharset()); - } - - /** - * Gets the contents of a {@code byte[]} as a String - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - * - * @param input the byte array to read from - * @param charsetName the name of the requested charset, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - */ - public static String toString(final byte[] input, final String charsetName) { - return new String(input, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents of an {@code InputStream} as a String - * using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input the {@code InputStream} to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @deprecated 2.5 use {@link #toString(InputStream, Charset)} instead - */ - @Deprecated - public static String toString(final InputStream input) throws IOException { - return toString(input, Charset.defaultCharset()); - } - - /** - * Gets the contents of an {@code InputStream} as a String - * using the specified character encoding. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - *

- * - * @param input the {@code InputStream} to read from - * @param charset the charset to use, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static String toString(final InputStream input, final Charset charset) throws IOException { - try (final StringBuilderWriter sw = new StringBuilderWriter()) { - copy(input, sw, charset); - return sw.toString(); - } - } - - /** - * Gets the contents of an {@code InputStream} as a String - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input the {@code InputStream} to read from - * @param charsetName the name of the requested charset, null means platform default - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - */ - public static String toString(final InputStream input, final String charsetName) - throws IOException { - return toString(input, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents of a {@code Reader} as a String. - *

- * This method buffers the input internally, so there is no need to use a - * {@code BufferedReader}. - * - * @param reader the {@code Reader} to read from - * @return the requested String - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static String toString(final Reader reader) throws IOException { - try (final StringBuilderWriter sw = new StringBuilderWriter()) { - copy(reader, sw); - return sw.toString(); - } - } - - /** - * Gets the contents at the given URI. - * - * @param uri The URI source. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @since 2.1 - * @deprecated 2.5 use {@link #toString(URI, Charset)} instead - */ - @Deprecated - public static String toString(final URI uri) throws IOException { - return toString(uri, Charset.defaultCharset()); - } - - /** - * Gets the contents at the given URI. - * - * @param uri The URI source. - * @param encoding The encoding name for the URL contents. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @since 2.3. - */ - public static String toString(final URI uri, final Charset encoding) throws IOException { - return toString(uri.toURL(), Charsets.toCharset(encoding)); - } - - /** - * Gets the contents at the given URI. - * - * @param uri The URI source. - * @param charsetName The encoding name for the URL contents. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 2.1 - */ - public static String toString(final URI uri, final String charsetName) throws IOException { - return toString(uri, Charsets.toCharset(charsetName)); - } - - /** - * Gets the contents at the given URL. - * - * @param url The URL source. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @since 2.1 - * @deprecated 2.5 use {@link #toString(URL, Charset)} instead - */ - @Deprecated - public static String toString(final URL url) throws IOException { - return toString(url, Charset.defaultCharset()); - } - - /** - * Gets the contents at the given URL. - * - * @param url The URL source. - * @param encoding The encoding name for the URL contents. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @since 2.3 - */ - public static String toString(final URL url, final Charset encoding) throws IOException { - try (InputStream inputStream = url.openStream()) { - return toString(inputStream, encoding); - } - } - - /** - * Gets the contents at the given URL. - * - * @param url The URL source. - * @param charsetName The encoding name for the URL contents. - * @return The contents of the URL as a String. - * @throws IOException if an I/O exception occurs. - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 2.1 - */ - public static String toString(final URL url, final String charsetName) throws IOException { - return toString(url, Charsets.toCharset(charsetName)); - } - - /** - * Writes bytes from a {@code byte[]} to an {@code OutputStream}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static void write(final byte[] data, final OutputStream output) - throws IOException { - if (data != null) { - output.write(data); - } - } - - /** - * Writes bytes from a {@code byte[]} to chars on a {@code Writer} - * using the default character encoding of the platform. - *

- * This method uses {@link String#String(byte[])}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #write(byte[], Writer, Charset)} instead - */ - @Deprecated - public static void write(final byte[] data, final Writer writer) throws IOException { - write(data, writer, Charset.defaultCharset()); - } - - /** - * Writes bytes from a {@code byte[]} to chars on a {@code Writer} - * using the specified character encoding. - *

- * This method uses {@link String#String(byte[], String)}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param writer the {@code Writer} to write to - * @param charset the charset to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void write(final byte[] data, final Writer writer, final Charset charset) throws IOException { - if (data != null) { - writer.write(new String(data, Charsets.toCharset(charset))); - } - } - - /** - * Writes bytes from a {@code byte[]} to chars on a {@code Writer} - * using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#String(byte[], String)}. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param writer the {@code Writer} to write to - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static void write(final byte[] data, final Writer writer, final String charsetName) throws IOException { - write(data, writer, Charsets.toCharset(charsetName)); - } - - /** - * Writes chars from a {@code char[]} to bytes on an - * {@code OutputStream}. - *

- * This method uses {@link String#String(char[])} and - * {@link String#getBytes()}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #write(char[], OutputStream, Charset)} instead - */ - @Deprecated - public static void write(final char[] data, final OutputStream output) - throws IOException { - write(data, output, Charset.defaultCharset()); - } - - /** - * Writes chars from a {@code char[]} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * This method uses {@link String#String(char[])} and - * {@link String#getBytes(String)}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the {@code OutputStream} to write to - * @param charset the charset to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void write(final char[] data, final OutputStream output, final Charset charset) throws IOException { - if (data != null) { - output.write(new String(data).getBytes(Charsets.toCharset(charset))); - } - } - - /** - * Writes chars from a {@code char[]} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#String(char[])} and - * {@link String#getBytes(String)}. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param output the {@code OutputStream} to write to - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. - * @since 1.1 - */ - public static void write(final char[] data, final OutputStream output, final String charsetName) - throws IOException { - write(data, output, Charsets.toCharset(charsetName)); - } - - /** - * Writes chars from a {@code char[]} to a {@code Writer} - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static void write(final char[] data, final Writer writer) throws IOException { - if (data != null) { - writer.write(data); - } - } - - /** - * Writes chars from a {@code CharSequence} to bytes on an - * {@code OutputStream} using the default character encoding of the - * platform. - *

- * This method uses {@link String#getBytes()}. - * - * @param data the {@code CharSequence} to write, null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.0 - * @deprecated 2.5 use {@link #write(CharSequence, OutputStream, Charset)} instead - */ - @Deprecated - public static void write(final CharSequence data, final OutputStream output) - throws IOException { - write(data, output, Charset.defaultCharset()); - } - - /** - * Writes chars from a {@code CharSequence} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the {@code CharSequence} to write, null ignored - * @param output the {@code OutputStream} to write to - * @param charset the charset to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void write(final CharSequence data, final OutputStream output, final Charset charset) - throws IOException { - if (data != null) { - write(data.toString(), output, charset); - } - } - - /** - * Writes chars from a {@code CharSequence} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the {@code CharSequence} to write, null ignored - * @param output the {@code OutputStream} to write to - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. - * @since 2.0 - */ - public static void write(final CharSequence data, final OutputStream output, final String charsetName) - throws IOException { - write(data, output, Charsets.toCharset(charsetName)); - } - - /** - * Writes chars from a {@code CharSequence} to a {@code Writer}. - * - * @param data the {@code CharSequence} to write, null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.0 - */ - public static void write(final CharSequence data, final Writer writer) throws IOException { - if (data != null) { - write(data.toString(), writer); - } - } - - - /** - * Writes chars from a {@code String} to bytes on an - * {@code OutputStream} using the default character encoding of the - * platform. - *

- * This method uses {@link String#getBytes()}. - * - * @param data the {@code String} to write, null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #write(String, OutputStream, Charset)} instead - */ - @Deprecated - public static void write(final String data, final OutputStream output) - throws IOException { - write(data, output, Charset.defaultCharset()); - } - - /** - * Writes chars from a {@code String} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the {@code String} to write, null ignored - * @param output the {@code OutputStream} to write to - * @param charset the charset to use, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void write(final String data, final OutputStream output, final Charset charset) throws IOException { - if (data != null) { - output.write(data.getBytes(Charsets.toCharset(charset))); - } - } - - /** - * Writes chars from a {@code String} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the {@code String} to write, null ignored - * @param output the {@code OutputStream} to write to - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. - * @since 1.1 - */ - public static void write(final String data, final OutputStream output, final String charsetName) - throws IOException { - write(data, output, Charsets.toCharset(charsetName)); - } - - /** - * Writes chars from a {@code String} to a {@code Writer}. - * - * @param data the {@code String} to write, null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static void write(final String data, final Writer writer) throws IOException { - if (data != null) { - writer.write(data); - } - } - - /** - * Writes chars from a {@code StringBuffer} to bytes on an - * {@code OutputStream} using the default character encoding of the - * platform. - *

- * This method uses {@link String#getBytes()}. - * - * @param data the {@code StringBuffer} to write, null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated replaced by write(CharSequence, OutputStream) - */ - @Deprecated - public static void write(final StringBuffer data, final OutputStream output) //NOSONAR - throws IOException { - write(data, output, (String) null); - } - - /** - * Writes chars from a {@code StringBuffer} to bytes on an - * {@code OutputStream} using the specified character encoding. - *

- * Character encoding names can be found at - * IANA. - *

- * This method uses {@link String#getBytes(String)}. - * - * @param data the {@code StringBuffer} to write, null ignored - * @param output the {@code OutputStream} to write to - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. - * @since 1.1 - * @deprecated replaced by write(CharSequence, OutputStream, String) - */ - @Deprecated - public static void write(final StringBuffer data, final OutputStream output, final String charsetName) //NOSONAR - throws IOException { - if (data != null) { - output.write(data.toString().getBytes(Charsets.toCharset(charsetName))); - } - } - - /** - * Writes chars from a {@code StringBuffer} to a {@code Writer}. - * - * @param data the {@code StringBuffer} to write, null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated replaced by write(CharSequence, Writer) - */ - @Deprecated - public static void write(final StringBuffer data, final Writer writer) //NOSONAR - throws IOException { - if (data != null) { - writer.write(data.toString()); - } - } - - /** - * Writes bytes from a {@code byte[]} to an {@code OutputStream} using chunked writes. - * This is intended for writing very large byte arrays which might otherwise cause excessive - * memory usage if the native code has to allocate a copy. - * - * @param data the byte array to write, do not modify during output, - * null ignored - * @param output the {@code OutputStream} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.5 - */ - public static void writeChunked(final byte[] data, final OutputStream output) - throws IOException { - if (data != null) { - int bytes = data.length; - int offset = 0; - while (bytes > 0) { - final int chunk = Math.min(bytes, DEFAULT_BUFFER_SIZE); - output.write(data, offset, chunk); - bytes -= chunk; - offset += chunk; - } - } - } - - /** - * Writes chars from a {@code char[]} to a {@code Writer} using chunked writes. - * This is intended for writing very large byte arrays which might otherwise cause excessive - * memory usage if the native code has to allocate a copy. - * - * @param data the char array to write, do not modify during output, - * null ignored - * @param writer the {@code Writer} to write to - * @throws NullPointerException if output is null - * @throws IOException if an I/O error occurs - * @since 2.5 - */ - public static void writeChunked(final char[] data, final Writer writer) throws IOException { - if (data != null) { - int bytes = data.length; - int offset = 0; - while (bytes > 0) { - final int chunk = Math.min(bytes, DEFAULT_BUFFER_SIZE); - writer.write(data, offset, chunk); - bytes -= chunk; - offset += chunk; - } - } - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * an {@code OutputStream} line by line, using the default character - * encoding of the platform and the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the {@code OutputStream} to write to, not null, not closed - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since 1.1 - * @deprecated 2.5 use {@link #writeLines(Collection, String, OutputStream, Charset)} instead - */ - @Deprecated - public static void writeLines(final Collection lines, final String lineEnding, - final OutputStream output) throws IOException { - writeLines(lines, lineEnding, output, Charset.defaultCharset()); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * an {@code OutputStream} line by line, using the specified character - * encoding and the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the {@code OutputStream} to write to, not null, not closed - * @param charset the charset to use, null means platform default - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @since 2.3 - */ - public static void writeLines(final Collection lines, String lineEnding, final OutputStream output, - final Charset charset) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = System.lineSeparator(); - } - final Charset cs = Charsets.toCharset(charset); - for (final Object line : lines) { - if (line != null) { - output.write(line.toString().getBytes(cs)); - } - output.write(lineEnding.getBytes(cs)); - } - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * an {@code OutputStream} line by line, using the specified character - * encoding and the specified line ending. - *

- * Character encoding names can be found at - * IANA. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param output the {@code OutputStream} to write to, not null, not closed - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if the output is null - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io - * .UnsupportedEncodingException} in version 2.2 if the - * encoding is not supported. - * @since 1.1 - */ - public static void writeLines(final Collection lines, final String lineEnding, - final OutputStream output, final String charsetName) throws IOException { - writeLines(lines, lineEnding, output, Charsets.toCharset(charsetName)); - } - - /** - * Writes the {@code toString()} value of each item in a collection to - * a {@code Writer} line by line, using the specified line ending. - * - * @param lines the lines to write, null entries produce blank lines - * @param lineEnding the line separator to use, null is system default - * @param writer the {@code Writer} to write to, not null, not closed - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - * @since 1.1 - */ - public static void writeLines(final Collection lines, String lineEnding, - final Writer writer) throws IOException { - if (lines == null) { - return; - } - if (lineEnding == null) { - lineEnding = System.lineSeparator(); - } - for (final Object line : lines) { - if (line != null) { - writer.write(line.toString()); - } - writer.write(lineEnding); - } - } - - /** - * Returns the given Appendable if it is already a {@link Writer}, otherwise creates a Writer wrapper around the - * given Appendable. - * - * @param appendable the Appendable to wrap or return (not null) - * @return the given Appendable or a Writer wrapper around the given Appendable - * @throws NullPointerException if the input parameter is null - * @since 2.7 - */ - public static Writer writer(final Appendable appendable) { - Objects.requireNonNull(appendable, "appendable"); - if (appendable instanceof Writer) { - return (Writer) appendable; - } - if (appendable instanceof StringBuilder) { - return new StringBuilderWriter((StringBuilder) appendable); - } - return new AppendableWriter<>(appendable); - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public IOUtils() { //NOSONAR - - } - -} diff --git a/src/org/apache/commons/io/LineIterator.java b/src/org/apache/commons/io/LineIterator.java deleted file mode 100644 index e49592f0..00000000 --- a/src/org/apache/commons/io/LineIterator.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.Reader; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * An Iterator over the lines in a {@code Reader}. - *

- * {@code LineIterator} holds a reference to an open {@code Reader}. - * When you have finished with the iterator you should close the reader - * to free internal resources. This can be done by closing the reader directly, - * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)} - * method on the iterator. - *

- * The recommended usage pattern is: - *

- * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
- * try {
- *   while (it.hasNext()) {
- *     String line = it.nextLine();
- *     // do something with line
- *   }
- * } finally {
- *   it.close();
- * }
- * 
- * - * @since 1.2 - */ -public class LineIterator implements Iterator, Closeable { - - // N.B. This class deliberately does not implement Iterable, see https://issues.apache.org/jira/browse/IO-181 - - /** The reader that is being read. */ - private final BufferedReader bufferedReader; - /** The current line. */ - private String cachedLine; - /** A flag indicating if the iterator has been fully read. */ - private boolean finished; - - /** - * Constructs an iterator of the lines for a {@code Reader}. - * - * @param reader the {@code Reader} to read from, not null - * @throws IllegalArgumentException if the reader is null - */ - public LineIterator(final Reader reader) throws IllegalArgumentException { - if (reader == null) { - throw new IllegalArgumentException("Reader must not be null"); - } - if (reader instanceof BufferedReader) { - bufferedReader = (BufferedReader) reader; - } else { - bufferedReader = new BufferedReader(reader); - } - } - - /** - * Indicates whether the {@code Reader} has more lines. - * If there is an {@code IOException} then {@link #close()} will - * be called on this instance. - * - * @return {@code true} if the Reader has more lines - * @throws IllegalStateException if an IO exception occurs - */ - @Override - public boolean hasNext() { - if (cachedLine != null) { - return true; - } - if (finished) { - return false; - } - try { - while (true) { - final String line = bufferedReader.readLine(); - if (line == null) { - finished = true; - return false; - } - if (isValidLine(line)) { - cachedLine = line; - return true; - } - } - } catch(final IOException ioe) { - IOUtils.closeQuietly(this, ioe::addSuppressed); - throw new IllegalStateException(ioe); - } - } - - /** - * Overridable method to validate each line that is returned. - * This implementation always returns true. - * @param line the line that is to be validated - * @return true if valid, false to remove from the iterator - */ - protected boolean isValidLine(final String line) { - return true; - } - - /** - * Returns the next line in the wrapped {@code Reader}. - * - * @return the next line from the input - * @throws NoSuchElementException if there is no line to return - */ - @Override - public String next() { - return nextLine(); - } - - /** - * Returns the next line in the wrapped {@code Reader}. - * - * @return the next line from the input - * @throws NoSuchElementException if there is no line to return - */ - public String nextLine() { - if (!hasNext()) { - throw new NoSuchElementException("No more lines"); - } - final String currentLine = cachedLine; - cachedLine = null; - return currentLine; - } - - /** - * Closes the underlying {@code Reader}. - * This method is useful if you only want to process the first few - * lines of a larger file. If you do not close the iterator - * then the {@code Reader} remains open. - * This method can safely be called multiple times. - * - * @throws IOException if closing the underlying {@code Reader} fails. - */ - @Override - public void close() throws IOException { - finished = true; - cachedLine = null; - IOUtils.close(bufferedReader); - } - - /** - * Unsupported. - * - * @throws UnsupportedOperationException always - */ - @Override - public void remove() { - throw new UnsupportedOperationException("remove not supported"); - } - - /** - * Closes a {@code LineIterator} quietly. - * - * @param iterator The iterator to close, or {@code null}. - * @deprecated As of 2.6 deprecated without replacement. Please use the try-with-resources statement or handle - * suppressed exceptions manually. - * @see Throwable#addSuppressed(java.lang.Throwable) - */ - @Deprecated - public static void closeQuietly(final LineIterator iterator) { - IOUtils.closeQuietly(iterator); - } - -} diff --git a/src/org/apache/commons/io/StandardLineSeparator.java b/src/org/apache/commons/io/StandardLineSeparator.java deleted file mode 100644 index c0b4ff96..00000000 --- a/src/org/apache/commons/io/StandardLineSeparator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.nio.charset.Charset; -import java.util.Objects; - -/** - * Enumerates standard line separators: {@link #CR}, {@link #CRLF}, {@link #LF}. - * - * @since 2.9.0 - */ -public enum StandardLineSeparator { - - /** - * Carriage return. This is the line ending used on Macos 9 and earlier. - */ - CR("\r"), - - /** - * Carriage return followed by line feed. This is the line ending used on Windows. - */ - CRLF("\r\n"), - - /** - * Line feed. This is the line ending used on Linux and Macos X and later. - */ - LF("\n"); - - private final String lineSeparator; - - /** - * Constructs a new instance for a non-null line separator. - * - * @param lineSeparator a non-null line separator. - */ - StandardLineSeparator(final String lineSeparator) { - this.lineSeparator = Objects.requireNonNull(lineSeparator, "lineSeparator"); - } - - /** - * Gets the bytes for this instance encoded using the given Charset. - * - * @param charset the encoding Charset. - * @return the bytes for this instance encoded using the given Charset. - */ - public byte[] getBytes(final Charset charset) { - return lineSeparator.getBytes(charset); - } - - /** - * Gets the String value of this instance. - * - * @return the String value of this instance. - */ - public String getString() { - return lineSeparator; - } -} diff --git a/src/org/apache/commons/io/StreamIterator.java b/src/org/apache/commons/io/StreamIterator.java deleted file mode 100644 index b5cc1c46..00000000 --- a/src/org/apache/commons/io/StreamIterator.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io; - -import java.io.Closeable; -import java.util.Iterator; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * Wraps and presents a stream as a closable iterator resource that automatically closes itself when reaching the end - * of stream. - * - * @param The stream and iterator type. - * @since 2.9.0 - */ -class StreamIterator implements Iterator, Closeable { - - /** - * Wraps and presents a stream as a closable resource that automatically closes itself when reaching the end of - * stream. - *

Warning

- *

- * In order to close the stream, the call site MUST either close the stream it allocated OR call the iterator until - * the end. - *

- * - * @param The stream and iterator type. - * @param stream The stream iterate. - * @return A new iterator. - */ - @SuppressWarnings("resource") // Caller MUST close or iterate to the end. - public static Iterator iterator(final Stream stream) { - return new StreamIterator<>(stream).iterator; - } - - private StreamIterator(final Stream stream) { - this.stream = Objects.requireNonNull(stream, "stream"); - this.iterator = stream.iterator(); - } - - private final Iterator iterator; - private final Stream stream; - - @Override - public boolean hasNext() { - final boolean hasNext = iterator.hasNext(); - if (!hasNext) { - close(); - } - return hasNext; - } - - @Override - public E next() { - final E next = iterator.next(); - if (next == null) { - close(); - } - return next; - } - - /** - * Closes the underlying stream. - */ - @Override - public void close() { - stream.close(); - - } - -} diff --git a/src/org/apache/commons/io/TaggedIOException.java b/src/org/apache/commons/io/TaggedIOException.java deleted file mode 100644 index 4234e9e9..00000000 --- a/src/org/apache/commons/io/TaggedIOException.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.io.IOException; -import java.io.Serializable; - -/** - * An {@link IOException} decorator that adds a serializable tag to the - * wrapped exception. Both the tag and the original exception can be used - * to determine further processing when this exception is caught. - * - * @since 2.0 - */ -@SuppressWarnings("deprecation") // needs to extend deprecated IOExceptionWithCause to preserve binary compatibility -public class TaggedIOException extends IOExceptionWithCause { - - /** - * Generated serial version UID. - */ - private static final long serialVersionUID = -6994123481142850163L; - - /** - * Checks whether the given throwable is tagged with the given tag. - *

- * This check can only succeed if the throwable is a - * {@link TaggedIOException} and the tag is {@link Serializable}, but - * the argument types are intentionally more generic to make it easier - * to use this method without type casts. - *

- * A typical use for this method is in a {@code catch} block to - * determine how a caught exception should be handled: - *

-     * Serializable tag = ...;
-     * try {
-     *     ...;
-     * } catch (Throwable t) {
-     *     if (TaggedIOException.isTaggedWith(t, tag)) {
-     *         // special processing for tagged exception
-     *     } else {
-     *         // handling of other kinds of exceptions
-     *     }
-     * }
-     * 
- * - * @param throwable The Throwable object to check - * @param tag tag object - * @return {@code true} if the throwable has the specified tag, - * otherwise {@code false} - */ - public static boolean isTaggedWith(final Throwable throwable, final Object tag) { - return tag != null - && throwable instanceof TaggedIOException - && tag.equals(((TaggedIOException) throwable).tag); - } - - /** - * Throws the original {@link IOException} if the given throwable is - * a {@link TaggedIOException} decorator the given tag. Does nothing - * if the given throwable is of a different type or if it is tagged - * with some other tag. - *

- * This method is typically used in a {@code catch} block to - * selectively rethrow tagged exceptions. - *

-     * Serializable tag = ...;
-     * try {
-     *     ...;
-     * } catch (Throwable t) {
-     *     TaggedIOException.throwCauseIfTagged(t, tag);
-     *     // handle other kinds of exceptions
-     * }
-     * 
- * - * @param throwable an exception - * @param tag tag object - * @throws IOException original exception from the tagged decorator, if any - */ - public static void throwCauseIfTaggedWith(final Throwable throwable, final Object tag) - throws IOException { - if (isTaggedWith(throwable, tag)) { - throw ((TaggedIOException) throwable).getCause(); - } - } - - /** - * The tag of this exception. - */ - private final Serializable tag; - - /** - * Creates a tagged wrapper for the given exception. - * - * @param original the exception to be tagged - * @param tag tag of this exception - */ - public TaggedIOException(final IOException original, final Serializable tag) { - super(original.getMessage(), original); - this.tag = tag; - } - - /** - * Returns the serializable tag object. - * - * @return tag object - */ - public Serializable getTag() { - return tag; - } - - /** - * Returns the wrapped exception. The only difference to the overridden - * {@link Throwable#getCause()} method is the narrower return type. - * - * @return wrapped exception - */ - @Override - public synchronized IOException getCause() { - return (IOException) super.getCause(); - } - -} diff --git a/src/org/apache/commons/io/ThreadMonitor.java b/src/org/apache/commons/io/ThreadMonitor.java deleted file mode 100644 index dee55b96..00000000 --- a/src/org/apache/commons/io/ThreadMonitor.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io; - -import java.time.Duration; - -/** - * Monitors a thread, interrupting it if it reaches the specified timeout. - *

- * This works by sleeping until the specified timeout amount and then - * interrupting the thread being monitored. If the thread being monitored - * completes its work before being interrupted, it should {@code interrupt()} - * the monitor thread. - *

- * - *
- *       long timeoutInMillis = 1000;
- *       try {
- *           Thread monitor = ThreadMonitor.start(timeoutInMillis);
- *           // do some work here
- *           ThreadMonitor.stop(monitor);
- *       } catch (InterruptedException e) {
- *           // timed amount was reached
- *       }
- * 
- * - */ -class ThreadMonitor implements Runnable { - - private final Thread thread; - private final Duration timeout; - - /** - * Start monitoring the current thread. - * - * @param timeout The timeout amount in milliseconds - * or no timeout if the value is zero or less - * @return The monitor thread or {@code null} - * if the timeout amount is not greater than zero - */ - static Thread start(final Duration timeout) { - return start(Thread.currentThread(), timeout); - } - - /** - * Start monitoring the specified thread. - * - * @param thread The thread The thread to monitor - * @param timeout The timeout amount in milliseconds - * or no timeout if the value is zero or less - * @return The monitor thread or {@code null} - * if the timeout amount is not greater than zero - */ - static Thread start(final Thread thread, final Duration timeout) { - if (timeout.isZero() || timeout.isNegative()) { - return null; - } - final ThreadMonitor timout = new ThreadMonitor(thread, timeout); - final Thread monitor = new Thread(timout, ThreadMonitor.class.getSimpleName()); - monitor.setDaemon(true); - monitor.start(); - return monitor; - } - - /** - * Stop monitoring the specified thread. - * - * @param thread The monitor thread, may be {@code null} - */ - static void stop(final Thread thread) { - if (thread != null) { - thread.interrupt(); - } - } - - /** - * Constructs a new monitor. - * - * @param thread The thread to monitor - * @param timeout The timeout amount in milliseconds - */ - private ThreadMonitor(final Thread thread, final Duration timeout) { - this.thread = thread; - this.timeout = timeout; - } - - /** - * Sleep until the specified timeout amount and then - * interrupt the thread being monitored. - * - * @see Runnable#run() - */ - @Override - public void run() { - try { - sleep(timeout); - thread.interrupt(); - } catch (final InterruptedException e) { - // timeout not reached - } - } - - /** - * Sleeps for a guaranteed minimum duration unless interrupted. - * - * This method exists because Thread.sleep(100) can sleep for 0, 70, 100 or 200ms or anything else - * it deems appropriate. Read the docs on Thread.sleep for further interesting details. - * - * @param duration the sleep duration. - * @throws InterruptedException if interrupted - */ - private static void sleep(final Duration duration) throws InterruptedException { - // Ignore nanos for now. - final long millis = duration.toMillis(); - final long finishAtMillis = System.currentTimeMillis() + millis; - long remainingMillis = millis; - do { - Thread.sleep(remainingMillis); - remainingMillis = finishAtMillis - System.currentTimeMillis(); - } while (remainingMillis > 0); - } - - -} \ No newline at end of file diff --git a/src/org/apache/commons/io/file/AccumulatorPathVisitor.java b/src/org/apache/commons/io/file/AccumulatorPathVisitor.java deleted file mode 100644 index 4b29163d..00000000 --- a/src/org/apache/commons/io/file/AccumulatorPathVisitor.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.file.Counters.PathCounters; - -/** - * Accumulates normalized paths during visitation. - *

- * Use with care on large file trees as each visited Path element is remembered. - *

- *

Example

- * - *
- * Path dir = Paths.get("");
- * // We are interested in files older than one day
- * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
- * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 2.7 - */ -public class AccumulatorPathVisitor extends CountingPathVisitor { - - /** - * Creates a new instance configured with a BigInteger {@link PathCounters}. - * - * @return a new instance configured with a BigInteger {@link PathCounters}. - */ - public static AccumulatorPathVisitor withBigIntegerCounters() { - return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters()); - } - - /** - * Creates a new instance configured with a BigInteger {@link PathCounters}. - * - * @param fileFilter Filters files to accumulate and count. - * @param dirFilter Filters directories to accumulate and count. - * @return a new instance configured with a long {@link PathCounters}. - * @since 2.9.0 - */ - public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter, - final PathFilter dirFilter) { - return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters(), fileFilter, dirFilter); - } - - /** - * Creates a new instance configured with a long {@link PathCounters}. - * - * @return a new instance configured with a long {@link PathCounters}. - */ - public static AccumulatorPathVisitor withLongCounters() { - return new AccumulatorPathVisitor(Counters.longPathCounters()); - } - - /** - * Creates a new instance configured with a long {@link PathCounters}. - * - * @param fileFilter Filters files to accumulate and count. - * @param dirFilter Filters directories to accumulate and count. - * @return a new instance configured with a long {@link PathCounters}. - * @since 2.9.0 - */ - public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) { - return new AccumulatorPathVisitor(Counters.longPathCounters(), fileFilter, dirFilter); - } - - private final List dirList = new ArrayList<>(); - - private final List fileList = new ArrayList<>(); - - /** - * Constructs a new instance. - * - * @since 2.9.0 - */ - public AccumulatorPathVisitor() { - super(Counters.noopPathCounters()); - } - - /** - * Constructs a new instance that counts file system elements. - * - * @param pathCounter How to count path visits. - */ - public AccumulatorPathVisitor(final PathCounters pathCounter) { - super(pathCounter); - } - - /** - * Constructs a new instance. - * - * @param pathCounter How to count path visits. - * @param fileFilter Filters which files to count. - * @param dirFilter Filters which directories to count. - * @since 2.9.0 - */ - public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, - final PathFilter dirFilter) { - super(pathCounter, fileFilter, dirFilter); - } - - private void add(final List list, final Path dir) { - list.add(dir.normalize()); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof AccumulatorPathVisitor)) { - return false; - } - final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj; - return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList); - } - - /** - * Gets the list of visited directories. - * - * @return the list of visited directories. - */ - public List getDirList() { - return dirList; - } - - /** - * Gets the list of visited files. - * - * @return the list of visited files. - */ - public List getFileList() { - return fileList; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Objects.hash(dirList, fileList); - return result; - } - - /** - * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally - * sorting the result. - * - * @param parent A parent path - * @param sort Whether to sort - * @param comparator How to sort, null uses default sorting. - * @return A new list - */ - public List relativizeDirectories(final Path parent, final boolean sort, - final Comparator comparator) { - return PathUtils.relativize(getDirList(), parent, sort, comparator); - } - - /** - * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally - * sorting the result. - * - * @param parent A parent path - * @param sort Whether to sort - * @param comparator How to sort, null uses default sorting. - * @return A new list - */ - public List relativizeFiles(final Path parent, final boolean sort, - final Comparator comparator) { - return PathUtils.relativize(getFileList(), parent, sort, comparator); - } - - @Override - protected void updateDirCounter(final Path dir, final IOException exc) { - super.updateDirCounter(dir, exc); - add(dirList, dir); - } - - @Override - protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) { - super.updateFileCounters(file, attributes); - add(fileList, file); - } - -} diff --git a/src/org/apache/commons/io/file/CleaningPathVisitor.java b/src/org/apache/commons/io/file/CleaningPathVisitor.java deleted file mode 100644 index 162ab8ff..00000000 --- a/src/org/apache/commons/io/file/CleaningPathVisitor.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.Objects; - -import org.apache.commons.io.file.Counters.PathCounters; - -/** - * Deletes files but not directories as a visit proceeds. - * - * @since 2.7 - */ -public class CleaningPathVisitor extends CountingPathVisitor { - - /** - * Creates a new instance configured with a BigInteger {@link PathCounters}. - * - * @return a new instance configured with a BigInteger {@link PathCounters}. - */ - public static CountingPathVisitor withBigIntegerCounters() { - return new CleaningPathVisitor(Counters.bigIntegerPathCounters()); - } - - /** - * Creates a new instance configured with a long {@link PathCounters}. - * - * @return a new instance configured with a long {@link PathCounters}. - */ - public static CountingPathVisitor withLongCounters() { - return new CleaningPathVisitor(Counters.longPathCounters()); - } - - private final String[] skip; - private final boolean overrideReadOnly; - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param deleteOption How deletion is handled. - * @param skip The files to skip deleting. - * @since 2.8.0 - */ - public CleaningPathVisitor(final PathCounters pathCounter, final DeleteOption[] deleteOption, - final String... skip) { - super(pathCounter); - final String[] temp = skip != null ? skip.clone() : EMPTY_STRING_ARRAY; - Arrays.sort(temp); - this.skip = temp; - this.overrideReadOnly = StandardDeleteOption.overrideReadOnly(deleteOption); - } - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param skip The files to skip deleting. - */ - public CleaningPathVisitor(final PathCounters pathCounter, final String... skip) { - this(pathCounter, PathUtils.EMPTY_DELETE_OPTION_ARRAY, skip); - } - - /** - * Returns true to process the given path, false if not. - * - * @param path the path to test. - * @return true to process the given path, false if not. - */ - private boolean accept(final Path path) { - return Arrays.binarySearch(skip, Objects.toString(path.getFileName(), null)) < 0; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CleaningPathVisitor other = (CleaningPathVisitor) obj; - return overrideReadOnly == other.overrideReadOnly && Arrays.equals(skip, other.skip); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(skip); - result = prime * result + Objects.hash(overrideReadOnly); - return result; - } - - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attributes) throws IOException { - super.preVisitDirectory(dir, attributes); - return accept(dir) ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE; - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attributes) throws IOException { - // Files.deleteIfExists() never follows links, so use LinkOption.NOFOLLOW_LINKS in other calls to Files. - if (accept(file) && Files.exists(file, LinkOption.NOFOLLOW_LINKS)) { - if (overrideReadOnly) { - PathUtils.setReadOnly(file, false, LinkOption.NOFOLLOW_LINKS); - } - Files.deleteIfExists(file); - } - updateFileCounters(file, attributes); - return FileVisitResult.CONTINUE; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/io/file/CopyDirectoryVisitor.java b/src/org/apache/commons/io/file/CopyDirectoryVisitor.java deleted file mode 100644 index ad1ce24c..00000000 --- a/src/org/apache/commons/io/file/CopyDirectoryVisitor.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.ProviderMismatchException; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.Objects; - -import org.apache.commons.io.file.Counters.PathCounters; - -/** - * Copies a source directory to a target directory. - * - * @since 2.7 - */ -public class CopyDirectoryVisitor extends CountingPathVisitor { - - private final CopyOption[] copyOptions; - private final Path sourceDirectory; - private final Path targetDirectory; - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param sourceDirectory The source directory - * @param targetDirectory The target directory - * @param copyOptions Specifies how the copying should be done. - */ - public CopyDirectoryVisitor(final PathCounters pathCounter, final Path sourceDirectory, final Path targetDirectory, - final CopyOption... copyOptions) { - super(pathCounter); - this.sourceDirectory = sourceDirectory; - this.targetDirectory = targetDirectory; - this.copyOptions = copyOptions == null ? PathUtils.EMPTY_COPY_OPTIONS : copyOptions.clone(); - } - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param fileFilter How to filter file paths. - * @param dirFilter How to filter directory paths. - * @param sourceDirectory The source directory - * @param targetDirectory The target directory - * @param copyOptions Specifies how the copying should be done. - * @since 2.9.0 - */ - public CopyDirectoryVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter, - final Path sourceDirectory, final Path targetDirectory, final CopyOption... copyOptions) { - super(pathCounter, fileFilter, dirFilter); - this.sourceDirectory = sourceDirectory; - this.targetDirectory = targetDirectory; - this.copyOptions = copyOptions == null ? PathUtils.EMPTY_COPY_OPTIONS : copyOptions.clone(); - } - - /** - * Copies the sourceFile to the targetFile. - * - * @param sourceFile the source file. - * @param targetFile the target file. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - protected void copy(final Path sourceFile, final Path targetFile) throws IOException { - Files.copy(sourceFile, targetFile, copyOptions); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final CopyDirectoryVisitor other = (CopyDirectoryVisitor) obj; - return Arrays.equals(copyOptions, other.copyOptions) && Objects.equals(sourceDirectory, other.sourceDirectory) - && Objects.equals(targetDirectory, other.targetDirectory); - } - - /** - * Gets the copy options. - * - * @return the copy options. - * @since 2.8.0 - */ - public CopyOption[] getCopyOptions() { - return copyOptions.clone(); - } - - /** - * Gets the source directory. - * - * @return the source directory. - * @since 2.8.0 - */ - public Path getSourceDirectory() { - return sourceDirectory; - } - - /** - * Gets the target directory. - * - * @return the target directory. - * @since 2.8.0 - */ - public Path getTargetDirectory() { - return targetDirectory; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(copyOptions); - result = prime * result + Objects.hash(sourceDirectory, targetDirectory); - return result; - } - - @Override - public FileVisitResult preVisitDirectory(final Path directory, final BasicFileAttributes attributes) - throws IOException { - final Path newTargetDir = resolveRelativeAsString(directory); - if (Files.notExists(newTargetDir)) { - Files.createDirectory(newTargetDir); - } - return super.preVisitDirectory(directory, attributes); - } - - /** - * Relativizes against {@code sourceDirectory}, then resolves against {@code targetDirectory}. - * - * We have to call {@link Path#toString()} relative value because we cannot use paths belonging to different - * FileSystems in the Path methods, usually this leads to {@link ProviderMismatchException}. - * - * @param directory the directory to relativize. - * @return a new path, relativized against sourceDirectory, then resolved against targetDirectory. - */ - private Path resolveRelativeAsString(final Path directory) { - return targetDirectory.resolve(sourceDirectory.relativize(directory).toString()); - } - - @Override - public FileVisitResult visitFile(final Path sourceFile, final BasicFileAttributes attributes) throws IOException { - final Path targetFile = resolveRelativeAsString(sourceFile); - copy(sourceFile, targetFile); - return super.visitFile(targetFile, attributes); - } - -} diff --git a/src/org/apache/commons/io/file/Counters.java b/src/org/apache/commons/io/file/Counters.java deleted file mode 100644 index d4103373..00000000 --- a/src/org/apache/commons/io/file/Counters.java +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.math.BigInteger; -import java.util.Objects; - -/** - * Provides counters for files, directories, and sizes, as a visit proceeds. - * - * @since 2.7 - */ -public class Counters { - - /** - * Counts files, directories, and sizes, as a visit proceeds. - */ - private static class AbstractPathCounters implements PathCounters { - - private final Counter byteCounter; - private final Counter directoryCounter; - private final Counter fileCounter; - - /** - * Constructs a new instance. - * - * @param byteCounter the byte counter. - * @param directoryCounter the directory counter. - * @param fileCounter the file counter. - */ - protected AbstractPathCounters(final Counter byteCounter, final Counter directoryCounter, - final Counter fileCounter) { - this.byteCounter = byteCounter; - this.directoryCounter = directoryCounter; - this.fileCounter = fileCounter; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof AbstractPathCounters)) { - return false; - } - final AbstractPathCounters other = (AbstractPathCounters) obj; - return Objects.equals(byteCounter, other.byteCounter) - && Objects.equals(directoryCounter, other.directoryCounter) - && Objects.equals(fileCounter, other.fileCounter); - } - - @Override - public Counter getByteCounter() { - return byteCounter; - } - - @Override - public Counter getDirectoryCounter() { - return directoryCounter; - } - - /** - * Gets the count of visited files. - * - * @return the byte count of visited files. - */ - @Override - public Counter getFileCounter() { - return this.fileCounter; - } - - @Override - public int hashCode() { - return Objects.hash(byteCounter, directoryCounter, fileCounter); - } - - @Override - public void reset() { - byteCounter.reset(); - directoryCounter.reset(); - fileCounter.reset(); - } - - @Override - public String toString() { - return String.format("%,d files, %,d directories, %,d bytes", Long.valueOf(fileCounter.get()), - Long.valueOf(directoryCounter.get()), Long.valueOf(byteCounter.get())); - } - - } - - /** - * Counts using a BigInteger number. - */ - private static final class BigIntegerCounter implements Counter { - - private BigInteger value = BigInteger.ZERO; - - @Override - public void add(final long val) { - value = value.add(BigInteger.valueOf(val)); - - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Counter)) { - return false; - } - final Counter other = (Counter) obj; - return Objects.equals(value, other.getBigInteger()); - } - - @Override - public long get() { - return value.longValueExact(); - } - - @Override - public BigInteger getBigInteger() { - return value; - } - - @Override - public Long getLong() { - return Long.valueOf(value.longValueExact()); - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public void increment() { - value = value.add(BigInteger.ONE); - } - - @Override - public String toString() { - return value.toString(); - } - - @Override - public void reset() { - value = BigInteger.ZERO; - } - } - - /** - * Counts files, directories, and sizes, as a visit proceeds, using BigInteger numbers. - */ - private final static class BigIntegerPathCounters extends AbstractPathCounters { - - /** - * Constructs a new initialized instance. - */ - protected BigIntegerPathCounters() { - super(Counters.bigIntegerCounter(), Counters.bigIntegerCounter(), Counters.bigIntegerCounter()); - } - - } - - /** - * Counts using a number. - */ - public interface Counter { - - /** - * Adds the given number to this counter. - * - * @param val the value to add. - */ - void add(long val); - - /** - * Gets the counter as a long. - * - * @return the counter as a long. - */ - long get(); - - /** - * Gets the counter as a BigInteger. - * - * @return the counter as a BigInteger. - */ - BigInteger getBigInteger(); - - /** - * Gets the counter as a Long. - * - * @return the counter as a Long. - */ - Long getLong(); - - /** - * Adds one to this counter. - */ - void increment(); - - /** - * Resets this count to 0. - */ - default void reset() { - // binary compat, do nothing - } - - } - - /** - * Counts using a long number. - */ - private final static class LongCounter implements Counter { - - private long value; - - @Override - public void add(final long add) { - value += add; - - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Counter)) { - return false; - } - final Counter other = (Counter) obj; - return value == other.get(); - } - - @Override - public long get() { - return value; - } - - @Override - public BigInteger getBigInteger() { - return BigInteger.valueOf(value); - } - - @Override - public Long getLong() { - return Long.valueOf(value); - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public void increment() { - value++; - } - - @Override - public String toString() { - return Long.toString(value); - } - - @Override - public void reset() { - value = 0L; - } - } - - /** - * Counts files, directories, and sizes, as a visit proceeds, using long numbers. - */ - private final static class LongPathCounters extends AbstractPathCounters { - - /** - * Constructs a new initialized instance. - */ - protected LongPathCounters() { - super(Counters.longCounter(), Counters.longCounter(), Counters.longCounter()); - } - - } - - /** - * Counts nothing. - */ - private final static class NoopCounter implements Counter { - - static final NoopCounter INSTANCE = new NoopCounter(); - - @Override - public void add(final long add) { - // noop - } - - @Override - public long get() { - return 0; - } - - @Override - public BigInteger getBigInteger() { - return BigInteger.ZERO; - } - - @Override - public Long getLong() { - return 0L; - } - - @Override - public void increment() { - // noop - } - - } - - /** - * Counts nothing. - */ - private static final class NoopPathCounters extends AbstractPathCounters { - - static final NoopPathCounters INSTANCE = new NoopPathCounters(); - - /** - * Constructs a new initialized instance. - */ - private NoopPathCounters() { - super(Counters.noopCounter(), Counters.noopCounter(), Counters.noopCounter()); - } - - } - - /** - * Counts files, directories, and sizes, as a visit proceeds. - */ - public interface PathCounters { - - /** - * Gets the byte counter. - * - * @return the byte counter. - */ - Counter getByteCounter(); - - /** - * Gets the directory counter. - * - * @return the directory counter. - */ - Counter getDirectoryCounter(); - - /** - * Gets the file counter. - * - * @return the file counter. - */ - Counter getFileCounter(); - - /** - * Resets the counts to 0. - */ - default void reset() { - // binary compat, do nothing - } - - } - - /** - * Returns a new BigInteger Counter. - * - * @return a new BigInteger Counter. - */ - public static Counter bigIntegerCounter() { - return new BigIntegerCounter(); - } - - /** - * Returns a new BigInteger PathCounters. - * - * @return a new BigInteger PathCounters. - */ - public static PathCounters bigIntegerPathCounters() { - return new BigIntegerPathCounters(); - } - - /** - * Returns a new long Counter. - * - * @return a new long Counter. - */ - public static Counter longCounter() { - return new LongCounter(); - } - - /** - * Returns a new BigInteger PathCounters. - * - * @return a new BigInteger PathCounters. - */ - public static PathCounters longPathCounters() { - return new LongPathCounters(); - } - - /** - * Returns the NOOP Counter. - * - * @return the NOOP Counter. - * @since 2.9.0 - */ - public static Counter noopCounter() { - return NoopCounter.INSTANCE; - } - - /** - * Returns the NOOP PathCounters. - * - * @return the NOOP PathCounters. - * @since 2.9.0 - */ - public static PathCounters noopPathCounters() { - return NoopPathCounters.INSTANCE; - } -} diff --git a/src/org/apache/commons/io/file/CountingPathVisitor.java b/src/org/apache/commons/io/file/CountingPathVisitor.java deleted file mode 100644 index f9ae727a..00000000 --- a/src/org/apache/commons/io/file/CountingPathVisitor.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Objects; - -import org.apache.commons.io.file.Counters.PathCounters; -import org.apache.commons.io.filefilter.TrueFileFilter; - -/** - * Counts files, directories, and sizes, as a visit proceeds. - * - * @since 2.7 - */ -public class CountingPathVisitor extends SimplePathVisitor { - - static final String[] EMPTY_STRING_ARRAY = {}; - - /** - * Creates a new instance configured with a BigInteger {@link PathCounters}. - * - * @return a new instance configured with a BigInteger {@link PathCounters}. - */ - public static CountingPathVisitor withBigIntegerCounters() { - return new CountingPathVisitor(Counters.bigIntegerPathCounters()); - } - - /** - * Creates a new instance configured with a long {@link PathCounters}. - * - * @return a new instance configured with a long {@link PathCounters}. - */ - public static CountingPathVisitor withLongCounters() { - return new CountingPathVisitor(Counters.longPathCounters()); - } - - private final PathCounters pathCounters; - private final PathFilter fileFilter; - private final PathFilter dirFilter; - - /** - * Constructs a new instance. - * - * @param pathCounter How to count path visits. - */ - public CountingPathVisitor(final PathCounters pathCounter) { - this(pathCounter, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE); - } - - /** - * Constructs a new instance. - * - * @param pathCounter How to count path visits. - * @param fileFilter Filters which files to count. - * @param dirFilter Filters which directories to count. - * @since 2.9.0 - */ - public CountingPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) { - this.pathCounters = Objects.requireNonNull(pathCounter, "pathCounter"); - this.fileFilter = Objects.requireNonNull(fileFilter, "fileFilter"); - this.dirFilter = Objects.requireNonNull(dirFilter, "dirFilter"); - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof CountingPathVisitor)) { - return false; - } - final CountingPathVisitor other = (CountingPathVisitor) obj; - return Objects.equals(pathCounters, other.pathCounters); - } - - /** - * Gets the visitation counts. - * - * @return the visitation counts. - */ - public PathCounters getPathCounters() { - return pathCounters; - } - - @Override - public int hashCode() { - return Objects.hash(pathCounters); - } - - @Override - public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException { - updateDirCounter(dir, exc); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attributes) throws IOException { - final FileVisitResult accept = dirFilter.accept(dir, attributes); - return accept != FileVisitResult.CONTINUE ? FileVisitResult.SKIP_SUBTREE : FileVisitResult.CONTINUE; - } - - @Override - public String toString() { - return pathCounters.toString(); - } - - /** - * Updates the counter for visiting the given directory. - * - * @param dir the visited directory. - * @param exc Encountered exception. - * @since 2.9.0 - */ - protected void updateDirCounter(final Path dir, final IOException exc) { - pathCounters.getDirectoryCounter().increment(); - } - - /** - * Updates the counters for visiting the given file. - * - * @param file the visited file. - * @param attributes the visited file attributes. - */ - protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) { - pathCounters.getFileCounter().increment(); - pathCounters.getByteCounter().add(attributes.size()); - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attributes) throws IOException { - if (Files.exists(file) && fileFilter.accept(file, attributes) == FileVisitResult.CONTINUE) { - updateFileCounters(file, attributes); - } - return FileVisitResult.CONTINUE; - } - -} diff --git a/src/org/apache/commons/io/file/DeleteOption.java b/src/org/apache/commons/io/file/DeleteOption.java deleted file mode 100644 index 3fe21add..00000000 --- a/src/org/apache/commons/io/file/DeleteOption.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -/** - * An object that configures how to delete a file. - * - *

- * The {@link StandardDeleteOption} enumeration type defines our standard options. - *

- * - * @see StandardDeleteOption - * @since 2.8.0 - */ -public interface DeleteOption { - // empty -} diff --git a/src/org/apache/commons/io/file/DeletingPathVisitor.java b/src/org/apache/commons/io/file/DeletingPathVisitor.java deleted file mode 100644 index b91bd145..00000000 --- a/src/org/apache/commons/io/file/DeletingPathVisitor.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.Objects; - -import org.apache.commons.io.file.Counters.PathCounters; - -/** - * Deletes files and directories as a visit proceeds. - * - * @since 2.7 - */ -public class DeletingPathVisitor extends CountingPathVisitor { - - /** - * Creates a new instance configured with a BigInteger {@link PathCounters}. - * - * @return a new instance configured with a BigInteger {@link PathCounters}. - */ - public static DeletingPathVisitor withBigIntegerCounters() { - return new DeletingPathVisitor(Counters.bigIntegerPathCounters()); - } - - /** - * Creates a new instance configured with a long {@link PathCounters}. - * - * @return a new instance configured with a long {@link PathCounters}. - */ - public static DeletingPathVisitor withLongCounters() { - return new DeletingPathVisitor(Counters.longPathCounters()); - } - - private final String[] skip; - private final boolean overrideReadOnly; - private final LinkOption[] linkOptions; - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param deleteOption How deletion is handled. - * @param skip The files to skip deleting. - * @since 2.8.0 - */ - public DeletingPathVisitor(final PathCounters pathCounter, final DeleteOption[] deleteOption, - final String... skip) { - this(pathCounter, PathUtils.NOFOLLOW_LINK_OPTION_ARRAY, deleteOption, skip); - } - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * @param linkOptions How symbolic links are handled. - * @param deleteOption How deletion is handled. - * @param skip The files to skip deleting. - * @since 2.9.0 - */ - public DeletingPathVisitor(final PathCounters pathCounter, final LinkOption[] linkOptions, - final DeleteOption[] deleteOption, final String... skip) { - super(pathCounter); - final String[] temp = skip != null ? skip.clone() : EMPTY_STRING_ARRAY; - Arrays.sort(temp); - this.skip = temp; - this.overrideReadOnly = StandardDeleteOption.overrideReadOnly(deleteOption); - // TODO Files.deleteIfExists() never follows links, so use LinkOption.NOFOLLOW_LINKS in other calls to Files. - this.linkOptions = linkOptions == null ? PathUtils.NOFOLLOW_LINK_OPTION_ARRAY : linkOptions.clone(); - } - - /** - * Constructs a new visitor that deletes files except for the files and directories explicitly given. - * - * @param pathCounter How to count visits. - * - * @param skip The files to skip deleting. - */ - public DeletingPathVisitor(final PathCounters pathCounter, final String... skip) { - this(pathCounter, PathUtils.EMPTY_DELETE_OPTION_ARRAY, skip); - } - - /** - * Returns true to process the given path, false if not. - * - * @param path the path to test. - * @return true to process the given path, false if not. - */ - private boolean accept(final Path path) { - return Arrays.binarySearch(skip, Objects.toString(path.getFileName(), null)) < 0; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final DeletingPathVisitor other = (DeletingPathVisitor) obj; - return overrideReadOnly == other.overrideReadOnly && Arrays.equals(skip, other.skip); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(skip); - result = prime * result + Objects.hash(overrideReadOnly); - return result; - } - - @Override - public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException { - if (PathUtils.isEmptyDirectory(dir)) { - Files.deleteIfExists(dir); - } - return super.postVisitDirectory(dir, exc); - } - - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { - super.preVisitDirectory(dir, attrs); - return accept(dir) ? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE; - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - if (accept(file)) { - // delete files and valid links, respecting linkOptions - if (Files.exists(file, linkOptions)) { - if (overrideReadOnly) { - PathUtils.setReadOnly(file, false, linkOptions); - } - Files.deleteIfExists(file); - } - // invalid links will survive previous delete, different approach needed: - if (Files.isSymbolicLink(file)) { - try { - // deleteIfExists does not work for this case - Files.delete(file); - } catch (final NoSuchFileException e) { - // ignore - } - } - } - updateFileCounters(file, attrs); - return FileVisitResult.CONTINUE; - } -} \ No newline at end of file diff --git a/src/org/apache/commons/io/file/DirectoryStreamFilter.java b/src/org/apache/commons/io/file/DirectoryStreamFilter.java deleted file mode 100644 index d4c0b46b..00000000 --- a/src/org/apache/commons/io/file/DirectoryStreamFilter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.util.Objects; - -/** - * A {@link java.nio.file.DirectoryStream.Filter DirectoryStream.Filter} that delegates to a {@link PathFilter}. - *

- * You pass this filter to {@link java.nio.file.Files#newDirectoryStream(Path, DirectoryStream.Filter) - * Files#newDirectoryStream(Path, DirectoryStream.Filter)}. - *

- * - * @since 2.9.0 - */ -public class DirectoryStreamFilter implements DirectoryStream.Filter { - - private final PathFilter pathFilter; - - /** - * Constructs a new instance for the given path filter. - * - * @param pathFilter How to filter paths. - */ - public DirectoryStreamFilter(final PathFilter pathFilter) { - // TODO Instead of NPE, we could map null to FalseFileFilter. - this.pathFilter = Objects.requireNonNull(pathFilter, "pathFilter"); - } - - @Override - public boolean accept(final Path path) throws IOException { - return pathFilter.accept(path, PathUtils.readBasicFileAttributes(path)) == FileVisitResult.CONTINUE; - } - - /** - * Gets the path filter. - * - * @return the path filter. - */ - public PathFilter getPathFilter() { - return pathFilter; - } - -} diff --git a/src/org/apache/commons/io/file/NoopPathVisitor.java b/src/org/apache/commons/io/file/NoopPathVisitor.java deleted file mode 100644 index 48a13239..00000000 --- a/src/org/apache/commons/io/file/NoopPathVisitor.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -/** - * A noop path visitor. - * - * @since 2.9.0 - */ -public class NoopPathVisitor extends SimplePathVisitor { - - /** - * The singleton instance. - */ - public static final NoopPathVisitor INSTANCE = new NoopPathVisitor(); -} diff --git a/src/org/apache/commons/io/file/PathFilter.java b/src/org/apache/commons/io/file/PathFilter.java deleted file mode 100644 index 837ddc02..00000000 --- a/src/org/apache/commons/io/file/PathFilter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * A filter for {@link Path}s. - * - * @since 2.9.0 - */ -@FunctionalInterface -public interface PathFilter { - - /** - * Tests whether or not to include the specified Path in a result. - * - * @param path The Path to test. - * @param attributes the file's basic attributes (TODO may be null). - * @return a FileVisitResult - */ - FileVisitResult accept(Path path, BasicFileAttributes attributes); -} diff --git a/src/org/apache/commons/io/file/PathUtils.java b/src/org/apache/commons/io/file/PathUtils.java deleted file mode 100644 index f8b364bc..00000000 --- a/src/org/apache/commons/io/file/PathUtils.java +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.net.URI; -import java.net.URL; -import java.nio.file.CopyOption; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitOption; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.NoSuchFileException; -import java.nio.file.NotDirectoryException; -import java.nio.file.OpenOption; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.AclEntry; -import java.nio.file.attribute.AclFileAttributeView; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.DosFileAttributeView; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.attribute.PosixFileAttributeView; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.PosixFilePermission; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.commons.io.IOExceptionList; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.file.Counters.PathCounters; -import org.apache.commons.io.filefilter.IOFileFilter; - -/** - * NIO Path utilities. - * - * @since 2.7 - */ -public final class PathUtils { - - /** - * Private worker/holder that computes and tracks relative path names and their equality. We reuse the sorted - * relative lists when comparing directories. - */ - private static class RelativeSortedPaths { - - final boolean equals; - // final List relativeDirList1; // might need later? - // final List relativeDirList2; // might need later? - final List relativeFileList1; - final List relativeFileList2; - - /** - * Constructs and initializes a new instance by accumulating directory and file info. - * - * @param dir1 First directory to compare. - * @param dir2 Seconds directory to compare. - * @param maxDepth See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param linkOptions Options indicating how symbolic links are handled. - * @param fileVisitOptions See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @throws IOException if an I/O error is thrown by a visitor method. - */ - private RelativeSortedPaths(final Path dir1, final Path dir2, final int maxDepth, - final LinkOption[] linkOptions, final FileVisitOption[] fileVisitOptions) throws IOException { - final List tmpRelativeDirList1; - final List tmpRelativeDirList2; - List tmpRelativeFileList1 = null; - List tmpRelativeFileList2 = null; - if (dir1 == null && dir2 == null) { - equals = true; - } else if (dir1 == null ^ dir2 == null) { - equals = false; - } else { - final boolean parentDirNotExists1 = Files.notExists(dir1, linkOptions); - final boolean parentDirNotExists2 = Files.notExists(dir2, linkOptions); - if (parentDirNotExists1 || parentDirNotExists2) { - equals = parentDirNotExists1 && parentDirNotExists2; - } else { - final AccumulatorPathVisitor visitor1 = accumulate(dir1, maxDepth, fileVisitOptions); - final AccumulatorPathVisitor visitor2 = accumulate(dir2, maxDepth, fileVisitOptions); - if (visitor1.getDirList().size() != visitor2.getDirList().size() - || visitor1.getFileList().size() != visitor2.getFileList().size()) { - equals = false; - } else { - tmpRelativeDirList1 = visitor1.relativizeDirectories(dir1, true, null); - tmpRelativeDirList2 = visitor2.relativizeDirectories(dir2, true, null); - if (!tmpRelativeDirList1.equals(tmpRelativeDirList2)) { - equals = false; - } else { - tmpRelativeFileList1 = visitor1.relativizeFiles(dir1, true, null); - tmpRelativeFileList2 = visitor2.relativizeFiles(dir2, true, null); - equals = tmpRelativeFileList1.equals(tmpRelativeFileList2); - } - } - } - } - // relativeDirList1 = tmpRelativeDirList1; - // relativeDirList2 = tmpRelativeDirList2; - relativeFileList1 = tmpRelativeFileList1; - relativeFileList2 = tmpRelativeFileList2; - } - } - - /** - * Empty {@link CopyOption} array. - * - * @since 2.8.0 - */ - public static final CopyOption[] EMPTY_COPY_OPTIONS = {}; - - /** - * Empty {@link LinkOption} array. - * - * @since 2.8.0 - */ - public static final DeleteOption[] EMPTY_DELETE_OPTION_ARRAY = {}; - - /** - * Empty {@link FileVisitOption} array. - */ - public static final FileVisitOption[] EMPTY_FILE_VISIT_OPTION_ARRAY = {}; - - /** - * Empty {@link LinkOption} array. - */ - public static final LinkOption[] EMPTY_LINK_OPTION_ARRAY = {}; - - /** - * {@link LinkOption} array for {@link LinkOption#NOFOLLOW_LINKS}. - * - * @since 2.9.0 - */ - public static final LinkOption[] NOFOLLOW_LINK_OPTION_ARRAY = {LinkOption.NOFOLLOW_LINKS}; - - /** - * Empty {@link OpenOption} array. - */ - public static final OpenOption[] EMPTY_OPEN_OPTION_ARRAY = {}; - - /** - * Empty {@link Path} array. - * - * @since 2.9.0 - */ - public static final Path[] EMPTY_PATH_ARRAY = {}; - - /** - * Accumulates file tree information in a {@link AccumulatorPathVisitor}. - * - * @param directory The directory to accumulate information. - * @param maxDepth See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param fileVisitOptions See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @throws IOException if an I/O error is thrown by a visitor method. - * @return file tree information. - */ - private static AccumulatorPathVisitor accumulate(final Path directory, final int maxDepth, - final FileVisitOption[] fileVisitOptions) throws IOException { - return visitFileTree(AccumulatorPathVisitor.withLongCounters(), directory, - toFileVisitOptionSet(fileVisitOptions), maxDepth); - } - - /** - * Cleans a directory including sub-directories without deleting directories. - * - * @param directory directory to clean. - * @return The visitation path counters. - * @throws IOException if an I/O error is thrown by a visitor method. - */ - public static PathCounters cleanDirectory(final Path directory) throws IOException { - return cleanDirectory(directory, EMPTY_DELETE_OPTION_ARRAY); - } - - /** - * Cleans a directory including sub-directories without deleting directories. - * - * @param directory directory to clean. - * @param deleteOptions How to handle deletion. - * @return The visitation path counters. - * @throws IOException if an I/O error is thrown by a visitor method. - * @since 2.8.0 - */ - public static PathCounters cleanDirectory(final Path directory, final DeleteOption... deleteOptions) - throws IOException { - return visitFileTree(new CleaningPathVisitor(Counters.longPathCounters(), deleteOptions), directory) - .getPathCounters(); - } - - /** - * Copies a directory to another directory. - * - * @param sourceDirectory The source directory. - * @param targetDirectory The target directory. - * @param copyOptions Specifies how the copying should be done. - * @return The visitation path counters. - * @throws IOException if an I/O error is thrown by a visitor method. - */ - public static PathCounters copyDirectory(final Path sourceDirectory, final Path targetDirectory, - final CopyOption... copyOptions) throws IOException { - final Path absoluteSource = sourceDirectory.toAbsolutePath(); - return visitFileTree( - new CopyDirectoryVisitor(Counters.longPathCounters(), absoluteSource, targetDirectory, copyOptions), - absoluteSource).getPathCounters(); - } - - /** - * Copies a URL to a directory. - * - * @param sourceFile The source URL. - * @param targetFile The target file. - * @param copyOptions Specifies how the copying should be done. - * @return The target file - * @throws IOException if an I/O error occurs. - * @see Files#copy(InputStream, Path, CopyOption...) - */ - public static Path copyFile(final URL sourceFile, final Path targetFile, final CopyOption... copyOptions) - throws IOException { - try (final InputStream inputStream = sourceFile.openStream()) { - Files.copy(inputStream, targetFile, copyOptions); - return targetFile; - } - } - - /** - * Copies a file to a directory. - * - * @param sourceFile The source file. - * @param targetDirectory The target directory. - * @param copyOptions Specifies how the copying should be done. - * @return The target file - * @throws IOException if an I/O error occurs. - * @see Files#copy(Path, Path, CopyOption...) - */ - public static Path copyFileToDirectory(final Path sourceFile, final Path targetDirectory, - final CopyOption... copyOptions) throws IOException { - return Files.copy(sourceFile, targetDirectory.resolve(sourceFile.getFileName()), copyOptions); - } - - /** - * Copies a URL to a directory. - * - * @param sourceFile The source URL. - * @param targetDirectory The target directory. - * @param copyOptions Specifies how the copying should be done. - * @return The target file - * @throws IOException if an I/O error occurs. - * @see Files#copy(InputStream, Path, CopyOption...) - */ - public static Path copyFileToDirectory(final URL sourceFile, final Path targetDirectory, - final CopyOption... copyOptions) throws IOException { - try (final InputStream inputStream = sourceFile.openStream()) { - Files.copy(inputStream, targetDirectory.resolve(sourceFile.getFile()), copyOptions); - return targetDirectory; - } - } - - /** - * Counts aspects of a directory including sub-directories. - * - * @param directory directory to delete. - * @return The visitor used to count the given directory. - * @throws IOException if an I/O error is thrown by a visitor method. - */ - public static PathCounters countDirectory(final Path directory) throws IOException { - return visitFileTree(new CountingPathVisitor(Counters.longPathCounters()), directory).getPathCounters(); - } - - /** - * Creates the parent directories for the given {@code path}. - * - * @param path The path to a file (or directory). - * @param attrs An optional list of file attributes to set atomically when creating the directories. - * @return The Path for the {@code path}'s parent directory or null if the given path has no parent. - * @throws IOException if an I/O error occurs. - * @since 2.9.0 - */ - public static Path createParentDirectories(final Path path, final FileAttribute... attrs) throws IOException { - final Path parent = path.getParent(); - if (parent == null) { - return null; - } - return Files.createDirectories(parent, attrs); - } - - /** - * Gets the current directory. - * - * @return the current directory. - * - * @since 2.9.0 - */ - public static Path current() { - return Paths.get(""); - } - - /** - * Deletes a file or directory. If the path is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

- *
    - *
  • A directory to delete does not have to be empty.
  • - *
  • You get exceptions when a file or directory cannot be deleted; {@link java.io.File#delete()} returns a - * boolean. - *
- * - * @param path file or directory to delete, must not be {@code null} - * @return The visitor used to delete the given directory. - * @throws NullPointerException if the directory is {@code null} - * @throws IOException if an I/O error is thrown by a visitor method or if an I/O error occurs. - */ - public static PathCounters delete(final Path path) throws IOException { - return delete(path, EMPTY_DELETE_OPTION_ARRAY); - } - - /** - * Deletes a file or directory. If the path is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

- *
    - *
  • A directory to delete does not have to be empty.
  • - *
  • You get exceptions when a file or directory cannot be deleted; {@link java.io.File#delete()} returns a - * boolean. - *
- * - * @param path file or directory to delete, must not be {@code null} - * @param deleteOptions How to handle deletion. - * @return The visitor used to delete the given directory. - * @throws NullPointerException if the directory is {@code null} - * @throws IOException if an I/O error is thrown by a visitor method or if an I/O error occurs. - * @since 2.8.0 - */ - public static PathCounters delete(final Path path, final DeleteOption... deleteOptions) throws IOException { - // File deletion through Files deletes links, not targets, so use LinkOption.NOFOLLOW_LINKS. - return Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS) ? deleteDirectory(path, deleteOptions) - : deleteFile(path, deleteOptions); - } - - /** - * Deletes a file or directory. If the path is a directory, delete it and all sub-directories. - *

- * The difference between File.delete() and this method are: - *

- *
    - *
  • A directory to delete does not have to be empty.
  • - *
  • You get exceptions when a file or directory cannot be deleted; {@link java.io.File#delete()} returns a - * boolean. - *
- * - * @param path file or directory to delete, must not be {@code null} - * @param linkOptions How to handle symbolic links. - * @param deleteOptions How to handle deletion. - * @return The visitor used to delete the given directory. - * @throws NullPointerException if the directory is {@code null} - * @throws IOException if an I/O error is thrown by a visitor method or if an I/O error occurs. - * @since 2.9.0 - */ - public static PathCounters delete(final Path path, final LinkOption[] linkOptions, - final DeleteOption... deleteOptions) throws IOException { - // File deletion through Files deletes links, not targets, so use LinkOption.NOFOLLOW_LINKS. - return Files.isDirectory(path, linkOptions) ? deleteDirectory(path, linkOptions, deleteOptions) - : deleteFile(path, linkOptions, deleteOptions); - } - - /** - * Deletes a directory including sub-directories. - * - * @param directory directory to delete. - * @return The visitor used to delete the given directory. - * @throws IOException if an I/O error is thrown by a visitor method. - */ - public static PathCounters deleteDirectory(final Path directory) throws IOException { - return deleteDirectory(directory, EMPTY_DELETE_OPTION_ARRAY); - } - - /** - * Deletes a directory including sub-directories. - * - * @param directory directory to delete. - * @param deleteOptions How to handle deletion. - * @return The visitor used to delete the given directory. - * @throws IOException if an I/O error is thrown by a visitor method. - * @since 2.8.0 - */ - public static PathCounters deleteDirectory(final Path directory, final DeleteOption... deleteOptions) - throws IOException { - return visitFileTree( - new DeletingPathVisitor(Counters.longPathCounters(), PathUtils.NOFOLLOW_LINK_OPTION_ARRAY, deleteOptions), - directory).getPathCounters(); - } - - /** - * Deletes a directory including sub-directories. - * - * @param directory directory to delete. - * @param linkOptions How to handle symbolic links. - * @param deleteOptions How to handle deletion. - * @return The visitor used to delete the given directory. - * @throws IOException if an I/O error is thrown by a visitor method. - * @since 2.9.0 - */ - public static PathCounters deleteDirectory(final Path directory, final LinkOption[] linkOptions, - final DeleteOption... deleteOptions) throws IOException { - return visitFileTree(new DeletingPathVisitor(Counters.longPathCounters(), linkOptions, deleteOptions), - directory).getPathCounters(); - } - - /** - * Deletes the given file. - * - * @param file The file to delete. - * @return A visitor with path counts set to 1 file, 0 directories, and the size of the deleted file. - * @throws IOException if an I/O error occurs. - * @throws NoSuchFileException if the file is a directory. - */ - public static PathCounters deleteFile(final Path file) throws IOException { - return deleteFile(file, EMPTY_DELETE_OPTION_ARRAY); - } - - /** - * Deletes the given file. - * - * @param file The file to delete. - * @param deleteOptions How to handle deletion. - * @return A visitor with path counts set to 1 file, 0 directories, and the size of the deleted file. - * @throws IOException if an I/O error occurs. - * @throws NoSuchFileException if the file is a directory. - * @since 2.8.0 - */ - public static PathCounters deleteFile(final Path file, final DeleteOption... deleteOptions) throws IOException { - // Files.deleteIfExists() never follows links, so use LinkOption.NOFOLLOW_LINKS in other calls to Files. - return deleteFile(file, NOFOLLOW_LINK_OPTION_ARRAY, deleteOptions); - } - - /** - * Deletes the given file. - * - * @param file The file to delete. - * @param linkOptions How to handle symbolic links. - * @param deleteOptions How to handle deletion. - * @return A visitor with path counts set to 1 file, 0 directories, and the size of the deleted file. - * @throws IOException if an I/O error occurs. - * @throws NoSuchFileException if the file is a directory. - * @since 2.9.0 - */ - public static PathCounters deleteFile(final Path file, final LinkOption[] linkOptions, - final DeleteOption... deleteOptions) throws NoSuchFileException, IOException { - if (Files.isDirectory(file, linkOptions)) { - throw new NoSuchFileException(file.toString()); - } - final PathCounters pathCounts = Counters.longPathCounters(); - final boolean exists = Files.exists(file, linkOptions); - final long size = exists && !Files.isSymbolicLink(file) ? Files.size(file) : 0; - if (overrideReadOnly(deleteOptions) && exists) { - setReadOnly(file, false, linkOptions); - } - if (Files.deleteIfExists(file)) { - pathCounts.getFileCounter().increment(); - pathCounts.getByteCounter().add(size); - } - return pathCounts; - } - - /** - * Compares the file sets of two Paths to determine if they are equal or not while considering file contents. The - * comparison includes all files in all sub-directories. - * - * @param path1 The first directory. - * @param path2 The second directory. - * @return Whether the two directories contain the same files while considering file contents. - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static boolean directoryAndFileContentEquals(final Path path1, final Path path2) throws IOException { - return directoryAndFileContentEquals(path1, path2, EMPTY_LINK_OPTION_ARRAY, EMPTY_OPEN_OPTION_ARRAY, - EMPTY_FILE_VISIT_OPTION_ARRAY); - } - - /** - * Compares the file sets of two Paths to determine if they are equal or not while considering file contents. The - * comparison includes all files in all sub-directories. - * - * @param path1 The first directory. - * @param path2 The second directory. - * @param linkOptions options to follow links. - * @param openOptions options to open files. - * @param fileVisitOption options to configure traversal. - * @return Whether the two directories contain the same files while considering file contents. - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static boolean directoryAndFileContentEquals(final Path path1, final Path path2, - final LinkOption[] linkOptions, final OpenOption[] openOptions, final FileVisitOption[] fileVisitOption) - throws IOException { - // First walk both file trees and gather normalized paths. - if (path1 == null && path2 == null) { - return true; - } - if (path1 == null || path2 == null) { - return false; - } - if (Files.notExists(path1) && Files.notExists(path2)) { - return true; - } - final RelativeSortedPaths relativeSortedPaths = new RelativeSortedPaths(path1, path2, Integer.MAX_VALUE, - linkOptions, fileVisitOption); - // If the normalized path names and counts are not the same, no need to compare contents. - if (!relativeSortedPaths.equals) { - return false; - } - // Both visitors contain the same normalized paths, we can compare file contents. - final List fileList1 = relativeSortedPaths.relativeFileList1; - final List fileList2 = relativeSortedPaths.relativeFileList2; - for (final Path path : fileList1) { - final int binarySearch = Collections.binarySearch(fileList2, path); - if (binarySearch <= -1) { - throw new IllegalStateException("Unexpected mismatch."); - } - if (!fileContentEquals(path1.resolve(path), path2.resolve(path), linkOptions, openOptions)) { - return false; - } - } - return true; - } - - /** - * Compares the file sets of two Paths to determine if they are equal or not without considering file contents. The - * comparison includes all files in all sub-directories. - * - * @param path1 The first directory. - * @param path2 The second directory. - * @return Whether the two directories contain the same files without considering file contents. - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static boolean directoryContentEquals(final Path path1, final Path path2) throws IOException { - return directoryContentEquals(path1, path2, Integer.MAX_VALUE, EMPTY_LINK_OPTION_ARRAY, - EMPTY_FILE_VISIT_OPTION_ARRAY); - } - - /** - * Compares the file sets of two Paths to determine if they are equal or not without considering file contents. The - * comparison includes all files in all sub-directories. - * - * @param path1 The first directory. - * @param path2 The second directory. - * @param maxDepth See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param linkOptions options to follow links. - * @param fileVisitOptions options to configure the traversal - * @return Whether the two directories contain the same files without considering file contents. - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static boolean directoryContentEquals(final Path path1, final Path path2, final int maxDepth, - final LinkOption[] linkOptions, final FileVisitOption[] fileVisitOptions) throws IOException { - return new RelativeSortedPaths(path1, path2, maxDepth, linkOptions, fileVisitOptions).equals; - } - - /** - * Compares the file contents of two Paths to determine if they are equal or not. - *

- * File content is accessed through {@link Files#newInputStream(Path,OpenOption...)}. - *

- * - * @param path1 the first stream. - * @param path2 the second stream. - * @return true if the content of the streams are equal or they both don't exist, false otherwise. - * @throws NullPointerException if either input is null. - * @throws IOException if an I/O error occurs. - * @see org.apache.commons.io.FileUtils#contentEquals(java.io.File, java.io.File) - */ - public static boolean fileContentEquals(final Path path1, final Path path2) throws IOException { - return fileContentEquals(path1, path2, EMPTY_LINK_OPTION_ARRAY, EMPTY_OPEN_OPTION_ARRAY); - } - - /** - * Compares the file contents of two Paths to determine if they are equal or not. - *

- * File content is accessed through {@link Files#newInputStream(Path,OpenOption...)}. - *

- * - * @param path1 the first stream. - * @param path2 the second stream. - * @param linkOptions options specifying how files are followed. - * @param openOptions options specifying how files are opened. - * @return true if the content of the streams are equal or they both don't exist, false otherwise. - * @throws NullPointerException if either input is null. - * @throws IOException if an I/O error occurs. - * @see org.apache.commons.io.FileUtils#contentEquals(java.io.File, java.io.File) - */ - public static boolean fileContentEquals(final Path path1, final Path path2, final LinkOption[] linkOptions, - final OpenOption[] openOptions) throws IOException { - if (path1 == null && path2 == null) { - return true; - } - if (path1 == null || path2 == null) { - return false; - } - final Path nPath1 = path1.normalize(); - final Path nPath2 = path2.normalize(); - final boolean path1Exists = Files.exists(nPath1, linkOptions); - if (path1Exists != Files.exists(nPath2, linkOptions)) { - return false; - } - if (!path1Exists) { - // Two not existing files are equal? - // Same as FileUtils - return true; - } - if (Files.isDirectory(nPath1, linkOptions)) { - // don't compare directory contents. - throw new IOException("Can't compare directories, only files: " + nPath1); - } - if (Files.isDirectory(nPath2, linkOptions)) { - // don't compare directory contents. - throw new IOException("Can't compare directories, only files: " + nPath2); - } - if (Files.size(nPath1) != Files.size(nPath2)) { - // lengths differ, cannot be equal - return false; - } - if (path1.equals(path2)) { - // same file - return true; - } - try (final InputStream inputStream1 = Files.newInputStream(nPath1, openOptions); - final InputStream inputStream2 = Files.newInputStream(nPath2, openOptions)) { - return IOUtils.contentEquals(inputStream1, inputStream2); - } - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} objects. The resulting array is a subset of the - * original file list that matches the provided filter. - *

- * - *

- * The {@link Set} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * Set<File> allFiles = ...
-     * Set<File> javaFiles = FileFilterUtils.filterSet(allFiles,
-     *     FileFilterUtils.suffixFileFilter(".java"));
-     * 
- * - * @param filter the filter to apply to the set of files. - * @param paths the array of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the file filter. - * @throws IllegalArgumentException if the filter is {@code null} or {@code files} contains a {@code null} - * value. - * - * @since 2.9.0 - */ - public static Path[] filter(final PathFilter filter, final Path... paths) { - Objects.requireNonNull(filter, "filter"); - if (paths == null) { - return EMPTY_PATH_ARRAY; - } - return filterPaths(filter, Stream.of(paths), Collectors.toList()).toArray(EMPTY_PATH_ARRAY); - } - - private static R filterPaths(final PathFilter filter, final Stream stream, - final Collector collector) { - Objects.requireNonNull(filter, "filter"); - Objects.requireNonNull(collector, "collector"); - if (stream == null) { - return Stream.empty().collect(collector); - } - return stream.filter(p -> { - try { - return p != null && filter.accept(p, readBasicFileAttributes(p)) == FileVisitResult.CONTINUE; - } catch (final IOException e) { - return false; - } - }).collect(collector); - } - - /** - * Reads the access control list from a file attribute view. - * - * @param sourcePath the path to the file. - * @return a file attribute view of the specified type, or null if the attribute view type is not available. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public static List getAclEntryList(final Path sourcePath) throws IOException { - final AclFileAttributeView fileAttributeView = Files.getFileAttributeView(sourcePath, - AclFileAttributeView.class); - return fileAttributeView == null ? null : fileAttributeView.getAcl(); - } - - /** - * Tests whether the specified {@code Path} is a directory or not. Implemented as a - * null-safe delegate to {@code Files.isDirectory(Path path, LinkOption... options)}. - * - * @param path the path to the file. - * @param options options indicating how symbolic links are handled - * @return {@code true} if the file is a directory; {@code false} if - * the path is null, the file does not exist, is not a directory, or it cannot - * be determined if the file is a directory or not. - * @throws SecurityException In the case of the default provider, and a security manager is installed, the - * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read - * access to the directory. - * @since 2.9.0 - */ - public static boolean isDirectory(final Path path, final LinkOption... options) { - return path != null && Files.isDirectory(path, options); - } - - /** - * Tests whether the given file or directory is empty. - * - * @param path the file or directory to query. - * @return whether the file or directory is empty. - * @throws IOException if an I/O error occurs. - */ - public static boolean isEmpty(final Path path) throws IOException { - return Files.isDirectory(path) ? isEmptyDirectory(path) : isEmptyFile(path); - } - - /** - * Tests whether the directory is empty. - * - * @param directory the directory to query. - * @return whether the directory is empty. - * @throws NotDirectoryException if the file could not otherwise be opened because it is not a directory - * (optional specific exception). - * @throws IOException if an I/O error occurs. - * @throws SecurityException In the case of the default provider, and a security manager is installed, the - * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read - * access to the directory. - */ - public static boolean isEmptyDirectory(final Path directory) throws IOException { - try (DirectoryStream directoryStream = Files.newDirectoryStream(directory)) { - return !directoryStream.iterator().hasNext(); - } - } - - /** - * Tests whether the given file is empty. - * - * @param file the file to query. - * @return whether the file is empty. - * @throws IOException if an I/O error occurs. - * @throws SecurityException In the case of the default provider, and a security manager is installed, its - * {@link SecurityManager#checkRead(String) checkRead} method denies read access to the - * file. - */ - public static boolean isEmptyFile(final Path file) throws IOException { - return Files.size(file) <= 0; - } - - /** - * Tests if the specified {@code Path} is newer than the specified time reference. - * - * @param file the {@code Path} of which the modification date must be compared - * @param timeMillis the time reference measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970) - * @param options options indicating how symbolic links are handled * @return true if the {@code Path} exists and - * has been modified after the given time reference. - * @return true if the {@code Path} exists and has been modified after the given time reference. - * @throws IOException if an I/O error occurs. - * @throws NullPointerException if the file is {@code null} - * @since 2.9.0 - */ - public static boolean isNewer(final Path file, final long timeMillis, final LinkOption... options) - throws IOException { - Objects.requireNonNull(file, "file"); - if (Files.notExists(file)) { - return false; - } - return Files.getLastModifiedTime(file, options).toMillis() > timeMillis; - } - - /** - * Tests whether the specified {@code Path} is a regular file or not. Implemented as a - * null-safe delegate to {@code Files.isRegularFile(Path path, LinkOption... options)}. - * - * @param path the path to the file. - * @param options options indicating how symbolic links are handled - * @return {@code true} if the file is a regular file; {@code false} if - * the path is null, the file does not exist, is not a directory, or it cannot - * be determined if the file is a regular file or not. - * @throws SecurityException In the case of the default provider, and a security manager is installed, the - * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read - * access to the directory. - * @since 2.9.0 - */ - public static boolean isRegularFile(final Path path, final LinkOption... options) { - return path != null && Files.isRegularFile(path, options); - } - - /** - * Creates a new DirectoryStream for Paths rooted at the given directory. - * - * @param dir the path to the directory to stream. - * @param pathFilter the directory stream filter. - * @return a new instance. - * @throws IOException if an I/O error occurs. - */ - public static DirectoryStream newDirectoryStream(final Path dir, final PathFilter pathFilter) - throws IOException { - return Files.newDirectoryStream(dir, new DirectoryStreamFilter(pathFilter)); - } - - /** - * Returns true if the given options contain {@link StandardDeleteOption#OVERRIDE_READ_ONLY}. - * - * @param deleteOptions the array to test - * @return true if the given options contain {@link StandardDeleteOption#OVERRIDE_READ_ONLY}. - */ - private static boolean overrideReadOnly(final DeleteOption... deleteOptions) { - if (deleteOptions == null) { - return false; - } - return Stream.of(deleteOptions).anyMatch(e -> e == StandardDeleteOption.OVERRIDE_READ_ONLY); - } - - /** - * Shorthand for {@code Files.readAttributes(path, BasicFileAttributes.class)} - * - * @param path the path to read. - * @return the path attributes. - * @throws IOException if an I/O error occurs. - * @since 2.9.0 - */ - public static BasicFileAttributes readBasicFileAttributes(final Path path) throws IOException { - return Files.readAttributes(path, BasicFileAttributes.class); - } - - /** - * Shorthand for {@code Files.readAttributes(path, BasicFileAttributes.class)} while wrapping {@link IOException} - * as {@link UncheckedIOException}. - * - * @param path the path to read. - * @return the path attributes. - * @throws UncheckedIOException if an I/O error occurs - * @since 2.9.0 - */ - public static BasicFileAttributes readBasicFileAttributesUnchecked(final Path path) { - try { - return readBasicFileAttributes(path); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * Relativizes all files in the given {@code collection} against a {@code parent}. - * - * @param collection The collection of paths to relativize. - * @param parent relativizes against this parent path. - * @param sort Whether to sort the result. - * @param comparator How to sort. - * @return A collection of relativized paths, optionally sorted. - */ - static List relativize(final Collection collection, final Path parent, final boolean sort, - final Comparator comparator) { - Stream stream = collection.stream().map(parent::relativize); - if (sort) { - stream = comparator == null ? stream.sorted() : stream.sorted(comparator); - } - return stream.collect(Collectors.toList()); - } - - /** - * Sets the given Path to the {@code readOnly} value. - *

- * This behavior is OS dependent. - *

- * - * @param path The path to set. - * @param readOnly true for read-only, false for not read-only. - * @param linkOptions options indicating how symbolic links are handled. - * @return The given path. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public static Path setReadOnly(final Path path, final boolean readOnly, final LinkOption... linkOptions) - throws IOException { - final List causeList = new ArrayList<>(2); - final DosFileAttributeView fileAttributeView = Files.getFileAttributeView(path, DosFileAttributeView.class, - linkOptions); - if (fileAttributeView != null) { - try { - fileAttributeView.setReadOnly(readOnly); - return path; - } catch (final IOException e) { - // ignore for now, retry with PosixFileAttributeView - causeList.add(e); - } - } - final PosixFileAttributeView posixFileAttributeView = Files.getFileAttributeView(path, - PosixFileAttributeView.class, linkOptions); - if (posixFileAttributeView != null) { - // Works on Windows but not on Ubuntu: - // Files.setAttribute(path, "unix:readonly", readOnly, options); - // java.lang.IllegalArgumentException: 'unix:readonly' not recognized - final PosixFileAttributes readAttributes = posixFileAttributeView.readAttributes(); - final Set permissions = readAttributes.permissions(); - permissions.remove(PosixFilePermission.OWNER_WRITE); - permissions.remove(PosixFilePermission.GROUP_WRITE); - permissions.remove(PosixFilePermission.OTHERS_WRITE); - try { - return Files.setPosixFilePermissions(path, permissions); - } catch (final IOException e) { - causeList.add(e); - } - } - if (!causeList.isEmpty()) { - throw new IOExceptionList(path.toString(), causeList); - } - throw new IOException( - String.format("No DosFileAttributeView or PosixFileAttributeView for '%s' (linkOptions=%s)", path, - Arrays.toString(linkOptions))); - } - - /** - * Converts an array of {@link FileVisitOption} to a {@link Set}. - * - * @param fileVisitOptions input array. - * @return a new Set. - */ - static Set toFileVisitOptionSet(final FileVisitOption... fileVisitOptions) { - return fileVisitOptions == null ? EnumSet.noneOf(FileVisitOption.class) - : Stream.of(fileVisitOptions).collect(Collectors.toSet()); - } - - /** - * Performs {@link Files#walkFileTree(Path,FileVisitor)} and returns the given visitor. - * - * Note that {@link Files#walkFileTree(Path,FileVisitor)} returns the given path. - * - * @param visitor See {@link Files#walkFileTree(Path,FileVisitor)}. - * @param directory See {@link Files#walkFileTree(Path,FileVisitor)}. - * @param See {@link Files#walkFileTree(Path,FileVisitor)}. - * @return the given visitor. - * - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static > T visitFileTree(final T visitor, final Path directory) - throws IOException { - Files.walkFileTree(directory, visitor); - return visitor; - } - - /** - * Performs {@link Files#walkFileTree(Path,FileVisitor)} and returns the given visitor. - * - * Note that {@link Files#walkFileTree(Path,FileVisitor)} returns the given path. - * - * @param start See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param options See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param maxDepth See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param visitor See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @param See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}. - * @return the given visitor. - * - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static > T visitFileTree(final T visitor, final Path start, - final Set options, final int maxDepth) throws IOException { - Files.walkFileTree(start, options, maxDepth, visitor); - return visitor; - } - - /** - * Performs {@link Files#walkFileTree(Path,FileVisitor)} and returns the given visitor. - * - * Note that {@link Files#walkFileTree(Path,FileVisitor)} returns the given path. - * - * @param visitor See {@link Files#walkFileTree(Path,FileVisitor)}. - * @param first See {@link Paths#get(String,String[])}. - * @param more See {@link Paths#get(String,String[])}. - * @param See {@link Files#walkFileTree(Path,FileVisitor)}. - * @return the given visitor. - * - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static > T visitFileTree(final T visitor, final String first, - final String... more) throws IOException { - return visitFileTree(visitor, Paths.get(first, more)); - } - - /** - * Performs {@link Files#walkFileTree(Path,FileVisitor)} and returns the given visitor. - * - * Note that {@link Files#walkFileTree(Path,FileVisitor)} returns the given path. - * - * @param visitor See {@link Files#walkFileTree(Path,FileVisitor)}. - * @param uri See {@link Paths#get(URI)}. - * @param See {@link Files#walkFileTree(Path,FileVisitor)}. - * @return the given visitor. - * - * @throws IOException if an I/O error is thrown by a visitor method - */ - public static > T visitFileTree(final T visitor, final URI uri) - throws IOException { - return visitFileTree(visitor, Paths.get(uri)); - } - - /** - * Returns a stream of filtered paths. - * - * @param start the start path - * @param pathFilter the path filter - * @param maxDepth the maximum depth of directories to walk. - * @param readAttributes whether to call the filters with file attributes (false passes null). - * @param options the options to configure the walk. - * @return a filtered stream of paths. - * @throws IOException if an I/O error is thrown when accessing the starting file. - * @since 2.9.0 - */ - public static Stream walk(final Path start, final PathFilter pathFilter, final int maxDepth, - final boolean readAttributes, final FileVisitOption... options) throws IOException { - return Files.walk(start, maxDepth, options).filter(path -> pathFilter.accept(path, - readAttributes ? readBasicFileAttributesUnchecked(path) : null) == FileVisitResult.CONTINUE); - } - - /** - * Does allow to instantiate. - */ - private PathUtils() { - // do not instantiate. - } - -} diff --git a/src/org/apache/commons/io/file/PathVisitor.java b/src/org/apache/commons/io/file/PathVisitor.java deleted file mode 100644 index dcd72580..00000000 --- a/src/org/apache/commons/io/file/PathVisitor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.nio.file.FileVisitor; -import java.nio.file.Path; - -/** - * A {@link FileVisitor} typed to a {@link Path}. - * - * @since 2.9.0 - */ -public interface PathVisitor extends FileVisitor { - // empty -} diff --git a/src/org/apache/commons/io/file/SimplePathVisitor.java b/src/org/apache/commons/io/file/SimplePathVisitor.java deleted file mode 100644 index b4bb2d9e..00000000 --- a/src/org/apache/commons/io/file/SimplePathVisitor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; - -/** - * A {@link SimpleFileVisitor} typed to a {@link Path}. - * - * @since 2.7 - */ -public abstract class SimplePathVisitor extends SimpleFileVisitor implements PathVisitor { - - /** - * Constructs a new instance. - */ - protected SimplePathVisitor() { - } - -} diff --git a/src/org/apache/commons/io/file/StandardDeleteOption.java b/src/org/apache/commons/io/file/StandardDeleteOption.java deleted file mode 100644 index 7dd3f730..00000000 --- a/src/org/apache/commons/io/file/StandardDeleteOption.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file; - -import org.apache.commons.io.IOUtils; - -/** - * Defines the standard delete options. - * - * @since 2.8.0 - */ -public enum StandardDeleteOption implements DeleteOption { - - /** - * Overrides the read-only attribute to allow deletion. - */ - OVERRIDE_READ_ONLY; - - /** - * Returns true if the given options contain {@link StandardDeleteOption#OVERRIDE_READ_ONLY}. - * - * For now, assume the array is not sorted. - * - * @param options the array to test - * @return true if the given options contain {@link StandardDeleteOption#OVERRIDE_READ_ONLY}. - */ - public static boolean overrideReadOnly(final DeleteOption[] options) { - if (IOUtils.length(options) == 0) { - return false; - } - for (final DeleteOption deleteOption : options) { - if (deleteOption == StandardDeleteOption.OVERRIDE_READ_ONLY) { - return true; - } - } - return false; - } - -} diff --git a/src/org/apache/commons/io/file/spi/FileSystemProviders.java b/src/org/apache/commons/io/file/spi/FileSystemProviders.java deleted file mode 100644 index c87ac057..00000000 --- a/src/org/apache/commons/io/file/spi/FileSystemProviders.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.file.spi; - -import java.net.URI; -import java.net.URL; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.spi.FileSystemProvider; -import java.util.List; -import java.util.Objects; - -/** - * Helps working with {@link FileSystemProvider}. - * - * @since 2.9.0 - */ -public class FileSystemProviders { - - private static final FileSystemProviders INSTALLED = new FileSystemProviders(FileSystemProvider.installedProviders()); - - /** - * Gets the {@link FileSystemProvider} for the given Path. - * - * @param path The Path to query - * @return the {@link FileSystemProvider} for the given Path. - */ - @SuppressWarnings("resource") // FileSystem is not allocated here. - public static FileSystemProvider getFileSystemProvider(final Path path) { - return Objects.requireNonNull(path, "path").getFileSystem().provider(); - } - - /** - * Returns the instance for the installed providers. - * - * @return the instance for the installed providers. - * @see FileSystemProvider#installedProviders() - */ - public static FileSystemProviders installed() { - return INSTALLED; - } - - private final List providers; - - /* - * Might make public later. - */ - private FileSystemProviders(final List providers) { - this.providers = providers; - } - - /** - * Gets the {@link FileSystemProvider} for the given scheme. - * - * @param scheme The scheme to query. - * @return the {@link FileSystemProvider} for the given URI or null. - */ - @SuppressWarnings("resource") // FileSystems.getDefault() returns a constant. - public FileSystemProvider getFileSystemProvider(final String scheme) { - Objects.requireNonNull(scheme, "scheme"); - // Check default provider first to avoid loading of installed providers. - if (scheme.equalsIgnoreCase("file")) { - return FileSystems.getDefault().provider(); - } - // Find provider. - if (providers != null) { - for (final FileSystemProvider provider : providers) { - if (provider.getScheme().equalsIgnoreCase(scheme)) { - return provider; - } - } - } - return null; - } - - /** - * Gets the {@link FileSystemProvider} for the given URI. - * - * @param uri The URI to query - * @return the {@link FileSystemProvider} for the given URI or null. - */ - public FileSystemProvider getFileSystemProvider(final URI uri) { - return getFileSystemProvider(Objects.requireNonNull(uri, "uri").getScheme()); - } - - /** - * Gets the {@link FileSystemProvider} for the given URL. - * - * @param url The URL to query - * @return the {@link FileSystemProvider} for the given URI or null. - */ - public FileSystemProvider getFileSystemProvider(final URL url) { - return getFileSystemProvider(Objects.requireNonNull(url, "url").getProtocol()); - } - -} diff --git a/src/org/apache/commons/io/filefilter/AbstractFileFilter.java b/src/org/apache/commons/io/filefilter/AbstractFileFilter.java deleted file mode 100644 index 4c1b5386..00000000 --- a/src/org/apache/commons/io/filefilter/AbstractFileFilter.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Objects; - -import org.apache.commons.io.file.PathFilter; -import org.apache.commons.io.file.PathVisitor; - -/** - * Abstracts the implementation of the {@link FileFilter} (IO), {@link FilenameFilter} (IO), {@link PathFilter} (NIO) - * interfaces via our own {@link IOFileFilter} interface. - *

- * Note that a subclass MUST override one of the {@code accept} methods, otherwise that subclass will infinitely loop. - *

- * - * @since 1.0 - */ -public abstract class AbstractFileFilter implements IOFileFilter, PathVisitor { - - static FileVisitResult toFileVisitResult(final boolean accept, final Path path) { - return accept ? FileVisitResult.CONTINUE : FileVisitResult.TERMINATE; - } - - /** - * Checks to see if the File should be accepted by this filter. - * - * @param file the File to check - * @return true if this file matches the test - */ - @Override - public boolean accept(final File file) { - Objects.requireNonNull(file, "file"); - return accept(file.getParentFile(), file.getName()); - } - - /** - * Checks to see if the File should be accepted by this filter. - * - * @param dir the directory File to check - * @param name the file name within the directory to check - * @return true if this file matches the test - */ - @Override - public boolean accept(final File dir, final String name) { - Objects.requireNonNull(name, "name"); - return accept(new File(dir, name)); - } - - /** - * Handles exceptions caught while accepting. - * - * @param t the caught Throwable. - * @return the given Throwable. - * @since 2.9.0 - */ - protected FileVisitResult handle(final Throwable t) { - return FileVisitResult.TERMINATE; - } - - @Override - public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attributes) throws IOException { - return accept(dir, attributes); - } - - /** - * Provides a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - return getClass().getSimpleName(); - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attributes) throws IOException { - return accept(file, attributes); - } - - @Override - public FileVisitResult visitFileFailed(final Path file, final IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - -} diff --git a/src/org/apache/commons/io/filefilter/AgeFileFilter.java b/src/org/apache/commons/io/filefilter/AgeFileFilter.java deleted file mode 100644 index 8742f705..00000000 --- a/src/org/apache/commons/io/filefilter/AgeFileFilter.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Date; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.file.PathUtils; - -/** - * Filters files based on a cutoff time, can filter either newer files or files equal to or older. - *

- * For example, to print all files and directories in the current directory older than one day: - *

- *

Using Classic IO

- *
- * Path dir = Paths.get("");
- * // We are interested in files older than one day
- * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
- * String[] files = dir.list(new AgeFileFilter(cutoff));
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * Path dir = Paths.get("");
- * // We are interested in files older than one day
- * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
- * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @see FileFilterUtils#ageFileFilter(Date) - * @see FileFilterUtils#ageFileFilter(File) - * @see FileFilterUtils#ageFileFilter(long) - * @see FileFilterUtils#ageFileFilter(Date, boolean) - * @see FileFilterUtils#ageFileFilter(File, boolean) - * @see FileFilterUtils#ageFileFilter(long, boolean) - * @since 1.2 - */ -public class AgeFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = -2132740084016138541L; - - /** Whether the files accepted will be older or newer. */ - private final boolean acceptOlder; - - /** The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970). */ - private final long cutoffMillis; - - /** - * Constructs a new age file filter for files older than (at or before) a certain cutoff date. - * - * @param cutoffDate the threshold age of the files - */ - public AgeFileFilter(final Date cutoffDate) { - this(cutoffDate, true); - } - - /** - * Constructs a new age file filter for files on any one side of a certain cutoff date. - * - * @param cutoffDate the threshold age of the files - * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the - * cutoff). - */ - public AgeFileFilter(final Date cutoffDate, final boolean acceptOlder) { - this(cutoffDate.getTime(), acceptOlder); - } - - /** - * Constructs a new age file filter for files older than (at or before) a certain File (whose last modification time - * will be used as reference). - * - * @param cutoffReference the file whose last modification time is used as the threshold age of the files - */ - public AgeFileFilter(final File cutoffReference) { - this(cutoffReference, true); - } - - /** - * Constructs a new age file filter for files on any one side of a certain File (whose last modification time will - * be used as reference). - * - * @param cutoffReference the file whose last modification time is used as the threshold age of the files - * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the - * cutoff). - */ - public AgeFileFilter(final File cutoffReference, final boolean acceptOlder) { - this(FileUtils.lastModifiedUnchecked(cutoffReference), acceptOlder); - } - - /** - * Constructs a new age file filter for files equal to or older than a certain cutoff - * - * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, - * 1970). - */ - public AgeFileFilter(final long cutoffMillis) { - this(cutoffMillis, true); - } - - /** - * Constructs a new age file filter for files on any one side of a certain cutoff. - * - * @param cutoffMillis The cutoff time threshold measured in milliseconds since the epoch (00:00:00 GMT, January 1, - * 1970). - * @param acceptOlder if true, older files (at or before the cutoff) are accepted, else newer ones (after the - * cutoff). - */ - public AgeFileFilter(final long cutoffMillis, final boolean acceptOlder) { - this.acceptOlder = acceptOlder; - this.cutoffMillis = cutoffMillis; - } - - /** - * Checks to see if the last modification of the file matches cutoff favorably. - *

- * If last modification time equals cutoff and newer files are required, file IS NOT selected. If last - * modification time equals cutoff and older files are required, file IS selected. - *

- * - * @param file the File to check - * @return true if the file name matches - */ - @Override - public boolean accept(final File file) { - final boolean newer = FileUtils.isFileNewer(file, cutoffMillis); - return acceptOlder != newer; - } - - /** - * Checks to see if the last modification of the file matches cutoff favorably. - *

- * If last modification time equals cutoff and newer files are required, file IS NOT selected. If last - * modification time equals cutoff and older files are required, file IS selected. - *

- * @param file the File to check - * - * @return true if the file name matches - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - final boolean newer; - try { - newer = PathUtils.isNewer(file, cutoffMillis); - } catch (final IOException e) { - return handle(e); - } - return toFileVisitResult(acceptOlder != newer, file); - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final String condition = acceptOlder ? "<=" : ">"; - return super.toString() + "(" + condition + cutoffMillis + ")"; - } -} diff --git a/src/org/apache/commons/io/filefilter/AndFileFilter.java b/src/org/apache/commons/io/filefilter/AndFileFilter.java deleted file mode 100644 index fa3b282e..00000000 --- a/src/org/apache/commons/io/filefilter/AndFileFilter.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * A {@link java.io.FileFilter} providing conditional AND logic across a list of - * file filters. This filter returns {@code true} if all filters in the - * list return {@code true}. Otherwise, it returns {@code false}. - * Checking of the file filter list stops when the first filter returns - * {@code false}. - * - * @since 1.0 - * @see FileFilterUtils#and(IOFileFilter...) - */ -public class AndFileFilter - extends AbstractFileFilter - implements ConditionalFileFilter, Serializable { - - private static final long serialVersionUID = 7215974688563965257L; - - /** The list of file filters. */ - private final List fileFilters; - - /** - * Constructs a new empty instance. - * - * @since 1.1 - */ - public AndFileFilter() { - this(0); - } - - /** - * Constructs a new instance with the given initial list. - * - * @param initialList the initial list. - */ - private AndFileFilter(final ArrayList initialList) { - this.fileFilters = Objects.requireNonNull(initialList, "initialList"); - } - - /** - * Constructs a new instance with the given initial capacity. - * - * @param initialCapacity the initial capacity. - */ - private AndFileFilter(final int initialCapacity) { - this(new ArrayList<>(initialCapacity)); - } - - /** - * Constructs a new file filter that ANDs the result of other filters. - * - * @param filter1 the first filter, must second be null - * @param filter2 the first filter, must not be null - * @throws IllegalArgumentException if either filter is null - */ - public AndFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) { - this(2); - addFileFilter(filter1); - addFileFilter(filter2); - } - - /** - * Constructs a new instance for the give filters. - * @param fileFilters filters to OR. - * - * @since 2.9.0 - */ - public AndFileFilter(final IOFileFilter... fileFilters) { - this(Objects.requireNonNull(fileFilters, "fileFilters").length); - addFileFilter(fileFilters); - } - - /** - * Constructs a new instance of {@code AndFileFilter} - * with the specified list of filters. - * - * @param fileFilters a List of IOFileFilter instances, copied. - * @since 1.1 - */ - public AndFileFilter(final List fileFilters) { - this(new ArrayList<>(Objects.requireNonNull(fileFilters, "fileFilters"))); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean accept(final File file) { - if (isEmpty()) { - return false; - } - for (final IOFileFilter fileFilter : fileFilters) { - if (!fileFilter.accept(file)) { - return false; - } - } - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean accept(final File file, final String name) { - if (isEmpty()) { - return false; - } - for (final IOFileFilter fileFilter : fileFilters) { - if (!fileFilter.accept(file, name)) { - return false; - } - } - return true; - } - - /** - * {@inheritDoc} - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - if (isEmpty()) { - return FileVisitResult.TERMINATE; - } - for (final IOFileFilter fileFilter : fileFilters) { - if (fileFilter.accept(file, attributes) != FileVisitResult.CONTINUE) { - return FileVisitResult.TERMINATE; - } - } - return FileVisitResult.CONTINUE; - } - - /** - * {@inheritDoc} - */ - @Override - public void addFileFilter(final IOFileFilter fileFilter) { - this.fileFilters.add(Objects.requireNonNull(fileFilter, "fileFilter")); - } - - /** - * Adds the given file filters. - * - * @param fileFilters the filters to add. - * @since 2.9.0 - */ - public void addFileFilter(final IOFileFilter... fileFilters) { - for (final IOFileFilter fileFilter : Objects.requireNonNull(fileFilters, "fileFilters")) { - addFileFilter(fileFilter); - } - } - - /** - * {@inheritDoc} - */ - @Override - public List getFileFilters() { - return Collections.unmodifiableList(this.fileFilters); - } - - private boolean isEmpty() { - return this.fileFilters.isEmpty(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean removeFileFilter(final IOFileFilter ioFileFilter) { - return this.fileFilters.remove(ioFileFilter); - } - - /** - * {@inheritDoc} - */ - @Override - public void setFileFilters(final List fileFilters) { - this.fileFilters.clear(); - this.fileFilters.addAll(fileFilters); - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - for (int i = 0; i < fileFilters.size(); i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(fileFilters.get(i)); - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/CanExecuteFileFilter.java b/src/org/apache/commons/io/filefilter/CanExecuteFileFilter.java deleted file mode 100644 index b6686be5..00000000 --- a/src/org/apache/commons/io/filefilter/CanExecuteFileFilter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that can be executed. - *

- * Example, showing how to print out a list of the - * current directory's executable files: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(CanExecuteFileFilter.CAN_EXECUTE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's non-executable files: - *

- * - *
- * File dir = new File(".");
- * String[] files = dir.list(CanExecuteFileFilter.CANNOT_EXECUTE);
- * for (int i = 0; i < files.length; i++) {
- *     System.out.println(files[i]);
- * }
- * 
- * - * @since 2.7 - */ -public class CanExecuteFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of executable filter */ - public static final IOFileFilter CAN_EXECUTE = new CanExecuteFileFilter(); - - /** Singleton instance of not executable filter */ - public static final IOFileFilter CANNOT_EXECUTE = CAN_EXECUTE.negate(); - - private static final long serialVersionUID = 3179904805251622989L; - - /** - * Restrictive constructor. - */ - protected CanExecuteFileFilter() { - // empty. - } - - /** - * Checks to see if the file can be executed. - * - * @param file the File to check. - * @return {@code true} if the file can be executed, otherwise {@code false}. - */ - @Override - public boolean accept(final File file) { - return file.canExecute(); - } - - /** - * Checks to see if the file can be executed. - * @param file the File to check. - * - * @return {@code true} if the file can be executed, otherwise {@code false}. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isExecutable(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/CanReadFileFilter.java b/src/org/apache/commons/io/filefilter/CanReadFileFilter.java deleted file mode 100644 index dd787283..00000000 --- a/src/org/apache/commons/io/filefilter/CanReadFileFilter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that can be read. - *

- * Example, showing how to print out a list of the current directory's readable files: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(CanReadFileFilter.CAN_READ);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the current directory's un-readable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list(CanReadFileFilter.CANNOT_READ);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the current directory's read-only files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list(CanReadFileFilter.READ_ONLY);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - * @since 1.3 - */ -public class CanReadFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of readable filter */ - public static final IOFileFilter CAN_READ = new CanReadFileFilter(); - - /** Singleton instance of not readable filter */ - public static final IOFileFilter CANNOT_READ = CAN_READ.negate(); - - /** Singleton instance of read-only filter */ - public static final IOFileFilter READ_ONLY = CAN_READ.and(CanWriteFileFilter.CANNOT_WRITE); - - private static final long serialVersionUID = 3179904805251622989L; - - /** - * Restrictive constructor. - */ - protected CanReadFileFilter() { - } - - /** - * Checks to see if the file can be read. - * - * @param file the File to check. - * @return {@code true} if the file can be read, otherwise {@code false}. - */ - @Override - public boolean accept(final File file) { - return file.canRead(); - } - - /** - * Checks to see if the file can be read. - * @param file the File to check. - * - * @return {@code true} if the file can be read, otherwise {@code false}. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isReadable(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java b/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java deleted file mode 100644 index e2269a24..00000000 --- a/src/org/apache/commons/io/filefilter/CanWriteFileFilter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that can be written to. - *

- * Example, showing how to print out a list of the current directory's writable files: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(CanWriteFileFilter.CAN_WRITE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the current directory's un-writable files: - * - *

- * File dir = new File(".");
- * String[] files = dir.list(CanWriteFileFilter.CANNOT_WRITE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * N.B. For read-only files, use {@code CanReadFileFilter.READ_ONLY}. - * - * @since 1.3 - */ -public class CanWriteFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of writable filter */ - public static final IOFileFilter CAN_WRITE = new CanWriteFileFilter(); - - /** Singleton instance of not writable filter */ - public static final IOFileFilter CANNOT_WRITE = CAN_WRITE.negate(); - - private static final long serialVersionUID = 5132005214688990379L; - - /** - * Restrictive constructor. - */ - protected CanWriteFileFilter() { - } - - /** - * Checks to see if the file can be written to. - * - * @param file the File to check - * @return {@code true} if the file can be written to, otherwise {@code false}. - */ - @Override - public boolean accept(final File file) { - return file.canWrite(); - } - - /** - * Checks to see if the file can be written to. - * @param file the File to check - * - * @return {@code true} if the file can be written to, otherwise {@code false}. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isWritable(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java b/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java deleted file mode 100644 index c51d47eb..00000000 --- a/src/org/apache/commons/io/filefilter/ConditionalFileFilter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.util.List; - -/** - * Defines operations for conditional file filters. - * - * @since 1.1 - */ -public interface ConditionalFileFilter { - - /** - * Adds the specified file filter to the list of file filters at the end of - * the list. - * - * @param ioFileFilter the filter to be added - * @since 1.1 - */ - void addFileFilter(IOFileFilter ioFileFilter); - - /** - * Gets this conditional file filter's list of file filters. - * - * @return the file filter list - * @since 1.1 - */ - List getFileFilters(); - - /** - * Removes the specified file filter. - * - * @param ioFileFilter filter to be removed - * @return {@code true} if the filter was found in the list, - * {@code false} otherwise - * @since 1.1 - */ - boolean removeFileFilter(IOFileFilter ioFileFilter); - - /** - * Sets the list of file filters, replacing any previously configured - * file filters on this filter. - * - * @param fileFilters the list of filters - * @since 1.1 - */ - void setFileFilters(List fileFilters); - -} diff --git a/src/org/apache/commons/io/filefilter/DelegateFileFilter.java b/src/org/apache/commons/io/filefilter/DelegateFileFilter.java deleted file mode 100644 index 88f4ea4e..00000000 --- a/src/org/apache/commons/io/filefilter/DelegateFileFilter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.io.Serializable; - -/** - * This class turns a Java FileFilter or FilenameFilter into an IO FileFilter. - * - * @since 1.0 - * @see FileFilterUtils#asFileFilter(FileFilter) - * @see FileFilterUtils#asFileFilter(FilenameFilter) - */ -public class DelegateFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = -8723373124984771318L; - /** The File filter */ - private final FileFilter fileFilter; - /** The Filename filter */ - private final FilenameFilter filenameFilter; - - /** - * Constructs a delegate file filter around an existing FileFilter. - * - * @param filter the filter to decorate - */ - public DelegateFileFilter(final FileFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The FileFilter must not be null"); - } - this.fileFilter = filter; - this.filenameFilter = null; - } - - /** - * Constructs a delegate file filter around an existing FilenameFilter. - * - * @param filter the filter to decorate - */ - public DelegateFileFilter(final FilenameFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The FilenameFilter must not be null"); - } - this.filenameFilter = filter; - this.fileFilter = null; - } - - /** - * Checks the filter. - * - * @param file the file to check - * @return true if the filter matches - */ - @Override - public boolean accept(final File file) { - if (fileFilter != null) { - return fileFilter.accept(file); - } - return super.accept(file); - } - - /** - * Checks the filter. - * - * @param dir the directory - * @param name the file name in the directory - * @return true if the filter matches - */ - @Override - public boolean accept(final File dir, final String name) { - if (filenameFilter != null) { - return filenameFilter.accept(dir, name); - } - return super.accept(dir, name); - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final String delegate = fileFilter != null ? fileFilter.toString() : filenameFilter.toString(); - return super.toString() + "(" + delegate + ")"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java b/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java deleted file mode 100644 index 8186f580..00000000 --- a/src/org/apache/commons/io/filefilter/DirectoryFileFilter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that are directories. - *

- * For example, here is how to print out a list of the current directory's subdirectories: - *

- *

Using Classic IO

- * - *
- * File dir = new File(".");
- * String[] files = dir.list(DirectoryFileFilter.INSTANCE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- * - *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(DirectoryFileFilter.INSTANCE);
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.0 - * @see FileFilterUtils#directoryFileFilter() - */ -public class DirectoryFileFilter extends AbstractFileFilter implements Serializable { - - /** - * Singleton instance of directory filter. - * - * @since 1.3 - */ - public static final IOFileFilter DIRECTORY = new DirectoryFileFilter(); - - /** - * Singleton instance of directory filter. Please use the identical DirectoryFileFilter.DIRECTORY constant. The new - * name is more JDK 1.5 friendly as it doesn't clash with other values when using static imports. - */ - public static final IOFileFilter INSTANCE = DIRECTORY; - - private static final long serialVersionUID = -5148237843784525732L; - - /** - * Restrictive constructor. - */ - protected DirectoryFileFilter() { - // empty. - } - - /** - * Checks to see if the file is a directory. - * - * @param file the File to check - * @return true if the file is a directory - */ - @Override - public boolean accept(final File file) { - return file.isDirectory(); - } - - /** - * Checks to see if the file is a directory. - * @param file the File to check - * - * @return true if the file is a directory - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isDirectory(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/EmptyFileFilter.java b/src/org/apache/commons/io/filefilter/EmptyFileFilter.java deleted file mode 100644 index 83c673bf..00000000 --- a/src/org/apache/commons/io/filefilter/EmptyFileFilter.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.stream.Stream; - -import org.apache.commons.io.IOUtils; - -/** - * This filter accepts files or directories that are empty. - *

- * If the {@code File} is a directory it checks that it contains no files. - *

- *

- * Example, showing how to print out a list of the current directory's empty files/directories: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(EmptyFileFilter.EMPTY);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the current directory's non-empty files/directories: - *

- * - *
- * File dir = new File(".");
- * String[] files = dir.list(EmptyFileFilter.NOT_EMPTY);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(EmptyFileFilter.EMPTY);
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.3 - */ -public class EmptyFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of empty filter */ - public static final IOFileFilter EMPTY = new EmptyFileFilter(); - - /** Singleton instance of not-empty filter */ - public static final IOFileFilter NOT_EMPTY = EMPTY.negate(); - - private static final long serialVersionUID = 3631422087512832211L; - - /** - * Restrictive constructor. - */ - protected EmptyFileFilter() { - } - - /** - * Checks to see if the file is empty. - * - * @param file the file or directory to check - * @return {@code true} if the file or directory is empty, otherwise {@code false}. - */ - @Override - public boolean accept(final File file) { - if (file.isDirectory()) { - final File[] files = file.listFiles(); - return IOUtils.length(files) == 0; - } - return file.length() == 0; - } - - /** - * Checks to see if the file is empty. - * @param file the file or directory to check - * - * @return {@code true} if the file or directory is empty, otherwise {@code false}. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - try { - if (Files.isDirectory(file)) { - try (Stream stream = Files.list(file)) { - return toFileVisitResult(!stream.findFirst().isPresent(), file); - } - } - return toFileVisitResult(Files.size(file) == 0, file); - } catch (final IOException e) { - return handle(e); - } - } - -} diff --git a/src/org/apache/commons/io/filefilter/FalseFileFilter.java b/src/org/apache/commons/io/filefilter/FalseFileFilter.java deleted file mode 100644 index 51545a1e..00000000 --- a/src/org/apache/commons/io/filefilter/FalseFileFilter.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * A file filter that always returns false. - * - * @since 1.0 - * @see FileFilterUtils#falseFileFilter() - */ -public class FalseFileFilter implements IOFileFilter, Serializable { - - private static final String TO_STRING = Boolean.FALSE.toString(); - - /** - * Singleton instance of false filter. - * - * @since 1.3 - */ - public static final IOFileFilter FALSE = new FalseFileFilter(); - - /** - * Singleton instance of false filter. Please use the identical FalseFileFilter.FALSE constant. The new name is more - * JDK 1.5 friendly as it doesn't clash with other values when using static imports. - */ - public static final IOFileFilter INSTANCE = FALSE; - - private static final long serialVersionUID = 6210271677940926200L; - - /** - * Restrictive constructor. - */ - protected FalseFileFilter() { - } - - /** - * Returns false. - * - * @param file the file to check (ignored) - * @return false - */ - @Override - public boolean accept(final File file) { - return false; - } - - /** - * Returns false. - * - * @param dir the directory to check (ignored) - * @param name the file name (ignored) - * @return false - */ - @Override - public boolean accept(final File dir, final String name) { - return false; - } - - /** - * Returns false. - * - * @param file the file to check (ignored) - * - * @return false - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return FileVisitResult.TERMINATE; - } - - @Override - public IOFileFilter negate() { - return TrueFileFilter.INSTANCE; - } - - @Override - public String toString() { - return TO_STRING; - } - - @Override - public IOFileFilter and(final IOFileFilter fileFilter) { - // FALSE AND expression <=> FALSE - return INSTANCE; - } - - @Override - public IOFileFilter or(final IOFileFilter fileFilter) { - // FALSE OR expression <=> expression - return fileFilter; - } -} diff --git a/src/org/apache/commons/io/filefilter/FileEqualsFileFilter.java b/src/org/apache/commons/io/filefilter/FileEqualsFileFilter.java deleted file mode 100644 index 34d0750c..00000000 --- a/src/org/apache/commons/io/filefilter/FileEqualsFileFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Objects; - -/** - * Accepts only an exact {@link File} object match. You can use this filter to visit the start directory when walking a - * file tree with - * {@link java.nio.file.Files#walkFileTree(java.nio.file.Path, java.util.Set, int, java.nio.file.FileVisitor)}. - * - * @since 2.9.0 - */ -public class FileEqualsFileFilter extends AbstractFileFilter { - - private final File file; - private final Path path; - - /** - * Constructs a new instance for the given {@link File}. - * - * @param file The file to match. - */ - public FileEqualsFileFilter(final File file) { - this.file = Objects.requireNonNull(file, "file"); - this.path = file.toPath(); - } - - @Override - public boolean accept(final File file) { - return Objects.equals(this.file, file); - } - - @Override - public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { - return toFileVisitResult(Objects.equals(this.path, path), path); - } -} diff --git a/src/org/apache/commons/io/filefilter/FileFileFilter.java b/src/org/apache/commons/io/filefilter/FileFileFilter.java deleted file mode 100644 index f4f61d58..00000000 --- a/src/org/apache/commons/io/filefilter/FileFileFilter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that are files (not directories). - *

- * For example, here is how to print out a list of the real files - * within the current directory: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(FileFileFilter.INSTANCE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(FileFileFilter.INSTANCE);
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.3 - * @see FileFilterUtils#fileFileFilter() - */ -public class FileFileFilter extends AbstractFileFilter implements Serializable { - - /** - * Singleton instance of file filter. - * - * @since 2.9.0 - */ - public static final IOFileFilter INSTANCE = new FileFileFilter(); - - /** - * Singleton instance of file filter. - * - * @deprecated Use {@link #INSTANCE}. - */ - @Deprecated - public static final IOFileFilter FILE = INSTANCE; - - private static final long serialVersionUID = 5345244090827540862L; - - /** - * Restrictive constructor. - */ - protected FileFileFilter() { - } - - /** - * Checks to see if the file is a file. - * - * @param file the File to check - * @return true if the file is a file - */ - @Override - public boolean accept(final File file) { - return file.isFile(); - } - - /** - * Checks to see if the file is a file. - * @param file the File to check - * - * @return true if the file is a file - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isRegularFile(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/FileFilterUtils.java b/src/org/apache/commons/io/filefilter/FileFilterUtils.java deleted file mode 100644 index bae94f12..00000000 --- a/src/org/apache/commons/io/filefilter/FileFilterUtils.java +++ /dev/null @@ -1,760 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOCase; - -/** - * Useful utilities for working with file filters. It provides access to all - * file filter implementations in this package so you don't have to import - * every class you use. - * - * @since 1.0 - */ -public class FileFilterUtils { - - /* Constructed on demand and then cached */ - private static final IOFileFilter cvsFilter = notFileFilter( - and(directoryFileFilter(), nameFileFilter("CVS"))); - - - /* Constructed on demand and then cached */ - private static final IOFileFilter svnFilter = notFileFilter( - and(directoryFileFilter(), nameFileFilter(".svn"))); - - /** - * Returns a filter that returns true if the file was last modified before - * or at the specified cutoff date. - * - * @param cutoffDate the time threshold - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final Date cutoffDate) { - return new AgeFileFilter(cutoffDate); - } - - /** - * Returns a filter that filters files based on a cutoff date. - * - * @param cutoffDate the time threshold - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final Date cutoffDate, final boolean acceptOlder) { - return new AgeFileFilter(cutoffDate, acceptOlder); - } - - /** - * Returns a filter that returns true if the file was last modified before - * or at the same time as the specified reference file. - * - * @param cutoffReference the file whose last modification - * time is used as the threshold age of the files - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final File cutoffReference) { - return new AgeFileFilter(cutoffReference); - } - - /** - * Returns a filter that filters files based on a cutoff reference file. - * - * @param cutoffReference the file whose last modification - * time is used as the threshold age of the files - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final File cutoffReference, final boolean acceptOlder) { - return new AgeFileFilter(cutoffReference, acceptOlder); - } - - /** - * Returns a filter that returns true if the file was last modified before - * or at the specified cutoff time. - * - * @param cutoff the time threshold - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final long cutoff) { - return new AgeFileFilter(cutoff); - } - - /** - * Returns a filter that filters files based on a cutoff time. - * - * @param cutoff the time threshold - * @param acceptOlder if true, older files get accepted, if false, newer - * @return an appropriately configured age file filter - * @see AgeFileFilter - * @since 1.2 - */ - public static IOFileFilter ageFileFilter(final long cutoff, final boolean acceptOlder) { - return new AgeFileFilter(cutoff, acceptOlder); - } - - /** - * Returns a filter that ANDs the specified filters. - * - * @param filters the IOFileFilters that will be ANDed together. - * @return a filter that ANDs the specified filters - * - * @throws IllegalArgumentException if the filters are null or contain a - * null value. - * @see AndFileFilter - * @since 2.0 - */ - public static IOFileFilter and(final IOFileFilter... filters) { - return new AndFileFilter(toList(filters)); - } - - /** - * Returns a filter that ANDs the two specified filters. - * - * @param filter1 the first filter - * @param filter2 the second filter - * @return a filter that ANDs the two specified filters - * @see #and(IOFileFilter...) - * @see AndFileFilter - * @deprecated use {@link #and(IOFileFilter...)} - */ - @Deprecated - public static IOFileFilter andFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) { - return new AndFileFilter(filter1, filter2); - } - - /** - * Returns an {@code IOFileFilter} that wraps the - * {@code FileFilter} instance. - * - * @param filter the filter to be wrapped - * @return a new filter that implements IOFileFilter - * @see DelegateFileFilter - */ - public static IOFileFilter asFileFilter(final FileFilter filter) { - return new DelegateFileFilter(filter); - } - - /** - * Returns an {@code IOFileFilter} that wraps the - * {@code FilenameFilter} instance. - * - * @param filter the filter to be wrapped - * @return a new filter that implements IOFileFilter - * @see DelegateFileFilter - */ - public static IOFileFilter asFileFilter(final FilenameFilter filter) { - return new DelegateFileFilter(filter); - } - - /** - * Returns a filter that checks if the file is a directory. - * - * @return file filter that accepts only directories and not files - * @see DirectoryFileFilter#DIRECTORY - */ - public static IOFileFilter directoryFileFilter() { - return DirectoryFileFilter.DIRECTORY; - } - - /** - * Returns a filter that always returns false. - * - * @return a false filter - * @see FalseFileFilter#FALSE - */ - public static IOFileFilter falseFileFilter() { - return FalseFileFilter.FALSE; - } - - /** - * Returns a filter that checks if the file is a file (and not a directory). - * - * @return file filter that accepts only files and not directories - * @see FileFileFilter#INSTANCE - */ - public static IOFileFilter fileFileFilter() { - return FileFileFilter.INSTANCE; - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting array is a subset of the original file list that - * matches the provided filter. - *

- * - *
-     * Set<File> allFiles = ...
-     * Set<File> javaFiles = FileFilterUtils.filterSet(allFiles,
-     *     FileFilterUtils.suffixFileFilter(".java"));
-     * 
- * @param filter the filter to apply to the set of files. - * @param files the array of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * or {@code files} contains a {@code null} value. - * - * @since 2.0 - */ - public static File[] filter(final IOFileFilter filter, final File... files) { - if (filter == null) { - throw new IllegalArgumentException("file filter is null"); - } - if (files == null) { - return FileUtils.EMPTY_FILE_ARRAY; - } - return filterFiles(filter, Stream.of(files), Collectors.toList()).toArray(FileUtils.EMPTY_FILE_ARRAY); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} stream and collects the accepted files. - *

- * - * @param filter the filter to apply to the stream of files. - * @param stream the stream of files on which to apply the filter. - * @param collector how to collect the end result. - * - * @param the return type. - * @param the mutable accumulation type of the reduction operation (often hidden as an implementation detail) - * @return a subset of files from the stream that is accepted by the filter. - * @throws IllegalArgumentException if the filter is {@code null}. - */ - private static R filterFiles(final IOFileFilter filter, final Stream stream, - final Collector collector) { - //Objects.requireNonNull(filter, "filter"); - Objects.requireNonNull(collector, "collector"); - if (filter == null) { - throw new IllegalArgumentException("file filter is null"); - } - if (stream == null) { - return Stream.empty().collect(collector); - } - return stream.filter(filter::accept).collect(collector); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting array is a subset of the original file list that - * matches the provided filter. - *

- * - *

- * The {@link Set} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * Set<File> allFiles = ...
-     * Set<File> javaFiles = FileFilterUtils.filterSet(allFiles,
-     *     FileFilterUtils.suffixFileFilter(".java"));
-     * 
- * @param filter the filter to apply to the set of files. - * @param files the array of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * or {@code files} contains a {@code null} value. - * - * @since 2.0 - */ - public static File[] filter(final IOFileFilter filter, final Iterable files) { - return filterList(filter, files).toArray(FileUtils.EMPTY_FILE_ARRAY); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting list is a subset of the original files that - * matches the provided filter. - *

- * - *

- * The {@link List} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * List<File> filesAndDirectories = ...
-     * List<File> directories = FileFilterUtils.filterList(filesAndDirectories,
-     *     FileFilterUtils.directoryFileFilter());
-     * 
- * @param filter the filter to apply to each files in the list. - * @param files the collection of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * or {@code files} contains a {@code null} value. - * @since 2.0 - */ - public static List filterList(final IOFileFilter filter, final File... files) { - return Arrays.asList(filter(filter, files)); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting list is a subset of the original files that - * matches the provided filter. - *

- * - *

- * The {@link List} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * List<File> filesAndDirectories = ...
-     * List<File> directories = FileFilterUtils.filterList(filesAndDirectories,
-     *     FileFilterUtils.directoryFileFilter());
-     * 
- * @param filter the filter to apply to each files in the list. - * @param files the collection of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * @since 2.0 - */ - public static List filterList(final IOFileFilter filter, final Iterable files) { - if (files == null) { - return Collections.emptyList(); - } - return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toList()); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting set is a subset of the original file list that - * matches the provided filter. - *

- * - *

- * The {@link Set} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * Set<File> allFiles = ...
-     * Set<File> javaFiles = FileFilterUtils.filterSet(allFiles,
-     *     FileFilterUtils.suffixFileFilter(".java"));
-     * 
- * @param filter the filter to apply to the set of files. - * @param files the collection of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * or {@code files} contains a {@code null} value. - * - * @since 2.0 - */ - public static Set filterSet(final IOFileFilter filter, final File... files) { - return new HashSet<>(Arrays.asList(filter(filter, files))); - } - - /** - *

- * Applies an {@link IOFileFilter} to the provided {@link File} - * objects. The resulting set is a subset of the original file list that - * matches the provided filter. - *

- * - *

- * The {@link Set} returned by this method is not guaranteed to be thread safe. - *

- * - *
-     * Set<File> allFiles = ...
-     * Set<File> javaFiles = FileFilterUtils.filterSet(allFiles,
-     *     FileFilterUtils.suffixFileFilter(".java"));
-     * 
- * @param filter the filter to apply to the set of files. - * @param files the collection of files to apply the filter to. - * - * @return a subset of {@code files} that is accepted by the - * file filter. - * @throws IllegalArgumentException if the filter is {@code null} - * - * @since 2.0 - */ - public static Set filterSet(final IOFileFilter filter, final Iterable files) { - if (files == null) { - return Collections.emptySet(); - } - return filterFiles(filter, StreamSupport.stream(files.spliterator(), false), Collectors.toSet()); - } - - /** - * Returns a filter that accepts files that begin with the provided magic - * number. - * - * @param magicNumber the magic number (byte sequence) to match at the - * beginning of each file. - * - * @return an IOFileFilter that accepts files beginning with the provided - * magic number. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null} or is of length zero. - * @see MagicNumberFileFilter - * @since 2.0 - */ - public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber) { - return new MagicNumberFileFilter(magicNumber); - } - - /** - * Returns a filter that accepts files that contains the provided magic - * number at a specified offset within the file. - * - * @param magicNumber the magic number (byte sequence) to match at the - * provided offset in each file. - * @param offset the offset within the files to look for the magic number. - * - * @return an IOFileFilter that accepts files containing the magic number - * at the specified offset. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null}, or contains no bytes, or {@code offset} - * is a negative number. - * @see MagicNumberFileFilter - * @since 2.0 - */ - public static IOFileFilter magicNumberFileFilter(final byte[] magicNumber, final long offset) { - return new MagicNumberFileFilter(magicNumber, offset); - } - - /** - * Returns a filter that accepts files that begin with the provided magic - * number. - * - * @param magicNumber the magic number (byte sequence) to match at the - * beginning of each file. - * - * @return an IOFileFilter that accepts files beginning with the provided - * magic number. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null} or the empty String. - * @see MagicNumberFileFilter - * @since 2.0 - */ - public static IOFileFilter magicNumberFileFilter(final String magicNumber) { - return new MagicNumberFileFilter(magicNumber); - } - - /** - * Returns a filter that accepts files that contains the provided magic - * number at a specified offset within the file. - * - * @param magicNumber the magic number (byte sequence) to match at the - * provided offset in each file. - * @param offset the offset within the files to look for the magic number. - * - * @return an IOFileFilter that accepts files containing the magic number - * at the specified offset. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null} or the empty String, or if offset is a - * negative number. - * @see MagicNumberFileFilter - * @since 2.0 - */ - public static IOFileFilter magicNumberFileFilter(final String magicNumber, final long offset) { - return new MagicNumberFileFilter(magicNumber, offset); - } - - /** - * Decorates a filter to make it ignore CVS directories. - * Passing in {@code null} will return a filter that accepts everything - * except CVS directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since 1.1 (method existed but had bug in 1.0) - */ - public static IOFileFilter makeCVSAware(final IOFileFilter filter) { - return filter == null ? cvsFilter : and(filter, cvsFilter); - } - - /** - * Decorates a filter so that it only applies to directories and not to files. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @see DirectoryFileFilter#DIRECTORY - * @since 1.3 - */ - public static IOFileFilter makeDirectoryOnly(final IOFileFilter filter) { - if (filter == null) { - return DirectoryFileFilter.DIRECTORY; - } - return DirectoryFileFilter.DIRECTORY.and(filter); - } - - /** - * Decorates a filter so that it only applies to files and not to directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @see FileFileFilter#INSTANCE - * @since 1.3 - */ - public static IOFileFilter makeFileOnly(final IOFileFilter filter) { - if (filter == null) { - return FileFileFilter.INSTANCE; - } - return FileFileFilter.INSTANCE.and(filter); - } - - /** - * Decorates a filter to make it ignore SVN directories. - * Passing in {@code null} will return a filter that accepts everything - * except SVN directories. - * - * @param filter the filter to decorate, null means an unrestricted filter - * @return the decorated filter, never null - * @since 1.1 - */ - public static IOFileFilter makeSVNAware(final IOFileFilter filter) { - return filter == null ? svnFilter : and(filter, svnFilter); - } - - /** - * Returns a filter that returns true if the file name matches the specified text. - * - * @param name the file name - * @return a name checking filter - * @see NameFileFilter - */ - public static IOFileFilter nameFileFilter(final String name) { - return new NameFileFilter(name); - } - - /** - * Returns a filter that returns true if the file name matches the specified text. - * - * @param name the file name - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @return a name checking filter - * @see NameFileFilter - * @since 2.0 - */ - public static IOFileFilter nameFileFilter(final String name, final IOCase caseSensitivity) { - return new NameFileFilter(name, caseSensitivity); - } - - /** - * Returns a filter that NOTs the specified filter. - * - * @param filter the filter to invert - * @return a filter that NOTs the specified filter - * @see NotFileFilter - */ - public static IOFileFilter notFileFilter(final IOFileFilter filter) { - return filter.negate(); - } - - /** - * Returns a filter that ORs the specified filters. - * - * @param filters the IOFileFilters that will be ORed together. - * @return a filter that ORs the specified filters - * - * @throws IllegalArgumentException if the filters are null or contain a - * null value. - * @see OrFileFilter - * @since 2.0 - */ - public static IOFileFilter or(final IOFileFilter... filters) { - return new OrFileFilter(toList(filters)); - } - - /** - * Returns a filter that ORs the two specified filters. - * - * @param filter1 the first filter - * @param filter2 the second filter - * @return a filter that ORs the two specified filters - * @see #or(IOFileFilter...) - * @see OrFileFilter - * @deprecated use {@link #or(IOFileFilter...)} - */ - @Deprecated - public static IOFileFilter orFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) { - return new OrFileFilter(filter1, filter2); - } - - /** - * Returns a filter that returns true if the file name starts with the specified text. - * - * @param prefix the file name prefix - * @return a prefix checking filter - * @see PrefixFileFilter - */ - public static IOFileFilter prefixFileFilter(final String prefix) { - return new PrefixFileFilter(prefix); - } - - /** - * Returns a filter that returns true if the file name starts with the specified text. - * - * @param prefix the file name prefix - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @return a prefix checking filter - * @see PrefixFileFilter - * @since 2.0 - */ - public static IOFileFilter prefixFileFilter(final String prefix, final IOCase caseSensitivity) { - return new PrefixFileFilter(prefix, caseSensitivity); - } - - /** - * Returns a filter that returns true if the file is bigger than a certain size. - * - * @param threshold the file size threshold - * @return an appropriately configured SizeFileFilter - * @see SizeFileFilter - * @since 1.2 - */ - public static IOFileFilter sizeFileFilter(final long threshold) { - return new SizeFileFilter(threshold); - } - - /** - * Returns a filter that filters based on file size. - * - * @param threshold the file size threshold - * @param acceptLarger if true, larger files get accepted, if false, smaller - * @return an appropriately configured SizeFileFilter - * @see SizeFileFilter - * @since 1.2 - */ - public static IOFileFilter sizeFileFilter(final long threshold, final boolean acceptLarger) { - return new SizeFileFilter(threshold, acceptLarger); - } - - /** - * Returns a filter that accepts files whose size is >= minimum size - * and <= maximum size. - * - * @param minSizeInclusive the minimum file size (inclusive) - * @param maxSizeInclusive the maximum file size (inclusive) - * @return an appropriately configured IOFileFilter - * @see SizeFileFilter - * @since 1.3 - */ - public static IOFileFilter sizeRangeFileFilter(final long minSizeInclusive, final long maxSizeInclusive ) { - final IOFileFilter minimumFilter = new SizeFileFilter(minSizeInclusive, true); - final IOFileFilter maximumFilter = new SizeFileFilter(maxSizeInclusive + 1L, false); - return minimumFilter.and(maximumFilter); - } - - /** - * Returns a filter that returns true if the file name ends with the specified text. - * - * @param suffix the file name suffix - * @return a suffix checking filter - * @see SuffixFileFilter - */ - public static IOFileFilter suffixFileFilter(final String suffix) { - return new SuffixFileFilter(suffix); - } - - /** - * Returns a filter that returns true if the file name ends with the specified text. - * - * @param suffix the file name suffix - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @return a suffix checking filter - * @see SuffixFileFilter - * @since 2.0 - */ - public static IOFileFilter suffixFileFilter(final String suffix, final IOCase caseSensitivity) { - return new SuffixFileFilter(suffix, caseSensitivity); - } - - /** - * Create a List of file filters. - * - * @param filters The file filters - * @return The list of file filters - * @throws IllegalArgumentException if the filters are null or contain a - * null value. - * @since 2.0 - */ - public static List toList(final IOFileFilter... filters) { - if (filters == null) { - throw new IllegalArgumentException("The filters must not be null"); - } - final List list = new ArrayList<>(filters.length); - for (int i = 0; i < filters.length; i++) { - if (filters[i] == null) { - throw new IllegalArgumentException("The filter[" + i + "] is null"); - } - list.add(filters[i]); - } - return list; - } - - /** - * Returns a filter that always returns true. - * - * @return a true filter - * @see TrueFileFilter#TRUE - */ - public static IOFileFilter trueFileFilter() { - return TrueFileFilter.TRUE; - } - - /** - * FileFilterUtils is not normally instantiated. - */ - public FileFilterUtils() { - } - -} diff --git a/src/org/apache/commons/io/filefilter/HiddenFileFilter.java b/src/org/apache/commons/io/filefilter/HiddenFileFilter.java deleted file mode 100644 index e4b09024..00000000 --- a/src/org/apache/commons/io/filefilter/HiddenFileFilter.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that are hidden. - *

- * Example, showing how to print out a list of the - * current directory's hidden files: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(HiddenFileFilter.HIDDEN);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

- * Example, showing how to print out a list of the - * current directory's visible (i.e. not hidden) files: - *

- * - *
- * File dir = new File(".");
- * String[] files = dir.list(HiddenFileFilter.VISIBLE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(HiddenFileFilter.HIDDEN);
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.3 - */ -public class HiddenFileFilter extends AbstractFileFilter implements Serializable { - - /** Singleton instance of hidden filter */ - public static final IOFileFilter HIDDEN = new HiddenFileFilter(); - - private static final long serialVersionUID = 8930842316112759062L; - - /** Singleton instance of visible filter */ - public static final IOFileFilter VISIBLE = HIDDEN.negate(); - - /** - * Restrictive constructor. - */ - protected HiddenFileFilter() { - } - - /** - * Checks to see if the file is hidden. - * - * @param file the File to check - * @return {@code true} if the file is - * hidden, otherwise {@code false}. - */ - @Override - public boolean accept(final File file) { - return file.isHidden(); - } - - /** - * Checks to see if the file is hidden. - * @param file the File to check - * - * @return {@code true} if the file is - * hidden, otherwise {@code false}. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - try { - return toFileVisitResult(Files.isHidden(file), file); - } catch (final IOException e) { - return handle(e); - } - } - -} diff --git a/src/org/apache/commons/io/filefilter/IOFileFilter.java b/src/org/apache/commons/io/filefilter/IOFileFilter.java deleted file mode 100644 index e45780e2..00000000 --- a/src/org/apache/commons/io/filefilter/IOFileFilter.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.FileFilter; -import java.io.FilenameFilter; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -import org.apache.commons.io.file.PathFilter; - -/** - * An interface which brings the FileFilter, FilenameFilter, and PathFilter interfaces together. - * - * @since 1.0 - */ -public interface IOFileFilter extends FileFilter, FilenameFilter, PathFilter { - - /** - * An empty String array. - */ - String[] EMPTY_STRING_ARRAY = {}; - - /** - * Checks to see if the File should be accepted by this filter. - *

- * Defined in {@link java.io.FileFilter}. - *

- * - * @param file the File to check. - * @return true if this file matches the test. - */ - @Override - boolean accept(File file); - - /** - * Checks to see if the File should be accepted by this filter. - *

- * Defined in {@link java.io.FilenameFilter}. - *

- * - * @param dir the directory File to check. - * @param name the file name within the directory to check. - * @return true if this file matches the test. - */ - @Override - boolean accept(File dir, String name); - - /** - * Checks to see if the Path should be accepted by this filter. - * - * @param path the Path to check. - * @return true if this path matches the test. - * @since 2.9.0 - */ - @Override - default FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { - return AbstractFileFilter.toFileVisitResult(accept(path.toFile()), path); - } - - /** - * Creates a new "and" filter with this filter. - * - * @param fileFilter the filter to "and". - * @return a new filter. - * @since 2.9.0 - */ - default IOFileFilter and(final IOFileFilter fileFilter) { - return new AndFileFilter(this, fileFilter); - } - - /** - * Creates a new "not" filter with this filter. - * - * @return a new filter. - * @since 2.9.0 - */ - default IOFileFilter negate() { - return new NotFileFilter(this); - } - - /** - * Creates a new "or" filter with this filter. - * - * @param fileFilter the filter to "or". - * @return a new filter. - * @since 2.9.0 - */ - default IOFileFilter or(final IOFileFilter fileFilter) { - return new OrFileFilter(this, fileFilter); - } - -} diff --git a/src/org/apache/commons/io/filefilter/MagicNumberFileFilter.java b/src/org/apache/commons/io/filefilter/MagicNumberFileFilter.java deleted file mode 100644 index 581d77a3..00000000 --- a/src/org/apache/commons/io/filefilter/MagicNumberFileFilter.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.charset.Charset; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; - -import org.apache.commons.io.IOUtils; - -/** - *

- * File filter for matching files containing a "magic number". A magic number - * is a unique series of bytes common to all files of a specific file format. - * For instance, all Java class files begin with the bytes - * {@code 0xCAFEBABE}. - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * MagicNumberFileFilter javaClassFileFilter =
- *     MagicNumberFileFilter(new byte[] {(byte) 0xCA, (byte) 0xFE,
- *       (byte) 0xBA, (byte) 0xBE});
- * String[] javaClassFiles = dir.list(javaClassFileFilter);
- * for (String javaClassFile : javaClassFiles) {
- *     System.out.println(javaClassFile);
- * }
- * 
- * - *

- * Sometimes, such as in the case of TAR files, the - * magic number will be offset by a certain number of bytes in the file. In the - * case of TAR archive files, this offset is 257 bytes. - *

- * - *
- * File dir = new File(".");
- * MagicNumberFileFilter tarFileFilter =
- *     MagicNumberFileFilter("ustar", 257);
- * String[] tarFiles = dir.list(tarFileFilter);
- * for (String tarFile : tarFiles) {
- *     System.out.println(tarFile);
- * }
- * 
- *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(MagicNumberFileFilter("ustar", 257));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 2.0 - * @see FileFilterUtils#magicNumberFileFilter(byte[]) - * @see FileFilterUtils#magicNumberFileFilter(String) - * @see FileFilterUtils#magicNumberFileFilter(byte[], long) - * @see FileFilterUtils#magicNumberFileFilter(String, long) - */ -public class MagicNumberFileFilter extends AbstractFileFilter implements - Serializable { - - /** - * The serialization version unique identifier. - */ - private static final long serialVersionUID = -547733176983104172L; - - /** - * The magic number to compare against the file's bytes at the provided - * offset. - */ - private final byte[] magicNumbers; - - /** - * The offset (in bytes) within the files that the magic number's bytes - * should appear. - */ - private final long byteOffset; - - /** - *

- * Constructs a new MagicNumberFileFilter and associates it with the magic - * number to test for in files. This constructor assumes a starting offset - * of {@code 0}. - *

- * - *

- * It is important to note that the array is not cloned and that - * any changes to the magic number array after construction will affect the - * behavior of this file filter. - *

- * - *
-     * MagicNumberFileFilter javaClassFileFilter =
-     *     MagicNumberFileFilter(new byte[] {(byte) 0xCA, (byte) 0xFE,
-     *       (byte) 0xBA, (byte) 0xBE});
-     * 
- * - * @param magicNumber the magic number to look for in the file. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null}, or contains no bytes. - */ - public MagicNumberFileFilter(final byte[] magicNumber) { - this(magicNumber, 0); - } - - /** - *

- * Constructs a new MagicNumberFileFilter and associates it with the magic - * number to test for in files and the byte offset location in the file to - * to look for that magic number. - *

- * - *
-     * MagicNumberFileFilter tarFileFilter =
-     *     MagicNumberFileFilter(new byte[] {0x75, 0x73, 0x74, 0x61, 0x72}, 257);
-     * 
- * - *
-     * MagicNumberFileFilter javaClassFileFilter =
-     *     MagicNumberFileFilter(new byte[] {0xCA, 0xFE, 0xBA, 0xBE}, 0);
-     * 
- * - * @param magicNumber the magic number to look for in the file. - * @param offset the byte offset in the file to start comparing bytes. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null}, or contains no bytes, or {@code offset} - * is a negative number. - */ - public MagicNumberFileFilter(final byte[] magicNumber, final long offset) { - if (magicNumber == null) { - throw new IllegalArgumentException("The magic number cannot be null"); - } - if (magicNumber.length == 0) { - throw new IllegalArgumentException("The magic number must contain at least one byte"); - } - if (offset < 0) { - throw new IllegalArgumentException("The offset cannot be negative"); - } - - this.magicNumbers = IOUtils.byteArray(magicNumber.length); - System.arraycopy(magicNumber, 0, this.magicNumbers, 0, magicNumber.length); - this.byteOffset = offset; - } - - /** - *

- * Constructs a new MagicNumberFileFilter and associates it with the magic - * number to test for in files. This constructor assumes a starting offset - * of {@code 0}. - *

- * - * Example usage: - *
-     * {@code
-     * MagicNumberFileFilter xmlFileFilter =
-     *     MagicNumberFileFilter("
-     *
-     * @param magicNumber the magic number to look for in the file.
-     *        The string is converted to bytes using the platform default charset.
-     *
-     * @throws IllegalArgumentException if {@code magicNumber} is
-     *         {@code null} or the empty String.
-     */
-    public MagicNumberFileFilter(final String magicNumber) {
-        this(magicNumber, 0);
-    }
-
-    /**
-     * 

- * Constructs a new MagicNumberFileFilter and associates it with the magic - * number to test for in files and the byte offset location in the file to - * to look for that magic number. - *

- * - *
-     * MagicNumberFileFilter tarFileFilter =
-     *     MagicNumberFileFilter("ustar", 257);
-     * 
- * - * @param magicNumber the magic number to look for in the file. - * The string is converted to bytes using the platform default charset. - * @param offset the byte offset in the file to start comparing bytes. - * - * @throws IllegalArgumentException if {@code magicNumber} is - * {@code null} or the empty String, or {@code offset} is - * a negative number. - */ - public MagicNumberFileFilter(final String magicNumber, final long offset) { - if (magicNumber == null) { - throw new IllegalArgumentException("The magic number cannot be null"); - } - if (magicNumber.isEmpty()) { - throw new IllegalArgumentException("The magic number must contain at least one byte"); - } - if (offset < 0) { - throw new IllegalArgumentException("The offset cannot be negative"); - } - - this.magicNumbers = magicNumber.getBytes(Charset.defaultCharset()); // explicitly uses the platform default - // charset - this.byteOffset = offset; - } - - /** - *

- * Accepts the provided file if the file contains the file filter's magic - * number at the specified offset. - *

- * - *

- * If any {@link IOException}s occur while reading the file, the file will - * be rejected. - *

- * - * @param file the file to accept or reject. - * - * @return {@code true} if the file contains the filter's magic number - * at the specified offset, {@code false} otherwise. - */ - @Override - public boolean accept(final File file) { - if (file != null && file.isFile() && file.canRead()) { - try { - try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) { - final byte[] fileBytes = IOUtils.byteArray(this.magicNumbers.length); - randomAccessFile.seek(byteOffset); - final int read = randomAccessFile.read(fileBytes); - if (read != magicNumbers.length) { - return false; - } - return Arrays.equals(this.magicNumbers, fileBytes); - } - } - catch (final IOException ioe) { - // Do nothing, fall through and do not accept file - } - } - - return false; - } - - /** - *

- * Accepts the provided file if the file contains the file filter's magic - * number at the specified offset. - *

- * - *

- * If any {@link IOException}s occur while reading the file, the file will - * be rejected. - *

- * @param file the file to accept or reject. - * - * @return {@code true} if the file contains the filter's magic number - * at the specified offset, {@code false} otherwise. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - if (file != null && Files.isRegularFile(file) && Files.isReadable(file)) { - try { - try (final FileChannel fileChannel = FileChannel.open(file)) { - final ByteBuffer byteBuffer = ByteBuffer.allocate(this.magicNumbers.length); - final int read = fileChannel.read(byteBuffer); - if (read != magicNumbers.length) { - return FileVisitResult.TERMINATE; - } - return toFileVisitResult(Arrays.equals(this.magicNumbers, byteBuffer.array()), file); - } - } - catch (final IOException ioe) { - // Do nothing, fall through and do not accept file - } - } - return FileVisitResult.TERMINATE; - } - - /** - * Returns a String representation of the file filter, which includes the - * magic number bytes and byte offset. - * - * @return a String representation of the file filter. - */ - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(super.toString()); - builder.append("("); - builder.append(new String(magicNumbers, Charset.defaultCharset()));// TODO perhaps use hex if value is not - // printable - builder.append(","); - builder.append(this.byteOffset); - builder.append(")"); - return builder.toString(); - } -} diff --git a/src/org/apache/commons/io/filefilter/NameFileFilter.java b/src/org/apache/commons/io/filefilter/NameFileFilter.java deleted file mode 100644 index 64e443da..00000000 --- a/src/org/apache/commons/io/filefilter/NameFileFilter.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.IOCase; - -/** - * Filters file names for a certain name. - *

- * For example, to print all files and directories in the - * current directory whose name is {@code Test}: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(new NameFileFilter("Test"));
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new NameFileFilter("Test"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.0 - * @see FileFilterUtils#nameFileFilter(String) - * @see FileFilterUtils#nameFileFilter(String, IOCase) - */ -public class NameFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = 176844364689077340L; - - /** The file names to search for */ - private final String[] names; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new case-sensitive name file filter for a list of names. - * - * @param names the names to allow, must not be null - * @throws IllegalArgumentException if the name list is null - * @throws ClassCastException if the list does not contain Strings - */ - public NameFileFilter(final List names) { - this(names, null); - } - - /** - * Constructs a new name file filter for a list of names specifying case-sensitivity. - * - * @param names the names to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the name list is null - * @throws ClassCastException if the list does not contain Strings - */ - public NameFileFilter(final List names, final IOCase caseSensitivity) { - if (names == null) { - throw new IllegalArgumentException("The list of names must not be null"); - } - this.names = names.toArray(EMPTY_STRING_ARRAY); - this.caseSensitivity = toIOCase(caseSensitivity); - } - - /** - * Constructs a new case-sensitive name file filter for a single name. - * - * @param name the name to allow, must not be null - * @throws IllegalArgumentException if the name is null - */ - public NameFileFilter(final String name) { - this(name, IOCase.SENSITIVE); - } - - /** - * Constructs a new case-sensitive name file filter for an array of names. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - *

- * - * @param names the names to allow, must not be null - * @throws IllegalArgumentException if the names array is null - */ - public NameFileFilter(final String... names) { - this(names, IOCase.SENSITIVE); - } - - /** - * Construct a new name file filter specifying case-sensitivity. - * - * @param name the name to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the name is null - */ - public NameFileFilter(final String name, final IOCase caseSensitivity) { - if (name == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.names = new String[] {name}; - this.caseSensitivity = toIOCase(caseSensitivity); - } - - /** - * Constructs a new name file filter for an array of names specifying case-sensitivity. - * - * @param names the names to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the names array is null - */ - public NameFileFilter(final String[] names, final IOCase caseSensitivity) { - if (names == null) { - throw new IllegalArgumentException("The array of names must not be null"); - } - this.names = new String[names.length]; - System.arraycopy(names, 0, this.names, 0, names.length); - this.caseSensitivity = toIOCase(caseSensitivity); - } - - /** - * Checks to see if the file name matches. - * - * @param file the File to check - * @return true if the file name matches - */ - @Override - public boolean accept(final File file) { - return acceptBaseName(file.getName()); - } - - /** - * Checks to see if the file name matches. - * - * @param dir the File directory (ignored) - * @param name the file name - * @return true if the file name matches - */ - @Override - public boolean accept(final File dir, final String name) { - return acceptBaseName(name); - } - - /** - * Checks to see if the file name matches. - * @param file the File to check - * - * @return true if the file name matches - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(acceptBaseName(Objects.toString(file.getFileName(), null)), file); - } - - private boolean acceptBaseName(final String baseName) { - for (final String testName : names) { - if (caseSensitivity.checkEquals(baseName, testName)) { - return true; - } - } - return false; - } - - private IOCase toIOCase(final IOCase caseSensitivity) { - return caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - if (names != null) { - for (int i = 0; i < names.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(names[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/NotFileFilter.java b/src/org/apache/commons/io/filefilter/NotFileFilter.java deleted file mode 100644 index 0523fff2..00000000 --- a/src/org/apache/commons/io/filefilter/NotFileFilter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter produces a logical NOT of the filters specified. - * - * @since 1.0 - * @see FileFilterUtils#notFileFilter(IOFileFilter) - */ -public class NotFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = 6131563330944994230L; - - /** The filter */ - private final IOFileFilter filter; - - /** - * Constructs a new file filter that NOTs the result of another filter. - * - * @param filter the filter, must not be null - * @throws IllegalArgumentException if the filter is null - */ - public NotFileFilter(final IOFileFilter filter) { - if (filter == null) { - throw new IllegalArgumentException("The filter must not be null"); - } - this.filter = filter; - } - - /** - * Returns the logical NOT of the underlying filter's return value for the same File. - * - * @param file the File to check - * @return true if the filter returns false - */ - @Override - public boolean accept(final File file) { - return !filter.accept(file); - } - - /** - * Returns the logical NOT of the underlying filter's return value for the same arguments. - * - * @param file the File directory - * @param name the file name - * @return true if the filter returns false - */ - @Override - public boolean accept(final File file, final String name) { - return !filter.accept(file, name); - } - - /** - * Returns the logical NOT of the underlying filter's return value for the same File. - * @param file the File to check - * - * @return true if the filter returns false - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return not(filter.accept(file, attributes)); - } - - private FileVisitResult not(final FileVisitResult accept) { - return accept == FileVisitResult.CONTINUE ? FileVisitResult.TERMINATE - : FileVisitResult.CONTINUE; - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - return "NOT (" + filter.toString() + ")"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/OrFileFilter.java b/src/org/apache/commons/io/filefilter/OrFileFilter.java deleted file mode 100644 index 7ac08f49..00000000 --- a/src/org/apache/commons/io/filefilter/OrFileFilter.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * A {@link java.io.FileFilter} providing conditional OR logic across a list of file filters. This filter returns - * {@code true} if any filters in the list return {@code true}. Otherwise, it returns {@code false}. Checking of the - * file filter list stops when the first filter returns {@code true}. - * - * @since 1.0 - * @see FileFilterUtils#or(IOFileFilter...) - */ -public class OrFileFilter extends AbstractFileFilter implements ConditionalFileFilter, Serializable { - - private static final long serialVersionUID = 5767770777065432721L; - - /** The list of file filters. */ - private final List fileFilters; - - /** - * Constructs a new instance of {@code OrFileFilter}. - * - * @since 1.1 - */ - public OrFileFilter() { - this(0); - } - - /** - * Constructs a new instance with the given initial list. - * - * @param initialList the initial list. - */ - private OrFileFilter(final ArrayList initialList) { - this.fileFilters = Objects.requireNonNull(initialList, "initialList"); - } - - /** - * Constructs a new instance with the given initial capacity. - * - * @param initialCapacity the initial capacity. - */ - private OrFileFilter(final int initialCapacity) { - this(new ArrayList<>(initialCapacity)); - } - - /** - * Constructs a new instance for the give filters. - * @param fileFilters filters to OR. - * - * @since 2.9.0 - */ - public OrFileFilter(final IOFileFilter... fileFilters) { - this(Objects.requireNonNull(fileFilters, "fileFilters").length); - addFileFilter(fileFilters); - } - - /** - * Constructs a new file filter that ORs the result of other filters. - * - * @param filter1 the first filter, must not be null - * @param filter2 the second filter, must not be null - * @throws IllegalArgumentException if either filter is null - */ - public OrFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) { - this(2); - addFileFilter(filter1); - addFileFilter(filter2); - } - - /** - * Constructs a new instance of {@code OrFileFilter} with the specified filters. - * - * @param fileFilters the file filters for this filter, copied. - * @since 1.1 - */ - public OrFileFilter(final List fileFilters) { - this(new ArrayList<>(Objects.requireNonNull(fileFilters, "fileFilters"))); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean accept(final File file) { - for (final IOFileFilter fileFilter : fileFilters) { - if (fileFilter.accept(file)) { - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean accept(final File file, final String name) { - for (final IOFileFilter fileFilter : fileFilters) { - if (fileFilter.accept(file, name)) { - return true; - } - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - for (final IOFileFilter fileFilter : fileFilters) { - if (fileFilter.accept(file, attributes) == FileVisitResult.CONTINUE) { - return FileVisitResult.CONTINUE; - } - } - return FileVisitResult.TERMINATE; - } - - /** - * {@inheritDoc} - */ - @Override - public void addFileFilter(final IOFileFilter fileFilter) { - this.fileFilters.add(Objects.requireNonNull(fileFilter, "fileFilter")); - } - - /** - * Adds the given file filters. - * - * @param fileFilters the filters to add. - * @since 2.9.0 - */ - public void addFileFilter(final IOFileFilter... fileFilters) { - for (final IOFileFilter fileFilter : Objects.requireNonNull(fileFilters, "fileFilters")) { - addFileFilter(fileFilter); - } - } - - /** - * {@inheritDoc} - */ - @Override - public List getFileFilters() { - return Collections.unmodifiableList(this.fileFilters); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean removeFileFilter(final IOFileFilter fileFilter) { - return this.fileFilters.remove(fileFilter); - } - - /** - * {@inheritDoc} - */ - @Override - public void setFileFilters(final List fileFilters) { - this.fileFilters.clear(); - this.fileFilters.addAll(Objects.requireNonNull(fileFilters, "fileFilters")); - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - if (fileFilters != null) { - for (int i = 0; i < fileFilters.size(); i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(fileFilters.get(i)); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/PathEqualsFileFilter.java b/src/org/apache/commons/io/filefilter/PathEqualsFileFilter.java deleted file mode 100644 index ccae9917..00000000 --- a/src/org/apache/commons/io/filefilter/PathEqualsFileFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Objects; - -/** - * Accepts only an exact {@link Path} object match. You can use this filter to visit the start directory when walking a - * file tree with - * {@link java.nio.file.Files#walkFileTree(java.nio.file.Path, java.util.Set, int, java.nio.file.FileVisitor)}. - * - * @since 2.9.0 - */ -public class PathEqualsFileFilter extends AbstractFileFilter { - - private final Path path; - - /** - * Constructs a new instance for the given {@link Path}. - * - * @param file The file to match. - */ - public PathEqualsFileFilter(final Path file) { - this.path = file; - } - - @Override - public boolean accept(final File file) { - return Objects.equals(this.path, file.toPath()); - } - - @Override - public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { - return toFileVisitResult(Objects.equals(this.path, path), path); - } -} diff --git a/src/org/apache/commons/io/filefilter/PathVisitorFileFilter.java b/src/org/apache/commons/io/filefilter/PathVisitorFileFilter.java deleted file mode 100644 index 543a7070..00000000 --- a/src/org/apache/commons/io/filefilter/PathVisitorFileFilter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -import org.apache.commons.io.file.NoopPathVisitor; -import org.apache.commons.io.file.PathUtils; -import org.apache.commons.io.file.PathVisitor; - -/** - * A file filter backed by a path visitor. - * - * @since 2.9.0 - */ -public class PathVisitorFileFilter extends AbstractFileFilter { - - private final PathVisitor pathVisitor; - - /** - * Constructs a new instance that will forward calls to the given visitor. - * - * @param pathVisitor visit me. - */ - public PathVisitorFileFilter(final PathVisitor pathVisitor) { - this.pathVisitor = pathVisitor == null ? NoopPathVisitor.INSTANCE : pathVisitor; - } - - @Override - public boolean accept(final File file) { - try { - final Path path = file.toPath(); - return visitFile(path, - file.exists() ? PathUtils.readBasicFileAttributes(path) : null) == FileVisitResult.CONTINUE; - } catch (final IOException e) { - return handle(e) == FileVisitResult.CONTINUE; - } - } - - @Override - public boolean accept(final File dir, final String name) { - try { - final Path path = dir.toPath().resolve(name); - return accept(path, PathUtils.readBasicFileAttributes(path)) == FileVisitResult.CONTINUE; - } catch (final IOException e) { - return handle(e) == FileVisitResult.CONTINUE; - } - } - - @Override - public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { - try { - return Files.isDirectory(path) ? pathVisitor.postVisitDirectory(path, null) : visitFile(path, attributes); - } catch (final IOException e) { - return handle(e); - } - } - - @Override - public FileVisitResult visitFile(final Path path, final BasicFileAttributes attributes) throws IOException { - return pathVisitor.visitFile(path, attributes); - } - -} diff --git a/src/org/apache/commons/io/filefilter/PrefixFileFilter.java b/src/org/apache/commons/io/filefilter/PrefixFileFilter.java deleted file mode 100644 index 47de834d..00000000 --- a/src/org/apache/commons/io/filefilter/PrefixFileFilter.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.List; - -import org.apache.commons.io.IOCase; - -/** - * Filters file names for a certain prefix. - *

- * For example, to print all files and directories in the - * current directory whose name starts with {@code Test}: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(new PrefixFileFilter("Test"));
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new PrefixFileFilter("Test"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.0 - * @see FileFilterUtils#prefixFileFilter(String) - * @see FileFilterUtils#prefixFileFilter(String, IOCase) - */ -public class PrefixFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = 8533897440809599867L; - - /** The file name prefixes to search for */ - private final String[] prefixes; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new Prefix file filter for a list of prefixes. - * - * @param prefixes the prefixes to allow, must not be null - * @throws IllegalArgumentException if the prefix list is null - * @throws ClassCastException if the list does not contain Strings - */ - public PrefixFileFilter(final List prefixes) { - this(prefixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for a list of prefixes - * specifying case-sensitivity. - * - * @param prefixes the prefixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix list is null - * @throws ClassCastException if the list does not contain Strings - * @since 1.4 - */ - public PrefixFileFilter(final List prefixes, final IOCase caseSensitivity) { - if (prefixes == null) { - throw new IllegalArgumentException("The list of prefixes must not be null"); - } - this.prefixes = prefixes.toArray(EMPTY_STRING_ARRAY); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Constructs a new Prefix file filter for a single prefix. - * - * @param prefix the prefix to allow, must not be null - * @throws IllegalArgumentException if the prefix is null - */ - public PrefixFileFilter(final String prefix) { - this(prefix, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for any of an array of prefixes. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param prefixes the prefixes to allow, must not be null - * @throws IllegalArgumentException if the prefix array is null - */ - public PrefixFileFilter(final String... prefixes) { - this(prefixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Prefix file filter for a single prefix - * specifying case-sensitivity. - * - * @param prefix the prefix to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix is null - * @since 1.4 - */ - public PrefixFileFilter(final String prefix, final IOCase caseSensitivity) { - if (prefix == null) { - throw new IllegalArgumentException("The prefix must not be null"); - } - this.prefixes = new String[] {prefix}; - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Constructs a new Prefix file filter for any of an array of prefixes - * specifying case-sensitivity. - * - * @param prefixes the prefixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the prefix is null - * @since 1.4 - */ - public PrefixFileFilter(final String[] prefixes, final IOCase caseSensitivity) { - if (prefixes == null) { - throw new IllegalArgumentException("The array of prefixes must not be null"); - } - this.prefixes = new String[prefixes.length]; - System.arraycopy(prefixes, 0, this.prefixes, 0, prefixes.length); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Checks to see if the file name starts with the prefix. - * - * @param file the File to check - * @return true if the file name starts with one of our prefixes - */ - @Override - public boolean accept(final File file) { - return accept(file == null ? null : file.getName()); - } - - /** - * Checks to see if the file name starts with the prefix. - * - * @param file the File directory - * @param name the file name - * @return true if the file name starts with one of our prefixes - */ - @Override - public boolean accept(final File file, final String name) { - return accept(name); - } - - /** - * Checks to see if the file name starts with the prefix. - * @param file the File to check - * - * @return true if the file name starts with one of our prefixes - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - final Path fileName = file.getFileName(); - return toFileVisitResult(accept(fileName == null ? null : fileName.toFile()), file); - } - - private boolean accept(final String name) { - for (final String prefix : prefixes) { - if (caseSensitivity.checkStartsWith(name, prefix)) { - return true; - } - } - return false; - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - if (prefixes != null) { - for (int i = 0; i < prefixes.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(prefixes[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/RegexFileFilter.java b/src/org/apache/commons/io/filefilter/RegexFileFilter.java deleted file mode 100644 index 2a5696ee..00000000 --- a/src/org/apache/commons/io/filefilter/RegexFileFilter.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.function.Function; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOCase; - -/** - * Filters files using supplied regular expression(s). - *

- * See java.util.regex.Pattern for regex matching rules. - *

- *

Using Classic IO

- *

- * e.g. - * - *

- * File dir = new File(".");
- * FileFilter fileFilter = new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$");
- * File[] files = dir.listFiles(fileFilter);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- * - *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.4 - */ -public class RegexFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = 4269646126155225062L; - - /** - * Compiles the given pattern source. - * - * @param pattern the source pattern. - * @param flags the compilation flags. - * @return a new Pattern. - */ - private static Pattern compile(final String pattern, final int flags) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - return Pattern.compile(pattern, flags); - } - - /** - * Converts IOCase to Pattern compilation flags. - * - * @param caseSensitivity case-sensitivity. - * @return Pattern compilation flags. - */ - private static int toFlags(final IOCase caseSensitivity) { - return IOCase.isCaseSensitive(caseSensitivity) ? Pattern.CASE_INSENSITIVE : 0; - } - - /** The regular expression pattern that will be used to match file names. */ - private final Pattern pattern; - - /** How convert a path to a string. */ - private final Function pathToString; - - /** - * Constructs a new regular expression filter for a compiled regular expression - * - * @param pattern regular expression to match. - * @throws IllegalArgumentException if the pattern is null. - */ - public RegexFileFilter(final Pattern pattern) { - this(pattern, p -> p.getFileName().toString()); - } - - /** - * Constructs a new regular expression filter for a compiled regular expression - * - * @param pattern regular expression to match. - * @param pathToString How convert a path to a string. - * @throws IllegalArgumentException if the pattern is null. - * @since 2.10.0 - */ - public RegexFileFilter(final Pattern pattern, final Function pathToString) { - if (pattern == null) { - throw new IllegalArgumentException("Pattern is missing"); - } - this.pattern = pattern; - this.pathToString = pathToString; - } - - /** - * Constructs a new regular expression filter. - * - * @param pattern regular string expression to match - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(final String pattern) { - this(pattern, 0); - } - - /** - * Constructs a new regular expression filter with the specified flags. - * - * @param pattern regular string expression to match - * @param flags pattern flags - e.g. {@link Pattern#CASE_INSENSITIVE} - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(final String pattern, final int flags) { - this(compile(pattern, flags)); - } - - /** - * Constructs a new regular expression filter with the specified flags case sensitivity. - * - * @param pattern regular string expression to match - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern is null - */ - public RegexFileFilter(final String pattern, final IOCase caseSensitivity) { - this(compile(pattern, toFlags(caseSensitivity))); - } - - /** - * Checks to see if the file name matches one of the regular expressions. - * - * @param dir the file directory (ignored) - * @param name the file name - * @return true if the file name matches one of the regular expressions - */ - @Override - public boolean accept(final File dir, final String name) { - return pattern.matcher(name).matches(); - } - - /** - * Checks to see if the file name matches one of the regular expressions. - * - * @param path the path - * @param attributes the path attributes - * @return true if the file name matches one of the regular expressions - */ - @Override - public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) { - return toFileVisitResult(pattern.matcher(pathToString.apply(path)).matches(), path); - } - - /** - * Returns a debug string. - * - * @since 2.10.0 - */ - @Override - public String toString() { - return "RegexFileFilter [pattern=" + pattern + "]"; - } - -} diff --git a/src/org/apache/commons/io/filefilter/SizeFileFilter.java b/src/org/apache/commons/io/filefilter/SizeFileFilter.java deleted file mode 100644 index 6b11c5f1..00000000 --- a/src/org/apache/commons/io/filefilter/SizeFileFilter.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * Filters files based on size, can filter either smaller files or - * files equal to or larger than a given threshold. - *

- * For example, to print all files and directories in the - * current directory whose size is greater than 1 MB: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(new SizeFileFilter(1024 * 1024));
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new SizeFileFilter(1024 * 1024));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.2 - * @see FileFilterUtils#sizeFileFilter(long) - * @see FileFilterUtils#sizeFileFilter(long, boolean) - * @see FileFilterUtils#sizeRangeFileFilter(long, long) - */ -public class SizeFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = 7388077430788600069L; - - /** Whether the files accepted will be larger or smaller. */ - private final boolean acceptLarger; - - /** The size threshold. */ - private final long size; - - /** - * Constructs a new size file filter for files equal to or - * larger than a certain size. - * - * @param size the threshold size of the files - * @throws IllegalArgumentException if the size is negative - */ - public SizeFileFilter(final long size) { - this(size, true); - } - - /** - * Constructs a new size file filter for files based on a certain size - * threshold. - * - * @param size the threshold size of the files - * @param acceptLarger if true, files equal to or larger are accepted, - * otherwise smaller ones (but not equal to) - * @throws IllegalArgumentException if the size is negative - */ - public SizeFileFilter(final long size, final boolean acceptLarger) { - if (size < 0) { - throw new IllegalArgumentException("The size must be non-negative"); - } - this.size = size; - this.acceptLarger = acceptLarger; - } - - /** - * Checks to see if the size of the file is favorable. - *

- * If size equals threshold and smaller files are required, - * file IS NOT selected. - * If size equals threshold and larger files are required, - * file IS selected. - *

- * - * @param file the File to check - * @return true if the file name matches - */ - @Override - public boolean accept(final File file) { - return accept(file.length()); - } - - private boolean accept(final long length) { - return acceptLarger != length < size; - } - - /** - * Checks to see if the size of the file is favorable. - *

- * If size equals threshold and smaller files are required, - * file IS NOT selected. - * If size equals threshold and larger files are required, - * file IS selected. - *

- * @param file the File to check - * - * @return true if the file name matches - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - try { - return toFileVisitResult(accept(Files.size(file)), file); - } catch (final IOException e) { - return handle(e); - } - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final String condition = acceptLarger ? ">=" : "<"; - return super.toString() + "(" + condition + size + ")"; - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - return toFileVisitResult(accept(Files.size(file)), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/SuffixFileFilter.java b/src/org/apache/commons/io/filefilter/SuffixFileFilter.java deleted file mode 100644 index 94a91fe2..00000000 --- a/src/org/apache/commons/io/filefilter/SuffixFileFilter.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.IOCase; - -/** - * Filters files based on the suffix (what the file name ends with). - * This is used in retrieving all the files of a particular type. - *

- * For example, to retrieve and print all {@code *.java} files - * in the current directory: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(new SuffixFileFilter(".java"));
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new SuffixFileFilter(".java"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.0 - * @see FileFilterUtils#suffixFileFilter(String) - * @see FileFilterUtils#suffixFileFilter(String, IOCase) - */ -public class SuffixFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = -3389157631240246157L; - - /** The file name suffixes to search for */ - private final String[] suffixes; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Constructs a new Suffix file filter for a list of suffixes. - * - * @param suffixes the suffixes to allow, must not be null - * @throws IllegalArgumentException if the suffix list is null - * @throws ClassCastException if the list does not contain Strings - */ - public SuffixFileFilter(final List suffixes) { - this(suffixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for a list of suffixes - * specifying case-sensitivity. - * - * @param suffixes the suffixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix list is null - * @throws ClassCastException if the list does not contain Strings - * @since 1.4 - */ - public SuffixFileFilter(final List suffixes, final IOCase caseSensitivity) { - if (suffixes == null) { - throw new IllegalArgumentException("The list of suffixes must not be null"); - } - this.suffixes = suffixes.toArray(EMPTY_STRING_ARRAY); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Constructs a new Suffix file filter for a single extension. - * - * @param suffix the suffix to allow, must not be null - * @throws IllegalArgumentException if the suffix is null - */ - public SuffixFileFilter(final String suffix) { - this(suffix, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for an array of suffixes. - *

- * The array is not cloned, so could be changed after constructing the - * instance. This would be inadvisable however. - * - * @param suffixes the suffixes to allow, must not be null - * @throws IllegalArgumentException if the suffix array is null - */ - public SuffixFileFilter(final String... suffixes) { - this(suffixes, IOCase.SENSITIVE); - } - - /** - * Constructs a new Suffix file filter for a single extension - * specifying case-sensitivity. - * - * @param suffix the suffix to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix is null - * @since 1.4 - */ - public SuffixFileFilter(final String suffix, final IOCase caseSensitivity) { - if (suffix == null) { - throw new IllegalArgumentException("The suffix must not be null"); - } - this.suffixes = new String[] {suffix}; - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Constructs a new Suffix file filter for an array of suffixes - * specifying case-sensitivity. - * - * @param suffixes the suffixes to allow, must not be null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the suffix array is null - * @since 1.4 - */ - public SuffixFileFilter(final String[] suffixes, final IOCase caseSensitivity) { - if (suffixes == null) { - throw new IllegalArgumentException("The array of suffixes must not be null"); - } - this.suffixes = new String[suffixes.length]; - System.arraycopy(suffixes, 0, this.suffixes, 0, suffixes.length); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Checks to see if the file name ends with the suffix. - * - * @param file the File to check - * @return true if the file name ends with one of our suffixes - */ - @Override - public boolean accept(final File file) { - return accept(file.getName()); - } - - /** - * Checks to see if the file name ends with the suffix. - * - * @param file the File directory - * @param name the file name - * @return true if the file name ends with one of our suffixes - */ - @Override - public boolean accept(final File file, final String name) { - return accept(name); - } - - /** - * Checks to see if the file name ends with the suffix. - * @param file the File to check - * - * @return true if the file name ends with one of our suffixes - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(accept(Objects.toString(file.getFileName(), null)), file); - } - - private boolean accept(final String name) { - for (final String suffix : this.suffixes) { - if (caseSensitivity.checkEndsWith(name, suffix)) { - return true; - } - } - return false; - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - if (suffixes != null) { - for (int i = 0; i < suffixes.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(suffixes[i]); - } - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/SymbolicLinkFileFilter.java b/src/org/apache/commons/io/filefilter/SymbolicLinkFileFilter.java deleted file mode 100644 index 3697766e..00000000 --- a/src/org/apache/commons/io/filefilter/SymbolicLinkFileFilter.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * This filter accepts {@code File}s that are symbolic links. - *

- * For example, here is how to print out a list of the real files - * within the current directory: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * String[] files = dir.list(SymbolicLinkFileFilter.INSTANCE);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(SymbolicLinkFileFilter.FILE);
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 2.11.0 - * @see FileFilterUtils#fileFileFilter() - */ -public class SymbolicLinkFileFilter extends AbstractFileFilter implements Serializable { - - /** - * Singleton instance of file filter. - */ - public static final SymbolicLinkFileFilter INSTANCE = new SymbolicLinkFileFilter(); - - private static final long serialVersionUID = 1L; - - /** - * Restrictive constructor. - */ - protected SymbolicLinkFileFilter() { - } - - /** - * Checks to see if the file is a file. - * - * @param file the File to check - * @return true if the file is a file - */ - @Override - public boolean accept(final File file) { - return file.isFile(); - } - - /** - * Checks to see if the file is a file. - * @param file the File to check - * - * @return true if the file is a file - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(Files.isSymbolicLink(file), file); - } - -} diff --git a/src/org/apache/commons/io/filefilter/TrueFileFilter.java b/src/org/apache/commons/io/filefilter/TrueFileFilter.java deleted file mode 100644 index a3fa9fde..00000000 --- a/src/org/apache/commons/io/filefilter/TrueFileFilter.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * A file filter that always returns true. - * - * @since 1.0 - * @see FileFilterUtils#trueFileFilter() - */ -public class TrueFileFilter implements IOFileFilter, Serializable { - - private static final String TO_STRING = Boolean.TRUE.toString(); - - private static final long serialVersionUID = 8782512160909720199L; - - /** - * Singleton instance of true filter. - * - * @since 1.3 - */ - public static final IOFileFilter TRUE = new TrueFileFilter(); - - /** - * Singleton instance of true filter. Please use the identical TrueFileFilter.TRUE constant. The new name is more - * JDK 1.5 friendly as it doesn't clash with other values when using static imports. - */ - public static final IOFileFilter INSTANCE = TRUE; - - /** - * Restrictive constructor. - */ - protected TrueFileFilter() { - } - - /** - * Returns true. - * - * @param file the file to check (ignored) - * @return true - */ - @Override - public boolean accept(final File file) { - return true; - } - - /** - * Returns true. - * - * @param dir the directory to check (ignored) - * @param name the file name (ignored) - * @return true - */ - @Override - public boolean accept(final File dir, final String name) { - return true; - } - - /** - * Returns true. - * @param file the file to check (ignored) - * - * @return true - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return FileVisitResult.CONTINUE; - } - - @Override - public IOFileFilter negate() { - return FalseFileFilter.INSTANCE; - } - - @Override - public IOFileFilter or(final IOFileFilter fileFilter) { - // TRUE OR expression <=> true - return INSTANCE; - } - - @Override - public IOFileFilter and(final IOFileFilter fileFilter) { - // TRUE AND expression <=> expression - return fileFilter; - } - - @Override - public String toString() { - return TO_STRING; - } -} diff --git a/src/org/apache/commons/io/filefilter/WildcardFileFilter.java b/src/org/apache/commons/io/filefilter/WildcardFileFilter.java deleted file mode 100644 index daa80de6..00000000 --- a/src/org/apache/commons/io/filefilter/WildcardFileFilter.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOCase; - -/** - * Filters files using the supplied wildcards. - *

- * This filter selects files and directories based on one or more wildcards. - * Testing is case-sensitive by default, but this can be configured. - *

- *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The check is case-sensitive by default. - * See {@link FilenameUtils#wildcardMatchOnSystem(String,String)} for more information. - *

- *

- * For example: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * FileFilter fileFilter = new WildcardFileFilter("*test*.java~*~");
- * File[] files = dir.listFiles(fileFilter);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new WildcardFileFilter("*test*.java~*~"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.3 - */ -public class WildcardFileFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = -7426486598995782105L; - - /** The wildcards that will be used to match file names. */ - private final String[] wildcards; - - /** Whether the comparison is case sensitive. */ - private final IOCase caseSensitivity; - - /** - * Construct a new case-sensitive wildcard filter for a list of wildcards. - * - * @param wildcards the list of wildcards to match, not null - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFileFilter(final List wildcards) { - this(wildcards, IOCase.SENSITIVE); - } - - /** - * Construct a new wildcard filter for a list of wildcards specifying case-sensitivity. - * - * @param wildcards the list of wildcards to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFileFilter(final List wildcards, final IOCase caseSensitivity) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard list must not be null"); - } - this.wildcards = wildcards.toArray(EMPTY_STRING_ARRAY); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Construct a new case-sensitive wildcard filter for a single wildcard. - * - * @param wildcard the wildcard to match - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFileFilter(final String wildcard) { - this(wildcard, IOCase.SENSITIVE); - } - - /** - * Construct a new case-sensitive wildcard filter for an array of wildcards. - *

- * - * @param wildcards the array of wildcards to match - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFileFilter(final String... wildcards) { - this(wildcards, IOCase.SENSITIVE); - } - - /** - * Construct a new wildcard filter for a single wildcard specifying case-sensitivity. - * - * @param wildcard the wildcard to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFileFilter(final String wildcard, final IOCase caseSensitivity) { - if (wildcard == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.wildcards = new String[] { wildcard }; - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Construct a new wildcard filter for an array of wildcards specifying case-sensitivity. - *

- * - * @param wildcards the array of wildcards to match, not null - * @param caseSensitivity how to handle case sensitivity, null means case-sensitive - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFileFilter(final String[] wildcards, final IOCase caseSensitivity) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard array must not be null"); - } - this.wildcards = new String[wildcards.length]; - System.arraycopy(wildcards, 0, this.wildcards, 0, wildcards.length); - this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity; - } - - /** - * Checks to see if the file name matches one of the wildcards. - * - * @param file the file to check - * @return true if the file name matches one of the wildcards - */ - @Override - public boolean accept(final File file) { - return accept(file.getName()); - } - - /** - * Checks to see if the file name matches one of the wildcards. - * - * @param dir the file directory (ignored) - * @param name the file name - * @return true if the file name matches one of the wildcards - */ - @Override - public boolean accept(final File dir, final String name) { - return accept(name); - } - - /** - * Checks to see if the file name matches one of the wildcards. - * @param file the file to check - * - * @return true if the file name matches one of the wildcards. - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - return toFileVisitResult(accept(Objects.toString(file.getFileName(), null)), file); - } - - private boolean accept(final String name) { - for (final String wildcard : wildcards) { - if (FilenameUtils.wildcardMatch(name, wildcard, caseSensitivity)) { - return true; - } - } - return false; - } - - /** - * Provide a String representation of this file filter. - * - * @return a String representation - */ - @Override - public String toString() { - final StringBuilder buffer = new StringBuilder(); - buffer.append(super.toString()); - buffer.append("("); - for (int i = 0; i < wildcards.length; i++) { - if (i > 0) { - buffer.append(","); - } - buffer.append(wildcards[i]); - } - buffer.append(")"); - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/io/filefilter/WildcardFilter.java b/src/org/apache/commons/io/filefilter/WildcardFilter.java deleted file mode 100644 index abd8f422..00000000 --- a/src/org/apache/commons/io/filefilter/WildcardFilter.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.filefilter; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.io.FilenameUtils; - -/** - * Filters files using the supplied wildcards. - *

- * This filter selects files, but not directories, based on one or more wildcards - * and using case-sensitive comparison. - *

- *

- * The wildcard matcher uses the characters '?' and '*' to represent a - * single or multiple wildcard characters. - * This is the same as often found on Dos/Unix command lines. - * The extension check is case-sensitive. - * See {@link FilenameUtils#wildcardMatch(String, String)} for more information. - *

- *

- * For example: - *

- *

Using Classic IO

- *
- * File dir = new File(".");
- * FileFilter fileFilter = new WildcardFilter("*test*.java~*~");
- * File[] files = dir.listFiles(fileFilter);
- * for (String file : files) {
- *     System.out.println(file);
- * }
- * 
- * - *

Using NIO

- *
- * final Path dir = Paths.get("");
- * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new WildcardFilter("*test*.java~*~"));
- * //
- * // Walk one dir
- * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getFileList());
- * //
- * visitor.getPathCounters().reset();
- * //
- * // Walk dir tree
- * Files.walkFileTree(dir, visitor);
- * System.out.println(visitor.getPathCounters());
- * System.out.println(visitor.getDirList());
- * System.out.println(visitor.getFileList());
- * 
- * - * @since 1.1 - * @deprecated Use WildcardFileFilter. Deprecated as this class performs directory - * filtering which it shouldn't do, but that can't be removed due to compatibility. - */ -@Deprecated -public class WildcardFilter extends AbstractFileFilter implements Serializable { - - private static final long serialVersionUID = -5037645902506953517L; - /** The wildcards that will be used to match file names. */ - private final String[] wildcards; - - /** - * Construct a new case-sensitive wildcard filter for a list of wildcards. - * - * @param wildcards the list of wildcards to match - * @throws IllegalArgumentException if the pattern list is null - * @throws ClassCastException if the list does not contain Strings - */ - public WildcardFilter(final List wildcards) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard list must not be null"); - } - this.wildcards = wildcards.toArray(EMPTY_STRING_ARRAY); - } - - /** - * Construct a new case-sensitive wildcard filter for a single wildcard. - * - * @param wildcard the wildcard to match - * @throws IllegalArgumentException if the pattern is null - */ - public WildcardFilter(final String wildcard) { - if (wildcard == null) { - throw new IllegalArgumentException("The wildcard must not be null"); - } - this.wildcards = new String[] { wildcard }; - } - - /** - * Construct a new case-sensitive wildcard filter for an array of wildcards. - * - * @param wildcards the array of wildcards to match - * @throws IllegalArgumentException if the pattern array is null - */ - public WildcardFilter(final String... wildcards) { - if (wildcards == null) { - throw new IllegalArgumentException("The wildcard array must not be null"); - } - this.wildcards = new String[wildcards.length]; - System.arraycopy(wildcards, 0, this.wildcards, 0, wildcards.length); - } - - /** - * Checks to see if the file name matches one of the wildcards. - * - * @param file the file to check - * @return true if the file name matches one of the wildcards - */ - @Override - public boolean accept(final File file) { - if (file.isDirectory()) { - return false; - } - - for (final String wildcard : wildcards) { - if (FilenameUtils.wildcardMatch(file.getName(), wildcard)) { - return true; - } - } - - return false; - } - - /** - * Checks to see if the file name matches one of the wildcards. - * @param file the file to check - * - * @return true if the file name matches one of the wildcards - * @since 2.9.0 - */ - @Override - public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) { - if (Files.isDirectory(file)) { - return FileVisitResult.TERMINATE; - } - - for (final String wildcard : wildcards) { - if (FilenameUtils.wildcardMatch(Objects.toString(file.getFileName(), null), wildcard)) { - return FileVisitResult.CONTINUE; - } - } - - return FileVisitResult.TERMINATE; - } - - /** - * Checks to see if the file name matches one of the wildcards. - * - * @param dir the file directory - * @param name the file name - * @return true if the file name matches one of the wildcards - */ - @Override - public boolean accept(final File dir, final String name) { - if (dir != null && new File(dir, name).isDirectory()) { - return false; - } - - for (final String wildcard : wildcards) { - if (FilenameUtils.wildcardMatch(name, wildcard)) { - return true; - } - } - - return false; - } - -} diff --git a/src/org/apache/commons/io/filefilter/package.html b/src/org/apache/commons/io/filefilter/package.html deleted file mode 100644 index e32a192f..00000000 --- a/src/org/apache/commons/io/filefilter/package.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - -

This package defines an interface (IOFileFilter) that combines both -{@link java.io.FileFilter} and {@link java.io.FilenameFilter}. Besides -that the package offers a series of ready-to-use implementations of the -IOFileFilter interface including implementation that allow you to combine -other such filters.

-

These filter can be used to list files or in {@link java.awt.FileDialog}, -for example.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
There are a number of 'primitive' filters:
DirectoryFilterOnly accept directories
PrefixFileFilterFilter based on a prefix
SuffixFileFilterFilter based on a suffix
NameFileFilterFilter based on a filename
WildcardFileFilterFilter based on wildcards
AgeFileFilterFilter based on last modified time of file
SizeFileFilterFilter based on file size
- - - - - - - - - - - - - - - - - - - - - - - - - -
And there are five 'boolean' filters:
TrueFileFilterAccept all files
FalseFileFilterAccept no files
NotFileFilterApplies a logical NOT to an existing filter
AndFileFilterCombines two filters using a logical AND
OrFileFilterCombines two filter using a logical OR
- -

These boolean FilenameFilters can be nested, to allow arbitrary expressions. -For example, here is how one could print all non-directory files in the -current directory, starting with "A", and ending in ".java" or ".class":

- -
-  File dir = new File(".");
-  String[] files = dir.list( 
-    new AndFileFilter(
-      new AndFileFilter(
-        new PrefixFileFilter("A"),
-        new OrFileFilter(
-          new SuffixFileFilter(".class"),
-          new SuffixFileFilter(".java")
-        )
-      ),
-      new NotFileFilter(
-        new DirectoryFileFilter()
-      )
-    )
-  );
-  for ( int i=0; i<files.length; i++ ) {
-    System.out.println(files[i]);
-  }
-
- -

This package also contains a utility class: -FileFilterUtils. It allows you to use all -file filters without having to put them in the import section. Here's how the -above example will look using FileFilterUtils:

-
-  File dir = new File(".");
-  String[] files = dir.list( 
-    FileFilterUtils.andFileFilter(
-      FileFilterUtils.andFileFilter(
-        FileFilterUtils.prefixFileFilter("A"),
-        FileFilterUtils.orFileFilter(
-          FileFilterUtils.suffixFileFilter(".class"),
-          FileFilterUtils.suffixFileFilter(".java")
-        )
-      ),
-      FileFilterUtils.notFileFilter(
-        FileFilterUtils.directoryFileFilter()
-      )
-    )
-  );
-  for ( int i=0; i<files.length; i++ ) {
-    System.out.println(files[i]);
-  }
-
-

There are a few other goodies in that class so please have a look at the -documentation in detail.

- - diff --git a/src/org/apache/commons/io/function/IOConsumer.java b/src/org/apache/commons/io/function/IOConsumer.java deleted file mode 100644 index 37031daf..00000000 --- a/src/org/apache/commons/io/function/IOConsumer.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.function; - -import java.io.IOException; -import java.util.Objects; -import java.util.function.Consumer; - -/** - * Like {@link Consumer} but throws {@link IOException}. - * - * @param the type of the input to the operations. - * @since 2.7 - */ -@FunctionalInterface -public interface IOConsumer { - - /** - * Package private constant; consider private. - */ - IOConsumer NOOP_IO_CONSUMER = t -> {/* noop */}; - - /** - * Returns a constant NOOP consumer. - * - * @param Type consumer type. - * @return a constant NOOP consumer. - * @since 2.9.0 - */ - @SuppressWarnings("unchecked") - static IOConsumer noop() { - return (IOConsumer) NOOP_IO_CONSUMER; - } - - /** - * Performs this operation on the given argument. - * - * @param t the input argument - * @throws IOException if an I/O error occurs. - */ - void accept(T t) throws IOException; - - /** - * Returns a composed {@code IoConsumer} that performs, in sequence, this operation followed by the {@code after} - * operation. If performing either operation throws an exception, it is relayed to the caller of the composed - * operation. If performing this operation throws an exception, the {@code after} operation will not be performed. - * - * @param after the operation to perform after this operation - * @return a composed {@code Consumer} that performs in sequence this operation followed by the {@code after} - * operation - * @throws NullPointerException if {@code after} is null - */ - default IOConsumer andThen(final IOConsumer after) { - Objects.requireNonNull(after, "after"); - return (final T t) -> { - accept(t); - after.accept(t); - }; - } -} diff --git a/src/org/apache/commons/io/function/IOFunction.java b/src/org/apache/commons/io/function/IOFunction.java deleted file mode 100644 index 4129f57a..00000000 --- a/src/org/apache/commons/io/function/IOFunction.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.function; - -import java.io.IOException; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Like {@link Function} but throws {@link IOException}. - * - * @param the type of the input to the operations. - * @param the return type of the operations. - * @since 2.7 - */ -@FunctionalInterface -public interface IOFunction { - - /** - * Applies this function to the given argument. - * - * @param t the function argument - * @return the function result - * - * @throws IOException if the function throws an IOException - */ - R apply(final T t) throws IOException; - - /** - * Returns a composed {@link IOFunction} that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the type of input to the {@code before} function, and to the - * composed function - * @param before the function to apply before this function is applied - * @return a composed function that first applies the {@code before} - * function and then applies this function - * @throws NullPointerException if before is null - * - * @see #andThen(IOFunction) - */ - default IOFunction compose(final IOFunction before) { - Objects.requireNonNull(before, "before"); - return (final V v) -> apply(before.apply(v)); - } - - /** - * Returns a composed {@link IOFunction} that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the type of input to the {@code before} function, and to the - * composed function - * @param before the function to apply before this function is applied - * @return a composed function that first applies the {@code before} - * function and then applies this function - * @throws NullPointerException if before is null - * - * @see #andThen(IOFunction) - */ - default IOFunction compose(final Function before) { - Objects.requireNonNull(before, "before"); - return (final V v) -> apply(before.apply(v)); - } - - /** - * Returns a composed {@link IOFunction} that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the supplier which feeds the application of this function - * @return a composed function that first applies the {@code before} - * function and then applies this function - * @throws NullPointerException if before is null - * - * @see #andThen(IOFunction) - */ - default IOSupplier compose(final IOSupplier before) { - Objects.requireNonNull(before, "before"); - return () -> apply(before.get()); - } - - /** - * Returns a composed {@link IOFunction} that first applies the {@code before} - * function to its input, and then applies this function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param before the supplier which feeds the application of this function - * @return a composed function that first applies the {@code before} - * function and then applies this function - * @throws NullPointerException if before is null - * - * @see #andThen(IOFunction) - */ - default IOSupplier compose(final Supplier before) { - Objects.requireNonNull(before, "before"); - return () -> apply(before.get()); - } - - /** - * Returns a composed {@link IOFunction} that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the type of output of the {@code after} function, and of the - * composed function - * @param after the function to apply after this function is applied - * @return a composed function that first applies this function and then - * applies the {@code after} function - * @throws NullPointerException if after is null - * - * @see #compose(IOFunction) - */ - default IOFunction andThen(final IOFunction after) { - Objects.requireNonNull(after, "after"); - return (final T t) -> after.apply(apply(t)); - } - - /** - * Returns a composed {@link IOFunction} that first applies this function to - * its input, and then applies the {@code after} function to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param the type of output of the {@code after} function, and of the - * composed function - * @param after the function to apply after this function is applied - * @return a composed function that first applies this function and then - * applies the {@code after} function - * @throws NullPointerException if after is null - * - * @see #compose(IOFunction) - */ - default IOFunction andThen(final Function after) { - Objects.requireNonNull(after, "after"); - return (final T t) -> after.apply(apply(t)); - } - - /** - * Returns a composed {@link IOFunction} that first applies this function to - * its input, and then applies the {@code after} consumer to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the consumer to apply after this function is applied - * @return a composed function that first applies this function and then - * applies the {@code after} consumer - * @throws NullPointerException if after is null - * - * @see #compose(IOFunction) - */ - default IOConsumer andThen(final IOConsumer after) { - Objects.requireNonNull(after, "after"); - return (final T t) -> after.accept(apply(t)); - } - - /** - * Returns a composed {@link IOFunction} that first applies this function to - * its input, and then applies the {@code after} consumer to the result. - * If evaluation of either function throws an exception, it is relayed to - * the caller of the composed function. - * - * @param after the consumer to apply after this function is applied - * @return a composed function that first applies this function and then - * applies the {@code after} consumer - * @throws NullPointerException if after is null - * - * @see #compose(IOFunction) - */ - default IOConsumer andThen(final Consumer after) { - Objects.requireNonNull(after, "after"); - return (final T t) -> after.accept(apply(t)); - } - - /** - * Returns a {@link IOFunction} that always returns its input argument. - * - * @param the type of the input and output objects to the function - * @return a function that always returns its input argument - */ - static IOFunction identity() { - return t -> t; - } -} diff --git a/src/org/apache/commons/io/function/IOSupplier.java b/src/org/apache/commons/io/function/IOSupplier.java deleted file mode 100644 index 5dc7dcb7..00000000 --- a/src/org/apache/commons/io/function/IOSupplier.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.function; - -import java.io.IOException; -import java.util.function.Supplier; - -/** - * Like {@link Supplier} but throws {@link IOException}. - * - * @param the return type of the operations. - * @since 2.7 - */ -@FunctionalInterface -public interface IOSupplier { - - /** - * Gets a result. - * - * @return a result - * - * @throws IOException if an IO error occurs whilst supplying the value. - */ - T get() throws IOException; -} diff --git a/src/org/apache/commons/io/input/AbstractCharacterFilterReader.java b/src/org/apache/commons/io/input/AbstractCharacterFilterReader.java deleted file mode 100644 index bc93cc14..00000000 --- a/src/org/apache/commons/io/input/AbstractCharacterFilterReader.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.FilterReader; -import java.io.IOException; -import java.io.Reader; -import java.util.function.IntPredicate; - -/** - * A filter reader that filters out characters where subclasses decide which characters to filter out. - */ -public abstract class AbstractCharacterFilterReader extends FilterReader { - - /** - * Skips nothing. - * - * @since 2.9.0 - */ - protected static final IntPredicate SKIP_NONE = ch -> false; - - private final IntPredicate skip; - - /** - * Constructs a new reader. - * - * @param reader the reader to filter - */ - protected AbstractCharacterFilterReader(final Reader reader) { - this(reader, SKIP_NONE); - } - - /** - * Constructs a new reader. - * - * @param reader the reader to filter. - * @param skip Skip test. - * @since 2.9.0 - */ - protected AbstractCharacterFilterReader(final Reader reader, final IntPredicate skip) { - super(reader); - this.skip = skip == null ? SKIP_NONE : skip; - } - - /** - * Returns true if the given character should be filtered out, false to keep the character. - * - * @param ch the character to test. - * @return true if the given character should be filtered out, false to keep the character. - */ - protected boolean filter(final int ch) { - return skip.test(ch); - } - - @Override - public int read() throws IOException { - int ch; - do { - ch = in.read(); - } while (ch != EOF && filter(ch)); - return ch; - } - - @Override - public int read(final char[] cbuf, final int off, final int len) throws IOException { - final int read = super.read(cbuf, off, len); - if (read == EOF) { - return EOF; - } - int pos = off - 1; - for (int readPos = off; readPos < off + read; readPos++) { - if (filter(cbuf[readPos])) { - continue; - } - pos++; - if (pos < readPos) { - cbuf[pos] = cbuf[readPos]; - } - } - return pos - off + 1; - } -} diff --git a/src/org/apache/commons/io/input/AutoCloseInputStream.java b/src/org/apache/commons/io/input/AutoCloseInputStream.java deleted file mode 100644 index 3b39ae2b..00000000 --- a/src/org/apache/commons/io/input/AutoCloseInputStream.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Proxy stream that closes and discards the underlying stream as soon as the - * end of input has been reached or when the stream is explicitly closed. - * Not even a reference to the underlying stream is kept after it has been - * closed, so any allocated in-memory buffers can be freed even if the - * client application still keeps a reference to the proxy stream. - *

- * This class is typically used to release any resources related to an open - * stream as soon as possible even if the client application (by not explicitly - * closing the stream when no longer needed) or the underlying stream (by not - * releasing resources once the last byte has been read) do not do that. - *

- * - * @since 1.4 - */ -public class AutoCloseInputStream extends ProxyInputStream { - - /** - * Creates an automatically closing proxy for the given input stream. - * - * @param in underlying input stream - */ - public AutoCloseInputStream(final InputStream in) { - super(in); - } - - /** - * Closes the underlying input stream and replaces the reference to it - * with a {@link ClosedInputStream} instance. - *

- * This method is automatically called by the read methods when the end - * of input has been reached. - *

- * Note that it is safe to call this method any number of times. The original - * underlying input stream is closed and discarded only once when this - * method is first called. - * - * @throws IOException if the underlying input stream can not be closed - */ - @Override - public void close() throws IOException { - in.close(); - in = ClosedInputStream.CLOSED_INPUT_STREAM; - } - - /** - * Automatically closes the stream if the end of stream was reached. - * - * @param n number of bytes read, or -1 if no more bytes are available - * @throws IOException if the stream could not be closed - * @since 2.0 - */ - @Override - protected void afterRead(final int n) throws IOException { - if (n == EOF) { - close(); - } - } - - /** - * Ensures that the stream is closed before it gets garbage-collected. - * As mentioned in {@link #close()}, this is a no-op if the stream has - * already been closed. - * @throws Throwable if an error occurs - */ - @SuppressWarnings("deprecation") - @Override - protected void finalize() throws Throwable { - close(); - super.finalize(); - } - -} diff --git a/src/org/apache/commons/io/input/BOMInputStream.java b/src/org/apache/commons/io/input/BOMInputStream.java deleted file mode 100644 index 5b2d037e..00000000 --- a/src/org/apache/commons/io/input/BOMInputStream.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.IOUtils; - -/** - * This class is used to wrap a stream that includes an encoded {@link ByteOrderMark} as its first bytes. - *

- * This class detects these bytes and, if required, can automatically skip them and return the subsequent byte as the - * first byte in the stream. - *

- *

- * The {@link ByteOrderMark} implementation has the following pre-defined BOMs: - *

- *
    - *
  • UTF-8 - {@link ByteOrderMark#UTF_8}
  • - *
  • UTF-16BE - {@link ByteOrderMark#UTF_16LE}
  • - *
  • UTF-16LE - {@link ByteOrderMark#UTF_16BE}
  • - *
  • UTF-32BE - {@link ByteOrderMark#UTF_32LE}
  • - *
  • UTF-32LE - {@link ByteOrderMark#UTF_32BE}
  • - *
- * - *

Example 1 - Detect and exclude a UTF-8 BOM

- * - *
- * BOMInputStream bomIn = new BOMInputStream(in);
- * if (bomIn.hasBOM()) {
- *     // has a UTF-8 BOM
- * }
- * 
- * - *

Example 2 - Detect a UTF-8 BOM (but don't exclude it)

- * - *
- * boolean include = true;
- * BOMInputStream bomIn = new BOMInputStream(in, include);
- * if (bomIn.hasBOM()) {
- *     // has a UTF-8 BOM
- * }
- * 
- * - *

Example 3 - Detect Multiple BOMs

- * - *
- * BOMInputStream bomIn = new BOMInputStream(in,
- *   ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE,
- *   ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE
- *   );
- * if (bomIn.hasBOM() == false) {
- *     // No BOM found
- * } else if (bomIn.hasBOM(ByteOrderMark.UTF_16LE)) {
- *     // has a UTF-16LE BOM
- * } else if (bomIn.hasBOM(ByteOrderMark.UTF_16BE)) {
- *     // has a UTF-16BE BOM
- * } else if (bomIn.hasBOM(ByteOrderMark.UTF_32LE)) {
- *     // has a UTF-32LE BOM
- * } else if (bomIn.hasBOM(ByteOrderMark.UTF_32BE)) {
- *     // has a UTF-32BE BOM
- * }
- * 
- * - * @see org.apache.commons.io.ByteOrderMark - * @see Wikipedia - Byte Order Mark - * @since 2.0 - */ -public class BOMInputStream extends ProxyInputStream { - private final boolean include; - /** - * BOMs are sorted from longest to shortest. - */ - private final List boms; - private ByteOrderMark byteOrderMark; - private int[] firstBytes; - private int fbLength; - private int fbIndex; - private int markFbIndex; - private boolean markedAtStart; - - /** - * Constructs a new BOM InputStream that excludes a {@link ByteOrderMark#UTF_8} BOM. - * - * @param delegate - * the InputStream to delegate to - */ - public BOMInputStream(final InputStream delegate) { - this(delegate, false, ByteOrderMark.UTF_8); - } - - /** - * Constructs a new BOM InputStream that detects a a {@link ByteOrderMark#UTF_8} and optionally includes it. - * - * @param delegate - * the InputStream to delegate to - * @param include - * true to include the UTF-8 BOM or false to exclude it - */ - public BOMInputStream(final InputStream delegate, final boolean include) { - this(delegate, include, ByteOrderMark.UTF_8); - } - - /** - * Constructs a new BOM InputStream that excludes the specified BOMs. - * - * @param delegate - * the InputStream to delegate to - * @param boms - * The BOMs to detect and exclude - */ - public BOMInputStream(final InputStream delegate, final ByteOrderMark... boms) { - this(delegate, false, boms); - } - - /** - * Compares ByteOrderMark objects in descending length order. - */ - private static final Comparator ByteOrderMarkLengthComparator = (bom1, bom2) -> { - final int len1 = bom1.length(); - final int len2 = bom2.length(); - return Integer.compare(len2, len1); - }; - - /** - * Constructs a new BOM InputStream that detects the specified BOMs and optionally includes them. - * - * @param delegate - * the InputStream to delegate to - * @param include - * true to include the specified BOMs or false to exclude them - * @param boms - * The BOMs to detect and optionally exclude - */ - public BOMInputStream(final InputStream delegate, final boolean include, final ByteOrderMark... boms) { - super(delegate); - if (IOUtils.length(boms) == 0) { - throw new IllegalArgumentException("No BOMs specified"); - } - this.include = include; - final List list = Arrays.asList(boms); - // Sort the BOMs to match the longest BOM first because some BOMs have the same starting two bytes. - list.sort(ByteOrderMarkLengthComparator); - this.boms = list; - - } - - /** - * Indicates whether the stream contains one of the specified BOMs. - * - * @return true if the stream has one of the specified BOMs, otherwise false if it does not - * @throws IOException - * if an error reading the first bytes of the stream occurs - */ - public boolean hasBOM() throws IOException { - return getBOM() != null; - } - - /** - * Indicates whether the stream contains the specified BOM. - * - * @param bom - * The BOM to check for - * @return true if the stream has the specified BOM, otherwise false if it does not - * @throws IllegalArgumentException - * if the BOM is not one the stream is configured to detect - * @throws IOException - * if an error reading the first bytes of the stream occurs - */ - public boolean hasBOM(final ByteOrderMark bom) throws IOException { - if (!boms.contains(bom)) { - throw new IllegalArgumentException("Stream not configure to detect " + bom); - } - getBOM(); - return byteOrderMark != null && byteOrderMark.equals(bom); - } - - /** - * Return the BOM (Byte Order Mark). - * - * @return The BOM or null if none - * @throws IOException - * if an error reading the first bytes of the stream occurs - */ - public ByteOrderMark getBOM() throws IOException { - if (firstBytes == null) { - fbLength = 0; - // BOMs are sorted from longest to shortest - final int maxBomSize = boms.get(0).length(); - firstBytes = new int[maxBomSize]; - // Read first maxBomSize bytes - for (int i = 0; i < firstBytes.length; i++) { - firstBytes[i] = in.read(); - fbLength++; - if (firstBytes[i] < 0) { - break; - } - } - // match BOM in firstBytes - byteOrderMark = find(); - if ((byteOrderMark != null) && !include) { - if (byteOrderMark.length() < firstBytes.length) { - fbIndex = byteOrderMark.length(); - } else { - fbLength = 0; - } - } - } - return byteOrderMark; - } - - /** - * Return the BOM charset Name - {@link ByteOrderMark#getCharsetName()}. - * - * @return The BOM charset Name or null if no BOM found - * @throws IOException - * if an error reading the first bytes of the stream occurs - * - */ - public String getBOMCharsetName() throws IOException { - getBOM(); - return byteOrderMark == null ? null : byteOrderMark.getCharsetName(); - } - - /** - * This method reads and either preserves or skips the first bytes in the stream. It behaves like the single-byte - * {@code read()} method, either returning a valid byte or -1 to indicate that the initial bytes have been - * processed already. - * - * @return the byte read (excluding BOM) or -1 if the end of stream - * @throws IOException - * if an I/O error occurs - */ - private int readFirstBytes() throws IOException { - getBOM(); - return fbIndex < fbLength ? firstBytes[fbIndex++] : EOF; - } - - /** - * Find a BOM with the specified bytes. - * - * @return The matched BOM or null if none matched - */ - private ByteOrderMark find() { - for (final ByteOrderMark bom : boms) { - if (matches(bom)) { - return bom; - } - } - return null; - } - - /** - * Check if the bytes match a BOM. - * - * @param bom - * The BOM - * @return true if the bytes match the bom, otherwise false - */ - private boolean matches(final ByteOrderMark bom) { - // if (bom.length() != fbLength) { - // return false; - // } - // firstBytes may be bigger than the BOM bytes - for (int i = 0; i < bom.length(); i++) { - if (bom.get(i) != firstBytes[i]) { - return false; - } - } - return true; - } - - // ---------------------------------------------------------------------------- - // Implementation of InputStream - // ---------------------------------------------------------------------------- - - /** - * Invokes the delegate's {@code read()} method, detecting and optionally skipping BOM. - * - * @return the byte read (excluding BOM) or -1 if the end of stream - * @throws IOException - * if an I/O error occurs - */ - @Override - public int read() throws IOException { - final int b = readFirstBytes(); - return b >= 0 ? b : in.read(); - } - - /** - * Invokes the delegate's {@code read(byte[], int, int)} method, detecting and optionally skipping BOM. - * - * @param buf - * the buffer to read the bytes into - * @param off - * The start offset - * @param len - * The number of bytes to read (excluding BOM) - * @return the number of bytes read or -1 if the end of stream - * @throws IOException - * if an I/O error occurs - */ - @Override - public int read(final byte[] buf, int off, int len) throws IOException { - int firstCount = 0; - int b = 0; - while (len > 0 && b >= 0) { - b = readFirstBytes(); - if (b >= 0) { - buf[off++] = (byte) (b & 0xFF); - len--; - firstCount++; - } - } - final int secondCount = in.read(buf, off, len); - return secondCount < 0 ? firstCount > 0 ? firstCount : EOF : firstCount + secondCount; - } - - /** - * Invokes the delegate's {@code read(byte[])} method, detecting and optionally skipping BOM. - * - * @param buf - * the buffer to read the bytes into - * @return the number of bytes read (excluding BOM) or -1 if the end of stream - * @throws IOException - * if an I/O error occurs - */ - @Override - public int read(final byte[] buf) throws IOException { - return read(buf, 0, buf.length); - } - - /** - * Invokes the delegate's {@code mark(int)} method. - * - * @param readlimit - * read ahead limit - */ - @Override - public synchronized void mark(final int readlimit) { - markFbIndex = fbIndex; - markedAtStart = firstBytes == null; - in.mark(readlimit); - } - - /** - * Invokes the delegate's {@code reset()} method. - * - * @throws IOException - * if an I/O error occurs - */ - @Override - public synchronized void reset() throws IOException { - fbIndex = markFbIndex; - if (markedAtStart) { - firstBytes = null; - } - - in.reset(); - } - - /** - * Invokes the delegate's {@code skip(long)} method, detecting and optionally skipping BOM. - * - * @param n - * the number of bytes to skip - * @return the number of bytes to skipped or -1 if the end of stream - * @throws IOException - * if an I/O error occurs - */ - @Override - public long skip(final long n) throws IOException { - int skipped = 0; - while ((n > skipped) && (readFirstBytes() >= 0)) { - skipped++; - } - return in.skip(n - skipped) + skipped; - } -} diff --git a/src/org/apache/commons/io/input/BoundedInputStream.java b/src/org/apache/commons/io/input/BoundedInputStream.java deleted file mode 100644 index 6babddb9..00000000 --- a/src/org/apache/commons/io/input/BoundedInputStream.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This is a stream that will only supply bytes up to a certain length - if its - * position goes above that, it will stop. - *

- * This is useful to wrap ServletInputStreams. The ServletInputStream will block - * if you try to read content from it that isn't there, because it doesn't know - * whether the content hasn't arrived yet or whether the content has finished. - * So, one of these, initialized with the Content-length sent in the - * ServletInputStream's header, will stop it blocking, providing it's been sent - * with a correct content length. - *

- * - * @since 2.0 - */ -public class BoundedInputStream extends InputStream { - - /** the wrapped input stream */ - private final InputStream in; - - /** the max length to provide */ - private final long max; - - /** the number of bytes already returned */ - private long pos; - - /** the marked position */ - private long mark = EOF; - - /** flag if close should be propagated */ - private boolean propagateClose = true; - - /** - * Creates a new {@code BoundedInputStream} that wraps the given input - * stream and limits it to a certain size. - * - * @param in The wrapped input stream - * @param size The maximum number of bytes to return - */ - public BoundedInputStream(final InputStream in, final long size) { - // Some badly designed methods - eg the servlet API - overload length - // such that "-1" means stream finished - this.max = size; - this.in = in; - } - - /** - * Creates a new {@code BoundedInputStream} that wraps the given input - * stream and is unlimited. - * - * @param in The wrapped input stream - */ - public BoundedInputStream(final InputStream in) { - this(in, EOF); - } - - /** - * Invokes the delegate's {@code read()} method if - * the current position is less than the limit. - * @return the byte read or -1 if the end of stream or - * the limit has been reached. - * @throws IOException if an I/O error occurs. - */ - @Override - public int read() throws IOException { - if (max >= 0 && pos >= max) { - return EOF; - } - final int result = in.read(); - pos++; - return result; - } - - /** - * Invokes the delegate's {@code read(byte[])} method. - * @param b the buffer to read the bytes into - * @return the number of bytes read or -1 if the end of stream or - * the limit has been reached. - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] b) throws IOException { - return this.read(b, 0, b.length); - } - - /** - * Invokes the delegate's {@code read(byte[], int, int)} method. - * @param b the buffer to read the bytes into - * @param off The start offset - * @param len The number of bytes to read - * @return the number of bytes read or -1 if the end of stream or - * the limit has been reached. - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (max>=0 && pos>=max) { - return EOF; - } - final long maxRead = max>=0 ? Math.min(len, max-pos) : len; - final int bytesRead = in.read(b, off, (int)maxRead); - - if (bytesRead==EOF) { - return EOF; - } - - pos+=bytesRead; - return bytesRead; - } - - /** - * Invokes the delegate's {@code skip(long)} method. - * @param n the number of bytes to skip - * @return the actual number of bytes skipped - * @throws IOException if an I/O error occurs. - */ - @Override - public long skip(final long n) throws IOException { - final long toSkip = max>=0 ? Math.min(n, max-pos) : n; - final long skippedBytes = in.skip(toSkip); - pos+=skippedBytes; - return skippedBytes; - } - - /** - * {@inheritDoc} - */ - @Override - public int available() throws IOException { - if (max>=0 && pos>=max) { - return 0; - } - return in.available(); - } - - /** - * Invokes the delegate's {@code toString()} method. - * @return the delegate's {@code toString()} - */ - @Override - public String toString() { - return in.toString(); - } - - /** - * Invokes the delegate's {@code close()} method - * if {@link #isPropagateClose()} is {@code true}. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - if (propagateClose) { - in.close(); - } - } - - /** - * Invokes the delegate's {@code reset()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void reset() throws IOException { - in.reset(); - pos = mark; - } - - /** - * Invokes the delegate's {@code mark(int)} method. - * @param readlimit read ahead limit - */ - @Override - public synchronized void mark(final int readlimit) { - in.mark(readlimit); - mark = pos; - } - - /** - * Invokes the delegate's {@code markSupported()} method. - * @return true if mark is supported, otherwise false - */ - @Override - public boolean markSupported() { - return in.markSupported(); - } - - /** - * Indicates whether the {@link #close()} method - * should propagate to the underling {@link InputStream}. - * - * @return {@code true} if calling {@link #close()} - * propagates to the {@code close()} method of the - * underlying stream or {@code false} if it does not. - */ - public boolean isPropagateClose() { - return propagateClose; - } - - /** - * Set whether the {@link #close()} method - * should propagate to the underling {@link InputStream}. - * - * @param propagateClose {@code true} if calling - * {@link #close()} propagates to the {@code close()} - * method of the underlying stream or - * {@code false} if it does not. - */ - public void setPropagateClose(final boolean propagateClose) { - this.propagateClose = propagateClose; - } -} diff --git a/src/org/apache/commons/io/input/BoundedReader.java b/src/org/apache/commons/io/input/BoundedReader.java deleted file mode 100644 index 00e9736c..00000000 --- a/src/org/apache/commons/io/input/BoundedReader.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.Reader; - -/** - * A reader that imposes a limit to the number of characters that can be read from an underlying reader, returning EOF - * when this limit is reached, regardless of state of underlying reader. - * - *

- * One use case is to avoid overrunning the readAheadLimit supplied to {@link java.io.Reader#mark(int)}, since reading - * too many characters removes the ability to do a successful reset. - *

- * - * @since 2.5 - */ -public class BoundedReader extends Reader { - - private static final int INVALID = -1; - - private final Reader target; - - private int charsRead; - - private int markedAt = INVALID; - - private int readAheadLimit; // Internally, this value will never exceed the allowed size - - private final int maxCharsFromTargetReader; - - /** - * Constructs a bounded reader - * - * @param target The target stream that will be used - * @param maxCharsFromTargetReader The maximum number of characters that can be read from target - */ - public BoundedReader(final Reader target, final int maxCharsFromTargetReader) { - this.target = target; - this.maxCharsFromTargetReader = maxCharsFromTargetReader; - } - - /** - * Closes the target - * - * @throws IOException If an I/O error occurs while calling the underlying reader's close method - */ - @Override - public void close() throws IOException { - target.close(); - } - - /** - * Resets the target to the latest mark, - * - * @throws IOException If an I/O error occurs while calling the underlying reader's reset method - * @see java.io.Reader#reset() - */ - @Override - public void reset() throws IOException { - charsRead = markedAt; - target.reset(); - } - - /** - * marks the target stream - * - * @param readAheadLimit The number of characters that can be read while still retaining the ability to do #reset(). - * Note that this parameter is not validated with respect to maxCharsFromTargetReader. There - * is no way to pass past maxCharsFromTargetReader, even if this value is greater. - * - * @throws IOException If an I/O error occurs while calling the underlying reader's mark method - * @see java.io.Reader#mark(int) - */ - @Override - public void mark(final int readAheadLimit) throws IOException { - this.readAheadLimit = readAheadLimit - charsRead; - - markedAt = charsRead; - - target.mark(readAheadLimit); - } - - /** - * Reads a single character - * - * @return -1 on EOF or the character read - * @throws IOException If an I/O error occurs while calling the underlying reader's read method - * @see java.io.Reader#read() - */ - @Override - public int read() throws IOException { - - if (charsRead >= maxCharsFromTargetReader) { - return EOF; - } - - if (markedAt >= 0 && (charsRead - markedAt) >= readAheadLimit) { - return EOF; - } - charsRead++; - return target.read(); - } - - /** - * Reads into an array - * - * @param cbuf The buffer to fill - * @param off The offset - * @param len The number of chars to read - * @return the number of chars read - * @throws IOException If an I/O error occurs while calling the underlying reader's read method - * @see java.io.Reader#read(char[], int, int) - */ - @Override - public int read(final char[] cbuf, final int off, final int len) throws IOException { - int c; - for (int i = 0; i < len; i++) { - c = read(); - if (c == EOF) { - return i == 0 ? EOF : i; - } - cbuf[off + i] = (char) c; - } - return len; - } -} diff --git a/src/org/apache/commons/io/input/BrokenInputStream.java b/src/org/apache/commons/io/input/BrokenInputStream.java deleted file mode 100644 index d9e97f6f..00000000 --- a/src/org/apache/commons/io/input/BrokenInputStream.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Broken input stream. This stream always throws an {@link IOException} from - * all the {@link InputStream} methods where the exception is declared. - *

- * This class is mostly useful for testing error handling in code that uses an - * input stream. - *

- * - * @since 2.0 - */ -public class BrokenInputStream extends InputStream { - - /** - * The exception that is thrown by all methods of this class. - */ - private final IOException exception; - - /** - * Creates a new stream that always throws the given exception. - * - * @param exception the exception to be thrown - */ - public BrokenInputStream(final IOException exception) { - this.exception = exception; - } - - /** - * Creates a new stream that always throws an {@link IOException} - */ - public BrokenInputStream() { - this(new IOException("Broken input stream")); - } - - /** - * Throws the configured exception. - * - * @return nothing - * @throws IOException always thrown - */ - @Override - public int read() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @return nothing - * @throws IOException always thrown - */ - @Override - public int available() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @param n ignored - * @return nothing - * @throws IOException always thrown - */ - @Override - public long skip(final long n) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public synchronized void reset() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void close() throws IOException { - throw exception; - } - -} diff --git a/src/org/apache/commons/io/input/BrokenReader.java b/src/org/apache/commons/io/input/BrokenReader.java deleted file mode 100644 index d13e4014..00000000 --- a/src/org/apache/commons/io/input/BrokenReader.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.Reader; - -/** - * Broken reader. This reader always throws an {@link IOException} from - * all the {@link Reader} methods where the exception is declared. - *

- * This class is mostly useful for testing error handling in code that uses a - * reader. - *

- * - * @since 2.7 - */ -public class BrokenReader extends Reader { - - /** - * The exception that is thrown by all methods of this class. - */ - private final IOException exception; - - /** - * Creates a new reader that always throws the given exception. - * - * @param exception the exception to be thrown - */ - public BrokenReader(final IOException exception) { - this.exception = exception; - } - - /** - * Creates a new reader that always throws an {@link IOException} - */ - public BrokenReader() { - this(new IOException("Broken reader")); - } - - /** - * Throws the configured exception. - * - * @param cbuf ignored - * @param off ignored - * @param len ignored - * @return nothing - * @throws IOException always thrown - */ - @Override - public int read(final char[] cbuf, final int off, final int len) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @param n ignored - * @return nothing - * @throws IOException always thrown - */ - @Override - public long skip(final long n) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @return nothing - * @throws IOException always thrown - */ - @Override - public boolean ready() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @param readAheadLimit ignored - * @throws IOException always thrown - */ - @Override - public void mark(final int readAheadLimit) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public synchronized void reset() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void close() throws IOException { - throw exception; - } - -} diff --git a/src/org/apache/commons/io/input/BufferedFileChannelInputStream.java b/src/org/apache/commons/io/input/BufferedFileChannelInputStream.java deleted file mode 100644 index a8bdcd1a..00000000 --- a/src/org/apache/commons/io/input/BufferedFileChannelInputStream.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Objects; - -import org.apache.commons.io.IOUtils; - -/** - * {@link InputStream} implementation which uses direct buffer to read a file to avoid extra copy of data between Java - * and native memory which happens when using {@link java.io.BufferedInputStream}. Unfortunately, this is not something - * already available in JDK, {@code sun.nio.ch.ChannelInputStream} supports reading a file using NIO, but does not - * support buffering. - *

- * This class was ported and adapted from Apache Spark commit 933dc6cb7b3de1d8ccaf73d124d6eb95b947ed19 where it was - * called {@code NioBufferedFileInputStream}. - *

- * - * @since 2.9.0 - */ -public final class BufferedFileChannelInputStream extends InputStream { - - private final ByteBuffer byteBuffer; - - private final FileChannel fileChannel; - - private static final Class DIRECT_BUFFER_CLASS = getDirectBufferClass(); - - private static Class getDirectBufferClass() { - Class res = null; - try { - res = Class.forName("sun.nio.ch.DirectBuffer"); - } catch (final IllegalAccessError | ClassNotFoundException ignored) { - // ignored - } - return res; - } - - private static boolean isDirectBuffer(final Object object) { - return DIRECT_BUFFER_CLASS != null && DIRECT_BUFFER_CLASS.isInstance(object); - } - - /** - * Constructs a new instance for the given File. - * - * @param file The file to stream. - * @throws IOException If an I/O error occurs - */ - public BufferedFileChannelInputStream(final File file) throws IOException { - this(file, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Constructs a new instance for the given File and buffer size. - * - * @param file The file to stream. - * @param bufferSizeInBytes buffer size. - * @throws IOException If an I/O error occurs - */ - public BufferedFileChannelInputStream(final File file, final int bufferSizeInBytes) throws IOException { - this(file.toPath(), bufferSizeInBytes); - } - - /** - * Constructs a new instance for the given Path. - * - * @param path The path to stream. - * @throws IOException If an I/O error occurs - */ - public BufferedFileChannelInputStream(final Path path) throws IOException { - this(path, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Constructs a new instance for the given Path and buffer size. - * - * @param path The path to stream. - * @param bufferSizeInBytes buffer size. - * @throws IOException If an I/O error occurs - */ - public BufferedFileChannelInputStream(final Path path, final int bufferSizeInBytes) throws IOException { - Objects.requireNonNull(path, "path"); - fileChannel = FileChannel.open(path, StandardOpenOption.READ); - byteBuffer = ByteBuffer.allocateDirect(bufferSizeInBytes); - byteBuffer.flip(); - } - - @Override - public synchronized int available() throws IOException { - return byteBuffer.remaining(); - } - - /** - * Attempts to clean up a ByteBuffer if it is direct or memory-mapped. This uses an *unsafe* Sun API that will cause - * errors if one attempts to read from the disposed buffer. However, neither the bytes allocated to direct buffers - * nor file descriptors opened for memory-mapped buffers put pressure on the garbage collector. Waiting for garbage - * collection may lead to the depletion of off-heap memory or huge numbers of open files. There's unfortunately no - * standard API to manually dispose of these kinds of buffers. - * - * @param buffer the buffer to clean. - */ - private void clean(final ByteBuffer buffer) { - if (isDirectBuffer(buffer)) { - cleanDirectBuffer(buffer); - } - } - - /** - * In Java 8, the type of DirectBuffer.cleaner() was sun.misc.Cleaner, and it was possible to access the method - * sun.misc.Cleaner.clean() to invoke it. The type changed to jdk.internal.ref.Cleaner in later JDKs, and the - * .clean() method is not accessible even with reflection. However sun.misc.Unsafe added a invokeCleaner() method in - * JDK 9+ and this is still accessible with reflection. - * - * @param buffer the buffer to clean. must be a DirectBuffer. - */ - private void cleanDirectBuffer(final ByteBuffer buffer) { - // - // Ported from StorageUtils.scala. - // -// private val bufferCleaner: DirectBuffer => Unit = -// if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) { -// val cleanerMethod = -// Utils.classForName("sun.misc.Unsafe").getMethod("invokeCleaner", classOf[ByteBuffer]) -// val unsafeField = classOf[Unsafe].getDeclaredField("theUnsafe") -// unsafeField.setAccessible(true) -// val unsafe = unsafeField.get(null).asInstanceOf[Unsafe] -// buffer: DirectBuffer => cleanerMethod.invoke(unsafe, buffer) -// } else { -// val cleanerMethod = Utils.classForName("sun.misc.Cleaner").getMethod("clean") -// buffer: DirectBuffer => { -// // Careful to avoid the return type of .cleaner(), which changes with JDK -// val cleaner: AnyRef = buffer.cleaner() -// if (cleaner != null) { -// cleanerMethod.invoke(cleaner) -// } -// } -// } - // - final String specVer = System.getProperty("java.specification.version"); - if ("1.8".equals(specVer)) { - // On Java 8, but also compiles on Java 11. - try { - final Class clsCleaner = Class.forName("sun.misc.Cleaner"); - final Method cleanerMethod = DIRECT_BUFFER_CLASS.getMethod("cleaner"); - final Object cleaner = cleanerMethod.invoke(buffer); - if (cleaner != null) { - final Method cleanMethod = clsCleaner.getMethod("clean"); - cleanMethod.invoke(cleaner); - } - } catch (final ReflectiveOperationException e) { - throw new IllegalStateException(e); - } - } else { - // On Java 9 and up, but compiles on Java 8. - try { - final Class clsUnsafe = Class.forName("sun.misc.Unsafe"); - final Method cleanerMethod = clsUnsafe.getMethod("invokeCleaner", ByteBuffer.class); - final Field unsafeField = clsUnsafe.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - cleanerMethod.invoke(unsafeField.get(null), buffer); - } catch (final ReflectiveOperationException e) { - throw new IllegalStateException(e); - } - } - } - - @Override - public synchronized void close() throws IOException { - try { - fileChannel.close(); - } finally { - clean(byteBuffer); - } - } - - @Override - public synchronized int read() throws IOException { - if (!refill()) { - return EOF; - } - return byteBuffer.get() & 0xFF; - } - - @Override - public synchronized int read(final byte[] b, final int offset, int len) throws IOException { - if (offset < 0 || len < 0 || offset + len < 0 || offset + len > b.length) { - throw new IndexOutOfBoundsException(); - } - if (!refill()) { - return EOF; - } - len = Math.min(len, byteBuffer.remaining()); - byteBuffer.get(b, offset, len); - return len; - } - - /** - * Checks whether data is left to be read from the input stream. - * - * @return true if data is left, false otherwise - */ - private boolean refill() throws IOException { - if (!byteBuffer.hasRemaining()) { - byteBuffer.clear(); - int nRead = 0; - while (nRead == 0) { - nRead = fileChannel.read(byteBuffer); - } - byteBuffer.flip(); - return nRead >= 0; - } - return true; - } - - @Override - public synchronized long skip(final long n) throws IOException { - if (n <= 0L) { - return 0L; - } - if (byteBuffer.remaining() >= n) { - // The buffered content is enough to skip - byteBuffer.position(byteBuffer.position() + (int) n); - return n; - } - final long skippedFromBuffer = byteBuffer.remaining(); - final long toSkipFromFileChannel = n - skippedFromBuffer; - // Discard everything we have read in the buffer. - byteBuffer.position(0); - byteBuffer.flip(); - return skippedFromBuffer + skipFromFileChannel(toSkipFromFileChannel); - } - - private long skipFromFileChannel(final long n) throws IOException { - final long currentFilePosition = fileChannel.position(); - final long size = fileChannel.size(); - if (n > size - currentFilePosition) { - fileChannel.position(size); - return size - currentFilePosition; - } - fileChannel.position(currentFilePosition + n); - return n; - } - -} diff --git a/src/org/apache/commons/io/input/CharSequenceInputStream.java b/src/org/apache/commons/io/input/CharSequenceInputStream.java deleted file mode 100644 index b627c3c4..00000000 --- a/src/org/apache/commons/io/input/CharSequenceInputStream.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.util.Objects; - -/** - * {@link InputStream} implementation that can read from String, StringBuffer, - * StringBuilder or CharBuffer. - *

- * Note: Supports {@link #mark(int)} and {@link #reset()}. - *

- * - * @since 2.2 - */ -public class CharSequenceInputStream extends InputStream { - - private static final int BUFFER_SIZE = 2048; - - private static final int NO_MARK = -1; - - private final CharsetEncoder encoder; - private final CharBuffer cbuf; - private final ByteBuffer bbuf; - - private int mark_cbuf; // position in cbuf - private int mark_bbuf; // position in bbuf - - /** - * Constructor. - * - * @param cs the input character sequence - * @param charset the character set name to use - * @param bufferSize the buffer size to use. - * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character - */ - public CharSequenceInputStream(final CharSequence cs, final Charset charset, final int bufferSize) { - this.encoder = charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - // Ensure that buffer is long enough to hold a complete character - final float maxBytesPerChar = encoder.maxBytesPerChar(); - if (bufferSize < maxBytesPerChar) { - throw new IllegalArgumentException("Buffer size " + bufferSize + " is less than maxBytesPerChar " + - maxBytesPerChar); - } - this.bbuf = ByteBuffer.allocate(bufferSize); - this.bbuf.flip(); - this.cbuf = CharBuffer.wrap(cs); - this.mark_cbuf = NO_MARK; - this.mark_bbuf = NO_MARK; - } - - /** - * Constructor, calls {@link #CharSequenceInputStream(CharSequence, Charset, int)}. - * - * @param cs the input character sequence - * @param charset the character set name to use - * @param bufferSize the buffer size to use. - * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character - */ - public CharSequenceInputStream(final CharSequence cs, final String charset, final int bufferSize) { - this(cs, Charset.forName(charset), bufferSize); - } - - /** - * Constructor, calls {@link #CharSequenceInputStream(CharSequence, Charset, int)} - * with a buffer size of 2048. - * - * @param cs the input character sequence - * @param charset the character set name to use - * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character - */ - public CharSequenceInputStream(final CharSequence cs, final Charset charset) { - this(cs, charset, BUFFER_SIZE); - } - - /** - * Constructor, calls {@link #CharSequenceInputStream(CharSequence, String, int)} - * with a buffer size of 2048. - * - * @param cs the input character sequence - * @param charset the character set name to use - * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character - */ - public CharSequenceInputStream(final CharSequence cs, final String charset) { - this(cs, charset, BUFFER_SIZE); - } - - /** - * Fills the byte output buffer from the input char buffer. - * - * @throws CharacterCodingException - * an error encoding data - */ - private void fillBuffer() throws CharacterCodingException { - this.bbuf.compact(); - final CoderResult result = this.encoder.encode(this.cbuf, this.bbuf, true); - if (result.isError()) { - result.throwException(); - } - this.bbuf.flip(); - } - - @Override - public int read(final byte[] array, int off, int len) throws IOException { - Objects.requireNonNull(array, "array"); - if (len < 0 || (off + len) > array.length) { - throw new IndexOutOfBoundsException("Array Size=" + array.length + - ", offset=" + off + ", length=" + len); - } - if (len == 0) { - return 0; // must return 0 for zero length read - } - if (!this.bbuf.hasRemaining() && !this.cbuf.hasRemaining()) { - return EOF; - } - int bytesRead = 0; - while (len > 0) { - if (this.bbuf.hasRemaining()) { - final int chunk = Math.min(this.bbuf.remaining(), len); - this.bbuf.get(array, off, chunk); - off += chunk; - len -= chunk; - bytesRead += chunk; - } else { - fillBuffer(); - if (!this.bbuf.hasRemaining() && !this.cbuf.hasRemaining()) { - break; - } - } - } - return bytesRead == 0 && !this.cbuf.hasRemaining() ? EOF : bytesRead; - } - - @Override - public int read() throws IOException { - for (;;) { - if (this.bbuf.hasRemaining()) { - return this.bbuf.get() & 0xFF; - } - fillBuffer(); - if (!this.bbuf.hasRemaining() && !this.cbuf.hasRemaining()) { - return EOF; - } - } - } - - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public long skip(long n) throws IOException { - /* - * This could be made more efficient by using position to skip within the current buffer. - */ - long skipped = 0; - while (n > 0 && available() > 0) { - this.read(); - n--; - skipped++; - } - return skipped; - } - - /** - * Return an estimate of the number of bytes remaining in the byte stream. - * @return the count of bytes that can be read without blocking (or returning EOF). - * - * @throws IOException if an error occurs (probably not possible) - */ - @Override - public int available() throws IOException { - // The cached entries are in bbuf; since encoding always creates at least one byte - // per character, we can add the two to get a better estimate (e.g. if bbuf is empty) - // Note that the previous implementation (2.4) could return zero even though there were - // encoded bytes still available. - return this.bbuf.remaining() + this.cbuf.remaining(); - } - - @Override - public void close() throws IOException { - // noop - } - - /** - * {@inheritDoc} - * @param readlimit max read limit (ignored) - */ - @Override - public synchronized void mark(final int readlimit) { - this.mark_cbuf = this.cbuf.position(); - this.mark_bbuf = this.bbuf.position(); - this.cbuf.mark(); - this.bbuf.mark(); - // It would be nice to be able to use mark & reset on the cbuf and bbuf; - // however the bbuf is re-used so that won't work - } - - @Override - public synchronized void reset() throws IOException { - /* - * This is not the most efficient implementation, as it re-encodes from the beginning. - * - * Since the bbuf is re-used, in general it's necessary to re-encode the data. - * - * It should be possible to apply some optimisations however: - * + use mark/reset on the cbuf and bbuf. This would only work if the buffer had not been (re)filled since - * the mark. The code would have to catch InvalidMarkException - does not seem possible to check if mark is - * valid otherwise. + Try saving the state of the cbuf before each fillBuffer; it might be possible to - * restart from there. - */ - if (this.mark_cbuf != NO_MARK) { - // if cbuf is at 0, we have not started reading anything, so skip re-encoding - if (this.cbuf.position() != 0) { - this.encoder.reset(); - this.cbuf.rewind(); - this.bbuf.rewind(); - this.bbuf.limit(0); // rewind does not clear the buffer - while(this.cbuf.position() < this.mark_cbuf) { - this.bbuf.rewind(); // empty the buffer (we only refill when empty during normal processing) - this.bbuf.limit(0); - fillBuffer(); - } - } - if (this.cbuf.position() != this.mark_cbuf) { - throw new IllegalStateException("Unexpected CharBuffer position: actual=" + cbuf.position() + " " + - "expected=" + this.mark_cbuf); - } - this.bbuf.position(this.mark_bbuf); - this.mark_cbuf = NO_MARK; - this.mark_bbuf = NO_MARK; - } - } - - @Override - public boolean markSupported() { - return true; - } - -} diff --git a/src/org/apache/commons/io/input/CharSequenceReader.java b/src/org/apache/commons/io/input/CharSequenceReader.java deleted file mode 100644 index 7a7fcd3c..00000000 --- a/src/org/apache/commons/io/input/CharSequenceReader.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.Reader; -import java.io.Serializable; -import java.util.Objects; - -/** - * {@link Reader} implementation that can read from String, StringBuffer, - * StringBuilder or CharBuffer. - *

- * Note: Supports {@link #mark(int)} and {@link #reset()}. - *

- * - * @since 1.4 - */ -public class CharSequenceReader extends Reader implements Serializable { - - private static final long serialVersionUID = 3724187752191401220L; - private final CharSequence charSequence; - private int idx; - private int mark; - - /** - * The start index in the character sequence, inclusive. - *

- * When de-serializing a CharSequenceReader that was serialized before - * this fields was added, this field will be initialized to 0, which - * gives the same behavior as before: start reading from the start. - *

- * - * @see #start() - * @since 2.7 - */ - private final int start; - - /** - * The end index in the character sequence, exclusive. - *

- * When de-serializing a CharSequenceReader that was serialized before - * this fields was added, this field will be initialized to {@code null}, - * which gives the same behavior as before: stop reading at the - * CharSequence's length. - * If this field was an int instead, it would be initialized to 0 when the - * CharSequenceReader is de-serialized, causing it to not return any - * characters at all. - *

- * - * @see #end() - * @since 2.7 - */ - private final Integer end; - - /** - * Constructs a new instance with the specified character sequence. - * - * @param charSequence The character sequence, may be {@code null} - */ - public CharSequenceReader(final CharSequence charSequence) { - this(charSequence, 0); - } - - /** - * Constructs a new instance with a portion of the specified character sequence. - *

- * The start index is not strictly enforced to be within the bounds of the - * character sequence. This allows the character sequence to grow or shrink - * in size without risking any {@link IndexOutOfBoundsException} to be thrown. - * Instead, if the character sequence grows smaller than the start index, this - * instance will act as if all characters have been read. - *

- * - * @param charSequence The character sequence, may be {@code null} - * @param start The start index in the character sequence, inclusive - * @throws IllegalArgumentException if the start index is negative - * @since 2.7 - */ - public CharSequenceReader(final CharSequence charSequence, final int start) { - this(charSequence, start, Integer.MAX_VALUE); - } - - /** - * Constructs a new instance with a portion of the specified character sequence. - *

- * The start and end indexes are not strictly enforced to be within the bounds - * of the character sequence. This allows the character sequence to grow or shrink - * in size without risking any {@link IndexOutOfBoundsException} to be thrown. - * Instead, if the character sequence grows smaller than the start index, this - * instance will act as if all characters have been read; if the character sequence - * grows smaller than the end, this instance will use the actual character sequence - * length. - *

- * - * @param charSequence The character sequence, may be {@code null} - * @param start The start index in the character sequence, inclusive - * @param end The end index in the character sequence, exclusive - * @throws IllegalArgumentException if the start index is negative, or if the end index is smaller than the start index - * @since 2.7 - */ - public CharSequenceReader(final CharSequence charSequence, final int start, final int end) { - if (start < 0) { - throw new IllegalArgumentException( - "Start index is less than zero: " + start); - } - if (end < start) { - throw new IllegalArgumentException( - "End index is less than start " + start + ": " + end); - } - // Don't check the start and end indexes against the CharSequence, - // to let it grow and shrink without breaking existing behavior. - - this.charSequence = charSequence != null ? charSequence : ""; - this.start = start; - this.end = end; - - this.idx = start; - this.mark = start; - } - - /** - * Returns the index in the character sequence to start reading from, taking into account its length. - * - * @return The start index in the character sequence (inclusive). - */ - private int start() { - return Math.min(charSequence.length(), start); - } - - /** - * Returns the index in the character sequence to end reading at, taking into account its length. - * - * @return The end index in the character sequence (exclusive). - */ - private int end() { - /* - * end == null for de-serialized instances that were serialized before start and end were added. - * Use Integer.MAX_VALUE to get the same behavior as before - use the entire CharSequence. - */ - return Math.min(charSequence.length(), end == null ? Integer.MAX_VALUE : end); - } - - /** - * Close resets the file back to the start and removes any marked position. - */ - @Override - public void close() { - idx = start; - mark = start; - } - - /** - * Tells whether this stream is ready to be read. - * - * @return {@code true} if more characters from the character sequence are available, or {@code false} otherwise. - */ - @Override - public boolean ready() { - return idx < end(); - } - - /** - * Mark the current position. - * - * @param readAheadLimit ignored - */ - @Override - public void mark(final int readAheadLimit) { - mark = idx; - } - - /** - * Mark is supported (returns true). - * - * @return {@code true} - */ - @Override - public boolean markSupported() { - return true; - } - - /** - * Read a single character. - * - * @return the next character from the character sequence - * or -1 if the end has been reached. - */ - @Override - public int read() { - if (idx >= end()) { - return EOF; - } - return charSequence.charAt(idx++); - } - - /** - * Read the specified number of characters into the array. - * - * @param array The array to store the characters in - * @param offset The starting position in the array to store - * @param length The maximum number of characters to read - * @return The number of characters read or -1 if there are - * no more - */ - @Override - public int read(final char[] array, final int offset, final int length) { - if (idx >= end()) { - return EOF; - } - Objects.requireNonNull(array, "array"); - if (length < 0 || offset < 0 || offset + length > array.length) { - throw new IndexOutOfBoundsException("Array Size=" + array.length + - ", offset=" + offset + ", length=" + length); - } - - if (charSequence instanceof String) { - final int count = Math.min(length, end() - idx); - ((String) charSequence).getChars(idx, idx + count, array, offset); - idx += count; - return count; - } - if (charSequence instanceof StringBuilder) { - final int count = Math.min(length, end() - idx); - ((StringBuilder) charSequence).getChars(idx, idx + count, array, offset); - idx += count; - return count; - } - if (charSequence instanceof StringBuffer) { - final int count = Math.min(length, end() - idx); - ((StringBuffer) charSequence).getChars(idx, idx + count, array, offset); - idx += count; - return count; - } - - int count = 0; - for (int i = 0; i < length; i++) { - final int c = read(); - if (c == EOF) { - return count; - } - array[offset + i] = (char)c; - count++; - } - return count; - } - - /** - * Reset the reader to the last marked position (or the beginning if - * mark has not been called). - */ - @Override - public void reset() { - idx = mark; - } - - /** - * Skip the specified number of characters. - * - * @param n The number of characters to skip - * @return The actual number of characters skipped - */ - @Override - public long skip(final long n) { - if (n < 0) { - throw new IllegalArgumentException( - "Number of characters to skip is less than zero: " + n); - } - if (idx >= end()) { - return 0; - } - final int dest = (int)Math.min(end(), idx + n); - final int count = dest - idx; - idx = dest; - return count; - } - - /** - * Return a String representation of the underlying - * character sequence. - * - * @return The contents of the character sequence - */ - @Override - public String toString() { - final CharSequence subSequence = charSequence.subSequence(start(), end()); - return subSequence.toString(); - } -} diff --git a/src/org/apache/commons/io/input/CharacterFilterReader.java b/src/org/apache/commons/io/input/CharacterFilterReader.java deleted file mode 100644 index c6edd5b8..00000000 --- a/src/org/apache/commons/io/input/CharacterFilterReader.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.Reader; -import java.util.function.IntPredicate; - -/** - * A filter reader that filters out a given character represented as an {@code int} code point, handy to remove - * known junk characters from CSV files for example. This class is the most efficient way to filter out a single - * character, as opposed to using a {@link CharacterSetFilterReader}. You can also nest {@link CharacterFilterReader}s. - */ -public class CharacterFilterReader extends AbstractCharacterFilterReader { - - /** - * Constructs a new reader. - * - * @param reader - * the reader to filter. - * @param skip - * the character to filter out. - */ - public CharacterFilterReader(final Reader reader, final int skip) { - super(reader, c -> c == skip); - } - - /** - * Constructs a new reader. - * - * @param reader the reader to filter. - * @param skip Skip test. - * @since 2.9.0 - */ - public CharacterFilterReader(final Reader reader, final IntPredicate skip) { - super(reader, skip); - } - -} diff --git a/src/org/apache/commons/io/input/CharacterSetFilterReader.java b/src/org/apache/commons/io/input/CharacterSetFilterReader.java deleted file mode 100644 index 0634c322..00000000 --- a/src/org/apache/commons/io/input/CharacterSetFilterReader.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.Reader; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.function.IntPredicate; - -/** - * A filter reader that removes a given set of characters represented as {@code int} code points, handy to remove known - * junk characters from CSV files for example. - *

- * This class must convert each {@code int} read to an {@code Integer}. You can increase the Integer cache with a system - * property, see {@link Integer}. - *

- */ -public class CharacterSetFilterReader extends AbstractCharacterFilterReader { - - private static IntPredicate toIntPredicate(final Set skip) { - if (skip == null) { - return SKIP_NONE; - } - final Set unmodifiableSet = Collections.unmodifiableSet(skip); - return c -> unmodifiableSet.contains(Integer.valueOf(c)); - } - - /** - * Constructs a new reader. - * - * @param reader the reader to filter. - * @param skip the set of characters to filter out. - * @since 2.9.0 - */ - public CharacterSetFilterReader(final Reader reader, final Integer... skip) { - this(reader, new HashSet<>(Arrays.asList(skip))); - } - - /** - * Constructs a new reader. - * - * @param reader the reader to filter. - * @param skip the set of characters to filter out. - */ - public CharacterSetFilterReader(final Reader reader, final Set skip) { - super(reader, toIntPredicate(skip)); - } - -} diff --git a/src/org/apache/commons/io/input/CircularInputStream.java b/src/org/apache/commons/io/input/CircularInputStream.java deleted file mode 100644 index bff1cad8..00000000 --- a/src/org/apache/commons/io/input/CircularInputStream.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - -import org.apache.commons.io.IOUtils; - -/** - * - * An {@link InputStream} that repeats provided bytes for given target byte count. - *

- * Closing this input stream has no effect. The methods in this class can be called after the stream has been closed - * without generating an {@link IOException}. - *

- * - * @see InfiniteCircularInputStream - * @since 2.8.0 - */ -public class CircularInputStream extends InputStream { - - /** - * Throws an {@link IllegalArgumentException} if the input contains -1. - * - * @param repeatContent input to validate. - * @return the input. - */ - private static byte[] validate(final byte[] repeatContent) { - Objects.requireNonNull(repeatContent, "repeatContent"); - for (final byte b : repeatContent) { - if (b == IOUtils.EOF) { - throw new IllegalArgumentException("repeatContent contains the end-of-stream marker " + IOUtils.EOF); - } - } - return repeatContent; - } - - private long byteCount; - private int position = -1; - private final byte[] repeatedContent; - private final long targetByteCount; - - /** - * Creates an instance from the specified array of bytes. - * - * @param repeatContent Input buffer to be repeated this buffer is not copied. - * @param targetByteCount How many bytes the read. A negative number means an infinite target count. - */ - public CircularInputStream(final byte[] repeatContent, final long targetByteCount) { - this.repeatedContent = validate(repeatContent); - if (repeatContent.length == 0) { - throw new IllegalArgumentException("repeatContent is empty."); - } - this.targetByteCount = targetByteCount; - } - - @Override - public int read() { - if (targetByteCount >= 0) { - if (byteCount == targetByteCount) { - return IOUtils.EOF; - } - byteCount++; - } - position = (position + 1) % repeatedContent.length; - return repeatedContent[position] & 0xff; - } - -} diff --git a/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java b/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java deleted file mode 100644 index e53a3af2..00000000 --- a/src/org/apache/commons/io/input/ClassLoaderObjectInputStream.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; -import java.io.StreamCorruptedException; -import java.lang.reflect.Proxy; - -/** - * A special ObjectInputStream that loads a class based on a specified - * {@code ClassLoader} rather than the system default. - *

- * This is useful in dynamic container environments. - *

- * - * @since 1.1 - */ -public class ClassLoaderObjectInputStream extends ObjectInputStream { - - /** The class loader to use. */ - private final ClassLoader classLoader; - - /** - * Constructs a new ClassLoaderObjectInputStream. - * - * @param classLoader the ClassLoader from which classes should be loaded - * @param inputStream the InputStream to work on - * @throws IOException in case of an I/O error - * @throws StreamCorruptedException if the stream is corrupted - */ - public ClassLoaderObjectInputStream( - final ClassLoader classLoader, final InputStream inputStream) - throws IOException, StreamCorruptedException { - super(inputStream); - this.classLoader = classLoader; - } - - /** - * Resolve a class specified by the descriptor using the - * specified ClassLoader or the super ClassLoader. - * - * @param objectStreamClass descriptor of the class - * @return the Class object described by the ObjectStreamClass - * @throws IOException in case of an I/O error - * @throws ClassNotFoundException if the Class cannot be found - */ - @Override - protected Class resolveClass(final ObjectStreamClass objectStreamClass) - throws IOException, ClassNotFoundException { - - try { - return Class.forName(objectStreamClass.getName(), false, classLoader); - } catch (final ClassNotFoundException cnfe) { - // delegate to super class loader which can resolve primitives - return super.resolveClass(objectStreamClass); - } - } - - /** - * Create a proxy class that implements the specified interfaces using - * the specified ClassLoader or the super ClassLoader. - * - * @param interfaces the interfaces to implement - * @return a proxy class implementing the interfaces - * @throws IOException in case of an I/O error - * @throws ClassNotFoundException if the Class cannot be found - * @see java.io.ObjectInputStream#resolveProxyClass(java.lang.String[]) - * @since 2.1 - */ - @SuppressWarnings("deprecation") - @Override - protected Class resolveProxyClass(final String[] interfaces) throws IOException, - ClassNotFoundException { - final Class[] interfaceClasses = new Class[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader); - } - try { - return Proxy.getProxyClass(classLoader, interfaceClasses); - } catch (final IllegalArgumentException e) { - return super.resolveProxyClass(interfaces); - } - } - -} diff --git a/src/org/apache/commons/io/input/CloseShieldInputStream.java b/src/org/apache/commons/io/input/CloseShieldInputStream.java deleted file mode 100644 index 4980e3e9..00000000 --- a/src/org/apache/commons/io/input/CloseShieldInputStream.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.InputStream; - -/** - * Proxy stream that prevents the underlying input stream from being closed. - *

- * This class is typically used in cases where an input stream needs to be - * passed to a component that wants to explicitly close the stream even if more - * input would still be available to other components. - *

- * - * @since 1.4 - */ -public class CloseShieldInputStream extends ProxyInputStream { - - /** - * Creates a proxy that shields the given input stream from being closed. - * - * @param inputStream the input stream to wrap - * @return the created proxy - * @since 2.9.0 - */ - public static CloseShieldInputStream wrap(final InputStream inputStream) { - return new CloseShieldInputStream(inputStream); - } - - /** - * Creates a proxy that shields the given input stream from being closed. - * - * @param inputStream underlying input stream - * @deprecated Using this constructor prevents IDEs from warning if the - * underlying input stream is never closed. Use - * {@link #wrap(InputStream)} instead. - */ - @Deprecated - public CloseShieldInputStream(final InputStream inputStream) { - super(inputStream); - } - - /** - * Replaces the underlying input stream with a {@link ClosedInputStream} - * sentinel. The original input stream will remain open, but this proxy will - * appear closed. - */ - @Override - public void close() { - in = ClosedInputStream.CLOSED_INPUT_STREAM; - } - -} diff --git a/src/org/apache/commons/io/input/CloseShieldReader.java b/src/org/apache/commons/io/input/CloseShieldReader.java deleted file mode 100644 index 51b12681..00000000 --- a/src/org/apache/commons/io/input/CloseShieldReader.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.Reader; - -/** - * Proxy reader that prevents the underlying reader from being closed. - *

- * This class is typically used in cases where a reader needs to be passed to a - * component that wants to explicitly close the reader even if more input would - * still be available to other components. - *

- * - * @since 2.7 - */ -public class CloseShieldReader extends ProxyReader { - - /** - * Creates a proxy that shields the given reader from being closed. - * - * @param reader the reader to wrap - * @return the created proxy - * @since 2.9.0 - */ - public static CloseShieldReader wrap(final Reader reader) { - return new CloseShieldReader(reader); - } - - /** - * Creates a proxy that shields the given reader from being closed. - * - * @param reader underlying reader - * @deprecated Using this constructor prevents IDEs from warning if the - * underlying reader is never closed. Use {@link #wrap(Reader)} - * instead. - */ - @Deprecated - public CloseShieldReader(final Reader reader) { - super(reader); - } - - /** - * Replaces the underlying reader with a {@link ClosedReader} sentinel. The - * original reader will remain open, but this proxy will appear closed. - */ - @Override - public void close() { - in = ClosedReader.CLOSED_READER; - } - -} diff --git a/src/org/apache/commons/io/input/ClosedInputStream.java b/src/org/apache/commons/io/input/ClosedInputStream.java deleted file mode 100644 index 492743cf..00000000 --- a/src/org/apache/commons/io/input/ClosedInputStream.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.InputStream; - -/** - * Closed input stream. This stream returns EOF to all attempts to read - * something from the stream. - *

- * Typically uses of this class include testing for corner cases in methods - * that accept input streams and acting as a sentinel value instead of a - * {@code null} input stream. - *

- * - * @since 1.4 - */ -public class ClosedInputStream extends InputStream { - - /** - * A singleton. - */ - public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); - - /** - * Returns -1 to indicate that the stream is closed. - * - * @return always -1 - */ - @Override - public int read() { - return EOF; - } - -} diff --git a/src/org/apache/commons/io/input/ClosedReader.java b/src/org/apache/commons/io/input/ClosedReader.java deleted file mode 100644 index dc906b8c..00000000 --- a/src/org/apache/commons/io/input/ClosedReader.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.Reader; - -/** - * Closed reader. This reader returns EOF to all attempts to read something from it. - *

- * Typically uses of this class include testing for corner cases in methods that accept readers and acting as a sentinel - * value instead of a {@code null} reader. - *

- * - * @since 2.7 - */ -public class ClosedReader extends Reader { - - /** - * A singleton. - */ - public static final ClosedReader CLOSED_READER = new ClosedReader(); - - /** - * Returns -1 to indicate that the stream is closed. - * - * @param cbuf ignored - * @param off ignored - * @param len ignored - * @return always -1 - */ - @Override - public int read(final char[] cbuf, final int off, final int len) { - return EOF; - } - - @Override - public void close() throws IOException { - // noop - } - -} diff --git a/src/org/apache/commons/io/input/CountingInputStream.java b/src/org/apache/commons/io/input/CountingInputStream.java deleted file mode 100644 index 17d7c296..00000000 --- a/src/org/apache/commons/io/input/CountingInputStream.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A decorating input stream that counts the number of bytes that have passed - * through the stream so far. - *

- * A typical use case would be during debugging, to ensure that data is being - * read as expected. - *

- */ -public class CountingInputStream extends ProxyInputStream { - - /** The count of bytes that have passed. */ - private long count; - - /** - * Constructs a new CountingInputStream. - * - * @param in the InputStream to delegate to - */ - public CountingInputStream(final InputStream in) { - super(in); - } - - - /** - * Skips the stream over the specified number of bytes, adding the skipped - * amount to the count. - * - * @param length the number of bytes to skip - * @return the actual number of bytes skipped - * @throws IOException if an I/O error occurs. - * @see java.io.InputStream#skip(long) - */ - @Override - public synchronized long skip(final long length) throws IOException { - final long skip = super.skip(length); - this.count += skip; - return skip; - } - - /** - * Adds the number of read bytes to the count. - * - * @param n number of bytes read, or -1 if no more bytes are available - * @since 2.0 - */ - @Override - protected synchronized void afterRead(final int n) { - if (n != EOF) { - this.count += n; - } - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an {@code int}. - * See {@link #getByteCount()} for a method using a {@code long}. - * - * @return the number of bytes accumulated - * @throws ArithmeticException if the byte count is too large - */ - public int getCount() { - final long result = getByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an {@code int}. - * See {@link #resetByteCount()} for a method using a {@code long}. - * - * @return the count previous to resetting - * @throws ArithmeticException if the byte count is too large - */ - public int resetCount() { - final long result = resetByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: This method is an alternative for {@code getCount()} - * and was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the number of bytes accumulated - * @since 1.3 - */ - public synchronized long getByteCount() { - return this.count; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: This method is an alternative for {@code resetCount()} - * and was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the count previous to resetting - * @since 1.3 - */ - public synchronized long resetByteCount() { - final long tmp = this.count; - this.count = 0; - return tmp; - } - -} diff --git a/src/org/apache/commons/io/input/DemuxInputStream.java b/src/org/apache/commons/io/input/DemuxInputStream.java deleted file mode 100644 index c92471d1..00000000 --- a/src/org/apache/commons/io/input/DemuxInputStream.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - -/** - * Data written to this stream is forwarded to a stream that has been associated with this thread. - */ -public class DemuxInputStream extends InputStream { - private final InheritableThreadLocal inputStreamLocal = new InheritableThreadLocal<>(); - - /** - * Binds the specified stream to the current thread. - * - * @param input the stream to bind - * @return the InputStream that was previously active - */ - public InputStream bindStream(final InputStream input) { - final InputStream oldValue = inputStreamLocal.get(); - inputStreamLocal.set(input); - return oldValue; - } - - /** - * Closes stream associated with current thread. - * - * @throws IOException if an error occurs - */ - @SuppressWarnings("resource") // we actually close the stream here - @Override - public void close() throws IOException { - IOUtils.close(inputStreamLocal.get()); - } - - /** - * Reads byte from stream associated with current thread. - * - * @return the byte read from stream - * @throws IOException if an error occurs - */ - @SuppressWarnings("resource") - @Override - public int read() throws IOException { - final InputStream inputStream = inputStreamLocal.get(); - if (null != inputStream) { - return inputStream.read(); - } - return EOF; - } -} diff --git a/src/org/apache/commons/io/input/InfiniteCircularInputStream.java b/src/org/apache/commons/io/input/InfiniteCircularInputStream.java deleted file mode 100644 index 0514c7e4..00000000 --- a/src/org/apache/commons/io/input/InfiniteCircularInputStream.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * - * An {@link InputStream} that infinitely repeats the provided bytes. - *

- * Closing this input stream has no effect. The methods in this class can be called after the stream has been closed - * without generating an {@link IOException}. - *

- * - * @since 2.6 - */ -public class InfiniteCircularInputStream extends CircularInputStream { - - /** - * Creates an instance from the specified array of bytes. - * - * @param repeatContent Input buffer to be repeated this buffer is not copied. - */ - public InfiniteCircularInputStream(final byte[] repeatContent) { - // A negative number means an infinite target count. - super(repeatContent, -1); - } - -} diff --git a/src/org/apache/commons/io/input/MarkShieldInputStream.java b/src/org/apache/commons/io/input/MarkShieldInputStream.java deleted file mode 100644 index b8725bd6..00000000 --- a/src/org/apache/commons/io/input/MarkShieldInputStream.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This is an alternative to {@link java.io.ByteArrayInputStream} - * which removes the synchronization overhead for non-concurrent - * access; as such this class is not thread-safe. - * - * Proxy stream that prevents the underlying input stream from being marked/reset. - *

- * This class is typically used in cases where an input stream that supports - * marking needs to be passed to a component that wants to explicitly mark - * the stream, but it it is not desirable to allow marking of the stream. - *

- * - * @since 2.8.0 - */ -public class MarkShieldInputStream extends ProxyInputStream { - - /** - * Creates a proxy that shields the given input stream from being - * marked or rest. - * - * @param in underlying input stream - */ - public MarkShieldInputStream(final InputStream in) { - super(in); - } - - @SuppressWarnings("sync-override") - @Override - public void mark(final int readlimit) { - // no-op - } - - @Override - public boolean markSupported() { - return false; - } - - @SuppressWarnings("sync-override") - @Override - public void reset() throws IOException { - throw UnsupportedOperationExceptions.reset(); - } -} diff --git a/src/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java b/src/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java deleted file mode 100644 index 1e9d46f7..00000000 --- a/src/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - - -/** - * This class is an example for using an {@link ObservableInputStream}. It - * creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer}, - * which calculates a checksum using a MessageDigest, for example an MD5 sum. - * Note: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, - * are thread safe. So is {@link MessageDigestCalculatingInputStream}. - */ -public class MessageDigestCalculatingInputStream extends ObservableInputStream { - - /** - * Maintains the message digest. - */ - public static class MessageDigestMaintainingObserver extends Observer { - private final MessageDigest messageDigest; - - /** - * Creates an MessageDigestMaintainingObserver for the given MessageDigest. - * @param messageDigest the message digest to use - */ - public MessageDigestMaintainingObserver(final MessageDigest messageDigest) { - this.messageDigest = messageDigest; - } - - @Override - public void data(final int input) throws IOException { - messageDigest.update((byte) input); - } - - @Override - public void data(final byte[] input, final int offset, final int length) throws IOException { - messageDigest.update(input, offset, length); - } - } - - private final MessageDigest messageDigest; - - /** Creates a new instance, which calculates a signature on the given stream, - * using the given {@link MessageDigest}. - * @param inputStream the stream to calculate the message digest for - * @param messageDigest the message digest to use - */ - public MessageDigestCalculatingInputStream(final InputStream inputStream, final MessageDigest messageDigest) { - super(inputStream, new MessageDigestMaintainingObserver(messageDigest)); - this.messageDigest = messageDigest; - } - - /** - * Creates a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the - * given algorithm. - * - * @param inputStream the stream to calculate the message digest for - * @param algorithm the name of the algorithm to use - * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified - * algorithm. - */ - public MessageDigestCalculatingInputStream(final InputStream inputStream, final String algorithm) - throws NoSuchAlgorithmException { - this(inputStream, MessageDigest.getInstance(algorithm)); - } - - /** - * Creates a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the - * "MD5" algorithm. - * - * @param inputStream the stream to calculate the message digest for - * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified - * algorithm. - */ - public MessageDigestCalculatingInputStream(final InputStream inputStream) throws NoSuchAlgorithmException { - this(inputStream, MessageDigest.getInstance("MD5")); - } - - /** Returns the {@link MessageDigest}, which is being used for generating the - * checksum. - * Note: The checksum will only reflect the data, which has been read so far. - * This is probably not, what you expect. Make sure, that the complete data has been - * read, if that is what you want. The easiest way to do so is by invoking - * {@link #consume()}. - * @return the message digest used - */ - public MessageDigest getMessageDigest() { - return messageDigest; - } -} diff --git a/src/org/apache/commons/io/input/NullInputStream.java b/src/org/apache/commons/io/input/NullInputStream.java deleted file mode 100644 index 80d7f4a9..00000000 --- a/src/org/apache/commons/io/input/NullInputStream.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -/** - * A functional, light weight {@link InputStream} that emulates - * a stream of a specified size. - *

- * This implementation provides a light weight - * object for testing with an {@link InputStream} - * where the contents don't matter. - *

- *

- * One use case would be for testing the handling of - * large {@link InputStream} as it can emulate that - * scenario without the overhead of actually processing - * large numbers of bytes - significantly speeding up - * test execution times. - *

- *

- * This implementation returns zero from the method that - * reads a byte and leaves the array unchanged in the read - * methods that are passed a byte array. - * If alternative data is required the {@code processByte()} and - * {@code processBytes()} methods can be implemented to generate - * data, for example: - *

- * - *
- *  public class TestInputStream extends NullInputStream {
- *      public TestInputStream(int size) {
- *          super(size);
- *      }
- *      protected int processByte() {
- *          return ... // return required value here
- *      }
- *      protected void processBytes(byte[] bytes, int offset, int length) {
- *          for (int i = offset; i < length; i++) {
- *              bytes[i] = ... // set array value here
- *          }
- *      }
- *  }
- * 
- * - * @since 1.3 - * - */ -public class NullInputStream extends InputStream { - - private final long size; - private long position; - private long mark = -1; - private long readlimit; - private boolean eof; - private final boolean throwEofException; - private final boolean markSupported; - - /** - * Create an {@link InputStream} that emulates a size 0 stream - * which supports marking and does not throw EOFException. - * - * @since 2.7 - */ - public NullInputStream() { - this(0, true, false); - } - - /** - * Create an {@link InputStream} that emulates a specified size - * which supports marking and does not throw EOFException. - * - * @param size The size of the input stream to emulate. - */ - public NullInputStream(final long size) { - this(size, true, false); - } - - /** - * Create an {@link InputStream} that emulates a specified - * size with option settings. - * - * @param size The size of the input stream to emulate. - * @param markSupported Whether this instance will support - * the {@code mark()} functionality. - * @param throwEofException Whether this implementation - * will throw an {@link EOFException} or return -1 when the - * end of file is reached. - */ - public NullInputStream(final long size, final boolean markSupported, final boolean throwEofException) { - this.size = size; - this.markSupported = markSupported; - this.throwEofException = throwEofException; - } - - /** - * Return the current position. - * - * @return the current position. - */ - public long getPosition() { - return position; - } - - /** - * Return the size this {@link InputStream} emulates. - * - * @return The size of the input stream to emulate. - */ - public long getSize() { - return size; - } - - /** - * Return the number of bytes that can be read. - * - * @return The number of bytes that can be read. - */ - @Override - public int available() { - final long avail = size - position; - if (avail <= 0) { - return 0; - } - if (avail > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - return (int) avail; - } - - /** - * Close this input stream - resets the internal state to - * the initial values. - * - * @throws IOException If an error occurs. - */ - @Override - public void close() throws IOException { - eof = false; - position = 0; - mark = -1; - } - - /** - * Mark the current position. - * - * @param readlimit The number of bytes before this marked position - * is invalid. - * @throws UnsupportedOperationException if mark is not supported. - */ - @Override - public synchronized void mark(final int readlimit) { - if (!markSupported) { - throw UnsupportedOperationExceptions.mark(); - } - mark = position; - this.readlimit = readlimit; - } - - /** - * Indicates whether mark is supported. - * - * @return Whether mark is supported or not. - */ - @Override - public boolean markSupported() { - return markSupported; - } - - /** - * Read a byte. - * - * @return Either The byte value returned by {@code processByte()} - * or {@code -1} if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read() throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position++; - return processByte(); - } - - /** - * Read some bytes into the specified array. - * - * @param bytes The byte array to read into - * @return The number of bytes read or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read(final byte[] bytes) throws IOException { - return read(bytes, 0, bytes.length); - } - - /** - * Read the specified number bytes into an array. - * - * @param bytes The byte array to read into. - * @param offset The offset to start reading bytes into. - * @param length The number of bytes to read. - * @return The number of bytes read or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read(final byte[] bytes, final int offset, final int length) throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += length; - int returnLength = length; - if (position > size) { - returnLength = length - (int)(position - size); - position = size; - } - processBytes(bytes, offset, returnLength); - return returnLength; - } - - /** - * Reset the stream to the point when mark was last called. - * - * @throws UnsupportedOperationException if mark is not supported. - * @throws IOException If no position has been marked - * or the read limit has been exceed since the last position was - * marked. - */ - @Override - public synchronized void reset() throws IOException { - if (!markSupported) { - throw UnsupportedOperationExceptions.reset(); - } - if (mark < 0) { - throw new IOException("No position has been marked"); - } - if (position > mark + readlimit) { - throw new IOException("Marked position [" + mark + - "] is no longer valid - passed the read limit [" + - readlimit + "]"); - } - position = mark; - eof = false; - } - - /** - * Skip a specified number of bytes. - * - * @param numberOfBytes The number of bytes to skip. - * @return The number of bytes skipped or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public long skip(final long numberOfBytes) throws IOException { - if (eof) { - throw new IOException("Skip after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += numberOfBytes; - long returnLength = numberOfBytes; - if (position > size) { - returnLength = numberOfBytes - (position - size); - position = size; - } - return returnLength; - } - - /** - * Return a byte value for the {@code read()} method. - *

- * This implementation returns zero. - * - * @return This implementation always returns zero. - */ - protected int processByte() { - // do nothing - overridable by subclass - return 0; - } - - /** - * Process the bytes for the {@code read(byte[], offset, length)} - * method. - *

- * This implementation leaves the byte array unchanged. - * - * @param bytes The byte array - * @param offset The offset to start at. - * @param length The number of bytes. - */ - protected void processBytes(final byte[] bytes, final int offset, final int length) { - // do nothing - overridable by subclass - } - - /** - * Handle End of File. - * - * @return {@code -1} if {@code throwEofException} is - * set to {@code false} - * @throws EOFException if {@code throwEofException} is set - * to {@code true}. - */ - private int doEndOfFile() throws EOFException { - eof = true; - if (throwEofException) { - throw new EOFException(); - } - return EOF; - } - -} diff --git a/src/org/apache/commons/io/input/NullReader.java b/src/org/apache/commons/io/input/NullReader.java deleted file mode 100644 index 82b47247..00000000 --- a/src/org/apache/commons/io/input/NullReader.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.EOFException; -import java.io.IOException; -import java.io.Reader; - -/** - * A functional, light weight {@link Reader} that emulates - * a reader of a specified size. - *

- * This implementation provides a light weight - * object for testing with an {@link Reader} - * where the contents don't matter. - *

- *

- * One use case would be for testing the handling of - * large {@link Reader} as it can emulate that - * scenario without the overhead of actually processing - * large numbers of characters - significantly speeding up - * test execution times. - *

- *

- * This implementation returns a space from the method that - * reads a character and leaves the array unchanged in the read - * methods that are passed a character array. - * If alternative data is required the {@code processChar()} and - * {@code processChars()} methods can be implemented to generate - * data, for example: - *

- * - *
- *  public class TestReader extends NullReader {
- *      public TestReader(int size) {
- *          super(size);
- *      }
- *      protected char processChar() {
- *          return ... // return required value here
- *      }
- *      protected void processChars(char[] chars, int offset, int length) {
- *          for (int i = offset; i < length; i++) {
- *              chars[i] = ... // set array value here
- *          }
- *      }
- *  }
- * 
- * - * @since 1.3 - */ -public class NullReader extends Reader { - - private final long size; - private long position; - private long mark = -1; - private long readlimit; - private boolean eof; - private final boolean throwEofException; - private final boolean markSupported; - - /** - * Creates a {@link Reader} that emulates a size 0 reader - * which supports marking and does not throw EOFException. - * - * @since 2.7 - */ - public NullReader() { - this(0, true, false); - } - - /** - * Creates a {@link Reader} that emulates a specified size - * which supports marking and does not throw EOFException. - * - * @param size The size of the reader to emulate. - */ - public NullReader(final long size) { - this(size, true, false); - } - - /** - * Creates a {@link Reader} that emulates a specified - * size with option settings. - * - * @param size The size of the reader to emulate. - * @param markSupported Whether this instance will support - * the {@code mark()} functionality. - * @param throwEofException Whether this implementation - * will throw an {@link EOFException} or return -1 when the - * end of file is reached. - */ - public NullReader(final long size, final boolean markSupported, final boolean throwEofException) { - this.size = size; - this.markSupported = markSupported; - this.throwEofException = throwEofException; - } - - /** - * Returns the current position. - * - * @return the current position. - */ - public long getPosition() { - return position; - } - - /** - * Returns the size this {@link Reader} emulates. - * - * @return The size of the reader to emulate. - */ - public long getSize() { - return size; - } - - /** - * Closes this Reader - resets the internal state to - * the initial values. - * - * @throws IOException If an error occurs. - */ - @Override - public void close() throws IOException { - eof = false; - position = 0; - mark = -1; - } - - /** - * Marks the current position. - * - * @param readlimit The number of characters before this marked position - * is invalid. - * @throws UnsupportedOperationException if mark is not supported. - */ - @Override - public synchronized void mark(final int readlimit) { - if (!markSupported) { - throw UnsupportedOperationExceptions.mark(); - } - mark = position; - this.readlimit = readlimit; - } - - /** - * Indicates whether mark is supported. - * - * @return Whether mark is supported or not. - */ - @Override - public boolean markSupported() { - return markSupported; - } - - /** - * Reads a character. - * - * @return Either The character value returned by {@code processChar()} - * or {@code -1} if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read() throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position++; - return processChar(); - } - - /** - * Reads some characters into the specified array. - * - * @param chars The character array to read into - * @return The number of characters read or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read(final char[] chars) throws IOException { - return read(chars, 0, chars.length); - } - - /** - * Reads the specified number characters into an array. - * - * @param chars The character array to read into. - * @param offset The offset to start reading characters into. - * @param length The number of characters to read. - * @return The number of characters read or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public int read(final char[] chars, final int offset, final int length) throws IOException { - if (eof) { - throw new IOException("Read after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += length; - int returnLength = length; - if (position > size) { - returnLength = length - (int)(position - size); - position = size; - } - processChars(chars, offset, returnLength); - return returnLength; - } - - /** - * Resets the stream to the point when mark was last called. - * - * @throws UnsupportedOperationException if mark is not supported. - * @throws IOException If no position has been marked - * or the read limit has been exceed since the last position was - * marked. - */ - @Override - public synchronized void reset() throws IOException { - if (!markSupported) { - throw UnsupportedOperationExceptions.reset(); - } - if (mark < 0) { - throw new IOException("No position has been marked"); - } - if (position > mark + readlimit) { - throw new IOException("Marked position [" + mark + - "] is no longer valid - passed the read limit [" + - readlimit + "]"); - } - position = mark; - eof = false; - } - - /** - * Skips a specified number of characters. - * - * @param numberOfChars The number of characters to skip. - * @return The number of characters skipped or {@code -1} - * if the end of file has been reached and - * {@code throwEofException} is set to {@code false}. - * @throws EOFException if the end of file is reached and - * {@code throwEofException} is set to {@code true}. - * @throws IOException if trying to read past the end of file. - */ - @Override - public long skip(final long numberOfChars) throws IOException { - if (eof) { - throw new IOException("Skip after end of file"); - } - if (position == size) { - return doEndOfFile(); - } - position += numberOfChars; - long returnLength = numberOfChars; - if (position > size) { - returnLength = numberOfChars - (position - size); - position = size; - } - return returnLength; - } - - /** - * Returns a character value for the {@code read()} method. - *

- * This implementation returns zero. - *

- * - * @return This implementation always returns zero. - */ - protected int processChar() { - // do nothing - overridable by subclass - return 0; - } - - /** - * Process the characters for the {@code read(char[], offset, length)} - * method. - *

- * This implementation leaves the character array unchanged. - *

- * - * @param chars The character array - * @param offset The offset to start at. - * @param length The number of characters. - */ - protected void processChars(final char[] chars, final int offset, final int length) { - // do nothing - overridable by subclass - } - - /** - * Handles End of File. - * - * @return {@code -1} if {@code throwEofException} is - * set to {@code false} - * @throws EOFException if {@code throwEofException} is set - * to {@code true}. - */ - private int doEndOfFile() throws EOFException { - eof = true; - if (throwEofException) { - throw new EOFException(); - } - return EOF; - } - -} diff --git a/src/org/apache/commons/io/input/ObservableInputStream.java b/src/org/apache/commons/io/input/ObservableInputStream.java deleted file mode 100644 index d57eb058..00000000 --- a/src/org/apache/commons/io/input/ObservableInputStream.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.io.IOUtils; - -/** - * The {@link ObservableInputStream} allows, that an InputStream may be consumed by other receivers, apart from the - * thread, which is reading it. The other consumers are implemented as instances of {@link Observer}. - *

- * A typical application may be the generation of a {@link java.security.MessageDigest} on the fly. - *

- *

- * Note: The {@link ObservableInputStream} is not thread safe, as instances of InputStream usually - * aren't. If you must access the stream from multiple threads, then synchronization, locking, or a similar means must - * be used. - *

- * - * @see MessageDigestCalculatingInputStream - */ -public class ObservableInputStream extends ProxyInputStream { - - /** - * Abstracts observer callback for {@code ObservableInputStream}s. - */ - public static abstract class Observer { - - /** - * Called to indicate that the {@link ObservableInputStream} has been closed. - * - * @throws IOException if an I/O error occurs. - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - public void closed() throws IOException { - // noop - } - - /** - * Called to indicate that {@link InputStream#read(byte[])}, or {@link InputStream#read(byte[], int, int)} have - * been called, and are about to invoke data. - * - * @param buffer The byte array, which has been passed to the read call, and where data has been stored. - * @param offset The offset within the byte array, where data has been stored. - * @param length The number of bytes, which have been stored in the byte array. - * @throws IOException if an I/O error occurs. - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - public void data(final byte[] buffer, final int offset, final int length) throws IOException { - // noop - } - - /** - * Called to indicate, that {@link InputStream#read()} has been invoked on the {@link ObservableInputStream}, - * and will return a value. - * - * @param value The value, which is being returned. This will never be -1 (EOF), because, in that case, - * {@link #finished()} will be invoked instead. - * @throws IOException if an I/O error occurs. - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - public void data(final int value) throws IOException { - // noop - } - - /** - * Called to indicate that an error occurred on the underlying stream. - * - * @param exception the exception to throw - * @throws IOException if an I/O error occurs. - */ - public void error(final IOException exception) throws IOException { - throw exception; - } - - /** - * Called to indicate that EOF has been seen on the underlying stream. This method may be called multiple times, - * if the reader keeps invoking either of the read methods, and they will consequently keep returning EOF. - * - * @throws IOException if an I/O error occurs. - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - public void finished() throws IOException { - // noop - } - } - - private final List observers; - - /** - * Creates a new ObservableInputStream for the given InputStream. - * - * @param inputStream the input stream to observe. - */ - public ObservableInputStream(final InputStream inputStream) { - this(inputStream, new ArrayList<>()); - } - - /** - * Creates a new ObservableInputStream for the given InputStream. - * - * @param inputStream the input stream to observe. - * @param observers List of observer callbacks. - */ - private ObservableInputStream(final InputStream inputStream, final List observers) { - super(inputStream); - this.observers = observers; - } - - /** - * Creates a new ObservableInputStream for the given InputStream. - * - * @param inputStream the input stream to observe. - * @param observers List of observer callbacks. - * @since 2.9.0 - */ - public ObservableInputStream(final InputStream inputStream, final Observer... observers) { - this(inputStream, Arrays.asList(observers)); - } - - /** - * Adds an Observer. - * - * @param observer the observer to add. - */ - public void add(final Observer observer) { - observers.add(observer); - } - - @Override - public void close() throws IOException { - IOException ioe = null; - try { - super.close(); - } catch (final IOException e) { - ioe = e; - } - if (ioe == null) { - noteClosed(); - } else { - noteError(ioe); - } - } - - /** - * Reads all data from the underlying {@link InputStream}, while notifying the observers. - * - * @throws IOException The underlying {@link InputStream}, or either of the observers has thrown an exception. - */ - public void consume() throws IOException { - final byte[] buffer = IOUtils.byteArray(); - while (read(buffer) != EOF) { - // empty - } - } - - /** - * Gets all currently registered observers. - * - * @return a list of the currently registered observers. - * @since 2.9.0 - */ - public List getObservers() { - return observers; - } - - /** - * Notifies the observers by invoking {@link Observer#finished()}. - * - * @throws IOException Some observer has thrown an exception, which is being passed down. - */ - protected void noteClosed() throws IOException { - for (final Observer observer : getObservers()) { - observer.closed(); - } - } - - /** - * Notifies the observers by invoking {@link Observer#data(int)} with the given arguments. - * - * @param value Passed to the observers. - * @throws IOException Some observer has thrown an exception, which is being passed down. - */ - protected void noteDataByte(final int value) throws IOException { - for (final Observer observer : getObservers()) { - observer.data(value); - } - } - - /** - * Notifies the observers by invoking {@link Observer#data(byte[],int,int)} with the given arguments. - * - * @param buffer Passed to the observers. - * @param offset Passed to the observers. - * @param length Passed to the observers. - * @throws IOException Some observer has thrown an exception, which is being passed down. - */ - protected void noteDataBytes(final byte[] buffer, final int offset, final int length) throws IOException { - for (final Observer observer : getObservers()) { - observer.data(buffer, offset, length); - } - } - - /** - * Notifies the observers by invoking {@link Observer#error(IOException)} with the given argument. - * - * @param exception Passed to the observers. - * @throws IOException Some observer has thrown an exception, which is being passed down. This may be the same - * exception, which has been passed as an argument. - */ - protected void noteError(final IOException exception) throws IOException { - for (final Observer observer : getObservers()) { - observer.error(exception); - } - } - - /** - * Notifies the observers by invoking {@link Observer#finished()}. - * - * @throws IOException Some observer has thrown an exception, which is being passed down. - */ - protected void noteFinished() throws IOException { - for (final Observer observer : getObservers()) { - observer.finished(); - } - } - - private void notify(final byte[] buffer, final int offset, final int result, final IOException ioe) throws IOException { - if (ioe != null) { - noteError(ioe); - throw ioe; - } - if (result == EOF) { - noteFinished(); - } else if (result > 0) { - noteDataBytes(buffer, offset, result); - } - } - - @Override - public int read() throws IOException { - int result = 0; - IOException ioe = null; - try { - result = super.read(); - } catch (final IOException ex) { - ioe = ex; - } - if (ioe != null) { - noteError(ioe); - throw ioe; - } - if (result == EOF) { - noteFinished(); - } else { - noteDataByte(result); - } - return result; - } - - @Override - public int read(final byte[] buffer) throws IOException { - int result = 0; - IOException ioe = null; - try { - result = super.read(buffer); - } catch (final IOException ex) { - ioe = ex; - } - notify(buffer, 0, result, ioe); - return result; - } - - @Override - public int read(final byte[] buffer, final int offset, final int length) throws IOException { - int result = 0; - IOException ioe = null; - try { - result = super.read(buffer, offset, length); - } catch (final IOException ex) { - ioe = ex; - } - notify(buffer, offset, result, ioe); - return result; - } - - /** - * Removes an Observer. - * - * @param observer the observer to remove - */ - public void remove(final Observer observer) { - observers.remove(observer); - } - - /** - * Removes all Observers. - */ - public void removeAllObservers() { - observers.clear(); - } - -} diff --git a/src/org/apache/commons/io/input/ProxyInputStream.java b/src/org/apache/commons/io/input/ProxyInputStream.java deleted file mode 100644 index fdea3637..00000000 --- a/src/org/apache/commons/io/input/ProxyInputStream.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. - *

- * It is an alternative base class to FilterInputStream - * to increase reusability, because FilterInputStream changes the - * methods being called, such as read(byte[]) to read(byte[], int, int). - *

- *

- * See the protected methods for ways in which a subclass can easily decorate - * a stream with custom pre-, post- or error processing functionality. - *

- */ -public abstract class ProxyInputStream extends FilterInputStream { - - /** - * Constructs a new ProxyInputStream. - * - * @param proxy the InputStream to delegate to - */ - public ProxyInputStream(final InputStream proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'in' - } - - /** - * Invokes the delegate's {@code read()} method. - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read() throws IOException { - try { - beforeRead(1); - final int b = in.read(); - afterRead(b != EOF ? 1 : EOF); - return b; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code read(byte[])} method. - * @param bts the buffer to read the bytes into - * @return the number of bytes read or EOF if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] bts) throws IOException { - try { - beforeRead(IOUtils.length(bts)); - final int n = in.read(bts); - afterRead(n); - return n; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code read(byte[], int, int)} method. - * @param bts the buffer to read the bytes into - * @param off The start offset - * @param len The number of bytes to read - * @return the number of bytes read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] bts, final int off, final int len) throws IOException { - try { - beforeRead(len); - final int n = in.read(bts, off, len); - afterRead(n); - return n; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code skip(long)} method. - * @param ln the number of bytes to skip - * @return the actual number of bytes skipped - * @throws IOException if an I/O error occurs. - */ - @Override - public long skip(final long ln) throws IOException { - try { - return in.skip(ln); - } catch (final IOException e) { - handleIOException(e); - return 0; - } - } - - /** - * Invokes the delegate's {@code available()} method. - * @return the number of available bytes - * @throws IOException if an I/O error occurs. - */ - @Override - public int available() throws IOException { - try { - return super.available(); - } catch (final IOException e) { - handleIOException(e); - return 0; - } - } - - /** - * Invokes the delegate's {@code close()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - IOUtils.close(in, this::handleIOException); - } - - /** - * Invokes the delegate's {@code mark(int)} method. - * @param readlimit read ahead limit - */ - @Override - public synchronized void mark(final int readlimit) { - in.mark(readlimit); - } - - /** - * Invokes the delegate's {@code reset()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void reset() throws IOException { - try { - in.reset(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code markSupported()} method. - * @return true if mark is supported, otherwise false - */ - @Override - public boolean markSupported() { - return in.markSupported(); - } - - /** - * Invoked by the read methods before the call is proxied. The number - * of bytes that the caller wanted to read (1 for the {@link #read()} - * method, buffer length for {@link #read(byte[])}, etc.) is given as - * an argument. - *

- * Subclasses can override this method to add common pre-processing - * functionality without having to override all the read methods. - * The default implementation does nothing. - *

- * Note this method is not called from {@link #skip(long)} or - * {@link #reset()}. You need to explicitly override those methods if - * you want to add pre-processing steps also to them. - * - * @since 2.0 - * @param n number of bytes that the caller asked to be read - * @throws IOException if the pre-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void beforeRead(final int n) throws IOException { - // no-op - } - - /** - * Invoked by the read methods after the proxied call has returned - * successfully. The number of bytes returned to the caller (or -1 if - * the end of stream was reached) is given as an argument. - *

- * Subclasses can override this method to add common post-processing - * functionality without having to override all the read methods. - * The default implementation does nothing. - *

- * Note this method is not called from {@link #skip(long)} or - * {@link #reset()}. You need to explicitly override those methods if - * you want to add post-processing steps also to them. - * - * @since 2.0 - * @param n number of bytes read, or -1 if the end of stream was reached - * @throws IOException if the post-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void afterRead(final int n) throws IOException { - // no-op - } - - /** - * Handle any IOExceptions thrown. - *

- * This method provides a point to implement custom exception - * handling. The default behavior is to re-throw the exception. - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - protected void handleIOException(final IOException e) throws IOException { - throw e; - } - -} diff --git a/src/org/apache/commons/io/input/ProxyReader.java b/src/org/apache/commons/io/input/ProxyReader.java deleted file mode 100644 index 8ed16ae4..00000000 --- a/src/org/apache/commons/io/input/ProxyReader.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.FilterReader; -import java.io.IOException; -import java.io.Reader; -import java.nio.CharBuffer; - -import org.apache.commons.io.IOUtils; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. - *

- * It is an alternative base class to FilterReader - * to increase reusability, because FilterReader changes the - * methods being called, such as read(char[]) to read(char[], int, int). - *

- */ -public abstract class ProxyReader extends FilterReader { - - /** - * Constructs a new ProxyReader. - * - * @param proxy the Reader to delegate to - */ - public ProxyReader(final Reader proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'in' - } - - /** - * Invokes the delegate's {@code read()} method. - * @return the character read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read() throws IOException { - try { - beforeRead(1); - final int c = in.read(); - afterRead(c != EOF ? 1 : EOF); - return c; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code read(char[])} method. - * @param chr the buffer to read the characters into - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final char[] chr) throws IOException { - try { - beforeRead(IOUtils.length(chr)); - final int n = in.read(chr); - afterRead(n); - return n; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code read(char[], int, int)} method. - * @param chr the buffer to read the characters into - * @param st The start offset - * @param len The number of bytes to read - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final char[] chr, final int st, final int len) throws IOException { - try { - beforeRead(len); - final int n = in.read(chr, st, len); - afterRead(n); - return n; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code read(CharBuffer)} method. - * @param target the char buffer to read the characters into - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - @Override - public int read(final CharBuffer target) throws IOException { - try { - beforeRead(IOUtils.length(target)); - final int n = in.read(target); - afterRead(n); - return n; - } catch (final IOException e) { - handleIOException(e); - return EOF; - } - } - - /** - * Invokes the delegate's {@code skip(long)} method. - * @param ln the number of bytes to skip - * @return the number of bytes to skipped or EOF if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public long skip(final long ln) throws IOException { - try { - return in.skip(ln); - } catch (final IOException e) { - handleIOException(e); - return 0; - } - } - - /** - * Invokes the delegate's {@code ready()} method. - * @return true if the stream is ready to be read - * @throws IOException if an I/O error occurs. - */ - @Override - public boolean ready() throws IOException { - try { - return in.ready(); - } catch (final IOException e) { - handleIOException(e); - return false; - } - } - - /** - * Invokes the delegate's {@code close()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - try { - in.close(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code mark(int)} method. - * @param idx read ahead limit - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void mark(final int idx) throws IOException { - try { - in.mark(idx); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code reset()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void reset() throws IOException { - try { - in.reset(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code markSupported()} method. - * @return true if mark is supported, otherwise false - */ - @Override - public boolean markSupported() { - return in.markSupported(); - } - - /** - * Invoked by the read methods before the call is proxied. The number - * of chars that the caller wanted to read (1 for the {@link #read()} - * method, buffer length for {@link #read(char[])}, etc.) is given as - * an argument. - *

- * Subclasses can override this method to add common pre-processing - * functionality without having to override all the read methods. - * The default implementation does nothing. - *

- * Note this method is not called from {@link #skip(long)} or - * {@link #reset()}. You need to explicitly override those methods if - * you want to add pre-processing steps also to them. - * - * @since 2.0 - * @param n number of chars that the caller asked to be read - * @throws IOException if the pre-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void beforeRead(final int n) throws IOException { - // noop - } - - /** - * Invoked by the read methods after the proxied call has returned - * successfully. The number of chars returned to the caller (or -1 if - * the end of stream was reached) is given as an argument. - *

- * Subclasses can override this method to add common post-processing - * functionality without having to override all the read methods. - * The default implementation does nothing. - *

- * Note this method is not called from {@link #skip(long)} or - * {@link #reset()}. You need to explicitly override those methods if - * you want to add post-processing steps also to them. - * - * @since 2.0 - * @param n number of chars read, or -1 if the end of stream was reached - * @throws IOException if the post-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void afterRead(final int n) throws IOException { - // noop - } - - /** - * Handle any IOExceptions thrown. - *

- * This method provides a point to implement custom exception - * handling. The default behavior is to re-throw the exception. - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - protected void handleIOException(final IOException e) throws IOException { - throw e; - } - -} diff --git a/src/org/apache/commons/io/input/QueueInputStream.java b/src/org/apache/commons/io/input/QueueInputStream.java deleted file mode 100644 index 6b954a8c..00000000 --- a/src/org/apache/commons/io/input/QueueInputStream.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import org.apache.commons.io.output.QueueOutputStream; - -import java.io.InputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.util.Objects; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Simple alternative to JDK {@link java.io.PipedInputStream}; queue input stream provides what's written in queue - * output stream. - * - *

- * Example usage: - *

- *
- * QueueInputStream inputStream = new QueueInputStream();
- * QueueOutputStream outputStream = inputStream.newQueueOutputStream();
- *
- * outputStream.write("hello world".getBytes(UTF_8));
- * inputStream.read();
- * 
- *

- * Unlike JDK {@link PipedInputStream} and {@link PipedOutputStream}, queue input/output streams may be used safely in a - * single thread or multiple threads. Also, unlike JDK classes, no special meaning is attached to initial or current - * thread. Instances can be used longer after initial threads exited. - *

- *

- * Closing a {@code QueueInputStream} has no effect. The methods in this class can be called after the stream has been - * closed without generating an {@code IOException}. - *

- * - * @see QueueOutputStream - * @since 2.9.0 - */ -public class QueueInputStream extends InputStream { - - private final BlockingQueue blockingQueue; - - /** - * Constructs a new instance with no limit to its internal buffer size. - */ - public QueueInputStream() { - this(new LinkedBlockingQueue<>()); - } - - /** - * Constructs a new instance with given buffer - * - * @param blockingQueue backing queue for the stream - */ - public QueueInputStream(final BlockingQueue blockingQueue) { - this.blockingQueue = Objects.requireNonNull(blockingQueue, "blockingQueue"); - } - - /** - * Creates a new QueueOutputStream instance connected to this. Writes to the output stream will be visible to this - * input stream. - * - * @return QueueOutputStream connected to this stream - */ - public QueueOutputStream newQueueOutputStream() { - return new QueueOutputStream(blockingQueue); - } - - /** - * Reads and returns a single byte. - * - * @return either the byte read or {@code -1} if the end of the stream has been reached - */ - @Override - public int read() { - final Integer value = blockingQueue.poll(); - return value == null ? EOF : ((0xFF) & value); - } - -} diff --git a/src/org/apache/commons/io/input/RandomAccessFileInputStream.java b/src/org/apache/commons/io/input/RandomAccessFileInputStream.java deleted file mode 100644 index 584d8f32..00000000 --- a/src/org/apache/commons/io/input/RandomAccessFileInputStream.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.util.Objects; - -/** - * Streams data from a {@link RandomAccessFile} starting at its current position. - * - * @since 2.8.0 - */ -public class RandomAccessFileInputStream extends InputStream { - - private final boolean closeOnClose; - private final RandomAccessFile randomAccessFile; - - /** - * Constructs a new instance configured to leave the underlying file open when this stream is closed. - * - * @param file The file to stream. - */ - public RandomAccessFileInputStream(final RandomAccessFile file) { - this(file, false); - } - - /** - * Constructs a new instance. - * - * @param file The file to stream. - * @param closeOnClose Whether to close the underlying file when this stream is closed. - */ - public RandomAccessFileInputStream(final RandomAccessFile file, final boolean closeOnClose) { - this.randomAccessFile = Objects.requireNonNull(file, "file"); - this.closeOnClose = closeOnClose; - } - - /** - * Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream. - * - * If there are more than {@link Integer#MAX_VALUE} bytes available, return {@link Integer#MAX_VALUE}. - * - * @return An estimate of the number of bytes that can be read. - * @throws IOException If an I/O error occurs. - */ - @Override - public int available() throws IOException { - final long avail = availableLong(); - if (avail > Integer.MAX_VALUE) { - return Integer.MAX_VALUE; - } - return (int) avail; - } - - /** - * Returns the number of bytes that can be read (or skipped over) from this input stream. - * - * @return The number of bytes that can be read. - * @throws IOException If an I/O error occurs. - */ - public long availableLong() throws IOException { - return randomAccessFile.length() - randomAccessFile.getFilePointer(); - } - - @Override - public void close() throws IOException { - super.close(); - if (closeOnClose) { - randomAccessFile.close(); - } - } - - /** - * Gets the underlying file. - * - * @return the underlying file. - */ - public RandomAccessFile getRandomAccessFile() { - return randomAccessFile; - } - - /** - * Returns whether to close the underlying file when this stream is closed. - * - * @return Whether to close the underlying file when this stream is closed. - */ - public boolean isCloseOnClose() { - return closeOnClose; - } - - @Override - public int read() throws IOException { - return randomAccessFile.read(); - } - - @Override - public int read(final byte[] bytes) throws IOException { - return randomAccessFile.read(bytes); - } - - @Override - public int read(final byte[] bytes, final int offset, final int length) throws IOException { - return randomAccessFile.read(bytes, offset, length); - } - - /** - * Delegates to the underlying file. - * - * @param position See {@link RandomAccessFile#seek(long)}. - * @throws IOException See {@link RandomAccessFile#seek(long)}. - * @see RandomAccessFile#seek(long) - */ - private void seek(final long position) throws IOException { - randomAccessFile.seek(position); - } - - @Override - public long skip(final long skipCount) throws IOException { - if (skipCount <= 0) { - return 0; - } - final long filePointer = randomAccessFile.getFilePointer(); - final long fileLength = randomAccessFile.length(); - if (filePointer >= fileLength) { - return 0; - } - final long targetPos = filePointer + skipCount; - final long newPos = targetPos > fileLength ? fileLength - 1 : targetPos; - if (newPos > 0) { - seek(newPos); - } - return randomAccessFile.getFilePointer() - filePointer; - } -} diff --git a/src/org/apache/commons/io/input/ReadAheadInputStream.java b/src/org/apache/commons/io/input/ReadAheadInputStream.java deleted file mode 100644 index 34e69ac4..00000000 --- a/src/org/apache/commons/io/input/ReadAheadInputStream.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -// import javax.annotation.concurrent.GuardedBy; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.nio.ByteBuffer; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Implements {@link InputStream} to asynchronously read ahead from an underlying input stream when a specified amount - * of data has been read from the current buffer. It does so by maintaining two buffers: an active buffer and a read - * ahead buffer. The active buffer contains data which should be returned when a read() call is issued. The read ahead - * buffer is used to asynchronously read from the underlying input stream. When the current active buffer is exhausted, - * we flip the two buffers so that we can start reading from the read ahead buffer without being blocked by disk I/O. - *

- * This class was ported and adapted from Apache Spark commit 933dc6cb7b3de1d8ccaf73d124d6eb95b947ed19. - *

- * - * @since 2.9.0 - */ -public class ReadAheadInputStream extends InputStream { - - private static final ThreadLocal oneByte = ThreadLocal.withInitial(() -> new byte[1]); - - /** - * Creates a new daemon executor service. - * - * @return a new daemon executor service. - */ - private static ExecutorService newExecutorService() { - return Executors.newSingleThreadExecutor(ReadAheadInputStream::newThread); - } - - /** - * Creates a new daemon thread. - * - * @param r the thread's runnable. - * @return a new daemon thread. - */ - private static Thread newThread(final Runnable r) { - final Thread thread = new Thread(r, "commons-io-read-ahead"); - thread.setDaemon(true); - return thread; - } - - private final ReentrantLock stateChangeLock = new ReentrantLock(); - - // @GuardedBy("stateChangeLock") - private ByteBuffer activeBuffer; - - // @GuardedBy("stateChangeLock") - private ByteBuffer readAheadBuffer; - - // @GuardedBy("stateChangeLock") - private boolean endOfStream; - - // @GuardedBy("stateChangeLock") - // true if async read is in progress - private boolean readInProgress; - - // @GuardedBy("stateChangeLock") - // true if read is aborted due to an exception in reading from underlying input stream. - private boolean readAborted; - - // @GuardedBy("stateChangeLock") - private Throwable readException; - - // @GuardedBy("stateChangeLock") - // whether the close method is called. - private boolean isClosed; - - // @GuardedBy("stateChangeLock") - // true when the close method will close the underlying input stream. This is valid only if - // `isClosed` is true. - private boolean isUnderlyingInputStreamBeingClosed; - - // @GuardedBy("stateChangeLock") - // whether there is a read ahead task running, - private boolean isReading; - - // Whether there is a reader waiting for data. - private final AtomicBoolean isWaiting = new AtomicBoolean(false); - - private final InputStream underlyingInputStream; - - private final ExecutorService executorService; - - private final boolean shutdownExecutorService; - - private final Condition asyncReadComplete = stateChangeLock.newCondition(); - - /** - * Creates an instance with the specified buffer size and read-ahead threshold - * - * @param inputStream The underlying input stream. - * @param bufferSizeInBytes The buffer size. - */ - public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes) { - this(inputStream, bufferSizeInBytes, newExecutorService(), true); - } - - /** - * Creates an instance with the specified buffer size and read-ahead threshold - * - * @param inputStream The underlying input stream. - * @param bufferSizeInBytes The buffer size. - * @param executorService An executor service for the read-ahead thread. - */ - public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes, - final ExecutorService executorService) { - this(inputStream, bufferSizeInBytes, executorService, false); - } - - /** - * Creates an instance with the specified buffer size and read-ahead threshold - * - * @param inputStream The underlying input stream. - * @param bufferSizeInBytes The buffer size. - * @param executorService An executor service for the read-ahead thread. - * @param shutdownExecutorService Whether or not to shutdown the given ExecutorService on close. - */ - private ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes, - final ExecutorService executorService, final boolean shutdownExecutorService) { - if (bufferSizeInBytes <= 0) { - throw new IllegalArgumentException( - "bufferSizeInBytes should be greater than 0, but the value is " + bufferSizeInBytes); - } - this.executorService = Objects.requireNonNull(executorService, "executorService"); - this.underlyingInputStream = Objects.requireNonNull(inputStream, "inputStream"); - this.shutdownExecutorService = shutdownExecutorService; - this.activeBuffer = ByteBuffer.allocate(bufferSizeInBytes); - this.readAheadBuffer = ByteBuffer.allocate(bufferSizeInBytes); - this.activeBuffer.flip(); - this.readAheadBuffer.flip(); - } - - @Override - public int available() throws IOException { - stateChangeLock.lock(); - // Make sure we have no integer overflow. - try { - return (int) Math.min(Integer.MAX_VALUE, (long) activeBuffer.remaining() + readAheadBuffer.remaining()); - } finally { - stateChangeLock.unlock(); - } - } - - private void checkReadException() throws IOException { - if (readAborted) { - if (readException instanceof IOException) { - throw (IOException) readException; - } - throw new IOException(readException); - } - } - - @Override - public void close() throws IOException { - boolean isSafeToCloseUnderlyingInputStream = false; - stateChangeLock.lock(); - try { - if (isClosed) { - return; - } - isClosed = true; - if (!isReading) { - // Nobody is reading, so we can close the underlying input stream in this method. - isSafeToCloseUnderlyingInputStream = true; - // Flip this to make sure the read ahead task will not close the underlying input stream. - isUnderlyingInputStreamBeingClosed = true; - } - } finally { - stateChangeLock.unlock(); - } - - if (shutdownExecutorService) { - try { - executorService.shutdownNow(); - executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); - } catch (final InterruptedException e) { - final InterruptedIOException iio = new InterruptedIOException(e.getMessage()); - iio.initCause(e); - throw iio; - } finally { - if (isSafeToCloseUnderlyingInputStream) { - underlyingInputStream.close(); - } - } - } - } - - private void closeUnderlyingInputStreamIfNecessary() { - boolean needToCloseUnderlyingInputStream = false; - stateChangeLock.lock(); - try { - isReading = false; - if (isClosed && !isUnderlyingInputStreamBeingClosed) { - // close method cannot close underlyingInputStream because we were reading. - needToCloseUnderlyingInputStream = true; - } - } finally { - stateChangeLock.unlock(); - } - if (needToCloseUnderlyingInputStream) { - try { - underlyingInputStream.close(); - } catch (final IOException e) { - // TODO ? - } - } - } - - private boolean isEndOfStream() { - return !activeBuffer.hasRemaining() && !readAheadBuffer.hasRemaining() && endOfStream; - } - - @Override - public int read() throws IOException { - if (activeBuffer.hasRemaining()) { - // short path - just get one byte. - return activeBuffer.get() & 0xFF; - } - final byte[] oneByteArray = oneByte.get(); - return read(oneByteArray, 0, 1) == EOF ? -1 : oneByteArray[0] & 0xFF; - } - - @Override - public int read(final byte[] b, final int offset, int len) throws IOException { - if (offset < 0 || len < 0 || len > b.length - offset) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) { - return 0; - } - - if (!activeBuffer.hasRemaining()) { - // No remaining in active buffer - lock and switch to write ahead buffer. - stateChangeLock.lock(); - try { - waitForAsyncReadComplete(); - if (!readAheadBuffer.hasRemaining()) { - // The first read. - readAsync(); - waitForAsyncReadComplete(); - if (isEndOfStream()) { - return EOF; - } - } - // Swap the newly read read ahead buffer in place of empty active buffer. - swapBuffers(); - // After swapping buffers, trigger another async read for read ahead buffer. - readAsync(); - } finally { - stateChangeLock.unlock(); - } - } - len = Math.min(len, activeBuffer.remaining()); - activeBuffer.get(b, offset, len); - - return len; - } - - /** Read data from underlyingInputStream to readAheadBuffer asynchronously. */ - private void readAsync() throws IOException { - stateChangeLock.lock(); - final byte[] arr; - try { - arr = readAheadBuffer.array(); - if (endOfStream || readInProgress) { - return; - } - checkReadException(); - readAheadBuffer.position(0); - readAheadBuffer.flip(); - readInProgress = true; - } finally { - stateChangeLock.unlock(); - } - executorService.execute(() -> { - stateChangeLock.lock(); - try { - if (isClosed) { - readInProgress = false; - return; - } - // Flip this so that the close method will not close the underlying input stream when we - // are reading. - isReading = true; - } finally { - stateChangeLock.unlock(); - } - - // Please note that it is safe to release the lock and read into the read ahead buffer - // because either of following two conditions will hold: - // - // 1. The active buffer has data available to read so the reader will not read from the read ahead buffer. - // - // 2. This is the first time read is called or the active buffer is exhausted, in that case the reader waits - // for this async read to complete. - // - // So there is no race condition in both the situations. - int read = 0; - int off = 0, len = arr.length; - Throwable exception = null; - try { - // try to fill the read ahead buffer. - // if a reader is waiting, possibly return early. - do { - read = underlyingInputStream.read(arr, off, len); - if (read <= 0) { - break; - } - off += read; - len -= read; - } while (len > 0 && !isWaiting.get()); - } catch (final Throwable ex) { - exception = ex; - if (ex instanceof Error) { - // `readException` may not be reported to the user. Rethrow Error to make sure at least - // The user can see Error in UncaughtExceptionHandler. - throw (Error) ex; - } - } finally { - stateChangeLock.lock(); - try { - readAheadBuffer.limit(off); - if (read < 0 || (exception instanceof EOFException)) { - endOfStream = true; - } else if (exception != null) { - readAborted = true; - readException = exception; - } - readInProgress = false; - signalAsyncReadComplete(); - } finally { - stateChangeLock.unlock(); - } - closeUnderlyingInputStreamIfNecessary(); - } - }); - } - - private void signalAsyncReadComplete() { - stateChangeLock.lock(); - try { - asyncReadComplete.signalAll(); - } finally { - stateChangeLock.unlock(); - } - } - - @Override - public long skip(final long n) throws IOException { - if (n <= 0L) { - return 0L; - } - if (n <= activeBuffer.remaining()) { - // Only skipping from active buffer is sufficient - activeBuffer.position((int) n + activeBuffer.position()); - return n; - } - stateChangeLock.lock(); - long skipped; - try { - skipped = skipInternal(n); - } finally { - stateChangeLock.unlock(); - } - return skipped; - } - - /** - * Internal skip function which should be called only from skip(). The assumption is that the stateChangeLock is - * already acquired in the caller before calling this function. - * - * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. - */ - private long skipInternal(final long n) throws IOException { - assert stateChangeLock.isLocked(); - waitForAsyncReadComplete(); - if (isEndOfStream()) { - return 0; - } - if (available() >= n) { - // we can skip from the internal buffers - int toSkip = (int) n; - // We need to skip from both active buffer and read ahead buffer - toSkip -= activeBuffer.remaining(); - assert toSkip > 0; // skipping from activeBuffer already handled. - activeBuffer.position(0); - activeBuffer.flip(); - readAheadBuffer.position(toSkip + readAheadBuffer.position()); - swapBuffers(); - // Trigger async read to emptied read ahead buffer. - readAsync(); - return n; - } - final int skippedBytes = available(); - final long toSkip = n - skippedBytes; - activeBuffer.position(0); - activeBuffer.flip(); - readAheadBuffer.position(0); - readAheadBuffer.flip(); - final long skippedFromInputStream = underlyingInputStream.skip(toSkip); - readAsync(); - return skippedBytes + skippedFromInputStream; - } - - /** - * Flips the active and read ahead buffer - */ - private void swapBuffers() { - final ByteBuffer temp = activeBuffer; - activeBuffer = readAheadBuffer; - readAheadBuffer = temp; - } - - private void waitForAsyncReadComplete() throws IOException { - stateChangeLock.lock(); - try { - isWaiting.set(true); - // There is only one reader, and one writer, so the writer should signal only once, - // but a while loop checking the wake up condition is still needed to avoid spurious wakeups. - while (readInProgress) { - asyncReadComplete.await(); - } - } catch (final InterruptedException e) { - final InterruptedIOException iio = new InterruptedIOException(e.getMessage()); - iio.initCause(e); - throw iio; - } finally { - isWaiting.set(false); - stateChangeLock.unlock(); - } - checkReadException(); - } -} diff --git a/src/org/apache/commons/io/input/ReaderInputStream.java b/src/org/apache/commons/io/input/ReaderInputStream.java deleted file mode 100644 index 806c2913..00000000 --- a/src/org/apache/commons/io/input/ReaderInputStream.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.util.Objects; - -/** - * {@link InputStream} implementation that reads a character stream from a {@link Reader} - * and transforms it to a byte stream using a specified charset encoding. The stream - * is transformed using a {@link CharsetEncoder} object, guaranteeing that all charset - * encodings supported by the JRE are handled correctly. In particular for charsets such as - * UTF-16, the implementation ensures that one and only one byte order marker - * is produced. - *

- * Since in general it is not possible to predict the number of characters to be read from the - * {@link Reader} to satisfy a read request on the {@link ReaderInputStream}, all reads from - * the {@link Reader} are buffered. There is therefore no well defined correlation - * between the current position of the {@link Reader} and that of the {@link ReaderInputStream}. - * This also implies that in general there is no need to wrap the underlying {@link Reader} - * in a {@link java.io.BufferedReader}. - *

- * {@link ReaderInputStream} implements the inverse transformation of {@link java.io.InputStreamReader}; - * in the following example, reading from {@code in2} would return the same byte - * sequence as reading from {@code in} (provided that the initial byte sequence is legal - * with respect to the charset encoding): - *

- * InputStream inputStream = ...
- * Charset cs = ...
- * InputStreamReader reader = new InputStreamReader(inputStream, cs);
- * ReaderInputStream in2 = new ReaderInputStream(reader, cs);
- * - * {@link ReaderInputStream} implements the same transformation as {@link java.io.OutputStreamWriter}, - * except that the control flow is reversed: both classes transform a character stream - * into a byte stream, but {@link java.io.OutputStreamWriter} pushes data to the underlying stream, - * while {@link ReaderInputStream} pulls it from the underlying stream. - *

- * Note that while there are use cases where there is no alternative to using - * this class, very often the need to use this class is an indication of a flaw - * in the design of the code. This class is typically used in situations where an existing - * API only accepts an {@link InputStream}, but where the most natural way to produce the data - * is as a character stream, i.e. by providing a {@link Reader} instance. An example of a situation - * where this problem may appear is when implementing the {@code javax.activation.DataSource} - * interface from the Java Activation Framework. - *

- * Given the fact that the {@link Reader} class doesn't provide any way to predict whether the next - * read operation will block or not, it is not possible to provide a meaningful - * implementation of the {@link InputStream#available()} method. A call to this method - * will always return 0. Also, this class doesn't support {@link InputStream#mark(int)}. - *

- *

- * Instances of {@link ReaderInputStream} are not thread safe. - *

- * - * @see org.apache.commons.io.output.WriterOutputStream - * - * @since 2.0 - */ -public class ReaderInputStream extends InputStream { - private static final int DEFAULT_BUFFER_SIZE = 1024; - - private final Reader reader; - private final CharsetEncoder encoder; - - /** - * CharBuffer used as input for the decoder. It should be reasonably - * large as we read data from the underlying Reader into this buffer. - */ - private final CharBuffer encoderIn; - - /** - * ByteBuffer used as output for the decoder. This buffer can be small - * as it is only used to transfer data from the decoder to the - * buffer provided by the caller. - */ - private final ByteBuffer encoderOut; - - private CoderResult lastCoderResult; - private boolean endOfInput; - - /** - * Construct a new {@link ReaderInputStream}. - * - * @param reader the target {@link Reader} - * @param encoder the charset encoder - * @since 2.1 - */ - public ReaderInputStream(final Reader reader, final CharsetEncoder encoder) { - this(reader, encoder, DEFAULT_BUFFER_SIZE); - } - - /** - * Construct a new {@link ReaderInputStream}. - * - * @param reader the target {@link Reader} - * @param encoder the charset encoder - * @param bufferSize the size of the input buffer in number of characters - * @since 2.1 - */ - public ReaderInputStream(final Reader reader, final CharsetEncoder encoder, final int bufferSize) { - this.reader = reader; - this.encoder = encoder; - this.encoderIn = CharBuffer.allocate(bufferSize); - this.encoderIn.flip(); - this.encoderOut = ByteBuffer.allocate(128); - this.encoderOut.flip(); - } - - /** - * Construct a new {@link ReaderInputStream}. - * - * @param reader the target {@link Reader} - * @param charset the charset encoding - * @param bufferSize the size of the input buffer in number of characters - */ - public ReaderInputStream(final Reader reader, final Charset charset, final int bufferSize) { - this(reader, - charset.newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE), - bufferSize); - } - - /** - * Construct a new {@link ReaderInputStream} with a default input buffer size of - * {@value #DEFAULT_BUFFER_SIZE} characters. - * - * @param reader the target {@link Reader} - * @param charset the charset encoding - */ - public ReaderInputStream(final Reader reader, final Charset charset) { - this(reader, charset, DEFAULT_BUFFER_SIZE); - } - - /** - * Construct a new {@link ReaderInputStream}. - * - * @param reader the target {@link Reader} - * @param charsetName the name of the charset encoding - * @param bufferSize the size of the input buffer in number of characters - */ - public ReaderInputStream(final Reader reader, final String charsetName, final int bufferSize) { - this(reader, Charset.forName(charsetName), bufferSize); - } - - /** - * Construct a new {@link ReaderInputStream} with a default input buffer size of - * {@value #DEFAULT_BUFFER_SIZE} characters. - * - * @param reader the target {@link Reader} - * @param charsetName the name of the charset encoding - */ - public ReaderInputStream(final Reader reader, final String charsetName) { - this(reader, charsetName, DEFAULT_BUFFER_SIZE); - } - - /** - * Construct a new {@link ReaderInputStream} that uses the default character encoding - * with a default input buffer size of {@value #DEFAULT_BUFFER_SIZE} characters. - * - * @param reader the target {@link Reader} - * @deprecated 2.5 use {@link #ReaderInputStream(Reader, Charset)} instead - */ - @Deprecated - public ReaderInputStream(final Reader reader) { - this(reader, Charset.defaultCharset()); - } - - /** - * Fills the internal char buffer from the reader. - * - * @throws IOException - * If an I/O error occurs - */ - private void fillBuffer() throws IOException { - if (!endOfInput && (lastCoderResult == null || lastCoderResult.isUnderflow())) { - encoderIn.compact(); - final int position = encoderIn.position(); - // We don't use Reader#read(CharBuffer) here because it is more efficient - // to write directly to the underlying char array (the default implementation - // copies data to a temporary char array). - final int c = reader.read(encoderIn.array(), position, encoderIn.remaining()); - if (c == EOF) { - endOfInput = true; - } else { - encoderIn.position(position+c); - } - encoderIn.flip(); - } - encoderOut.compact(); - lastCoderResult = encoder.encode(encoderIn, encoderOut, endOfInput); - encoderOut.flip(); - } - - /** - * Read the specified number of bytes into an array. - * - * @param array the byte array to read into - * @param off the offset to start reading bytes into - * @param len the number of bytes to read - * @return the number of bytes read or {@code -1} - * if the end of the stream has been reached - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] array, int off, int len) throws IOException { - Objects.requireNonNull(array, "array"); - if (len < 0 || off < 0 || (off + len) > array.length) { - throw new IndexOutOfBoundsException("Array Size=" + array.length + - ", offset=" + off + ", length=" + len); - } - int read = 0; - if (len == 0) { - return 0; // Always return 0 if len == 0 - } - while (len > 0) { - if (encoderOut.hasRemaining()) { - final int c = Math.min(encoderOut.remaining(), len); - encoderOut.get(array, off, c); - off += c; - len -= c; - read += c; - } else { - fillBuffer(); - if (endOfInput && !encoderOut.hasRemaining()) { - break; - } - } - } - return read == 0 && endOfInput ? EOF : read; - } - - /** - * Read the specified number of bytes into an array. - * - * @param b the byte array to read into - * @return the number of bytes read or {@code -1} - * if the end of the stream has been reached - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final byte[] b) throws IOException { - return read(b, 0, b.length); - } - - /** - * Read a single byte. - * - * @return either the byte read or {@code -1} if the end of the stream - * has been reached - * @throws IOException if an I/O error occurs. - */ - @Override - public int read() throws IOException { - for (;;) { - if (encoderOut.hasRemaining()) { - return encoderOut.get() & 0xFF; - } - fillBuffer(); - if (endOfInput && !encoderOut.hasRemaining()) { - return EOF; - } - } - } - - /** - * Close the stream. This method will cause the underlying {@link Reader} - * to be closed. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - reader.close(); - } -} diff --git a/src/org/apache/commons/io/input/ReversedLinesFileReader.java b/src/org/apache/commons/io/input/ReversedLinesFileReader.java deleted file mode 100644 index 3cd8a968..00000000 --- a/src/org/apache/commons/io/input/ReversedLinesFileReader.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.io.Charsets; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.StandardLineSeparator; - -/** - * Reads lines in a file reversely (similar to a BufferedReader, but starting at - * the last line). Useful for e.g. searching in log files. - * - * @since 2.2 - */ -public class ReversedLinesFileReader implements Closeable { - - private class FilePart { - private final long no; - - private final byte[] data; - - private byte[] leftOver; - - private int currentLastBytePos; - - /** - * ctor - * - * @param no the part number - * @param length its length - * @param leftOverOfLastFilePart remainder - * @throws IOException if there is a problem reading the file - */ - private FilePart(final long no, final int length, final byte[] leftOverOfLastFilePart) throws IOException { - this.no = no; - final int dataLength = length + (leftOverOfLastFilePart != null ? leftOverOfLastFilePart.length : 0); - this.data = new byte[dataLength]; - final long off = (no - 1) * blockSize; - - // read data - if (no > 0 /* file not empty */) { - channel.position(off); - final int countRead = channel.read(ByteBuffer.wrap(data, 0, length)); - if (countRead != length) { - throw new IllegalStateException("Count of requested bytes and actually read bytes don't match"); - } - } - // copy left over part into data arr - if (leftOverOfLastFilePart != null) { - System.arraycopy(leftOverOfLastFilePart, 0, data, length, leftOverOfLastFilePart.length); - } - this.currentLastBytePos = data.length - 1; - this.leftOver = null; - } - - /** - * Creates the buffer containing any left over bytes. - */ - private void createLeftOver() { - final int lineLengthBytes = currentLastBytePos + 1; - if (lineLengthBytes > 0) { - // create left over for next block - leftOver = IOUtils.byteArray(lineLengthBytes); - System.arraycopy(data, 0, leftOver, 0, lineLengthBytes); - } else { - leftOver = null; - } - currentLastBytePos = -1; - } - - /** - * Finds the new-line sequence and return its length. - * - * @param data buffer to scan - * @param i start offset in buffer - * @return length of newline sequence or 0 if none found - */ - private int getNewLineMatchByteCount(final byte[] data, final int i) { - for (final byte[] newLineSequence : newLineSequences) { - boolean match = true; - for (int j = newLineSequence.length - 1; j >= 0; j--) { - final int k = i + j - (newLineSequence.length - 1); - match &= k >= 0 && data[k] == newLineSequence[j]; - } - if (match) { - return newLineSequence.length; - } - } - return 0; - } - - /** - * Reads a line. - * - * @return the line or null - */ - private String readLine() { - - String line = null; - int newLineMatchByteCount; - - final boolean isLastFilePart = no == 1; - - int i = currentLastBytePos; - while (i > -1) { - - if (!isLastFilePart && i < avoidNewlineSplitBufferSize) { - // avoidNewlineSplitBuffer: for all except the last file part we - // take a few bytes to the next file part to avoid splitting of newlines - createLeftOver(); - break; // skip last few bytes and leave it to the next file part - } - - // --- check for newline --- - if ((newLineMatchByteCount = getNewLineMatchByteCount(data, i)) > 0 /* found newline */) { - final int lineStart = i + 1; - final int lineLengthBytes = currentLastBytePos - lineStart + 1; - - if (lineLengthBytes < 0) { - throw new IllegalStateException("Unexpected negative line length=" + lineLengthBytes); - } - final byte[] lineData = IOUtils.byteArray(lineLengthBytes); - System.arraycopy(data, lineStart, lineData, 0, lineLengthBytes); - - line = new String(lineData, charset); - - currentLastBytePos = i - newLineMatchByteCount; - break; // found line - } - - // --- move cursor --- - i -= byteDecrement; - - // --- end of file part handling --- - if (i < 0) { - createLeftOver(); - break; // end of file part - } - } - - // --- last file part handling --- - if (isLastFilePart && leftOver != null) { - // there will be no line break anymore, this is the first line of the file - line = new String(leftOver, charset); - leftOver = null; - } - - return line; - } - - /** - * Handles block rollover - * - * @return the new FilePart or null - * @throws IOException if there was a problem reading the file - */ - private FilePart rollOver() throws IOException { - - if (currentLastBytePos > -1) { - throw new IllegalStateException("Current currentLastCharPos unexpectedly positive... " - + "last readLine() should have returned something! currentLastCharPos=" + currentLastBytePos); - } - - if (no > 1) { - return new FilePart(no - 1, blockSize, leftOver); - } - // NO 1 was the last FilePart, we're finished - if (leftOver != null) { - throw new IllegalStateException("Unexpected leftover of the last block: leftOverOfThisFilePart=" - + new String(leftOver, charset)); - } - return null; - } - } - - private static final String EMPTY_STRING = ""; - private static final int DEFAULT_BLOCK_SIZE = IOUtils.DEFAULT_BUFFER_SIZE; - - private final int blockSize; - private final Charset charset; - private final SeekableByteChannel channel; - private final long totalByteLength; - private final long totalBlockCount; - private final byte[][] newLineSequences; - private final int avoidNewlineSplitBufferSize; - private final int byteDecrement; - private FilePart currentFilePart; - private boolean trailingNewlineOfFileSkipped; - - /** - * Creates a ReversedLinesFileReader with default block size of 4KB and the - * platform's default encoding. - * - * @param file the file to be read - * @throws IOException if an I/O error occurs. - * @deprecated 2.5 use {@link #ReversedLinesFileReader(File, Charset)} instead - */ - @Deprecated - public ReversedLinesFileReader(final File file) throws IOException { - this(file, DEFAULT_BLOCK_SIZE, Charset.defaultCharset()); - } - - /** - * Creates a ReversedLinesFileReader with default block size of 4KB and the - * specified encoding. - * - * @param file the file to be read - * @param charset the charset to use, null uses the default Charset. - * @throws IOException if an I/O error occurs. - * @since 2.5 - */ - public ReversedLinesFileReader(final File file, final Charset charset) throws IOException { - this(file.toPath(), charset); - } - - /** - * Creates a ReversedLinesFileReader with the given block size and encoding. - * - * @param file the file to be read - * @param blockSize size of the internal buffer (for ideal performance this - * should match with the block size of the underlying file - * system). - * @param charset the encoding of the file, null uses the default Charset. - * @throws IOException if an I/O error occurs. - * @since 2.3 - */ - public ReversedLinesFileReader(final File file, final int blockSize, final Charset charset) throws IOException { - this(file.toPath(), blockSize, charset); - } - - /** - * Creates a ReversedLinesFileReader with the given block size and encoding. - * - * @param file the file to be read - * @param blockSize size of the internal buffer (for ideal performance this - * should match with the block size of the underlying file - * system). - * @param charsetName the encoding of the file, null uses the default Charset. - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of - * {@link UnsupportedEncodingException} - * in version 2.2 if the - * encoding is not - * supported. - */ - public ReversedLinesFileReader(final File file, final int blockSize, final String charsetName) throws IOException { - this(file.toPath(), blockSize, charsetName); - } - - /** - * Creates a ReversedLinesFileReader with default block size of 4KB and the - * specified encoding. - * - * @param file the file to be read - * @param charset the charset to use, null uses the default Charset. - * @throws IOException if an I/O error occurs. - * @since 2.7 - */ - public ReversedLinesFileReader(final Path file, final Charset charset) throws IOException { - this(file, DEFAULT_BLOCK_SIZE, charset); - } - - /** - * Creates a ReversedLinesFileReader with the given block size and encoding. - * - * @param file the file to be read - * @param blockSize size of the internal buffer (for ideal performance this - * should match with the block size of the underlying file - * system). - * @param charset the encoding of the file, null uses the default Charset. - * @throws IOException if an I/O error occurs. - * @since 2.7 - */ - public ReversedLinesFileReader(final Path file, final int blockSize, final Charset charset) throws IOException { - this.blockSize = blockSize; - this.charset = Charsets.toCharset(charset); - - // --- check & prepare encoding --- - final CharsetEncoder charsetEncoder = this.charset.newEncoder(); - final float maxBytesPerChar = charsetEncoder.maxBytesPerChar(); - if (maxBytesPerChar == 1f) { - // all one byte encodings are no problem - byteDecrement = 1; - } else if (this.charset == StandardCharsets.UTF_8) { - // UTF-8 works fine out of the box, for multibyte sequences a second UTF-8 byte - // can never be a newline byte - // http://en.wikipedia.org/wiki/UTF-8 - byteDecrement = 1; - } else if (this.charset == Charset.forName("Shift_JIS") || // Same as for UTF-8 - // http://www.herongyang.com/Unicode/JIS-Shift-JIS-Encoding.html - this.charset == Charset.forName("windows-31j") || // Windows code page 932 (Japanese) - this.charset == Charset.forName("x-windows-949") || // Windows code page 949 (Korean) - this.charset == Charset.forName("gbk") || // Windows code page 936 (Simplified Chinese) - this.charset == Charset.forName("x-windows-950")) { // Windows code page 950 (Traditional Chinese) - byteDecrement = 1; - } else if (this.charset == StandardCharsets.UTF_16BE || this.charset == StandardCharsets.UTF_16LE) { - // UTF-16 new line sequences are not allowed as second tuple of four byte - // sequences, - // however byte order has to be specified - byteDecrement = 2; - } else if (this.charset == StandardCharsets.UTF_16) { - throw new UnsupportedEncodingException( - "For UTF-16, you need to specify the byte order (use UTF-16BE or " + "UTF-16LE)"); - } else { - throw new UnsupportedEncodingException( - "Encoding " + charset + " is not supported yet (feel free to " + "submit a patch)"); - } - - // NOTE: The new line sequences are matched in the order given, so it is - // important that \r\n is BEFORE \n - this.newLineSequences = new byte[][] { - StandardLineSeparator.CRLF.getBytes(this.charset), - StandardLineSeparator.LF.getBytes(this.charset), - StandardLineSeparator.CR.getBytes(this.charset) - }; - - this.avoidNewlineSplitBufferSize = newLineSequences[0].length; - - // Open file - this.channel = Files.newByteChannel(file, StandardOpenOption.READ); - this.totalByteLength = channel.size(); - int lastBlockLength = (int) (this.totalByteLength % blockSize); - if (lastBlockLength > 0) { - this.totalBlockCount = this.totalByteLength / blockSize + 1; - } else { - this.totalBlockCount = this.totalByteLength / blockSize; - if (this.totalByteLength > 0) { - lastBlockLength = blockSize; - } - } - this.currentFilePart = new FilePart(totalBlockCount, lastBlockLength, null); - - } - - /** - * Creates a ReversedLinesFileReader with the given block size and encoding. - * - * @param file the file to be read - * @param blockSize size of the internal buffer (for ideal performance this - * should match with the block size of the underlying file - * system). - * @param charsetName the encoding of the file, null uses the default Charset. - * @throws IOException if an I/O error occurs - * @throws java.nio.charset.UnsupportedCharsetException thrown instead of - * {@link UnsupportedEncodingException} - * in version 2.2 if the - * encoding is not - * supported. - * @since 2.7 - */ - public ReversedLinesFileReader(final Path file, final int blockSize, final String charsetName) throws IOException { - this(file, blockSize, Charsets.toCharset(charsetName)); - } - - /** - * Closes underlying resources. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - channel.close(); - } - - /** - * Returns the lines of the file from bottom to top. - * - * @return the next line or null if the start of the file is reached - * @throws IOException if an I/O error occurs. - */ - public String readLine() throws IOException { - - String line = currentFilePart.readLine(); - while (line == null) { - currentFilePart = currentFilePart.rollOver(); - if (currentFilePart == null) { - // no more fileparts: we're done, leave line set to null - break; - } - line = currentFilePart.readLine(); - } - - // aligned behavior with BufferedReader that doesn't return a last, empty line - if (EMPTY_STRING.equals(line) && !trailingNewlineOfFileSkipped) { - trailingNewlineOfFileSkipped = true; - line = readLine(); - } - - return line; - } - - /** - * Returns {@code lineCount} lines of the file from bottom to top. - *

- * If there are less than {@code lineCount} lines in the file, then that's what - * you get. - *

- *

- * Note: You can easily flip the result with {@link Collections#reverse(List)}. - *

- * - * @param lineCount How many lines to read. - * @return A new list - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public List readLines(final int lineCount) throws IOException { - if (lineCount < 0) { - throw new IllegalArgumentException("lineCount < 0"); - } - final ArrayList arrayList = new ArrayList<>(lineCount); - for (int i = 0; i < lineCount; i++) { - final String line = readLine(); - if (line == null) { - return arrayList; - } - arrayList.add(line); - } - return arrayList; - } - - /** - * Returns the last {@code lineCount} lines of the file. - *

- * If there are less than {@code lineCount} lines in the file, then that's what - * you get. - *

- * - * @param lineCount How many lines to read. - * @return A String. - * @throws IOException if an I/O error occurs. - * @since 2.8.0 - */ - public String toString(final int lineCount) throws IOException { - final List lines = readLines(lineCount); - Collections.reverse(lines); - return lines.isEmpty() ? EMPTY_STRING : String.join(System.lineSeparator(), lines) + System.lineSeparator(); - } - -} diff --git a/src/org/apache/commons/io/input/SequenceReader.java b/src/org/apache/commons/io/input/SequenceReader.java deleted file mode 100644 index a80552f7..00000000 --- a/src/org/apache/commons/io/input/SequenceReader.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.Reader; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Objects; - -/** - * Provides the contents of multiple Readers in sequence. - * - * @since 2.7 - */ -public class SequenceReader extends Reader { - - private Reader reader; - private Iterator readers; - - /** - * Construct a new instance with readers - * - * @param readers the readers to read - */ - public SequenceReader(final Iterable readers) { - this.readers = Objects.requireNonNull(readers, "readers").iterator(); - this.reader = nextReader(); - } - - /** - * Construct a new instance with readers - * - * @param readers the readers to read - */ - public SequenceReader(final Reader... readers) { - this(Arrays.asList(readers)); - } - - /* - * (non-Javadoc) - * - * @see java.io.Reader#close() - */ - @Override - public void close() throws IOException { - this.readers = null; - this.reader = null; - } - - /** - * Returns the next available reader or null if done. - * - * @return the next available reader or null - */ - private Reader nextReader() { - return this.readers.hasNext() ? this.readers.next() : null; - } - - /* - * (non-Javadoc) - * - * @see java.io.Reader#read(char[], int, int) - */ - @Override - public int read() throws IOException { - int c = EOF; - while (reader != null) { - c = reader.read(); - if (c != EOF) { - break; - } - reader = nextReader(); - } - return c; - } - - /* - * (non-Javadoc) - * - * @see java.io.Reader#read() - */ - @Override - public int read(final char[] cbuf, int off, int len) throws IOException { - Objects.requireNonNull(cbuf, "cbuf"); - if (len < 0 || off < 0 || off + len > cbuf.length) { - throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + ", offset=" + off + ", length=" + len); - } - int count = 0; - while (reader != null) { - final int readLen = reader.read(cbuf, off, len); - if (readLen == EOF) { - reader = nextReader(); - } else { - count += readLen; - off += readLen; - len -= readLen; - if (len <= 0) { - break; - } - } - } - if (count > 0) { - return count; - } - return EOF; - } -} diff --git a/src/org/apache/commons/io/input/SwappedDataInputStream.java b/src/org/apache/commons/io/input/SwappedDataInputStream.java deleted file mode 100644 index 3df793aa..00000000 --- a/src/org/apache/commons/io/input/SwappedDataInputStream.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.DataInput; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.EndianUtils; - -/** - * DataInput for systems relying on little endian data formats. When read, values will be changed from little endian to - * big endian formats for internal usage. - *

- * Origin of code: Avalon Excalibur (IO) - *

- * - */ -public class SwappedDataInputStream extends ProxyInputStream implements DataInput { - - /** - * Constructs a SwappedDataInputStream. - * - * @param input InputStream to read from - */ - public SwappedDataInputStream(final InputStream input) { - super(input); - } - - /** - * Return {@link #readByte()} != 0 - * - * @return false if the byte read is zero, otherwise true - * @throws IOException if an I/O error occurs. - * @throws EOFException if an end of file is reached unexpectedly - */ - @Override - public boolean readBoolean() throws IOException, EOFException { - return 0 != readByte(); - } - - /** - * Invokes the delegate's {@code read()} method. - * - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - * @throws EOFException if an end of file is reached unexpectedly - */ - @Override - public byte readByte() throws IOException, EOFException { - return (byte) in.read(); - } - - /** - * Reads a character delegating to {@link #readShort()}. - * - * @return the byte read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - * @throws EOFException if an end of file is reached unexpectedly - */ - @Override - public char readChar() throws IOException, EOFException { - return (char) readShort(); - } - - /** - * Delegates to {@link EndianUtils#readSwappedDouble(InputStream)}. - * - * @return the read long - * @throws IOException if an I/O error occurs. - * @throws EOFException if an end of file is reached unexpectedly - */ - @Override - public double readDouble() throws IOException, EOFException { - return EndianUtils.readSwappedDouble(in); - } - - /** - * Delegates to {@link EndianUtils#readSwappedFloat(InputStream)}. - * - * @return the read long - * @throws IOException if an I/O error occurs. - * @throws EOFException if an end of file is reached unexpectedly - */ - @Override - public float readFloat() throws IOException, EOFException { - return EndianUtils.readSwappedFloat(in); - } - - /** - * Invokes the delegate's {@code read(byte[] data, int, int)} method. - * - * @param data the buffer to read the bytes into - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public void readFully(final byte[] data) throws IOException, EOFException { - readFully(data, 0, data.length); - } - - /** - * Invokes the delegate's {@code read(byte[] data, int, int)} method. - * - * @param data the buffer to read the bytes into - * @param offset The start offset - * @param length The number of bytes to read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public void readFully(final byte[] data, final int offset, final int length) throws IOException, EOFException { - int remaining = length; - - while (remaining > 0) { - final int location = offset + length - remaining; - final int count = read(data, location, remaining); - - if (EOF == count) { - throw new EOFException(); - } - - remaining -= count; - } - } - - /** - * Delegates to {@link EndianUtils#readSwappedInteger(InputStream)}. - * - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public int readInt() throws IOException, EOFException { - return EndianUtils.readSwappedInteger(in); - } - - /** - * Not currently supported - throws {@link UnsupportedOperationException}. - * - * @return the line read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public String readLine() throws IOException, EOFException { - throw UnsupportedOperationExceptions.method("readLine"); - } - - /** - * Delegates to {@link EndianUtils#readSwappedLong(InputStream)}. - * - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public long readLong() throws IOException, EOFException { - return EndianUtils.readSwappedLong(in); - } - - /** - * Delegates to {@link EndianUtils#readSwappedShort(InputStream)}. - * - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public short readShort() throws IOException, EOFException { - return EndianUtils.readSwappedShort(in); - } - - /** - * Invokes the delegate's {@code read()} method. - * - * @return the byte read or -1 if the end of stream - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public int readUnsignedByte() throws IOException, EOFException { - return in.read(); - } - - /** - * Delegates to {@link EndianUtils#readSwappedUnsignedShort(InputStream)}. - * - * @return the read long - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public int readUnsignedShort() throws IOException, EOFException { - return EndianUtils.readSwappedUnsignedShort(in); - } - - /** - * Not currently supported - throws {@link UnsupportedOperationException}. - * - * @return UTF String read - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public String readUTF() throws IOException, EOFException { - throw UnsupportedOperationExceptions.method("readUTF"); - } - - /** - * Invokes the delegate's {@code skip(int)} method. - * - * @param count the number of bytes to skip - * @return the number of bytes to skipped or -1 if the end of stream - * @throws EOFException if an end of file is reached unexpectedly - * @throws IOException if an I/O error occurs. - */ - @Override - public int skipBytes(final int count) throws IOException, EOFException { - return (int) in.skip(count); - } - -} diff --git a/src/org/apache/commons/io/input/TaggedInputStream.java b/src/org/apache/commons/io/input/TaggedInputStream.java deleted file mode 100644 index d30dc84a..00000000 --- a/src/org/apache/commons/io/input/TaggedInputStream.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.UUID; - -import org.apache.commons.io.TaggedIOException; - -/** - * An input stream decorator that tags potential exceptions so that the - * stream that caused the exception can easily be identified. This is - * done by using the {@link TaggedIOException} class to wrap all thrown - * {@link IOException}s. See below for an example of using this class. - *
- * TaggedInputStream stream = new TaggedInputStream(...);
- * try {
- *     // Processing that may throw an IOException either from this stream
- *     // or from some other IO activity like temporary files, etc.
- *     processStream(stream);
- * } catch (IOException e) {
- *     if (stream.isCauseOf(e)) {
- *         // The exception was caused by this stream.
- *         // Use e.getCause() to get the original exception.
- *     } else {
- *         // The exception was caused by something else.
- *     }
- * }
- * 
- *

- * Alternatively, the {@link #throwIfCauseOf(Throwable)} method can be - * used to let higher levels of code handle the exception caused by this - * stream while other processing errors are being taken care of at this - * lower level. - *

- *
- * TaggedInputStream stream = new TaggedInputStream(...);
- * try {
- *     processStream(stream);
- * } catch (IOException e) {
- *     stream.throwIfCauseOf(e);
- *     // ... or process the exception that was caused by something else
- * }
- * 
- * - * @see TaggedIOException - * @since 2.0 - */ -public class TaggedInputStream extends ProxyInputStream { - - /** - * The unique tag associated with exceptions from stream. - */ - private final Serializable tag = UUID.randomUUID(); - - /** - * Creates a tagging decorator for the given input stream. - * - * @param proxy input stream to be decorated - */ - public TaggedInputStream(final InputStream proxy) { - super(proxy); - } - - /** - * Tests if the given exception was caused by this stream. - * - * @param exception an exception - * @return {@code true} if the exception was thrown by this stream, - * {@code false} otherwise - */ - public boolean isCauseOf(final Throwable exception) { - return TaggedIOException.isTaggedWith(exception, tag); - } - - /** - * Re-throws the original exception thrown by this stream. This method - * first checks whether the given exception is a {@link TaggedIOException} - * wrapper created by this decorator, and then unwraps and throws the - * original wrapped exception. Returns normally if the exception was - * not thrown by this stream. - * - * @param throwable an exception - * @throws IOException original exception, if any, thrown by this stream - */ - public void throwIfCauseOf(final Throwable throwable) throws IOException { - TaggedIOException.throwCauseIfTaggedWith(throwable, tag); - } - - /** - * Tags any IOExceptions thrown, wrapping and re-throwing. - * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - */ - @Override - protected void handleIOException(final IOException e) throws IOException { - throw new TaggedIOException(e, tag); - } - -} diff --git a/src/org/apache/commons/io/input/TaggedReader.java b/src/org/apache/commons/io/input/TaggedReader.java deleted file mode 100644 index 6805f874..00000000 --- a/src/org/apache/commons/io/input/TaggedReader.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; -import java.io.Reader; -import java.io.Serializable; -import java.util.UUID; - -import org.apache.commons.io.TaggedIOException; - -/** - * A reader decorator that tags potential exceptions so that the reader that caused the exception can easily be - * identified. This is done by using the {@link TaggedIOException} class to wrap all thrown {@link IOException}s. See - * below for an example of using this class. - * - *
- * TaggedReader reader = new TaggedReader(...);
- * try {
- *     // Processing that may throw an IOException either from this reader
- *     // or from some other IO activity like temporary files, etc.
- *     processReader(reader);
- * } catch (IOException e) {
- *     if (reader.isCauseOf(e)) {
- *         // The exception was caused by this reader.
- *         // Use e.getCause() to get the original exception.
- *     } else {
- *         // The exception was caused by something else.
- *     }
- * }
- * 
- *

- * Alternatively, the {@link #throwIfCauseOf(Throwable)} method can be used to let higher levels of code handle the - * exception caused by this reader while other processing errors are being taken care of at this lower level. - *

- * - *
- * TaggedReader reader = new TaggedReader(...);
- * try {
- *     processReader(reader);
- * } catch (IOException e) {
- *     reader.throwIfCauseOf(e);
- *     // ... or process the exception that was caused by something else
- * }
- * 
- * - * @see TaggedIOException - * @since 2.7 - */ -public class TaggedReader extends ProxyReader { - - /** - * The unique tag associated with exceptions from reader. - */ - private final Serializable tag = UUID.randomUUID(); - - /** - * Creates a tagging decorator for the given reader. - * - * @param proxy reader to be decorated - */ - public TaggedReader(final Reader proxy) { - super(proxy); - } - - /** - * Tests if the given exception was caused by this reader. - * - * @param exception an exception - * @return {@code true} if the exception was thrown by this reader, {@code false} otherwise - */ - public boolean isCauseOf(final Throwable exception) { - return TaggedIOException.isTaggedWith(exception, tag); - } - - /** - * Re-throws the original exception thrown by this reader. This method first checks whether the given exception is a - * {@link TaggedIOException} wrapper created by this decorator, and then unwraps and throws the original wrapped - * exception. Returns normally if the exception was not thrown by this reader. - * - * @param throwable an exception - * @throws IOException original exception, if any, thrown by this reader - */ - public void throwIfCauseOf(final Throwable throwable) throws IOException { - TaggedIOException.throwCauseIfTaggedWith(throwable, tag); - } - - /** - * Tags any IOExceptions thrown, wrapping and re-throwing. - * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - */ - @Override - protected void handleIOException(final IOException e) throws IOException { - throw new TaggedIOException(e, tag); - } - -} diff --git a/src/org/apache/commons/io/input/Tailer.java b/src/org/apache/commons/io/input/Tailer.java deleted file mode 100644 index 4d347295..00000000 --- a/src/org/apache/commons/io/input/Tailer.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.CR; -import static org.apache.commons.io.IOUtils.EOF; -import static org.apache.commons.io.IOUtils.LF; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.charset.Charset; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -/** - * Simple implementation of the unix "tail -f" functionality. - * - *

1. Create a TailerListener implementation

- *

- * First you need to create a {@link TailerListener} implementation - * ({@link TailerListenerAdapter} is provided for convenience so that you don't have to - * implement every method). - *

- * - *

For example:

- *
- *  public class MyTailerListener extends TailerListenerAdapter {
- *      public void handle(String line) {
- *          System.out.println(line);
- *      }
- *  }
- * - *

2. Using a Tailer

- * - *

- * You can create and use a Tailer in one of three ways: - *

- *
    - *
  • Using one of the static helper methods: - *
      - *
    • {@link Tailer#create(File, TailerListener)}
    • - *
    • {@link Tailer#create(File, TailerListener, long)}
    • - *
    • {@link Tailer#create(File, TailerListener, long, boolean)}
    • - *
    - *
  • - *
  • Using an {@link java.util.concurrent.Executor}
  • - *
  • Using an {@link Thread}
  • - *
- * - *

- * An example of each of these is shown below. - *

- * - *

2.1 Using the static helper method

- * - *
- *      TailerListener listener = new MyTailerListener();
- *      Tailer tailer = Tailer.create(file, listener, delay);
- * - *

2.2 Using an Executor

- * - *
- *      TailerListener listener = new MyTailerListener();
- *      Tailer tailer = new Tailer(file, listener, delay);
- *
- *      // stupid executor impl. for demo purposes
- *      Executor executor = new Executor() {
- *          public void execute(Runnable command) {
- *              command.run();
- *           }
- *      };
- *
- *      executor.execute(tailer);
- * 
- * - * - *

2.3 Using a Thread

- *
- *      TailerListener listener = new MyTailerListener();
- *      Tailer tailer = new Tailer(file, listener, delay);
- *      Thread thread = new Thread(tailer);
- *      thread.setDaemon(true); // optional
- *      thread.start();
- * - *

3. Stopping a Tailer

- *

Remember to stop the tailer when you have done with it:

- *
- *      tailer.stop();
- * 
- * - *

4. Interrupting a Tailer

- *

You can interrupt the thread a tailer is running on by calling {@link Thread#interrupt()}. - *

- *
- *      thread.interrupt();
- * 
- *

- * If you interrupt a tailer, the tailer listener is called with the {@link InterruptedException}. - *

- *

- * The file is read using the default charset; this can be overridden if necessary. - *

- * @see TailerListener - * @see TailerListenerAdapter - * @since 2.0 - * @since 2.5 Updated behavior and documentation for {@link Thread#interrupt()} - */ -public class Tailer implements Runnable { - - private static final int DEFAULT_DELAY_MILLIS = 1000; - - private static final String RAF_MODE = "r"; - - // The default charset used for reading files - private static final Charset DEFAULT_CHARSET = Charset.defaultCharset(); - - /** - * Buffer on top of RandomAccessFile. - */ - private final byte[] inbuf; - - /** - * The file which will be tailed. - */ - private final File file; - - /** - * The character set that will be used to read the file. - */ - private final Charset charset; - - /** - * The amount of time to wait for the file to be updated. - */ - private final long delayMillis; - - /** - * Whether to tail from the end or start of file - */ - private final boolean end; - - /** - * The listener to notify of events when tailing. - */ - private final TailerListener listener; - - /** - * Whether to close and reopen the file whilst waiting for more input. - */ - private final boolean reOpen; - - /** - * The tailer will run as long as this value is true. - */ - private volatile boolean run = true; - - /** - * Creates a Tailer for the given file, starting from the beginning, with the default delay of 1.0s. - * @param file The file to follow. - * @param listener the TailerListener to use. - */ - public Tailer(final File file, final TailerListener listener) { - this(file, listener, DEFAULT_DELAY_MILLIS); - } - - /** - * Creates a Tailer for the given file, starting from the beginning. - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - */ - public Tailer(final File file, final TailerListener listener, final long delayMillis) { - this(file, listener, delayMillis, false); - } - - /** - * Creates a Tailer for the given file, with a delay other than the default 1.0s. - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - */ - public Tailer(final File file, final TailerListener listener, final long delayMillis, final boolean end) { - this(file, listener, delayMillis, end, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Creates a Tailer for the given file, with a delay other than the default 1.0s. - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen if true, close and reopen the file between reading chunks - */ - public Tailer(final File file, final TailerListener listener, final long delayMillis, final boolean end, - final boolean reOpen) { - this(file, listener, delayMillis, end, reOpen, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Creates a Tailer for the given file, with a specified buffer size. - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param bufSize Buffer size - */ - public Tailer(final File file, final TailerListener listener, final long delayMillis, final boolean end, - final int bufSize) { - this(file, listener, delayMillis, end, false, bufSize); - } - - /** - * Creates a Tailer for the given file, with a specified buffer size. - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen if true, close and reopen the file between reading chunks - * @param bufSize Buffer size - */ - public Tailer(final File file, final TailerListener listener, final long delayMillis, final boolean end, - final boolean reOpen, final int bufSize) { - this(file, DEFAULT_CHARSET, listener, delayMillis, end, reOpen, bufSize); - } - - /** - * Creates a Tailer for the given file, with a specified buffer size. - * @param file the file to follow. - * @param charset the Charset to be used for reading the file - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen if true, close and reopen the file between reading chunks - * @param bufSize Buffer size - */ - public Tailer(final File file, final Charset charset, final TailerListener listener, final long delayMillis, - final boolean end, final boolean reOpen - , final int bufSize) { - this.file = file; - this.delayMillis = delayMillis; - this.end = end; - - this.inbuf = IOUtils.byteArray(bufSize); - - // Save and prepare the listener - this.listener = listener; - listener.init(this); - this.reOpen = reOpen; - this.charset = charset; - } - - /** - * Creates and starts a Tailer for the given file. - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param bufSize buffer size. - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener, final long delayMillis, - final boolean end, final int bufSize) { - return create(file, listener, delayMillis, end, false, bufSize); - } - - /** - * Creates and starts a Tailer for the given file. - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen whether to close/reopen the file between chunks - * @param bufSize buffer size. - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener, final long delayMillis, - final boolean end, final boolean reOpen, - final int bufSize) { - return create(file, DEFAULT_CHARSET, listener, delayMillis, end, reOpen, bufSize); - } - - /** - * Creates and starts a Tailer for the given file. - * - * @param file the file to follow. - * @param charset the character set to use for reading the file - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen whether to close/reopen the file between chunks - * @param bufSize buffer size. - * @return The new tailer - */ - public static Tailer create(final File file, final Charset charset, final TailerListener listener, - final long delayMillis, final boolean end, final boolean reOpen - ,final int bufSize) { - final Tailer tailer = new Tailer(file, charset, listener, delayMillis, end, reOpen, bufSize); - final Thread thread = new Thread(tailer); - thread.setDaemon(true); - thread.start(); - return tailer; - } - - /** - * Creates and starts a Tailer for the given file with default buffer size. - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener, final long delayMillis, - final boolean end) { - return create(file, listener, delayMillis, end, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Creates and starts a Tailer for the given file with default buffer size. - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @param end Set to true to tail from the end of the file, false to tail from the beginning of the file. - * @param reOpen whether to close/reopen the file between chunks - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener, final long delayMillis, - final boolean end, final boolean reOpen) { - return create(file, listener, delayMillis, end, reOpen, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Creates and starts a Tailer for the given file, starting at the beginning of the file - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @param delayMillis the delay between checks of the file for new content in milliseconds. - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener, final long delayMillis) { - return create(file, listener, delayMillis, false); - } - - /** - * Creates and starts a Tailer for the given file, starting at the beginning of the file - * with the default delay of 1.0s - * - * @param file the file to follow. - * @param listener the TailerListener to use. - * @return The new tailer - */ - public static Tailer create(final File file, final TailerListener listener) { - return create(file, listener, DEFAULT_DELAY_MILLIS, false); - } - - /** - * Return the file. - * - * @return the file - */ - public File getFile() { - return file; - } - - /** - * Gets whether to keep on running. - * - * @return whether to keep on running. - * @since 2.5 - */ - protected boolean getRun() { - return run; - } - - /** - * Return the delay in milliseconds. - * - * @return the delay in milliseconds. - */ - public long getDelay() { - return delayMillis; - } - - /** - * Follows changes in the file, calling the TailerListener's handle method for each new line. - */ - @Override - public void run() { - RandomAccessFile reader = null; - try { - long last = 0; // The last time the file was checked for changes - long position = 0; // position within the file - // Open the file - while (getRun() && reader == null) { - try { - reader = new RandomAccessFile(file, RAF_MODE); - } catch (final FileNotFoundException e) { - listener.fileNotFound(); - } - if (reader == null) { - Thread.sleep(delayMillis); - } else { - // The current position in the file - position = end ? file.length() : 0; - last = FileUtils.lastModified(file); - reader.seek(position); - } - } - while (getRun()) { - final boolean newer = FileUtils.isFileNewer(file, last); // IO-279, must be done first - // Check the file length to see if it was rotated - final long length = file.length(); - if (length < position) { - // File was rotated - listener.fileRotated(); - // Reopen the reader after rotation ensuring that the old file is closed iff we re-open it - // successfully - try (RandomAccessFile save = reader) { - reader = new RandomAccessFile(file, RAF_MODE); - // At this point, we're sure that the old file is rotated - // Finish scanning the old file and then we'll start with the new one - try { - readLines(save); - } catch (final IOException ioe) { - listener.handle(ioe); - } - position = 0; - } catch (final FileNotFoundException e) { - // in this case we continue to use the previous reader and position values - listener.fileNotFound(); - Thread.sleep(delayMillis); - } - continue; - } - // File was not rotated - // See if the file needs to be read again - if (length > position) { - // The file has more content than it did last time - position = readLines(reader); - last = FileUtils.lastModified(file); - } else if (newer) { - /* - * This can happen if the file is truncated or overwritten with the exact same length of - * information. In cases like this, the file position needs to be reset - */ - position = 0; - reader.seek(position); // cannot be null here - - // Now we can read new lines - position = readLines(reader); - last = FileUtils.lastModified(file); - } - if (reOpen && reader != null) { - reader.close(); - } - Thread.sleep(delayMillis); - if (getRun() && reOpen) { - reader = new RandomAccessFile(file, RAF_MODE); - reader.seek(position); - } - } - } catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - listener.handle(e); - } catch (final Exception e) { - listener.handle(e); - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (final IOException e) { - listener.handle(e); - } - stop(); - } - } - - /** - * Allows the tailer to complete its current loop and return. - */ - public void stop() { - this.run = false; - } - - /** - * Read new lines. - * - * @param reader The file to read - * @return The new position after the lines have been read - * @throws java.io.IOException if an I/O error occurs. - */ - private long readLines(final RandomAccessFile reader) throws IOException { - try (ByteArrayOutputStream lineBuf = new ByteArrayOutputStream(64)) { - long pos = reader.getFilePointer(); - long rePos = pos; // position to re-read - int num; - boolean seenCR = false; - while (getRun() && ((num = reader.read(inbuf)) != EOF)) { - for (int i = 0; i < num; i++) { - final byte ch = inbuf[i]; - switch (ch) { - case LF: - seenCR = false; // swallow CR before LF - listener.handle(new String(lineBuf.toByteArray(), charset)); - lineBuf.reset(); - rePos = pos + i + 1; - break; - case CR: - if (seenCR) { - lineBuf.write(CR); - } - seenCR = true; - break; - default: - if (seenCR) { - seenCR = false; // swallow final CR - listener.handle(new String(lineBuf.toByteArray(), charset)); - lineBuf.reset(); - rePos = pos + i + 1; - } - lineBuf.write(ch); - } - } - pos = reader.getFilePointer(); - } - - reader.seek(rePos); // Ensure we can re-read if necessary - - if (listener instanceof TailerListenerAdapter) { - ((TailerListenerAdapter) listener).endOfFileReached(); - } - - return rePos; - } - } -} diff --git a/src/org/apache/commons/io/input/TailerListener.java b/src/org/apache/commons/io/input/TailerListener.java deleted file mode 100644 index dc26c149..00000000 --- a/src/org/apache/commons/io/input/TailerListener.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -/** - * Listener for events from a {@link Tailer}. - * - * @since 2.0 - */ -public interface TailerListener { - - /** - * The tailer will call this method during construction, - * giving the listener a method of stopping the tailer. - * @param tailer the tailer. - */ - void init(Tailer tailer); - - /** - * This method is called if the tailed file is not found. - *

- * Note: this is called from the tailer thread. - */ - void fileNotFound(); - - /** - * Called if a file rotation is detected. - * - * This method is called before the file is reopened, and fileNotFound may - * be called if the new file has not yet been created. - *

- * Note: this is called from the tailer thread. - */ - void fileRotated(); - - /** - * Handles a line from a Tailer. - *

- * Note: this is called from the tailer thread. - * @param line the line. - */ - void handle(String line); - - /** - * Handles an Exception . - *

- * Note: this is called from the tailer thread. - * @param ex the exception. - */ - void handle(Exception ex); - -} diff --git a/src/org/apache/commons/io/input/TailerListenerAdapter.java b/src/org/apache/commons/io/input/TailerListenerAdapter.java deleted file mode 100644 index fbf0b44f..00000000 --- a/src/org/apache/commons/io/input/TailerListenerAdapter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -/** - * {@link TailerListener} Adapter. - * - * @since 2.0 - */ -public class TailerListenerAdapter implements TailerListener { - - /** - * The tailer will call this method during construction, - * giving the listener a method of stopping the tailer. - * @param tailer the tailer. - */ - @Override - public void init(final Tailer tailer) { - // noop - } - - /** - * This method is called if the tailed file is not found. - */ - @Override - public void fileNotFound() { - // noop - } - - /** - * Called if a file rotation is detected. - * - * This method is called before the file is reopened, and fileNotFound may - * be called if the new file has not yet been created. - */ - @Override - public void fileRotated() { - // noop - } - - /** - * Handles a line from a Tailer. - * @param line the line. - */ - @Override - public void handle(final String line) { - // noop - } - - /** - * Handles an Exception . - * @param ex the exception. - */ - @Override - public void handle(final Exception ex) { - // noop - } - - /** - * Called each time the Tailer reaches the end of the file. - * - * Note: this is called from the tailer thread. - * - * Note: a future version of commons-io will pull this method up to the TailerListener interface, - * for now clients must subclass this class to use this feature. - * - * @since 2.5 - */ - public void endOfFileReached() { - // noop - } -} diff --git a/src/org/apache/commons/io/input/TeeInputStream.java b/src/org/apache/commons/io/input/TeeInputStream.java deleted file mode 100644 index 27d32b8f..00000000 --- a/src/org/apache/commons/io/input/TeeInputStream.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * InputStream proxy that transparently writes a copy of all bytes read - * from the proxied stream to a given OutputStream. Using {@link #skip(long)} - * or {@link #mark(int)}/{@link #reset()} on the stream will result on some - * bytes from the input stream being skipped or duplicated in the output - * stream. - *

- * The proxied input stream is closed when the {@link #close()} method is - * called on this proxy. You may configure whether the input stream closes the - * output stream. - *

- * - * @since 1.4 - * @see ObservableInputStream - */ -public class TeeInputStream extends ProxyInputStream { - - /** - * The output stream that will receive a copy of all bytes read from the - * proxied input stream. - */ - private final OutputStream branch; - - /** - * Flag for closing the associated output stream when this stream is closed. - */ - private final boolean closeBranch; - - /** - * Creates a TeeInputStream that proxies the given {@link InputStream} - * and copies all read bytes to the given {@link OutputStream}. The given - * output stream will not be closed when this stream gets closed. - * - * @param input input stream to be proxied - * @param branch output stream that will receive a copy of all bytes read - */ - public TeeInputStream(final InputStream input, final OutputStream branch) { - this(input, branch, false); - } - - /** - * Creates a TeeInputStream that proxies the given {@link InputStream} - * and copies all read bytes to the given {@link OutputStream}. The given - * output stream will be closed when this stream gets closed if the - * closeBranch parameter is {@code true}. - * - * @param input input stream to be proxied - * @param branch output stream that will receive a copy of all bytes read - * @param closeBranch flag for closing also the output stream when this - * stream is closed - */ - public TeeInputStream( - final InputStream input, final OutputStream branch, final boolean closeBranch) { - super(input); - this.branch = branch; - this.closeBranch = closeBranch; - } - - /** - * Closes the proxied input stream and, if so configured, the associated - * output stream. An exception thrown from one stream will not prevent - * closing of the other stream. - * - * @throws IOException if either of the streams could not be closed - */ - @Override - public void close() throws IOException { - try { - super.close(); - } finally { - if (closeBranch) { - branch.close(); - } - } - } - - /** - * Reads a single byte from the proxied input stream and writes it to - * the associated output stream. - * - * @return next byte from the stream, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - @Override - public int read() throws IOException { - final int ch = super.read(); - if (ch != EOF) { - branch.write(ch); - } - return ch; - } - - /** - * Reads bytes from the proxied input stream and writes the read bytes - * to the associated output stream. - * - * @param bts byte buffer - * @param st start offset within the buffer - * @param end maximum number of bytes to read - * @return number of bytes read, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - @Override - public int read(final byte[] bts, final int st, final int end) throws IOException { - final int n = super.read(bts, st, end); - if (n != EOF) { - branch.write(bts, st, n); - } - return n; - } - - /** - * Reads bytes from the proxied input stream and writes the read bytes - * to the associated output stream. - * - * @param bts byte buffer - * @return number of bytes read, or -1 if the stream has ended - * @throws IOException if the stream could not be read (or written) - */ - @Override - public int read(final byte[] bts) throws IOException { - final int n = super.read(bts); - if (n != EOF) { - branch.write(bts, 0, n); - } - return n; - } - -} diff --git a/src/org/apache/commons/io/input/TeeReader.java b/src/org/apache/commons/io/input/TeeReader.java deleted file mode 100644 index 354cac9f..00000000 --- a/src/org/apache/commons/io/input/TeeReader.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; -import java.nio.CharBuffer; - -/** - * Reader proxy that transparently writes a copy of all characters read from the proxied reader to a given Reader. Using - * {@link #skip(long)} or {@link #mark(int)}/{@link #reset()} on the reader will result on some characters from the - * reader being skipped or duplicated in the writer. - *

- * The proxied reader is closed when the {@link #close()} method is called on this proxy. You may configure whether the - * reader closes the writer. - *

- * - * @since 2.7 - */ -public class TeeReader extends ProxyReader { - - /** - * The writer that will receive a copy of all characters read from the proxied reader. - */ - private final Writer branch; - - /** - * Flag for closing the associated writer when this reader is closed. - */ - private final boolean closeBranch; - - /** - * Creates a TeeReader that proxies the given {@link Reader} and copies all read characters to the given - * {@link Writer}. The given writer will not be closed when this reader gets closed. - * - * @param input reader to be proxied - * @param branch writer that will receive a copy of all characters read - */ - public TeeReader(final Reader input, final Writer branch) { - this(input, branch, false); - } - - /** - * Creates a TeeReader that proxies the given {@link Reader} and copies all read characters to the given - * {@link Writer}. The given writer will be closed when this reader gets closed if the closeBranch parameter is - * {@code true}. - * - * @param input reader to be proxied - * @param branch writer that will receive a copy of all characters read - * @param closeBranch flag for closing also the writer when this reader is closed - */ - public TeeReader(final Reader input, final Writer branch, final boolean closeBranch) { - super(input); - this.branch = branch; - this.closeBranch = closeBranch; - } - - /** - * Closes the proxied reader and, if so configured, the associated writer. An exception thrown from the reader will - * not prevent closing of the writer. - * - * @throws IOException if either the reader or writer could not be closed - */ - @Override - public void close() throws IOException { - try { - super.close(); - } finally { - if (closeBranch) { - branch.close(); - } - } - } - - /** - * Reads a single character from the proxied reader and writes it to the associated writer. - * - * @return next character from the reader, or -1 if the reader has ended - * @throws IOException if the reader could not be read (or written) - */ - @Override - public int read() throws IOException { - final int ch = super.read(); - if (ch != EOF) { - branch.write(ch); - } - return ch; - } - - /** - * Reads characters from the proxied reader and writes the read characters to the associated writer. - * - * @param chr character buffer - * @return number of characters read, or -1 if the reader has ended - * @throws IOException if the reader could not be read (or written) - */ - @Override - public int read(final char[] chr) throws IOException { - final int n = super.read(chr); - if (n != EOF) { - branch.write(chr, 0, n); - } - return n; - } - - /** - * Reads characters from the proxied reader and writes the read characters to the associated writer. - * - * @param chr character buffer - * @param st start offset within the buffer - * @param end maximum number of characters to read - * @return number of characters read, or -1 if the reader has ended - * @throws IOException if the reader could not be read (or written) - */ - @Override - public int read(final char[] chr, final int st, final int end) throws IOException { - final int n = super.read(chr, st, end); - if (n != EOF) { - branch.write(chr, st, n); - } - return n; - } - - /** - * Reads characters from the proxied reader and writes the read characters to the associated writer. - * - * @param target character buffer - * @return number of characters read, or -1 if the reader has ended - * @throws IOException if the reader could not be read (or written) - */ - @Override - public int read(final CharBuffer target) throws IOException { - final int originalPosition = target.position(); - final int n = super.read(target); - if (n != EOF) { - // Appending can only be done after resetting the CharBuffer to the - // right position and limit. - final int newPosition = target.position(); - final int newLimit = target.limit(); - try { - target.position(originalPosition).limit(newPosition); - branch.append(target); - } finally { - // Reset the CharBuffer as if the appending never happened. - target.position(newPosition).limit(newLimit); - } - } - return n; - } - -} diff --git a/src/org/apache/commons/io/input/TimestampedObserver.java b/src/org/apache/commons/io/input/TimestampedObserver.java deleted file mode 100644 index c9af8498..00000000 --- a/src/org/apache/commons/io/input/TimestampedObserver.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.input; - -import java.io.IOException; -import java.time.Duration; -import java.time.Instant; - -import org.apache.commons.io.input.ObservableInputStream.Observer; - -/** - * An observer with timestamps. - *

- * For example: - *

- * - *
- * final TimestampedObserver timetampedObserver = new TimestampedObserver();
- * try (final ObservableInputStream inputStream = new ObservableInputStream(...),
- *     timetampedObserver)) {
- *     ...
- * }
- * System.out.printf("IO duration: %s%n", timetampedObserver.getOpenToCloseDuration());
- * 
- * - * @since 2.9.0 - */ -public class TimestampedObserver extends Observer { - - private volatile Instant closeInstant; - private final Instant openInstant = Instant.now(); - - @Override - public void closed() throws IOException { - closeInstant = Instant.now(); - } - - /** - * Gets the instant for when this instance was closed. - * - * @return the instant for when closed was called. - */ - public Instant getCloseInstant() { - return closeInstant; - } - - /** - * Gets the Duration between creation and close. - * - * @return the Duration between creation and close. - */ - public Duration getOpenToCloseDuration() { - return Duration.between(openInstant, closeInstant); - } - - /** - * Gets the Duration between creation and now. - * - * @return the Duration between creation and now. - */ - public Duration getOpenToNowDuration() { - return Duration.between(openInstant, Instant.now()); - } - - /** - * Gets the instant for when this instance was created. - * - * @return the instant for when this instance was created. - */ - public Instant getOpenInstant() { - return openInstant; - } - - @Override - public String toString() { - return "TimestampedObserver [openInstant=" + openInstant + ", closeInstant=" + closeInstant + "]"; - } - -} diff --git a/src/org/apache/commons/io/input/UnixLineEndingInputStream.java b/src/org/apache/commons/io/input/UnixLineEndingInputStream.java deleted file mode 100644 index e4bfe71c..00000000 --- a/src/org/apache/commons/io/input/UnixLineEndingInputStream.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.CR; -import static org.apache.commons.io.IOUtils.EOF; -import static org.apache.commons.io.IOUtils.LF; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering input stream that ensures the content will have UNIX-style line endings, LF. - * - * @since 2.5 - */ -public class UnixLineEndingInputStream extends InputStream { - - private boolean slashNSeen; - - private boolean slashRSeen; - - private boolean eofSeen; - - private final InputStream target; - - private final boolean ensureLineFeedAtEndOfFile; - - /** - * Creates an input stream that filters another stream - * - * @param in The input stream to wrap - * @param ensureLineFeedAtEndOfFile true to ensure that the file ends with LF - */ - public UnixLineEndingInputStream(final InputStream in, final boolean ensureLineFeedAtEndOfFile) { - this.target = in; - this.ensureLineFeedAtEndOfFile = ensureLineFeedAtEndOfFile; - } - - /** - * Reads the next item from the target, updating internal flags in the process - * @return the next int read from the target stream - * @throws IOException upon error - */ - private int readWithUpdate() throws IOException { - final int target = this.target.read(); - eofSeen = target == EOF; - if (eofSeen) { - return target; - } - slashNSeen = target == LF; - slashRSeen = target == CR; - return target; - } - - /** - * {@inheritDoc} - */ - @Override - public int read() throws IOException { - final boolean previousWasSlashR = slashRSeen; - if (eofSeen) { - return eofGame(previousWasSlashR); - } - final int target = readWithUpdate(); - if (eofSeen) { - return eofGame(previousWasSlashR); - } - if (slashRSeen) { - return LF; - } - - if (previousWasSlashR && slashNSeen) { - return read(); - } - - return target; - } - - /** - * Handles the EOF-handling at the end of the stream - * @param previousWasSlashR Indicates if the last seen was a \r - * @return The next char to output to the stream - */ - private int eofGame(final boolean previousWasSlashR) { - if (previousWasSlashR || !ensureLineFeedAtEndOfFile) { - return EOF; - } - if (!slashNSeen) { - slashNSeen = true; - return LF; - } - return EOF; - } - - /** - * Closes the stream. Also closes the underlying stream. - * @throws IOException upon error - */ - @Override - public void close() throws IOException { - super.close(); - target.close(); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void mark(final int readlimit) { - throw UnsupportedOperationExceptions.mark(); - } -} diff --git a/src/org/apache/commons/io/input/UnsupportedOperationExceptions.java b/src/org/apache/commons/io/input/UnsupportedOperationExceptions.java deleted file mode 100644 index 9799e99e..00000000 --- a/src/org/apache/commons/io/input/UnsupportedOperationExceptions.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.input; - -/** - * Package-private factory for {@link UnsupportedOperationException} to provide messages with consistent formatting. - * - *

- * TODO Consider making this public and use from LineIterator but this feels like it belongs in LANG rather than IO. - *

- */ -class UnsupportedOperationExceptions { - - private static final String MARK_RESET = "mark/reset"; - - /** - * Creates a new instance of UnsupportedOperationException for a {@code mark} method. - * - * @return a new instance of UnsupportedOperationException - */ - static UnsupportedOperationException mark() { - // Use the same message as in java.io.InputStream.reset() in OpenJDK 8.0.275-1. - return method(MARK_RESET); - } - - /** - * Creates a new instance of UnsupportedOperationException for the given unsupported a {@code method} name. - * - * @param method A method name - * @return a new instance of UnsupportedOperationException - */ - static UnsupportedOperationException method(final String method) { - return new UnsupportedOperationException(method + " not supported"); - } - - /** - * Creates a new instance of UnsupportedOperationException for a {@code reset} method. - * - * @return a new instance of UnsupportedOperationException - */ - static UnsupportedOperationException reset() { - // Use the same message as in java.io.InputStream.reset() in OpenJDK 8.0.275-1. - return method(MARK_RESET); - } -} diff --git a/src/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java b/src/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java deleted file mode 100644 index 86ab4bec..00000000 --- a/src/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.InputStream; -import java.util.Objects; - -import static java.lang.Math.min; - -/** - * This is an alternative to {@link java.io.ByteArrayInputStream} - * which removes the synchronization overhead for non-concurrent - * access; as such this class is not thread-safe. - * - * @since 2.7 - */ -//@NotThreadSafe -public class UnsynchronizedByteArrayInputStream extends InputStream { - - /** - * The end of stream marker. - */ - public static final int END_OF_STREAM = -1; - - /** - * The underlying data buffer. - */ - private final byte[] data; - - /** - * End Of Data. - * - * Similar to data.length, - * i.e. the last readable offset + 1. - */ - private final int eod; - - /** - * Current offset in the data buffer. - */ - private int offset; - - /** - * The current mark (if any). - */ - private int markedOffset; - - /** - * Creates a new byte array input stream. - * - * @param data the buffer - */ - public UnsynchronizedByteArrayInputStream(final byte[] data) { - this.data = Objects.requireNonNull(data, "data"); - this.offset = 0; - this.eod = data.length; - this.markedOffset = this.offset; - } - - /** - * Creates a new byte array input stream. - * - * @param data the buffer - * @param offset the offset into the buffer - * - * @throws IllegalArgumentException if the offset is less than zero - */ - public UnsynchronizedByteArrayInputStream(final byte[] data, final int offset) { - Objects.requireNonNull(data, "data"); - if (offset < 0) { - throw new IllegalArgumentException("offset cannot be negative"); - } - this.data = data; - this.offset = min(offset, data.length > 0 ? data.length : offset); - this.eod = data.length; - this.markedOffset = this.offset; - } - - - /** - * Creates a new byte array input stream. - * - * @param data the buffer - * @param offset the offset into the buffer - * @param length the length of the buffer - * - * @throws IllegalArgumentException if the offset or length less than zero - */ - public UnsynchronizedByteArrayInputStream(final byte[] data, final int offset, final int length) { - if (offset < 0) { - throw new IllegalArgumentException("offset cannot be negative"); - } - if (length < 0) { - throw new IllegalArgumentException("length cannot be negative"); - } - this.data = Objects.requireNonNull(data, "data"); - this.offset = min(offset, data.length > 0 ? data.length : offset); - this.eod = min(this.offset + length, data.length); - this.markedOffset = this.offset; - } - - @Override - public int available() { - return offset < eod ? eod - offset : 0; - } - - @Override - public int read() { - return offset < eod ? data[offset++] & 0xff : END_OF_STREAM; - } - - @Override - public int read(final byte[] dest) { - Objects.requireNonNull(dest, "dest"); - return read(dest, 0, dest.length); - } - - @Override - public int read(final byte[] dest, final int off, final int len) { - Objects.requireNonNull(dest, "dest"); - if (off < 0 || len < 0 || off + len > dest.length) { - throw new IndexOutOfBoundsException(); - } - - if (offset >= eod) { - return END_OF_STREAM; - } - - int actualLen = eod - offset; - if (len < actualLen) { - actualLen = len; - } - if (actualLen <= 0) { - return 0; - } - System.arraycopy(data, offset, dest, off, actualLen); - offset += actualLen; - return actualLen; - } - - @Override - public long skip(final long n) { - if (n < 0) { - throw new IllegalArgumentException("Skipping backward is not supported"); - } - - long actualSkip = eod - offset; - if (n < actualSkip) { - actualSkip = n; - } - - offset += actualSkip; - return actualSkip; - } - - @Override - public boolean markSupported() { - return true; - } - - @SuppressWarnings("sync-override") - @Override - public void mark(final int readlimit) { - this.markedOffset = this.offset; - } - - @SuppressWarnings("sync-override") - @Override - public void reset() { - this.offset = this.markedOffset; - } -} diff --git a/src/org/apache/commons/io/input/WindowsLineEndingInputStream.java b/src/org/apache/commons/io/input/WindowsLineEndingInputStream.java deleted file mode 100644 index 921b334e..00000000 --- a/src/org/apache/commons/io/input/WindowsLineEndingInputStream.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import static org.apache.commons.io.IOUtils.CR; -import static org.apache.commons.io.IOUtils.EOF; -import static org.apache.commons.io.IOUtils.LF; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A filtering input stream that ensures the content will have Windows line endings, CRLF. - * - * @since 2.5 - */ -public class WindowsLineEndingInputStream extends InputStream { - - private boolean slashRSeen; - - private boolean slashNSeen; - - private boolean injectSlashN; - - private boolean eofSeen; - - private final InputStream target; - - private final boolean ensureLineFeedAtEndOfFile; - - /** - * Creates an input stream that filters another stream - * - * @param in The input stream to wrap - * @param ensureLineFeedAtEndOfFile true to ensure that the file ends with CRLF - */ - public WindowsLineEndingInputStream(final InputStream in, final boolean ensureLineFeedAtEndOfFile) { - this.target = in; - this.ensureLineFeedAtEndOfFile = ensureLineFeedAtEndOfFile; - } - - /** - * Reads the next item from the target, updating internal flags in the process - * @return the next int read from the target stream - * @throws IOException upon error - */ - private int readWithUpdate() throws IOException { - final int target = this.target.read(); - eofSeen = target == EOF; - if (eofSeen) { - return target; - } - slashRSeen = target == CR; - slashNSeen = target == LF; - return target; - } - - /** - * {@inheritDoc} - */ - @Override - public int read() throws IOException { - if (eofSeen) { - return eofGame(); - } - if (injectSlashN) { - injectSlashN = false; - return LF; - } - final boolean prevWasSlashR = slashRSeen; - final int target = readWithUpdate(); - if (eofSeen) { - return eofGame(); - } - if ((target == LF) && !prevWasSlashR) { - injectSlashN = true; - return CR; - } - return target; - } - - /** - * Handles the EOF-handling at the end of the stream - * @return The next char to output to the stream - */ - private int eofGame() { - if (!ensureLineFeedAtEndOfFile) { - return EOF; - } - if (!slashNSeen && !slashRSeen) { - slashRSeen = true; - return CR; - } - if (!slashNSeen) { - slashRSeen = false; - slashNSeen = true; - return LF; - } - return EOF; - } - - /** - * Closes the stream. Also closes the underlying stream. - * @throws IOException upon error - */ - @Override - public void close() throws IOException { - super.close(); - target.close(); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void mark(final int readlimit) { - throw UnsupportedOperationExceptions.mark(); - } -} diff --git a/src/org/apache/commons/io/input/XmlStreamReader.java b/src/org/apache/commons/io/input/XmlStreamReader.java deleted file mode 100644 index d5615004..00000000 --- a/src/org/apache/commons/io/input/XmlStreamReader.java +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Locale; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.IOUtils; - -/** - * Character stream that handles all the necessary Voodoo to figure out the - * charset encoding of the XML document within the stream. - *

- * IMPORTANT: This class is not related in any way to the org.xml.sax.XMLReader. - * This one IS a character stream. - *

- *

- * All this has to be done without consuming characters from the stream, if not - * the XML parser will not recognized the document as a valid XML. This is not - * 100% true, but it's close enough (UTF-8 BOM is not handled by all parsers - * right now, XmlStreamReader handles it and things work in all parsers). - *

- *

- * The XmlStreamReader class handles the charset encoding of XML documents in - * Files, raw streams and HTTP streams by offering a wide set of constructors. - *

- *

- * By default the charset encoding detection is lenient, the constructor with - * the lenient flag can be used for a script (following HTTP MIME and XML - * specifications). All this is nicely explained by Mark Pilgrim in his blog, - * Determining the character encoding of a feed. - *

- *

- * Originally developed for ROME under - * Apache License 2.0. - *

- * - * @see org.apache.commons.io.output.XmlStreamWriter - * @since 2.0 - */ -public class XmlStreamReader extends Reader { - private static final String UTF_8 = "UTF-8"; - - private static final String US_ASCII = "US-ASCII"; - - private static final String UTF_16BE = "UTF-16BE"; - - private static final String UTF_16LE = "UTF-16LE"; - - private static final String UTF_32BE = "UTF-32BE"; - - private static final String UTF_32LE = "UTF-32LE"; - - private static final String UTF_16 = "UTF-16"; - - private static final String UTF_32 = "UTF-32"; - - private static final String EBCDIC = "CP1047"; - - private static final ByteOrderMark[] BOMS = { - ByteOrderMark.UTF_8, - ByteOrderMark.UTF_16BE, - ByteOrderMark.UTF_16LE, - ByteOrderMark.UTF_32BE, - ByteOrderMark.UTF_32LE - }; - - // UTF_16LE and UTF_32LE have the same two starting BOM bytes. - private static final ByteOrderMark[] XML_GUESS_BYTES = { - new ByteOrderMark(UTF_8, 0x3C, 0x3F, 0x78, 0x6D), - new ByteOrderMark(UTF_16BE, 0x00, 0x3C, 0x00, 0x3F), - new ByteOrderMark(UTF_16LE, 0x3C, 0x00, 0x3F, 0x00), - new ByteOrderMark(UTF_32BE, 0x00, 0x00, 0x00, 0x3C, - 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6D), - new ByteOrderMark(UTF_32LE, 0x3C, 0x00, 0x00, 0x00, - 0x3F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00), - new ByteOrderMark(EBCDIC, 0x4C, 0x6F, 0xA7, 0x94) - }; - - private static final Pattern CHARSET_PATTERN = Pattern - .compile("charset=[\"']?([.[^; \"']]*)[\"']?"); - - /** - * Pattern capturing the encoding of the "xml" processing instruction. - */ - public static final Pattern ENCODING_PATTERN = Pattern.compile( - "<\\?xml.*encoding[\\s]*=[\\s]*((?:\".[^\"]*\")|(?:'.[^']*'))", - Pattern.MULTILINE); - - private static final String RAW_EX_1 = - "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] encoding mismatch"; - - private static final String RAW_EX_2 = - "Invalid encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] unknown BOM"; - - private static final String HTTP_EX_1 = - "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], BOM must be NULL"; - - private static final String HTTP_EX_2 = - "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], encoding mismatch"; - - private static final String HTTP_EX_3 = - "Invalid encoding, CT-MIME [{0}] CT-Enc [{1}] BOM [{2}] XML guess [{3}] XML prolog [{4}], Invalid MIME"; - - /** - * Returns charset parameter value, NULL if not present, NULL if - * httpContentType is NULL. - * - * @param httpContentType the HTTP content type - * @return The content type encoding (upcased) - */ - static String getContentTypeEncoding(final String httpContentType) { - String encoding = null; - if (httpContentType != null) { - final int i = httpContentType.indexOf(";"); - if (i > -1) { - final String postMime = httpContentType.substring(i + 1); - final Matcher m = CHARSET_PATTERN.matcher(postMime); - encoding = m.find() ? m.group(1) : null; - encoding = encoding != null ? encoding.toUpperCase(Locale.ROOT) : null; - } - } - return encoding; - } - - /** - * Returns MIME type or NULL if httpContentType is NULL. - * - * @param httpContentType the HTTP content type - * @return The mime content type - */ - static String getContentTypeMime(final String httpContentType) { - String mime = null; - if (httpContentType != null) { - final int i = httpContentType.indexOf(";"); - if (i >= 0) { - mime = httpContentType.substring(0, i); - } else { - mime = httpContentType; - } - mime = mime.trim(); - } - return mime; - } - - /** - * Returns the encoding declared in the , NULL if none. - * - * @param inputStream InputStream to create the reader from. - * @param guessedEnc guessed encoding - * @return the encoding declared in the - * @throws IOException thrown if there is a problem reading the stream. - */ - private static String getXmlProlog(final InputStream inputStream, final String guessedEnc) - throws IOException { - String encoding = null; - if (guessedEnc != null) { - final byte[] bytes = IOUtils.byteArray(); - inputStream.mark(IOUtils.DEFAULT_BUFFER_SIZE); - int offset = 0; - int max = IOUtils.DEFAULT_BUFFER_SIZE; - int c = inputStream.read(bytes, offset, max); - int firstGT = -1; - String xmlProlog = ""; // avoid possible NPE warning (cannot happen; this just silences the warning) - while (c != -1 && firstGT == -1 && offset < IOUtils.DEFAULT_BUFFER_SIZE) { - offset += c; - max -= c; - c = inputStream.read(bytes, offset, max); - xmlProlog = new String(bytes, 0, offset, guessedEnc); - firstGT = xmlProlog.indexOf('>'); - } - if (firstGT == -1) { - if (c == -1) { - throw new IOException("Unexpected end of XML stream"); - } - throw new IOException( - "XML prolog or ROOT element not found on first " - + offset + " bytes"); - } - final int bytesRead = offset; - if (bytesRead > 0) { - inputStream.reset(); - final BufferedReader bReader = new BufferedReader(new StringReader( - xmlProlog.substring(0, firstGT + 1))); - final StringBuffer prolog = new StringBuffer(); - String line; - while ((line = bReader.readLine()) != null) { - prolog.append(line); - } - final Matcher m = ENCODING_PATTERN.matcher(prolog); - if (m.find()) { - encoding = m.group(1).toUpperCase(Locale.ROOT); - encoding = encoding.substring(1, encoding.length() - 1); - } - } - } - return encoding; - } - - /** - * Indicates if the MIME type belongs to the APPLICATION XML family. - * - * @param mime The mime type - * @return true if the mime type belongs to the APPLICATION XML family, - * otherwise false - */ - static boolean isAppXml(final String mime) { - return mime != null && - (mime.equals("application/xml") || - mime.equals("application/xml-dtd") || - mime.equals("application/xml-external-parsed-entity") || - mime.startsWith("application/") && mime.endsWith("+xml")); - } - - /** - * Indicates if the MIME type belongs to the TEXT XML family. - * - * @param mime The mime type - * @return true if the mime type belongs to the TEXT XML family, - * otherwise false - */ - static boolean isTextXml(final String mime) { - return mime != null && - (mime.equals("text/xml") || - mime.equals("text/xml-external-parsed-entity") || - mime.startsWith("text/") && mime.endsWith("+xml")); - } - - private final Reader reader; - - private final String encoding; - - private final String defaultEncoding; - - /** - * Creates a Reader for a File. - *

- * It looks for the UTF-8 BOM first, if none sniffs the XML prolog charset, - * if this is also missing defaults to UTF-8. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param file File to create a Reader from. - * @throws IOException thrown if there is a problem reading the file. - */ - public XmlStreamReader(final File file) throws IOException { - this(Objects.requireNonNull(file, "file").toPath()); - } - - /** - * Creates a Reader for a raw InputStream. - *

- * It follows the same logic used for files. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param inputStream InputStream to create a Reader from. - * @throws IOException thrown if there is a problem reading the stream. - */ - public XmlStreamReader(final InputStream inputStream) throws IOException { - this(inputStream, true); - } - - /** - * Creates a Reader for a raw InputStream. - *

- * It follows the same logic used for files. - *

- * If lenient detection is indicated and the detection above fails as per - * specifications it then attempts the following: - *

- * If the content type was 'text/html' it replaces it with 'text/xml' and - * tries the detection again. - *

- * Else if the XML prolog had a charset encoding that encoding is used. - *

- * Else if the content type had a charset encoding that encoding is used. - *

- * Else 'UTF-8' is used. - *

- * If lenient detection is indicated an XmlStreamReaderException is never - * thrown. - * - * @param inputStream InputStream to create a Reader from. - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @throws IOException thrown if there is a problem reading the stream. - * @throws XmlStreamReaderException thrown if the charset encoding could not - * be determined according to the specs. - */ - public XmlStreamReader(final InputStream inputStream, final boolean lenient) throws IOException { - this(inputStream, lenient, null); - } - - /** - * Creates a Reader for a raw InputStream. - *

- * It follows the same logic used for files. - *

- * If lenient detection is indicated and the detection above fails as per - * specifications it then attempts the following: - *

- * If the content type was 'text/html' it replaces it with 'text/xml' and - * tries the detection again. - *

- * Else if the XML prolog had a charset encoding that encoding is used. - *

- * Else if the content type had a charset encoding that encoding is used. - *

- * Else 'UTF-8' is used. - *

- * If lenient detection is indicated an XmlStreamReaderException is never - * thrown. - * - * @param inputStream InputStream to create a Reader from. - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @param defaultEncoding The default encoding - * @throws IOException thrown if there is a problem reading the stream. - * @throws XmlStreamReaderException thrown if the charset encoding could not - * be determined according to the specs. - */ - @SuppressWarnings("resource") // InputStream is managed through a InputStreamReader in this instance. - public XmlStreamReader(final InputStream inputStream, final boolean lenient, final String defaultEncoding) - throws IOException { - Objects.requireNonNull(inputStream, "inputStream"); - this.defaultEncoding = defaultEncoding; - final BOMInputStream bom = new BOMInputStream(new BufferedInputStream(inputStream, IOUtils.DEFAULT_BUFFER_SIZE), false, BOMS); - final BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES); - this.encoding = doRawStream(bom, pis, lenient); - this.reader = new InputStreamReader(pis, encoding); - } - - /** - * Creates a Reader using an InputStream and the associated content-type - * header. - *

- * First it checks if the stream has BOM. If there is not BOM checks the - * content-type encoding. If there is not content-type encoding checks the - * XML prolog encoding. If there is not XML prolog encoding uses the default - * encoding mandated by the content-type MIME type. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param inputStream InputStream to create the reader from. - * @param httpContentType content-type header to use for the resolution of - * the charset encoding. - * @throws IOException thrown if there is a problem reading the file. - */ - public XmlStreamReader(final InputStream inputStream, final String httpContentType) - throws IOException { - this(inputStream, httpContentType, true); - } - - /** - * Creates a Reader using an InputStream and the associated content-type - * header. This constructor is lenient regarding the encoding detection. - *

- * First it checks if the stream has BOM. If there is not BOM checks the - * content-type encoding. If there is not content-type encoding checks the - * XML prolog encoding. If there is not XML prolog encoding uses the default - * encoding mandated by the content-type MIME type. - *

- * If lenient detection is indicated and the detection above fails as per - * specifications it then attempts the following: - *

- * If the content type was 'text/html' it replaces it with 'text/xml' and - * tries the detection again. - *

- * Else if the XML prolog had a charset encoding that encoding is used. - *

- * Else if the content type had a charset encoding that encoding is used. - *

- * Else 'UTF-8' is used. - *

- * If lenient detection is indicated an XmlStreamReaderException is never - * thrown. - * - * @param inputStream InputStream to create the reader from. - * @param httpContentType content-type header to use for the resolution of - * the charset encoding. - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @throws IOException thrown if there is a problem reading the file. - * @throws XmlStreamReaderException thrown if the charset encoding could not - * be determined according to the specs. - */ - public XmlStreamReader(final InputStream inputStream, final String httpContentType, - final boolean lenient) throws IOException { - this(inputStream, httpContentType, lenient, null); - } - - - /** - * Creates a Reader using an InputStream and the associated content-type - * header. This constructor is lenient regarding the encoding detection. - *

- * First it checks if the stream has BOM. If there is not BOM checks the - * content-type encoding. If there is not content-type encoding checks the - * XML prolog encoding. If there is not XML prolog encoding uses the default - * encoding mandated by the content-type MIME type. - *

- * If lenient detection is indicated and the detection above fails as per - * specifications it then attempts the following: - *

- * If the content type was 'text/html' it replaces it with 'text/xml' and - * tries the detection again. - *

- * Else if the XML prolog had a charset encoding that encoding is used. - *

- * Else if the content type had a charset encoding that encoding is used. - *

- * Else 'UTF-8' is used. - *

- * If lenient detection is indicated an XmlStreamReaderException is never - * thrown. - * - * @param inputStream InputStream to create the reader from. - * @param httpContentType content-type header to use for the resolution of - * the charset encoding. - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @param defaultEncoding The default encoding - * @throws IOException thrown if there is a problem reading the file. - * @throws XmlStreamReaderException thrown if the charset encoding could not - * be determined according to the specs. - */ - @SuppressWarnings("resource") // InputStream is managed through a InputStreamReader in this instance. - public XmlStreamReader(final InputStream inputStream, final String httpContentType, - final boolean lenient, final String defaultEncoding) throws IOException { - Objects.requireNonNull(inputStream, "inputStream"); - this.defaultEncoding = defaultEncoding; - final BOMInputStream bom = new BOMInputStream(new BufferedInputStream(inputStream, IOUtils.DEFAULT_BUFFER_SIZE), false, BOMS); - final BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES); - this.encoding = processHttpStream(bom, pis, httpContentType, lenient); - this.reader = new InputStreamReader(pis, encoding); - } - - /** - * Creates a Reader for a File. - *

- * It looks for the UTF-8 BOM first, if none sniffs the XML prolog charset, - * if this is also missing defaults to UTF-8. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param file File to create a Reader from. - * @throws IOException thrown if there is a problem reading the file. - * @since 2.11.0 - */ - @SuppressWarnings("resource") // InputStream is managed through another reader in this instance. - public XmlStreamReader(final Path file) throws IOException { - this(Files.newInputStream(Objects.requireNonNull(file, "file"))); - } - - /** - * Creates a Reader using the InputStream of a URL. - *

- * If the URL is not of type HTTP and there is not 'content-type' header in - * the fetched data it uses the same logic used for Files. - *

- * If the URL is a HTTP Url or there is a 'content-type' header in the - * fetched data it uses the same logic used for an InputStream with - * content-type. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param url URL to create a Reader from. - * @throws IOException thrown if there is a problem reading the stream of - * the URL. - */ - public XmlStreamReader(final URL url) throws IOException { - this(Objects.requireNonNull(url, "url").openConnection(), null); - } - - /** - * Creates a Reader using the InputStream of a URLConnection. - *

- * If the URLConnection is not of type HttpURLConnection and there is not - * 'content-type' header in the fetched data it uses the same logic used for - * files. - *

- * If the URLConnection is a HTTP Url or there is a 'content-type' header in - * the fetched data it uses the same logic used for an InputStream with - * content-type. - *

- * It does a lenient charset encoding detection, check the constructor with - * the lenient parameter for details. - * - * @param conn URLConnection to create a Reader from. - * @param defaultEncoding The default encoding - * @throws IOException thrown if there is a problem reading the stream of - * the URLConnection. - */ - public XmlStreamReader(final URLConnection conn, final String defaultEncoding) throws IOException { - Objects.requireNonNull(conn, "conn"); - this.defaultEncoding = defaultEncoding; - final boolean lenient = true; - final String contentType = conn.getContentType(); - final InputStream inputStream = conn.getInputStream(); - @SuppressWarnings("resource") // managed by the InputStreamReader tracked by this instance - final BOMInputStream bom = new BOMInputStream(new BufferedInputStream(inputStream, IOUtils.DEFAULT_BUFFER_SIZE), false, BOMS); - final BOMInputStream pis = new BOMInputStream(bom, true, XML_GUESS_BYTES); - if (conn instanceof HttpURLConnection || contentType != null) { - this.encoding = processHttpStream(bom, pis, contentType, lenient); - } else { - this.encoding = doRawStream(bom, pis, lenient); - } - this.reader = new InputStreamReader(pis, encoding); - } - - /** - * Calculate the HTTP encoding. - * - * @param httpContentType The HTTP content type - * @param bomEnc BOM encoding - * @param xmlGuessEnc XML Guess encoding - * @param xmlEnc XML encoding - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @return the HTTP encoding - * @throws IOException thrown if there is a problem reading the stream. - */ - String calculateHttpEncoding(final String httpContentType, - final String bomEnc, final String xmlGuessEnc, final String xmlEnc, - final boolean lenient) throws IOException { - - // Lenient and has XML encoding - if (lenient && xmlEnc != null) { - return xmlEnc; - } - - // Determine mime/encoding content types from HTTP Content Type - final String cTMime = getContentTypeMime(httpContentType); - final String cTEnc = getContentTypeEncoding(httpContentType); - final boolean appXml = isAppXml(cTMime); - final boolean textXml = isTextXml(cTMime); - - // Mime type NOT "application/xml" or "text/xml" - if (!appXml && !textXml) { - final String msg = MessageFormat.format(HTTP_EX_3, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - } - - // No content type encoding - if (cTEnc == null) { - if (appXml) { - return calculateRawEncoding(bomEnc, xmlGuessEnc, xmlEnc); - } - return defaultEncoding == null ? US_ASCII : defaultEncoding; - } - - // UTF-16BE or UTF-16LE content type encoding - if (cTEnc.equals(UTF_16BE) || cTEnc.equals(UTF_16LE)) { - if (bomEnc != null) { - final String msg = MessageFormat.format(HTTP_EX_1, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - } - return cTEnc; - } - - // UTF-16 content type encoding - if (cTEnc.equals(UTF_16)) { - if (bomEnc != null && bomEnc.startsWith(UTF_16)) { - return bomEnc; - } - final String msg = MessageFormat.format(HTTP_EX_2, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - } - - // UTF-32BE or UTF-132E content type encoding - if (cTEnc.equals(UTF_32BE) || cTEnc.equals(UTF_32LE)) { - if (bomEnc != null) { - final String msg = MessageFormat.format(HTTP_EX_1, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - } - return cTEnc; - } - - // UTF-32 content type encoding - if (cTEnc.equals(UTF_32)) { - if (bomEnc != null && bomEnc.startsWith(UTF_32)) { - return bomEnc; - } - final String msg = MessageFormat.format(HTTP_EX_2, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, cTMime, cTEnc, bomEnc, xmlGuessEnc, xmlEnc); - } - - return cTEnc; - } - - /** - * Calculate the raw encoding. - * - * @param bomEnc BOM encoding - * @param xmlGuessEnc XML Guess encoding - * @param xmlEnc XML encoding - * @return the raw encoding - * @throws IOException thrown if there is a problem reading the stream. - */ - String calculateRawEncoding(final String bomEnc, final String xmlGuessEnc, - final String xmlEnc) throws IOException { - - // BOM is Null - if (bomEnc == null) { - if (xmlGuessEnc == null || xmlEnc == null) { - return defaultEncoding == null ? UTF_8 : defaultEncoding; - } - if (xmlEnc.equals(UTF_16) && - (xmlGuessEnc.equals(UTF_16BE) || xmlGuessEnc.equals(UTF_16LE))) { - return xmlGuessEnc; - } - return xmlEnc; - } - - // BOM is UTF-8 - if (bomEnc.equals(UTF_8)) { - if (xmlGuessEnc != null && !xmlGuessEnc.equals(UTF_8)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - if (xmlEnc != null && !xmlEnc.equals(UTF_8)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - return bomEnc; - } - - // BOM is UTF-16BE or UTF-16LE - if (bomEnc.equals(UTF_16BE) || bomEnc.equals(UTF_16LE)) { - if (xmlGuessEnc != null && !xmlGuessEnc.equals(bomEnc)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - if (xmlEnc != null && !xmlEnc.equals(UTF_16) && !xmlEnc.equals(bomEnc)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - return bomEnc; - } - - // BOM is UTF-32BE or UTF-32LE - if (bomEnc.equals(UTF_32BE) || bomEnc.equals(UTF_32LE)) { - if (xmlGuessEnc != null && !xmlGuessEnc.equals(bomEnc)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - if (xmlEnc != null && !xmlEnc.equals(UTF_32) && !xmlEnc.equals(bomEnc)) { - final String msg = MessageFormat.format(RAW_EX_1, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - return bomEnc; - } - - // BOM is something else - final String msg = MessageFormat.format(RAW_EX_2, bomEnc, xmlGuessEnc, xmlEnc); - throw new XmlStreamReaderException(msg, bomEnc, xmlGuessEnc, xmlEnc); - } - - /** - * Closes the XmlStreamReader stream. - * - * @throws IOException thrown if there was a problem closing the stream. - */ - @Override - public void close() throws IOException { - reader.close(); - } - - /** - * Do lenient detection. - * - * @param httpContentType content-type header to use for the resolution of - * the charset encoding. - * @param ex The thrown exception - * @return the encoding - * @throws IOException thrown if there is a problem reading the stream. - */ - private String doLenientDetection(String httpContentType, - XmlStreamReaderException ex) throws IOException { - if (httpContentType != null && httpContentType.startsWith("text/html")) { - httpContentType = httpContentType.substring("text/html".length()); - httpContentType = "text/xml" + httpContentType; - try { - return calculateHttpEncoding(httpContentType, ex.getBomEncoding(), - ex.getXmlGuessEncoding(), ex.getXmlEncoding(), true); - } catch (final XmlStreamReaderException ex2) { - ex = ex2; - } - } - String encoding = ex.getXmlEncoding(); - if (encoding == null) { - encoding = ex.getContentTypeEncoding(); - } - if (encoding == null) { - encoding = defaultEncoding == null ? UTF_8 : defaultEncoding; - } - return encoding; - } - - /** - * Process the raw stream. - * - * @param bom BOMInputStream to detect byte order marks - * @param pis BOMInputStream to guess XML encoding - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @return the encoding to be used - * @throws IOException thrown if there is a problem reading the stream. - */ - private String doRawStream(final BOMInputStream bom, final BOMInputStream pis, final boolean lenient) - throws IOException { - final String bomEnc = bom.getBOMCharsetName(); - final String xmlGuessEnc = pis.getBOMCharsetName(); - final String xmlEnc = getXmlProlog(pis, xmlGuessEnc); - try { - return calculateRawEncoding(bomEnc, xmlGuessEnc, xmlEnc); - } catch (final XmlStreamReaderException ex) { - if (lenient) { - return doLenientDetection(null, ex); - } - throw ex; - } - } - - /** - * Returns the default encoding to use if none is set in HTTP content-type, - * XML prolog and the rules based on content-type are not adequate. - *

- * If it is NULL the content-type based rules are used. - * - * @return the default encoding to use. - */ - public String getDefaultEncoding() { - return defaultEncoding; - } - - /** - * Returns the charset encoding of the XmlStreamReader. - * - * @return charset encoding. - */ - public String getEncoding() { - return encoding; - } - - /** - * Process a HTTP stream. - * - * @param bom BOMInputStream to detect byte order marks - * @param pis BOMInputStream to guess XML encoding - * @param httpContentType The HTTP content type - * @param lenient indicates if the charset encoding detection should be - * relaxed. - * @return the encoding to be used - * @throws IOException thrown if there is a problem reading the stream. - */ - private String processHttpStream(final BOMInputStream bom, final BOMInputStream pis, final String httpContentType, - final boolean lenient) throws IOException { - final String bomEnc = bom.getBOMCharsetName(); - final String xmlGuessEnc = pis.getBOMCharsetName(); - final String xmlEnc = getXmlProlog(pis, xmlGuessEnc); - try { - return calculateHttpEncoding(httpContentType, bomEnc, xmlGuessEnc, xmlEnc, lenient); - } catch (final XmlStreamReaderException ex) { - if (lenient) { - return doLenientDetection(httpContentType, ex); - } - throw ex; - } - } - - /** - * Invokes the underlying reader's {@code read(char[], int, int)} method. - * @param buf the buffer to read the characters into - * @param offset The start offset - * @param len The number of bytes to read - * @return the number of characters read or -1 if the end of stream - * @throws IOException if an I/O error occurs. - */ - @Override - public int read(final char[] buf, final int offset, final int len) throws IOException { - return reader.read(buf, offset, len); - } - -} diff --git a/src/org/apache/commons/io/input/XmlStreamReaderException.java b/src/org/apache/commons/io/input/XmlStreamReaderException.java deleted file mode 100644 index ca61be73..00000000 --- a/src/org/apache/commons/io/input/XmlStreamReaderException.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input; - -import java.io.IOException; - -/** - * 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. - *

- * - * @since 2.0 - */ -public class XmlStreamReaderException extends IOException { - - private static final long serialVersionUID = 1L; - - private final String bomEncoding; - - private final String xmlGuessEncoding; - - private final String xmlEncoding; - - private final String contentTypeMime; - - private final String contentTypeEncoding; - - /** - * Creates an exception instance if the charset encoding could not be - * determined. - *

- * Instances of this exception are thrown by the XmlStreamReader. - *

- * - * @param msg message describing the reason for the exception. - * @param bomEnc BOM encoding. - * @param xmlGuessEnc XML guess encoding. - * @param xmlEnc XML prolog encoding. - */ - public XmlStreamReaderException(final String msg, final String bomEnc, - final String xmlGuessEnc, final String xmlEnc) { - this(msg, null, null, bomEnc, xmlGuessEnc, xmlEnc); - } - - /** - * Creates an exception instance if the charset encoding could not be - * determined. - *

- * Instances of this exception are thrown by the XmlStreamReader. - *

- * - * @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. - */ - public XmlStreamReaderException(final String msg, final String ctMime, final String ctEnc, - final String bomEnc, final String xmlGuessEnc, final String xmlEnc) { - super(msg); - contentTypeMime = ctMime; - contentTypeEncoding = ctEnc; - bomEncoding = bomEnc; - xmlGuessEncoding = xmlGuessEnc; - xmlEncoding = xmlEnc; - } - - /** - * 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; - } -} diff --git a/src/org/apache/commons/io/input/buffer/CircularBufferInputStream.java b/src/org/apache/commons/io/input/buffer/CircularBufferInputStream.java deleted file mode 100644 index 78535336..00000000 --- a/src/org/apache/commons/io/input/buffer/CircularBufferInputStream.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input.buffer; - -import static org.apache.commons.io.IOUtils.EOF; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - -import org.apache.commons.io.IOUtils; - -/** - * Implements a buffered input stream, which is internally based on a {@link CircularByteBuffer}. Unlike the - * {@link java.io.BufferedInputStream}, this one doesn't need to reallocate byte arrays internally. - */ -public class CircularBufferInputStream extends InputStream { - - /** What we are streaming, used to fill the internal buffer. */ - protected final InputStream in; - - /** Internal buffer. */ - protected final CircularByteBuffer buffer; - - /** Internal buffer size. */ - protected final int bufferSize; - - /** Whether we've see the input stream EOF. */ - private boolean eof; - - /** - * Creates a new instance, which filters the given input stream, and uses the given buffer size. - * - * @param inputStream The input stream, which is being buffered. - * @param bufferSize The size of the {@link CircularByteBuffer}, which is used internally. - */ - public CircularBufferInputStream(final InputStream inputStream, final int bufferSize) { - if (bufferSize <= 0) { - throw new IllegalArgumentException("Invalid bufferSize: " + bufferSize); - } - this.in = Objects.requireNonNull(inputStream, "inputStream"); - this.buffer = new CircularByteBuffer(bufferSize); - this.bufferSize = bufferSize; - this.eof = false; - } - - /** - * Creates a new instance, which filters the given input stream, and uses a reasonable default buffer size - * ({@link IOUtils#DEFAULT_BUFFER_SIZE}). - * - * @param inputStream The input stream, which is being buffered. - */ - public CircularBufferInputStream(final InputStream inputStream) { - this(inputStream, IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Fills the buffer with the contents of the input stream. - * - * @throws IOException in case of an error while reading from the input stream. - */ - protected void fillBuffer() throws IOException { - if (eof) { - return; - } - int space = buffer.getSpace(); - final byte[] buf = IOUtils.byteArray(space); - while (space > 0) { - final int res = in.read(buf, 0, space); - if (res == EOF) { - eof = true; - return; - } - if (res > 0) { - buffer.add(buf, 0, res); - space -= res; - } - } - } - - /** - * Fills the buffer from the input stream until the given number of bytes have been added to the buffer. - * - * @param count number of byte to fill into the buffer - * @return true if the buffer has bytes - * @throws IOException in case of an error while reading from the input stream. - */ - protected boolean haveBytes(final int count) throws IOException { - if (buffer.getCurrentNumberOfBytes() < count) { - fillBuffer(); - } - return buffer.hasBytes(); - } - - @Override - public int read() throws IOException { - if (!haveBytes(1)) { - return EOF; - } - return buffer.read() & 0xFF; // return unsigned byte - } - - @Override - public int read(final byte[] buffer) throws IOException { - return read(buffer, 0, buffer.length); - } - - @Override - public int read(final byte[] targetBuffer, final int offset, final int length) throws IOException { - Objects.requireNonNull(targetBuffer, "targetBuffer"); - if (offset < 0) { - throw new IllegalArgumentException("Offset must not be negative"); - } - if (length < 0) { - throw new IllegalArgumentException("Length must not be negative"); - } - if (!haveBytes(length)) { - return EOF; - } - final int result = Math.min(length, buffer.getCurrentNumberOfBytes()); - for (int i = 0; i < result; i++) { - targetBuffer[offset + i] = buffer.read(); - } - return result; - } - - @Override - public void close() throws IOException { - in.close(); - eof = true; - buffer.clear(); - } -} diff --git a/src/org/apache/commons/io/input/buffer/CircularByteBuffer.java b/src/org/apache/commons/io/input/buffer/CircularByteBuffer.java deleted file mode 100644 index 78998c37..00000000 --- a/src/org/apache/commons/io/input/buffer/CircularByteBuffer.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input.buffer; - -import java.util.Objects; - -import org.apache.commons.io.IOUtils; - -/** - * A buffer, which doesn't need reallocation of byte arrays, because it - * reuses a single byte array. This works particularly well, if reading - * from the buffer takes place at the same time than writing to. Such is the - * case, for example, when using the buffer within a filtering input stream, - * like the {@link CircularBufferInputStream}. - */ -public class CircularByteBuffer { - private final byte[] buffer; - private int startOffset; - private int endOffset; - private int currentNumberOfBytes; - - /** - * Creates a new instance with the given buffer size. - * - * @param size the size of buffer to create - */ - public CircularByteBuffer(final int size) { - buffer = IOUtils.byteArray(size); - startOffset = 0; - endOffset = 0; - currentNumberOfBytes = 0; - } - - /** - * Creates a new instance with a reasonable default buffer size ({@link IOUtils#DEFAULT_BUFFER_SIZE}). - */ - public CircularByteBuffer() { - this(IOUtils.DEFAULT_BUFFER_SIZE); - } - - /** - * Returns the next byte from the buffer, removing it at the same time, so - * that following invocations won't return it again. - * - * @return The byte, which is being returned. - * @throws IllegalStateException The buffer is empty. Use {@link #hasBytes()}, - * or {@link #getCurrentNumberOfBytes()}, to prevent this exception. - */ - public byte read() { - if (currentNumberOfBytes <= 0) { - throw new IllegalStateException("No bytes available."); - } - final byte b = buffer[startOffset]; - --currentNumberOfBytes; - if (++startOffset == buffer.length) { - startOffset = 0; - } - return b; - } - - /** - * Returns the given number of bytes from the buffer by storing them in - * the given byte array at the given offset. - * - * @param targetBuffer The byte array, where to add bytes. - * @param targetOffset The offset, where to store bytes in the byte array. - * @param length The number of bytes to return. - * @throws NullPointerException The byte array {@code pBuffer} is null. - * @throws IllegalArgumentException Either of {@code pOffset}, or {@code length} is negative, - * or the length of the byte array {@code targetBuffer} is too small. - * @throws IllegalStateException The buffer doesn't hold the given number - * of bytes. Use {@link #getCurrentNumberOfBytes()} to prevent this - * exception. - */ - public void read(final byte[] targetBuffer, final int targetOffset, final int length) { - Objects.requireNonNull(targetBuffer, "targetBuffer"); - if (targetOffset < 0 || targetOffset >= targetBuffer.length) { - throw new IllegalArgumentException("Invalid offset: " + targetOffset); - } - if (length < 0 || length > buffer.length) { - throw new IllegalArgumentException("Invalid length: " + length); - } - if (targetOffset + length > targetBuffer.length) { - throw new IllegalArgumentException("The supplied byte array contains only " - + targetBuffer.length + " bytes, but offset, and length would require " - + (targetOffset + length - 1)); - } - if (currentNumberOfBytes < length) { - throw new IllegalStateException("Currently, there are only " + currentNumberOfBytes - + "in the buffer, not " + length); - } - int offset = targetOffset; - for (int i = 0; i < length; i++) { - targetBuffer[offset++] = buffer[startOffset]; - --currentNumberOfBytes; - if (++startOffset == buffer.length) { - startOffset = 0; - } - } - } - - /** - * Adds a new byte to the buffer, which will eventually be returned by following - * invocations of {@link #read()}. - * - * @param value The byte, which is being added to the buffer. - * @throws IllegalStateException The buffer is full. Use {@link #hasSpace()}, - * or {@link #getSpace()}, to prevent this exception. - */ - public void add(final byte value) { - if (currentNumberOfBytes >= buffer.length) { - throw new IllegalStateException("No space available"); - } - buffer[endOffset] = value; - ++currentNumberOfBytes; - if (++endOffset == buffer.length) { - endOffset = 0; - } - } - - /** - * Returns, whether the next bytes in the buffer are exactly those, given by - * {@code sourceBuffer}, {@code offset}, and {@code length}. No bytes are being - * removed from the buffer. If the result is true, then the following invocations - * of {@link #read()} are guaranteed to return exactly those bytes. - * - * @param sourceBuffer the buffer to compare against - * @param offset start offset - * @param length length to compare - * @return True, if the next invocations of {@link #read()} will return the - * bytes at offsets {@code pOffset}+0, {@code pOffset}+1, ..., - * {@code pOffset}+{@code length}-1 of byte array {@code pBuffer}. - * @throws IllegalArgumentException Either of {@code pOffset}, or {@code length} is negative. - * @throws NullPointerException The byte array {@code pBuffer} is null. - */ - public boolean peek(final byte[] sourceBuffer, final int offset, final int length) { - Objects.requireNonNull(sourceBuffer, "Buffer"); - if (offset < 0 || offset >= sourceBuffer.length) { - throw new IllegalArgumentException("Invalid offset: " + offset); - } - if (length < 0 || length > buffer.length) { - throw new IllegalArgumentException("Invalid length: " + length); - } - if (length < currentNumberOfBytes) { - return false; - } - int localOffset = startOffset; - for (int i = 0; i < length; i++) { - if (buffer[localOffset] != sourceBuffer[i + offset]) { - return false; - } - if (++localOffset == buffer.length) { - localOffset = 0; - } - } - return true; - } - - /** - * Adds the given bytes to the buffer. This is the same as invoking {@link #add(byte)} - * for the bytes at offsets {@code offset+0}, {@code offset+1}, ..., - * {@code offset+length-1} of byte array {@code targetBuffer}. - * - * @param targetBuffer the buffer to copy - * @param offset start offset - * @param length length to copy - * @throws IllegalStateException The buffer doesn't have sufficient space. Use - * {@link #getSpace()} to prevent this exception. - * @throws IllegalArgumentException Either of {@code offset}, or {@code length} is negative. - * @throws NullPointerException The byte array {@code pBuffer} is null. - */ - public void add(final byte[] targetBuffer, final int offset, final int length) { - Objects.requireNonNull(targetBuffer, "Buffer"); - if (offset < 0 || offset >= targetBuffer.length) { - throw new IllegalArgumentException("Invalid offset: " + offset); - } - if (length < 0) { - throw new IllegalArgumentException("Invalid length: " + length); - } - if (currentNumberOfBytes + length > buffer.length) { - throw new IllegalStateException("No space available"); - } - for (int i = 0; i < length; i++) { - buffer[endOffset] = targetBuffer[offset + i]; - if (++endOffset == buffer.length) { - endOffset = 0; - } - } - currentNumberOfBytes += length; - } - - /** - * Returns, whether there is currently room for a single byte in the buffer. - * Same as {@link #hasSpace(int) hasSpace(1)}. - * - * @return true if there is space for a byte - * @see #hasSpace(int) - * @see #getSpace() - */ - public boolean hasSpace() { - return currentNumberOfBytes < buffer.length; - } - - /** - * Returns, whether there is currently room for the given number of bytes in the buffer. - * - * @param count the byte count - * @return true if there is space for the given number of bytes - * @see #hasSpace() - * @see #getSpace() - */ - public boolean hasSpace(final int count) { - return currentNumberOfBytes + count <= buffer.length; - } - - /** - * Returns, whether the buffer is currently holding, at least, a single byte. - * - * @return true if the buffer is not empty - */ - public boolean hasBytes() { - return currentNumberOfBytes > 0; - } - - /** - * Returns the number of bytes, that can currently be added to the buffer. - * - * @return the number of bytes that can be added - */ - public int getSpace() { - return buffer.length - currentNumberOfBytes; - } - - /** - * Returns the number of bytes, that are currently present in the buffer. - * - * @return the number of bytes - */ - public int getCurrentNumberOfBytes() { - return currentNumberOfBytes; - } - - /** - * Removes all bytes from the buffer. - */ - public void clear() { - startOffset = 0; - endOffset = 0; - currentNumberOfBytes = 0; - } -} diff --git a/src/org/apache/commons/io/input/buffer/PeekableInputStream.java b/src/org/apache/commons/io/input/buffer/PeekableInputStream.java deleted file mode 100644 index df15e708..00000000 --- a/src/org/apache/commons/io/input/buffer/PeekableInputStream.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.input.buffer; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Objects; - -/** - * Implements a buffered input stream, which allows to peek into the buffers first bytes. This comes in handy when - * manually implementing scanners, lexers, parsers, and the like. - */ -public class PeekableInputStream extends CircularBufferInputStream { - - /** - * Creates a new instance, which filters the given input stream, and uses the given buffer size. - * - * @param inputStream The input stream, which is being buffered. - * @param bufferSize The size of the {@link CircularByteBuffer}, which is used internally. - */ - public PeekableInputStream(final InputStream inputStream, final int bufferSize) { - super(inputStream, bufferSize); - } - - /** - * Creates a new instance, which filters the given input stream, and uses a reasonable default buffer size (8192). - * - * @param inputStream The input stream, which is being buffered. - */ - public PeekableInputStream(final InputStream inputStream) { - super(inputStream); - } - - /** - * Returns whether the next bytes in the buffer are as given by {@code sourceBuffer}. This is equivalent to - * {@link #peek(byte[], int, int)} with {@code offset} == 0, and {@code length} == {@code sourceBuffer.length} - * - * @param sourceBuffer the buffer to compare against - * @return true if the next bytes are as given - * @throws IOException Refilling the buffer failed. - */ - public boolean peek(final byte[] sourceBuffer) throws IOException { - Objects.requireNonNull(sourceBuffer, "sourceBuffer"); - return peek(sourceBuffer, 0, sourceBuffer.length); - } - - /** - * Returns whether the next bytes in the buffer are as given by {@code sourceBuffer}, {code offset}, and - * {@code length}. - * - * @param sourceBuffer the buffer to compare against - * @param offset the start offset - * @param length the length to compare - * @return true if the next bytes in the buffer are as given - * @throws IOException if there is a problem calling fillBuffer() - */ - public boolean peek(final byte[] sourceBuffer, final int offset, final int length) throws IOException { - Objects.requireNonNull(sourceBuffer, "sourceBuffer"); - if (sourceBuffer.length > bufferSize) { - throw new IllegalArgumentException("Peek request size of " + sourceBuffer.length - + " bytes exceeds buffer size of " + bufferSize + " bytes"); - } - if (buffer.getCurrentNumberOfBytes() < sourceBuffer.length) { - fillBuffer(); - } - return buffer.peek(sourceBuffer, offset, length); - } -} diff --git a/src/org/apache/commons/io/output/AbstractByteArrayOutputStream.java b/src/org/apache/commons/io/output/AbstractByteArrayOutputStream.java deleted file mode 100644 index eb950ad2..00000000 --- a/src/org/apache/commons/io/output/AbstractByteArrayOutputStream.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.input.ClosedInputStream; - -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.SequenceInputStream; -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.apache.commons.io.IOUtils.EOF; - -/** - * This is the base class for implementing an output stream in which the data - * is written into a byte array. The buffer automatically grows as data - * is written to it. - *

- * The data can be retrieved using {@code toByteArray()} and - * {@code toString()}. - * Closing an {@code AbstractByteArrayOutputStream} has no effect. The methods in - * this class can be called after the stream has been closed without - * generating an {@code IOException}. - *

- *

- * This is the base for an alternative implementation of the - * {@link java.io.ByteArrayOutputStream} class. The original implementation - * only allocates 32 bytes at the beginning. As this class is designed for - * heavy duty it starts at {@value #DEFAULT_SIZE} bytes. In contrast to the original it doesn't - * reallocate the whole memory block but allocates additional buffers. This - * way no buffers need to be garbage collected and the contents don't have - * to be copied to the new buffer. This class is designed to behave exactly - * like the original. The only exception is the deprecated - * {@link java.io.ByteArrayOutputStream#toString(int)} method that has been - * ignored. - *

- * - * @since 2.7 - */ -public abstract class AbstractByteArrayOutputStream extends OutputStream { - - static final int DEFAULT_SIZE = 1024; - - /** The list of buffers, which grows and never reduces. */ - private final List buffers = new ArrayList<>(); - /** The index of the current buffer. */ - private int currentBufferIndex; - /** The total count of bytes in all the filled buffers. */ - private int filledBufferSum; - /** The current buffer. */ - private byte[] currentBuffer; - /** The total count of bytes written. */ - protected int count; - /** Flag to indicate if the buffers can be reused after reset */ - private boolean reuseBuffers = true; - - /** - * Makes a new buffer available either by allocating - * a new one or re-cycling an existing one. - * - * @param newcount the size of the buffer if one is created - */ - protected void needNewBuffer(final int newcount) { - if (currentBufferIndex < buffers.size() - 1) { - //Recycling old buffer - filledBufferSum += currentBuffer.length; - - currentBufferIndex++; - currentBuffer = buffers.get(currentBufferIndex); - } else { - //Creating new buffer - final int newBufferSize; - if (currentBuffer == null) { - newBufferSize = newcount; - filledBufferSum = 0; - } else { - newBufferSize = Math.max( - currentBuffer.length << 1, - newcount - filledBufferSum); - filledBufferSum += currentBuffer.length; - } - - currentBufferIndex++; - currentBuffer = IOUtils.byteArray(newBufferSize); - buffers.add(currentBuffer); - } - } - - /** - * Writes the bytes to the byte array. - * @param b the bytes to write - * @param off The start offset - * @param len The number of bytes to write - */ - @Override - public abstract void write(final byte[] b, final int off, final int len); - - /** - * Writes the bytes to the byte array. - * @param b the bytes to write - * @param off The start offset - * @param len The number of bytes to write - */ - protected void writeImpl(final byte[] b, final int off, final int len) { - final int newcount = count + len; - int remaining = len; - int inBufferPos = count - filledBufferSum; - while (remaining > 0) { - final int part = Math.min(remaining, currentBuffer.length - inBufferPos); - System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part); - remaining -= part; - if (remaining > 0) { - needNewBuffer(newcount); - inBufferPos = 0; - } - } - count = newcount; - } - - /** - * Write a byte to byte array. - * @param b the byte to write - */ - @Override - public abstract void write(final int b); - - /** - * Write a byte to byte array. - * @param b the byte to write - */ - protected void writeImpl(final int b) { - int inBufferPos = count - filledBufferSum; - if (inBufferPos == currentBuffer.length) { - needNewBuffer(count + 1); - inBufferPos = 0; - } - currentBuffer[inBufferPos] = (byte) b; - count++; - } - - - /** - * Writes the entire contents of the specified input stream to this - * byte stream. Bytes from the input stream are read directly into the - * internal buffers of this streams. - * - * @param in the input stream to read from - * @return total number of bytes read from the input stream - * (and written to this stream) - * @throws IOException if an I/O error occurs while reading the input stream - * @since 1.4 - */ - public abstract int write(final InputStream in) throws IOException; - - /** - * Writes the entire contents of the specified input stream to this - * byte stream. Bytes from the input stream are read directly into the - * internal buffers of this streams. - * - * @param in the input stream to read from - * @return total number of bytes read from the input stream - * (and written to this stream) - * @throws IOException if an I/O error occurs while reading the input stream - * @since 2.7 - */ - protected int writeImpl(final InputStream in) throws IOException { - int readCount = 0; - int inBufferPos = count - filledBufferSum; - int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); - while (n != EOF) { - readCount += n; - inBufferPos += n; - count += n; - if (inBufferPos == currentBuffer.length) { - needNewBuffer(currentBuffer.length); - inBufferPos = 0; - } - n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); - } - return readCount; - } - - /** - * Returns the current size of the byte array. - * - * @return the current size of the byte array - */ - public abstract int size(); - - /** - * Closing a {@code ByteArrayOutputStream} has no effect. The methods in - * this class can be called after the stream has been closed without - * generating an {@code IOException}. - * - * @throws IOException never (this method should not declare this exception - * but it has to now due to backwards compatibility) - */ - @Override - public void close() throws IOException { - //nop - } - - /** - * @see java.io.ByteArrayOutputStream#reset() - */ - public abstract void reset(); - - /** - * @see java.io.ByteArrayOutputStream#reset() - */ - protected void resetImpl() { - count = 0; - filledBufferSum = 0; - currentBufferIndex = 0; - if (reuseBuffers) { - currentBuffer = buffers.get(currentBufferIndex); - } else { - //Throw away old buffers - currentBuffer = null; - final int size = buffers.get(0).length; - buffers.clear(); - needNewBuffer(size); - reuseBuffers = true; - } - } - - /** - * Writes the entire contents of this byte stream to the - * specified output stream. - * - * @param out the output stream to write to - * @throws IOException if an I/O error occurs, such as if the stream is closed - * @see java.io.ByteArrayOutputStream#writeTo(OutputStream) - */ - public abstract void writeTo(final OutputStream out) throws IOException; - - /** - * Writes the entire contents of this byte stream to the - * specified output stream. - * - * @param out the output stream to write to - * @throws IOException if an I/O error occurs, such as if the stream is closed - * @see java.io.ByteArrayOutputStream#writeTo(OutputStream) - */ - protected void writeToImpl(final OutputStream out) throws IOException { - int remaining = count; - for (final byte[] buf : buffers) { - final int c = Math.min(buf.length, remaining); - out.write(buf, 0, c); - remaining -= c; - if (remaining == 0) { - break; - } - } - } - - /** - * Gets the current contents of this byte stream as a Input Stream. The - * returned stream is backed by buffers of {@code this} stream, - * avoiding memory allocation and copy, thus saving space and time.
- * - * @return the current contents of this output stream. - * @see java.io.ByteArrayOutputStream#toByteArray() - * @see #reset() - * @since 2.5 - */ - public abstract InputStream toInputStream(); - - /** - * Gets the current contents of this byte stream as a Input Stream. The - * returned stream is backed by buffers of {@code this} stream, - * avoiding memory allocation and copy, thus saving space and time.
- * - * @param the type of the InputStream which makes up - * the {@link SequenceInputStream}. - * @param isConstructor A constructor for an InputStream which makes - * up the {@link SequenceInputStream}. - * - * @return the current contents of this output stream. - * @see java.io.ByteArrayOutputStream#toByteArray() - * @see #reset() - * @since 2.7 - */ - protected InputStream toInputStream( - final InputStreamConstructor isConstructor) { - int remaining = count; - if (remaining == 0) { - return ClosedInputStream.CLOSED_INPUT_STREAM; - } - final List list = new ArrayList<>(buffers.size()); - for (final byte[] buf : buffers) { - final int c = Math.min(buf.length, remaining); - list.add(isConstructor.construct(buf, 0, c)); - remaining -= c; - if (remaining == 0) { - break; - } - } - reuseBuffers = false; - return new SequenceInputStream(Collections.enumeration(list)); - } - - /** - * Constructor for an InputStream subclass. - * - * @param the type of the InputStream. - */ - @FunctionalInterface - protected interface InputStreamConstructor { - - /** - * Construct an InputStream subclass. - * - * @param buf the buffer - * @param offset the offset into the buffer - * @param length the length of the buffer - * - * @return the InputStream subclass. - */ - T construct(final byte[] buf, final int offset, final int length); - } - - /** - * Gets the current contents of this byte stream as a byte array. - * The result is independent of this stream. - * - * @return the current contents of this output stream, as a byte array - * @see java.io.ByteArrayOutputStream#toByteArray() - */ - public abstract byte[] toByteArray(); - - /** - * Gets the current contents of this byte stream as a byte array. - * The result is independent of this stream. - * - * @return the current contents of this output stream, as a byte array - * @see java.io.ByteArrayOutputStream#toByteArray() - */ - protected byte[] toByteArrayImpl() { - int remaining = count; - if (remaining == 0) { - return IOUtils.EMPTY_BYTE_ARRAY; - } - final byte[] newbuf = IOUtils.byteArray(remaining); - int pos = 0; - for (final byte[] buf : buffers) { - final int c = Math.min(buf.length, remaining); - System.arraycopy(buf, 0, newbuf, pos, c); - pos += c; - remaining -= c; - if (remaining == 0) { - break; - } - } - return newbuf; - } - - /** - * Gets the current contents of this byte stream as a string - * using the platform default charset. - * @return the contents of the byte array as a String - * @see java.io.ByteArrayOutputStream#toString() - * @deprecated 2.5 use {@link #toString(String)} instead - */ - @Override - @Deprecated - public String toString() { - // make explicit the use of the default charset - return new String(toByteArray(), Charset.defaultCharset()); - } - - /** - * Gets the current contents of this byte stream as a string - * using the specified encoding. - * - * @param enc the name of the character encoding - * @return the string converted from the byte array - * @throws UnsupportedEncodingException if the encoding is not supported - * @see java.io.ByteArrayOutputStream#toString(String) - */ - public String toString(final String enc) throws UnsupportedEncodingException { - return new String(toByteArray(), enc); - } - - /** - * Gets the current contents of this byte stream as a string - * using the specified encoding. - * - * @param charset the character encoding - * @return the string converted from the byte array - * @see java.io.ByteArrayOutputStream#toString(String) - * @since 2.5 - */ - public String toString(final Charset charset) { - return new String(toByteArray(), charset); - } - -} diff --git a/src/org/apache/commons/io/output/AppendableOutputStream.java b/src/org/apache/commons/io/output/AppendableOutputStream.java deleted file mode 100644 index fd818b17..00000000 --- a/src/org/apache/commons/io/output/AppendableOutputStream.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * OutputStream implementation that writes the data to an {@link Appendable} - * Object. - *

- * For example, can be used with any {@link java.io.Writer} or a {@link java.lang.StringBuilder} - * or {@link java.lang.StringBuffer}. - *

- * - * @since 2.5 - * @see java.lang.Appendable - * - * @param The type of the {@link Appendable} wrapped by this AppendableOutputStream. - */ -public class AppendableOutputStream extends OutputStream { - - private final T appendable; - - /** - * Construct a new instance with the specified appendable. - * - * @param appendable the appendable to write to - */ - public AppendableOutputStream(final T appendable) { - this.appendable = appendable; - } - - /** - * Write a character to the underlying appendable. - * - * @param b the character to write - * @throws IOException upon error - */ - @Override - public void write(final int b) throws IOException { - appendable.append((char)b); - } - - /** - * Return the target appendable. - * - * @return the target appendable - */ - public T getAppendable() { - return appendable; - } - -} diff --git a/src/org/apache/commons/io/output/AppendableWriter.java b/src/org/apache/commons/io/output/AppendableWriter.java deleted file mode 100644 index d0ec4575..00000000 --- a/src/org/apache/commons/io/output/AppendableWriter.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.Writer; -import java.util.Objects; - -/** - * Writer implementation that writes the data to an {@link Appendable} - * Object. - *

- * For example, can be used with a {@link java.lang.StringBuilder} - * or {@link java.lang.StringBuffer}. - *

- * - * @since 2.7 - * @see java.lang.Appendable - * - * @param The type of the {@link Appendable} wrapped by this AppendableWriter. - */ -public class AppendableWriter extends Writer { - - private final T appendable; - - /** - * Constructs a new instance with the specified appendable. - * - * @param appendable the appendable to write to - */ - public AppendableWriter(final T appendable) { - this.appendable = appendable; - } - - /** - * Appends the specified character to the underlying appendable. - * - * @param c the character to append - * @return this writer - * @throws IOException upon error - */ - @Override - public Writer append(final char c) throws IOException { - appendable.append(c); - return this; - } - - /** - * Appends the specified character sequence to the underlying appendable. - * - * @param csq the character sequence to append - * @return this writer - * @throws IOException upon error - */ - @Override - public Writer append(final CharSequence csq) throws IOException { - appendable.append(csq); - return this; - } - - /** - * Appends a subsequence of the specified character sequence to the underlying appendable. - * - * @param csq the character sequence from which a subsequence will be appended - * @param start the index of the first character in the subsequence - * @param end the index of the character following the last character in the subsequence - * @return this writer - * @throws IOException upon error - */ - @Override - public Writer append(final CharSequence csq, final int start, final int end) throws IOException { - appendable.append(csq, start, end); - return this; - } - - /** - * Closes the stream. This implementation does nothing. - * - * @throws IOException upon error - */ - @Override - public void close() throws IOException { - // noop - } - - /** - * Flushes the stream. This implementation does nothing. - * - * @throws IOException upon error - */ - @Override - public void flush() throws IOException { - // noop - } - - /** - * Return the target appendable. - * - * @return the target appendable - */ - public T getAppendable() { - return appendable; - } - - /** - * Writes a portion of an array of characters to the underlying appendable. - * - * @param cbuf an array with the characters to write - * @param off offset from which to start writing characters - * @param len number of characters to write - * @throws IOException upon error - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - Objects.requireNonNull(cbuf, "Character array is missing"); - if (len < 0 || (off + len) > cbuf.length) { - throw new IndexOutOfBoundsException("Array Size=" + cbuf.length + - ", offset=" + off + ", length=" + len); - } - for (int i = 0; i < len; i++) { - appendable.append(cbuf[off + i]); - } - } - - /** - * Writes a character to the underlying appendable. - * - * @param c the character to write - * @throws IOException upon error - */ - @Override - public void write(final int c) throws IOException { - appendable.append((char)c); - } - - /** - * Writes a portion of a String to the underlying appendable. - * - * @param str a string - * @param off offset from which to start writing characters - * @param len number of characters to write - * @throws IOException upon error - */ - @Override - public void write(final String str, final int off, final int len) throws IOException { - // appendable.append will add "null" for a null String; add an explicit null check - Objects.requireNonNull(str, "String is missing"); - appendable.append(str, off, off + len); - } - -} diff --git a/src/org/apache/commons/io/output/BrokenOutputStream.java b/src/org/apache/commons/io/output/BrokenOutputStream.java deleted file mode 100644 index 70befe2d..00000000 --- a/src/org/apache/commons/io/output/BrokenOutputStream.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Broken output stream. This stream always throws an {@link IOException} from - * all {@link OutputStream} methods. - *

- * This class is mostly useful for testing error handling in code that uses an - * output stream. - *

- * - * @since 2.0 - */ -public class BrokenOutputStream extends OutputStream { - - /** - * The exception that is thrown by all methods of this class. - */ - private final IOException exception; - - /** - * Creates a new stream that always throws the given exception. - * - * @param exception the exception to be thrown - */ - public BrokenOutputStream(final IOException exception) { - this.exception = exception; - } - - /** - * Creates a new stream that always throws an {@link IOException} - */ - public BrokenOutputStream() { - this(new IOException("Broken output stream")); - } - - /** - * Throws the configured exception. - * - * @param b ignored - * @throws IOException always thrown - */ - @Override - public void write(final int b) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void flush() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void close() throws IOException { - throw exception; - } - -} diff --git a/src/org/apache/commons/io/output/BrokenWriter.java b/src/org/apache/commons/io/output/BrokenWriter.java deleted file mode 100644 index 547de29a..00000000 --- a/src/org/apache/commons/io/output/BrokenWriter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.Writer; - -/** - * Broken writer. This writer always throws an {@link IOException} from - * all {@link Writer} methods. - *

- * This class is mostly useful for testing error handling in code that uses a - * writer. - *

- * - * @since 2.0 - */ -public class BrokenWriter extends Writer { - - /** - * The exception that is thrown by all methods of this class. - */ - private final IOException exception; - - /** - * Creates a new writer that always throws the given exception. - * - * @param exception the exception to be thrown - */ - public BrokenWriter(final IOException exception) { - this.exception = exception; - } - - /** - * Creates a new writer that always throws an {@link IOException} - */ - public BrokenWriter() { - this(new IOException("Broken writer")); - } - - /** - * Throws the configured exception. - * - * @param cbuf ignored - * @param off ignored - * @param len ignored - * @throws IOException always thrown - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void flush() throws IOException { - throw exception; - } - - /** - * Throws the configured exception. - * - * @throws IOException always thrown - */ - @Override - public void close() throws IOException { - throw exception; - } - -} diff --git a/src/org/apache/commons/io/output/ByteArrayOutputStream.java b/src/org/apache/commons/io/output/ByteArrayOutputStream.java deleted file mode 100644 index 70320043..00000000 --- a/src/org/apache/commons/io/output/ByteArrayOutputStream.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Implements a ThreadSafe version of {@link AbstractByteArrayOutputStream} using instance synchronization. - */ -//@ThreadSafe -public class ByteArrayOutputStream extends AbstractByteArrayOutputStream { - - /** - * Creates a new byte array output stream. The buffer capacity is - * initially {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary. - */ - public ByteArrayOutputStream() { - this(DEFAULT_SIZE); - } - - /** - * Creates a new byte array output stream, with a buffer capacity of - * the specified size, in bytes. - * - * @param size the initial size - * @throws IllegalArgumentException if size is negative - */ - public ByteArrayOutputStream(final int size) { - if (size < 0) { - throw new IllegalArgumentException( - "Negative initial size: " + size); - } - synchronized (this) { - needNewBuffer(size); - } - } - - @Override - public void write(final byte[] b, final int off, final int len) { - if ((off < 0) - || (off > b.length) - || (len < 0) - || ((off + len) > b.length) - || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) { - return; - } - synchronized (this) { - writeImpl(b, off, len); - } - } - - @Override - public synchronized void write(final int b) { - writeImpl(b); - } - - @Override - public synchronized int write(final InputStream in) throws IOException { - return writeImpl(in); - } - - @Override - public synchronized int size() { - return count; - } - - /** - * @see java.io.ByteArrayOutputStream#reset() - */ - @Override - public synchronized void reset() { - resetImpl(); - } - - @Override - public synchronized void writeTo(final OutputStream out) throws IOException { - writeToImpl(out); - } - - /** - * Fetches entire contents of an {@code InputStream} and represent - * same data as result InputStream. - *

- * This method is useful where, - *

- *
    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for - * long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray()}, since it - * avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - public static InputStream toBufferedInputStream(final InputStream input) - throws IOException { - return toBufferedInputStream(input, DEFAULT_SIZE); - } - - /** - * Fetches entire contents of an {@code InputStream} and represent - * same data as result InputStream. - *

- * This method is useful where, - *

- *
    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for - * long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray()}, since it - * avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a - * {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @param size the initial buffer size - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - * @since 2.5 - */ - public static InputStream toBufferedInputStream(final InputStream input, final int size) - throws IOException { - try (final ByteArrayOutputStream output = new ByteArrayOutputStream(size)) { - output.write(input); - return output.toInputStream(); - } - } - - @Override - public synchronized InputStream toInputStream() { - return toInputStream(java.io.ByteArrayInputStream::new); - } - - @Override - public synchronized byte[] toByteArray() { - return toByteArrayImpl(); - } -} diff --git a/src/org/apache/commons/io/output/ChunkedOutputStream.java b/src/org/apache/commons/io/output/ChunkedOutputStream.java deleted file mode 100644 index 394b84eb..00000000 --- a/src/org/apache/commons/io/output/ChunkedOutputStream.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * OutputStream which breaks larger output blocks into chunks. - * Native code may need to copy the input array; if the write buffer - * is very large this can cause OOME. - * - * @since 2.5 - */ -public class ChunkedOutputStream extends FilterOutputStream { - - /** - * The default chunk size to use, i.e. {@value} bytes. - */ - private static final int DEFAULT_CHUNK_SIZE = 1024 * 4; - - /** - * The maximum chunk size to us when writing data arrays - */ - private final int chunkSize; - - /** - * Creates a new stream that uses the specified chunk size. - * - * @param stream the stream to wrap - * @param chunkSize the chunk size to use; must be a positive number. - * @throws IllegalArgumentException if the chunk size is <= 0 - */ - public ChunkedOutputStream(final OutputStream stream, final int chunkSize) { - super(stream); - if (chunkSize <= 0) { - throw new IllegalArgumentException(); - } - this.chunkSize = chunkSize; - } - - /** - * Creates a new stream that uses a chunk size of {@link #DEFAULT_CHUNK_SIZE}. - * - * @param stream the stream to wrap - */ - public ChunkedOutputStream(final OutputStream stream) { - this(stream, DEFAULT_CHUNK_SIZE); - } - - /** - * Writes the data buffer in chunks to the underlying stream - * - * @param data the data to write - * @param srcOffset the offset - * @param length the length of data to write - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final byte[] data, final int srcOffset, final int length) throws IOException { - int bytes = length; - int dstOffset = srcOffset; - while(bytes > 0) { - final int chunk = Math.min(bytes, chunkSize); - out.write(data, dstOffset, chunk); - bytes -= chunk; - dstOffset += chunk; - } - } - -} diff --git a/src/org/apache/commons/io/output/ChunkedWriter.java b/src/org/apache/commons/io/output/ChunkedWriter.java deleted file mode 100644 index 7b9a16a1..00000000 --- a/src/org/apache/commons/io/output/ChunkedWriter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; - -/** - * Writer which breaks larger output blocks into chunks. - * Native code may need to copy the input array; if the write buffer - * is very large this can cause OOME. - * - * @since 2.5 - */ -public class ChunkedWriter extends FilterWriter { - - /** - * The default chunk size to use, i.e. {@value} bytes. - */ - private static final int DEFAULT_CHUNK_SIZE = 1024 * 4; - - /** - * The maximum chunk size to us when writing data arrays - */ - private final int chunkSize; - - /** - * Creates a new writer that uses the specified chunk size. - * - * @param writer the writer to wrap - * @param chunkSize the chunk size to use; must be a positive number. - * @throws IllegalArgumentException if the chunk size is <= 0 - */ - public ChunkedWriter(final Writer writer, final int chunkSize) { - super(writer); - if (chunkSize <= 0) { - throw new IllegalArgumentException(); - } - this.chunkSize = chunkSize; - } - - /** - * Creates a new writer that uses a chunk size of {@link #DEFAULT_CHUNK_SIZE} - * @param writer the writer to wrap - */ - public ChunkedWriter(final Writer writer) { - this(writer, DEFAULT_CHUNK_SIZE); - } - - /** - * writes the data buffer in chunks to the underlying writer - * @param data The data - * @param srcOffset the offset - * @param length the number of bytes to write - * - * @throws IOException upon error - */ - @Override - public void write(final char[] data, final int srcOffset, final int length) throws IOException { - int bytes = length; - int dstOffset = srcOffset; - while(bytes > 0) { - final int chunk = Math.min(bytes, chunkSize); - out.write(data, dstOffset, chunk); - bytes -= chunk; - dstOffset += chunk; - } - } - -} diff --git a/src/org/apache/commons/io/output/CloseShieldOutputStream.java b/src/org/apache/commons/io/output/CloseShieldOutputStream.java deleted file mode 100644 index 16088905..00000000 --- a/src/org/apache/commons/io/output/CloseShieldOutputStream.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.OutputStream; - -/** - * Proxy stream that prevents the underlying output stream from being closed. - *

- * This class is typically used in cases where an output stream needs to be - * passed to a component that wants to explicitly close the stream even if other - * components would still use the stream for output. - *

- * - * @since 1.4 - */ -public class CloseShieldOutputStream extends ProxyOutputStream { - - /** - * Creates a proxy that shields the given output stream from being closed. - * - * @param outputStream the output stream to wrap - * @return the created proxy - * @since 2.9.0 - */ - public static CloseShieldOutputStream wrap(final OutputStream outputStream) { - return new CloseShieldOutputStream(outputStream); - } - - /** - * Creates a proxy that shields the given output stream from being closed. - * - * @param outputStream underlying output stream - * @deprecated Using this constructor prevents IDEs from warning if the - * underlying output stream is never closed. Use - * {@link #wrap(OutputStream)} instead. - */ - @Deprecated - public CloseShieldOutputStream(final OutputStream outputStream) { - super(outputStream); - } - - /** - * Replaces the underlying output stream with a {@link ClosedOutputStream} - * sentinel. The original output stream will remain open, but this proxy will - * appear closed. - */ - @Override - public void close() { - out = ClosedOutputStream.CLOSED_OUTPUT_STREAM; - } - -} diff --git a/src/org/apache/commons/io/output/CloseShieldWriter.java b/src/org/apache/commons/io/output/CloseShieldWriter.java deleted file mode 100644 index bd14c58b..00000000 --- a/src/org/apache/commons/io/output/CloseShieldWriter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.Writer; - -/** - * Proxy writer that prevents the underlying writer from being closed. - *

- * This class is typically used in cases where a writer needs to be passed to a - * component that wants to explicitly close the writer even if other components - * would still use the writer for output. - *

- * - * @since 2.7 - */ -public class CloseShieldWriter extends ProxyWriter { - - /** - * Creates a proxy that shields the given writer from being closed. - * - * @param writer the writer to wrap - * @return the created proxy - * @since 2.9.0 - */ - public static CloseShieldWriter wrap(final Writer writer) { - return new CloseShieldWriter(writer); - } - - /** - * Creates a proxy that shields the given writer from being closed. - * - * @param writer underlying writer - * @deprecated Using this constructor prevents IDEs from warning if the - * underlying writer is never closed. Use {@link #wrap(Writer)} - * instead. - */ - @Deprecated - public CloseShieldWriter(final Writer writer) { - super(writer); - } - - /** - * Replaces the underlying writer with a {@link ClosedWriter} sentinel. The - * original writer will remain open, but this proxy will appear closed. - */ - @Override - public void close() { - out = ClosedWriter.CLOSED_WRITER; - } - -} diff --git a/src/org/apache/commons/io/output/ClosedOutputStream.java b/src/org/apache/commons/io/output/ClosedOutputStream.java deleted file mode 100644 index cc77d9d9..00000000 --- a/src/org/apache/commons/io/output/ClosedOutputStream.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Throws an exception on all attempts to write to the stream. - *

- * Typically uses of this class include testing for corner cases in methods that accept an output stream and acting as a - * sentinel value instead of a {@code null} output stream. - *

- * - * @since 1.4 - */ -public class ClosedOutputStream extends OutputStream { - - /** - * A singleton. - */ - public static final ClosedOutputStream CLOSED_OUTPUT_STREAM = new ClosedOutputStream(); - - /** - * Throws an {@link IOException} to indicate that the stream is closed. - * - * @param b ignored - * @throws IOException always thrown - */ - @Override - public void write(final int b) throws IOException { - throw new IOException("write(" + b + ") failed: stream is closed"); - } - - /** - * Throws an {@link IOException} to indicate that the stream is closed. - * - * @throws IOException always thrown - */ - @Override - public void flush() throws IOException { - throw new IOException("flush() failed: stream is closed"); - } -} diff --git a/src/org/apache/commons/io/output/ClosedWriter.java b/src/org/apache/commons/io/output/ClosedWriter.java deleted file mode 100644 index 0d77bebf..00000000 --- a/src/org/apache/commons/io/output/ClosedWriter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.Writer; - -/** - * Throws an exception on all attempts to write with {@link #close()} implemented as a noop. - *

- * Typically uses of this class include testing for corner cases in methods that accept a writer and acting as a - * sentinel value instead of a {@code null} writer. - *

- * - * @since 2.7 - */ -public class ClosedWriter extends Writer { - - /** - * A singleton. - */ - public static final ClosedWriter CLOSED_WRITER = new ClosedWriter(); - - /** - * Throws an {@link IOException} to indicate that the writer is closed. - * - * @param cbuf ignored - * @param off ignored - * @param len ignored - * @throws IOException always thrown - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - throw new IOException("write(" + new String(cbuf) + ", " + off + ", " + len + ") failed: stream is closed"); - } - - /** - * Throws an {@link IOException} to indicate that the stream is closed. - * - * @throws IOException always thrown - */ - @Override - public void flush() throws IOException { - throw new IOException("flush() failed: stream is closed"); - } - - @Override - public void close() throws IOException { - // noop - } -} diff --git a/src/org/apache/commons/io/output/CountingOutputStream.java b/src/org/apache/commons/io/output/CountingOutputStream.java deleted file mode 100644 index 486b7898..00000000 --- a/src/org/apache/commons/io/output/CountingOutputStream.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.OutputStream; - -/** - * A decorating output stream that counts the number of bytes that have passed - * through the stream so far. - *

- * A typical use case would be during debugging, to ensure that data is being - * written as expected. - *

- * - */ -public class CountingOutputStream extends ProxyOutputStream { - - /** The count of bytes that have passed. */ - private long count; - - /** - * Constructs a new CountingOutputStream. - * - * @param out the OutputStream to write to - */ - public CountingOutputStream( final OutputStream out ) { - super(out); - } - - - /** - * Updates the count with the number of bytes that are being written. - * - * @param n number of bytes to be written to the stream - * @since 2.0 - */ - @Override - protected synchronized void beforeWrite(final int n) { - count += n; - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an {@code int}. - * See {@link #getByteCount()} for a method using a {@code long}. - * - * @return the number of bytes accumulated - * @throws ArithmeticException if the byte count is too large - */ - public int getCount() { - final long result = getByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: From v1.3 this method throws an ArithmeticException if the - * count is greater than can be expressed by an {@code int}. - * See {@link #resetByteCount()} for a method using a {@code long}. - * - * @return the count previous to resetting - * @throws ArithmeticException if the byte count is too large - */ - public int resetCount() { - final long result = resetByteCount(); - if (result > Integer.MAX_VALUE) { - throw new ArithmeticException("The byte count " + result + " is too large to be converted to an int"); - } - return (int) result; - } - - /** - * The number of bytes that have passed through this stream. - *

- * NOTE: This method is an alternative for {@code getCount()}. - * It was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the number of bytes accumulated - * @since 1.3 - */ - public synchronized long getByteCount() { - return this.count; - } - - /** - * Set the byte count back to 0. - *

- * NOTE: This method is an alternative for {@code resetCount()}. - * It was added because that method returns an integer which will - * result in incorrect count for files over 2GB. - * - * @return the count previous to resetting - * @since 1.3 - */ - public synchronized long resetByteCount() { - final long tmp = this.count; - this.count = 0; - return tmp; - } - -} diff --git a/src/org/apache/commons/io/output/DeferredFileOutputStream.java b/src/org/apache/commons/io/output/DeferredFileOutputStream.java deleted file mode 100644 index 990657fd..00000000 --- a/src/org/apache/commons/io/output/DeferredFileOutputStream.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -/** - * An output stream which will retain data in memory until a specified threshold is reached, and only then commit it to - * disk. If the stream is closed before the threshold is reached, the data will not be written to disk at all. - *

- * This class originated in FileUpload processing. In this use case, you do not know in advance the size of the file - * being uploaded. If the file is small you want to store it in memory (for speed), but if the file is large you want to - * store it to file (to avoid memory issues). - *

- */ -public class DeferredFileOutputStream extends ThresholdingOutputStream { - - /** - * The output stream to which data will be written prior to the threshold being reached. - */ - private ByteArrayOutputStream memoryOutputStream; - - /** - * The output stream to which data will be written at any given time. This will always be one of - * {@code memoryOutputStream} or {@code diskOutputStream}. - */ - private OutputStream currentOutputStream; - - /** - * The file to which output will be directed if the threshold is exceeded. - */ - private File outputFile; - - /** - * The temporary file prefix. - */ - private final String prefix; - - /** - * The temporary file suffix. - */ - private final String suffix; - - /** - * The directory to use for temporary files. - */ - private final File directory; - - /** - * True when close() has been called successfully. - */ - private boolean closed; - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a - * file beyond that point. The initial buffer size will default to - * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes which is ByteArrayOutputStream's default buffer size. - * - * @param threshold The number of bytes at which to trigger an event. - * @param outputFile The file to which data is saved beyond the threshold. - */ - public DeferredFileOutputStream(final int threshold, final File outputFile) { - this(threshold, outputFile, null, null, null, AbstractByteArrayOutputStream.DEFAULT_SIZE); - } - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data either - * to a file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param outputFile The file to which data is saved beyond the threshold. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * @param initialBufferSize The initial size of the in memory buffer. - */ - private DeferredFileOutputStream(final int threshold, final File outputFile, final String prefix, - final String suffix, final File directory, final int initialBufferSize) { - super(threshold); - this.outputFile = outputFile; - this.prefix = prefix; - this.suffix = suffix; - this.directory = directory; - - memoryOutputStream = new ByteArrayOutputStream(initialBufferSize); - currentOutputStream = memoryOutputStream; - } - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a - * file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param initialBufferSize The initial size of the in memory buffer. - * @param outputFile The file to which data is saved beyond the threshold. - * - * @since 2.5 - */ - public DeferredFileOutputStream(final int threshold, final int initialBufferSize, final File outputFile) { - this(threshold, outputFile, null, null, null, initialBufferSize); - if (initialBufferSize < 0) { - throw new IllegalArgumentException("Initial buffer size must be atleast 0."); - } - } - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a - * temporary file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param initialBufferSize The initial size of the in memory buffer. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * - * @since 2.5 - */ - public DeferredFileOutputStream(final int threshold, final int initialBufferSize, final String prefix, - final String suffix, final File directory) { - this(threshold, null, prefix, suffix, directory, initialBufferSize); - if (prefix == null) { - throw new IllegalArgumentException("Temporary file prefix is missing"); - } - if (initialBufferSize < 0) { - throw new IllegalArgumentException("Initial buffer size must be atleast 0."); - } - } - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a - * temporary file beyond that point. The initial buffer size will default to 32 bytes which is - * ByteArrayOutputStream's default buffer size. - * - * @param threshold The number of bytes at which to trigger an event. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * - * @since 1.4 - */ - public DeferredFileOutputStream(final int threshold, final String prefix, final String suffix, - final File directory) { - this(threshold, null, prefix, suffix, directory, AbstractByteArrayOutputStream.DEFAULT_SIZE); - if (prefix == null) { - throw new IllegalArgumentException("Temporary file prefix is missing"); - } - } - - /** - * Closes underlying output stream, and mark this as closed - * - * @throws IOException if an error occurs. - */ - @Override - public void close() throws IOException { - super.close(); - closed = true; - } - - /** - * Returns the data for this output stream as an array of bytes, assuming that the data has been retained in memory. - * If the data was written to disk, this method returns {@code null}. - * - * @return The data for this output stream, or {@code null} if no such data is available. - */ - public byte[] getData() { - return memoryOutputStream != null ? memoryOutputStream.toByteArray() : null; - } - - /** - * Returns either the output file specified in the constructor or the temporary file created or null. - *

- * If the constructor specifying the file is used then it returns that same output file, even when threshold has not - * been reached. - *

- * If constructor specifying a temporary file prefix/suffix is used then the temporary file created once the - * threshold is reached is returned If the threshold was not reached then {@code null} is returned. - * - * @return The file for this output stream, or {@code null} if no such file exists. - */ - public File getFile() { - return outputFile; - } - - /** - * Returns the current output stream. This may be memory based or disk based, depending on the current state with - * respect to the threshold. - * - * @return The underlying output stream. - * - * @throws IOException if an error occurs. - */ - @Override - protected OutputStream getStream() throws IOException { - return currentOutputStream; - } - - /** - * Determines whether or not the data for this output stream has been retained in memory. - * - * @return {@code true} if the data is available in memory; {@code false} otherwise. - */ - public boolean isInMemory() { - return !isThresholdExceeded(); - } - - /** - * Switches the underlying output stream from a memory based stream to one that is backed by disk. This is the point - * at which we realize that too much data is being written to keep in memory, so we elect to switch to disk-based - * storage. - * - * @throws IOException if an error occurs. - */ - @Override - protected void thresholdReached() throws IOException { - if (prefix != null) { - outputFile = File.createTempFile(prefix, suffix, directory); - } - FileUtils.forceMkdirParent(outputFile); - final OutputStream fos = Files.newOutputStream(outputFile.toPath()); - try { - memoryOutputStream.writeTo(fos); - } catch (final IOException e) { - fos.close(); - throw e; - } - currentOutputStream = fos; - memoryOutputStream = null; - } - - /** - * Gets the current contents of this byte stream as an {@link InputStream}. - * If the data for this output stream has been retained in memory, the - * returned stream is backed by buffers of {@code this} stream, - * avoiding memory allocation and copy, thus saving space and time.
- * Otherwise, the returned stream will be one that is created from the data - * that has been committed to disk. - * - * @return the current contents of this output stream. - * @throws IOException if this stream is not yet closed or an error occurs. - * @see org.apache.commons.io.output.ByteArrayOutputStream#toInputStream() - * - * @since 2.9.0 - */ - public InputStream toInputStream() throws IOException { - // we may only need to check if this is closed if we are working with a file - // but we should force the habit of closing whether we are working with - // a file or memory. - if (!closed) { - throw new IOException("Stream not closed"); - } - - if (isInMemory()) { - return memoryOutputStream.toInputStream(); - } - return Files.newInputStream(outputFile.toPath()); - } - - /** - * Writes the data from this output stream to the specified output stream, after it has been closed. - * - * @param outputStream output stream to write to. - * @throws NullPointerException if the OutputStream is {@code null}. - * @throws IOException if this stream is not yet closed or an error occurs. - */ - public void writeTo(final OutputStream outputStream) throws IOException { - // we may only need to check if this is closed if we are working with a file - // but we should force the habit of closing whether we are working with - // a file or memory. - if (!closed) { - throw new IOException("Stream not closed"); - } - - if (isInMemory()) { - memoryOutputStream.writeTo(outputStream); - } else { - try (InputStream fis = Files.newInputStream(outputFile.toPath())) { - IOUtils.copy(fis, outputStream); - } - } - } -} diff --git a/src/org/apache/commons/io/output/DemuxOutputStream.java b/src/org/apache/commons/io/output/DemuxOutputStream.java deleted file mode 100644 index 0b43020b..00000000 --- a/src/org/apache/commons/io/output/DemuxOutputStream.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; - -/** - * Forwards data to a stream that has been associated with this thread. - * - */ -public class DemuxOutputStream extends OutputStream { - private final InheritableThreadLocal outputStreamThreadLocal = new InheritableThreadLocal<>(); - - /** - * Binds the specified stream to the current thread. - * - * @param output - * the stream to bind - * @return the OutputStream that was previously active - */ - public OutputStream bindStream(final OutputStream output) { - final OutputStream stream = outputStreamThreadLocal.get(); - outputStreamThreadLocal.set(output); - return stream; - } - - /** - * Closes stream associated with current thread. - * - * @throws IOException - * if an error occurs - */ - @SuppressWarnings("resource") // we actually close the stream here - @Override - public void close() throws IOException { - IOUtils.close(outputStreamThreadLocal.get()); - } - - /** - * Flushes stream associated with current thread. - * - * @throws IOException - * if an error occurs - */ - @Override - public void flush() throws IOException { - @SuppressWarnings("resource") - final OutputStream output = outputStreamThreadLocal.get(); - if (null != output) { - output.flush(); - } - } - - /** - * Writes byte to stream associated with current thread. - * - * @param ch - * the byte to write to stream - * @throws IOException - * if an error occurs - */ - @Override - public void write(final int ch) throws IOException { - @SuppressWarnings("resource") - final OutputStream output = outputStreamThreadLocal.get(); - if (null != output) { - output.write(ch); - } - } -} diff --git a/src/org/apache/commons/io/output/FileWriterWithEncoding.java b/src/org/apache/commons/io/output/FileWriterWithEncoding.java deleted file mode 100644 index ce8c2079..00000000 --- a/src/org/apache/commons/io/output/FileWriterWithEncoding.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.file.Files; -import java.nio.file.StandardOpenOption; -import java.util.Objects; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -/** - * Writer of files that allows the encoding to be set. - *

- * This class provides a simple alternative to {@code FileWriter} - * that allows an encoding to be set. Unfortunately, it cannot subclass - * {@code FileWriter}. - *

- *

- * By default, the file will be overwritten, but this may be changed to append. - *

- *

- * The encoding must be specified using either the name of the {@link Charset}, - * the {@link Charset}, or a {@link CharsetEncoder}. If the default encoding - * is required then use the {@link java.io.FileWriter} directly, rather than - * this implementation. - *

- * - * @since 1.4 - */ -public class FileWriterWithEncoding extends Writer { - // Cannot extend ProxyWriter, as requires writer to be - // known when super() is called - - /** The writer to decorate. */ - private final Writer out; - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param charsetName the name of the requested charset, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final String charsetName) throws IOException { - this(new File(fileName), charsetName, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param charsetName the name of the requested charset, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final String charsetName, final boolean append) - throws IOException { - this(new File(fileName), charsetName, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param charset the charset to use, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final Charset charset) throws IOException { - this(new File(fileName), charset, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param charset the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final Charset charset, final boolean append) - throws IOException { - this(new File(fileName), charset, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param encoding the encoding to use, not null - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final CharsetEncoder encoding) throws IOException { - this(new File(fileName), encoding, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param fileName the name of the file to write to, not null - * @param charsetEncoder the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file name or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final String fileName, final CharsetEncoder charsetEncoder, final boolean append) - throws IOException { - this(new File(fileName), charsetEncoder, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param charsetName the name of the requested charset, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final String charsetName) throws IOException { - this(file, charsetName, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param charsetName the name of the requested charset, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final String charsetName, final boolean append) throws IOException { - this.out = initWriter(file, charsetName, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param charset the encoding to use, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final Charset charset) throws IOException { - this(file, charset, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param encoding the name of the requested charset, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final Charset encoding, final boolean append) throws IOException { - this.out = initWriter(file, encoding, append); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param charsetEncoder the encoding to use, not null - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final CharsetEncoder charsetEncoder) throws IOException { - this(file, charsetEncoder, false); - } - - /** - * Constructs a FileWriterWithEncoding with a file encoding. - * - * @param file the file to write to, not null - * @param charsetEncoder the encoding to use, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file or encoding is null - * @throws IOException in case of an I/O error - */ - public FileWriterWithEncoding(final File file, final CharsetEncoder charsetEncoder, final boolean append) - throws IOException { - this.out = initWriter(file, charsetEncoder, append); - } - - /** - * Initialize the wrapped file writer. - * Ensure that a cleanup occurs if the writer creation fails. - * - * @param file the file to be accessed - * @param encoding the encoding to use - may be Charset, CharsetEncoder or String - * @param append true to append - * @return the initialized writer - * @throws NullPointerException if the file or encoding is null - * @throws IOException if an error occurs - */ - private static Writer initWriter(final File file, final Object encoding, final boolean append) throws IOException { - Objects.requireNonNull(file, "file"); - Objects.requireNonNull(encoding, "encoding"); - OutputStream stream = null; - final boolean fileExistedAlready = file.exists(); - try { - stream = Files.newOutputStream(file.toPath(), append ? StandardOpenOption.APPEND : StandardOpenOption.CREATE); - if (encoding instanceof Charset) { - return new OutputStreamWriter(stream, (Charset)encoding); - } - if (encoding instanceof CharsetEncoder) { - return new OutputStreamWriter(stream, (CharsetEncoder)encoding); - } - return new OutputStreamWriter(stream, (String)encoding); - } catch (final IOException | RuntimeException ex) { - try { - IOUtils.close(stream); - } catch (final IOException e) { - ex.addSuppressed(e); - } - if (!fileExistedAlready) { - FileUtils.deleteQuietly(file); - } - throw ex; - } - } - - /** - * Write a character. - * @param idx the character to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int idx) throws IOException { - out.write(idx); - } - - /** - * Write the characters from an array. - * @param chr the characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] chr) throws IOException { - out.write(chr); - } - - /** - * Write the specified characters from an array. - * @param chr the characters to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] chr, final int st, final int end) throws IOException { - out.write(chr, st, end); - } - - /** - * Write the characters from a string. - * @param str the string to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str) throws IOException { - out.write(str); - } - - /** - * Write the specified characters from a string. - * @param str the string to write - * @param st The start offset - * @param end The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str, final int st, final int end) throws IOException { - out.write(str, st, end); - } - - /** - * Flush the stream. - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - out.flush(); - } - - /** - * Close the stream. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - out.close(); - } -} diff --git a/src/org/apache/commons/io/output/FilterCollectionWriter.java b/src/org/apache/commons/io/output/FilterCollectionWriter.java deleted file mode 100644 index 6f45a450..00000000 --- a/src/org/apache/commons/io/output/FilterCollectionWriter.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.output; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.io.IOExceptionList; -import org.apache.commons.io.IOIndexedException; - -/** - * Abstract class for writing filtered character streams to a {@link Collection} of writers. This is in contrast to - * {@link FilterWriter} which is backed by a single {@link Writer}. - *

- * This abstract class provides default methods that pass all requests to the contained writers. Subclasses should - * likely override some of these methods. - *

- *

- * The class {@link Writer} defines method signatures with {@code throws} {@link IOException}, which in this class are - * actually {@link IOExceptionList} containing a list of {@link IOIndexedException}. - *

- * - * @since 2.7 - */ -public class FilterCollectionWriter extends Writer { - - /** - * Empty and immutable collection of writers. - */ - protected final Collection EMPTY_WRITERS = Collections.emptyList(); - - /** - * The underlying writers. - */ - protected final Collection writers; - - /** - * Creates a new filtered collection writer. - * - * @param writers Writers to provide the underlying targets. - */ - protected FilterCollectionWriter(final Collection writers) { - this.writers = writers == null ? EMPTY_WRITERS : writers; - } - - /** - * Creates a new filtered collection writer. - * - * @param writers Writers to provide the underlying targets. - */ - protected FilterCollectionWriter(final Writer... writers) { - this.writers = writers == null ? EMPTY_WRITERS : Arrays.asList(writers); - } - - /** - * Adds an indexed exception to the list. - * - * @param causeList The target list. - * @param i The index. - * @param e The cause. - * @return the given list or a new list on null input. - */ - private List add(List causeList, final int i, final IOException e) { - if (causeList == null) { - causeList = new ArrayList<>(); - } - causeList.add(new IOIndexedException(i, e)); - return causeList; - } - - @Override - public Writer append(final char c) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.append(c); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("append", causeList); - } - return this; - } - - @Override - public Writer append(final CharSequence csq) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.append(csq); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("append", causeList); - } - return this; - } - - @Override - public Writer append(final CharSequence csq, final int start, final int end) throws IOException { - - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.append(csq, start, end); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("append", causeList); - } - return this; - } - - @Override - public void close() throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.close(); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("close", causeList); - } - - } - - /** - * Flushes the stream. - * - * @exception IOException If an I/O error occurs - */ - @Override - public void flush() throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.flush(); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("flush", causeList); - } - - } - - /** - * Tests if the given list is empty in a null-safe manner. - * - * @param causeList the list to test. - * @return true if empty or null. - */ - private boolean notEmpty(final List causeList) { - return causeList != null && !causeList.isEmpty(); - } - - @Override - public void write(final char[] cbuf) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.write(cbuf); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("write", causeList); - } - } - - /** - * Writes a portion of an array of characters. - * - * @param cbuf Buffer of characters to be written - * @param off Offset from which to start reading characters - * @param len Number of characters to be written - * - * @exception IOException If an I/O error occurs - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.write(cbuf, off, len); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("write", causeList); - } - } - - /** - * Writes a single character. - * - * @exception IOException If an I/O error occurs - */ - @Override - public void write(final int c) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.write(c); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("write", causeList); - } - } - - @Override - public void write(final String str) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.write(str); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("write", causeList); - } - - } - - /** - * Writes a portion of a string. - * - * @param str String to be written - * @param off Offset from which to start reading characters - * @param len Number of characters to be written - * - * @exception IOException If an I/O error occurs - */ - @Override - public void write(final String str, final int off, final int len) throws IOException { - List causeList = null; - int i = 0; - for (final Writer w : writers) { - if (w != null) { - try { - w.write(str, off, len); - } catch (final IOException e) { - causeList = add(causeList, i, e); - } - } - i++; - } - if (notEmpty(causeList)) { - throw new IOExceptionList("write", causeList); - } - - } - -} diff --git a/src/org/apache/commons/io/output/LockableFileWriter.java b/src/org/apache/commons/io/output/LockableFileWriter.java deleted file mode 100644 index 418424dd..00000000 --- a/src/org/apache/commons/io/output/LockableFileWriter.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.Charset; - -import org.apache.commons.io.Charsets; -import org.apache.commons.io.FileUtils; - -/** - * FileWriter that will create and honor lock files to allow simple - * cross thread file lock handling. - *

- * This class provides a simple alternative to {@code FileWriter} - * that will use a lock file to prevent duplicate writes. - *

- *

- * Note: The lock file is deleted when {@link #close()} is called - * - or if the main file cannot be opened initially. - * In the (unlikely) event that the lock file cannot be deleted, - * an exception is thrown. - *

- *

- * By default, the file will be overwritten, but this may be changed to append. - * The lock directory may be specified, but defaults to the system property - * {@code java.io.tmpdir}. - * The encoding may also be specified, and defaults to the platform default. - *

- */ -public class LockableFileWriter extends Writer { - // Cannot extend ProxyWriter, as requires writer to be - // known when super() is called - - /** The extension for the lock file. */ - private static final String LCK = ".lck"; - - /** The writer to decorate. */ - private final Writer out; - - /** The lock file. */ - private final File lockFile; - - /** - * Constructs a LockableFileWriter. - * If the file exists, it is overwritten. - * - * @param fileName the file to write to, not null - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(final String fileName) throws IOException { - this(fileName, false, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param fileName file to write to, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(final String fileName, final boolean append) throws IOException { - this(fileName, append, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param fileName the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(final String fileName, final boolean append, final String lockDir) throws IOException { - this(new File(fileName), append, lockDir); - } - - /** - * Constructs a LockableFileWriter. - * If the file exists, it is overwritten. - * - * @param file the file to write to, not null - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(final File file) throws IOException { - this(file, false, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param file the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - */ - public LockableFileWriter(final File file, final boolean append) throws IOException { - this(file, append, null); - } - - /** - * Constructs a LockableFileWriter. - * - * @param file the file to write to, not null - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - * @deprecated 2.5 use {@link #LockableFileWriter(File, Charset, boolean, String)} instead - */ - @Deprecated - public LockableFileWriter(final File file, final boolean append, final String lockDir) throws IOException { - this(file, Charset.defaultCharset(), append, lockDir); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param charset the charset to use, null means platform default - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - * @since 2.3 - */ - public LockableFileWriter(final File file, final Charset charset) throws IOException { - this(file, charset, false, null); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param charsetName the name of the requested charset, null means platform default - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - * @throws java.nio.charset.UnsupportedCharsetException - * thrown instead of {@link java.io.UnsupportedEncodingException} in version 2.2 if the encoding is not - * supported. - */ - public LockableFileWriter(final File file, final String charsetName) throws IOException { - this(file, charsetName, false, null); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param charset the name of the requested charset, null means platform default - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - * @since 2.3 - */ - public LockableFileWriter(File file, final Charset charset, final boolean append, - String lockDir) throws IOException { - // init file to create/append - file = file.getAbsoluteFile(); - if (file.getParentFile() != null) { - FileUtils.forceMkdir(file.getParentFile()); - } - if (file.isDirectory()) { - throw new IOException("File specified is a directory"); - } - - // init lock file - if (lockDir == null) { - lockDir = System.getProperty("java.io.tmpdir"); - } - final File lockDirFile = new File(lockDir); - FileUtils.forceMkdir(lockDirFile); - testLockDir(lockDirFile); - lockFile = new File(lockDirFile, file.getName() + LCK); - - // check if locked - createLock(); - - // init wrapped writer - out = initWriter(file, charset, append); - } - - /** - * Constructs a LockableFileWriter with a file encoding. - * - * @param file the file to write to, not null - * @param charsetName the encoding to use, null means platform default - * @param append true if content should be appended, false to overwrite - * @param lockDir the directory in which the lock file should be held - * @throws NullPointerException if the file is null - * @throws IOException in case of an I/O error - * @throws java.nio.charset.UnsupportedCharsetException - * thrown instead of {@link java.io.UnsupportedEncodingException} in version 2.2 if the encoding is not - * supported. - */ - public LockableFileWriter(final File file, final String charsetName, final boolean append, - final String lockDir) throws IOException { - this(file, Charsets.toCharset(charsetName), append, lockDir); - } - - /** - * Tests that we can write to the lock directory. - * - * @param lockDir the File representing the lock directory - * @throws IOException if we cannot write to the lock directory - * @throws IOException if we cannot find the lock file - */ - private void testLockDir(final File lockDir) throws IOException { - if (!lockDir.exists()) { - throw new IOException( - "Could not find lockDir: " + lockDir.getAbsolutePath()); - } - if (!lockDir.canWrite()) { - throw new IOException( - "Could not write to lockDir: " + lockDir.getAbsolutePath()); - } - } - - /** - * Creates the lock file. - * - * @throws IOException if we cannot create the file - */ - private void createLock() throws IOException { - synchronized (LockableFileWriter.class) { - if (!lockFile.createNewFile()) { - throw new IOException("Can't write file, lock " + - lockFile.getAbsolutePath() + " exists"); - } - lockFile.deleteOnExit(); - } - } - - /** - * Initializes the wrapped file writer. - * Ensure that a cleanup occurs if the writer creation fails. - * - * @param file the file to be accessed - * @param charset the charset to use - * @param append true to append - * @return The initialized writer - * @throws IOException if an error occurs - */ - private Writer initWriter(final File file, final Charset charset, final boolean append) throws IOException { - final boolean fileExistedAlready = file.exists(); - try { - return new OutputStreamWriter(new FileOutputStream(file.getAbsolutePath(), append), - Charsets.toCharset(charset)); - - } catch (final IOException | RuntimeException ex) { - FileUtils.deleteQuietly(lockFile); - if (!fileExistedAlready) { - FileUtils.deleteQuietly(file); - } - throw ex; - } - } - - /** - * Closes the file writer and deletes the lock file. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - try { - out.close(); - } finally { - FileUtils.delete(lockFile); - } - } - - /** - * Writes a character. - * @param c the character to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int c) throws IOException { - out.write(c); - } - - /** - * Writes the characters from an array. - * @param cbuf the characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf) throws IOException { - out.write(cbuf); - } - - /** - * Writes the specified characters from an array. - * @param cbuf the characters to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - out.write(cbuf, off, len); - } - - /** - * Writes the characters from a string. - * @param str the string to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str) throws IOException { - out.write(str); - } - - /** - * Writes the specified characters from a string. - * @param str the string to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str, final int off, final int len) throws IOException { - out.write(str, off, len); - } - - /** - * Flushes the stream. - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - out.flush(); - } - -} diff --git a/src/org/apache/commons/io/output/NullAppendable.java b/src/org/apache/commons/io/output/NullAppendable.java deleted file mode 100644 index e2eaf33c..00000000 --- a/src/org/apache/commons/io/output/NullAppendable.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.output; - -import java.io.IOException; - -/** - * Appends all data to the famous /dev/null. - *

- * This Appendable has no destination (file/socket etc.) and all characters written to it are ignored and lost. - *

- * - * @since 2.8.0 - */ -public class NullAppendable implements Appendable { - - /** - * A singleton. - */ - public static final NullAppendable INSTANCE = new NullAppendable(); - - /** Use the singleton. */ - private NullAppendable() { - // no instances. - } - - @Override - public Appendable append(final char c) throws IOException { - return this; - } - - @Override - public Appendable append(final CharSequence csq) throws IOException { - return this; - } - - @Override - public Appendable append(final CharSequence csq, final int start, final int end) throws IOException { - return this; - } - -} diff --git a/src/org/apache/commons/io/output/NullOutputStream.java b/src/org/apache/commons/io/output/NullOutputStream.java deleted file mode 100644 index ee0579b0..00000000 --- a/src/org/apache/commons/io/output/NullOutputStream.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Writes all data to the famous /dev/null. - *

- * This output stream has no destination (file/socket etc.) and all bytes written to it are ignored and lost. - *

- */ -public class NullOutputStream extends OutputStream { - - /** - * Deprecated in favor of {@link #NULL_OUTPUT_STREAM}. - * - * TODO: Will be private in 3.0. - * - * @deprecated Use {@link #NULL_OUTPUT_STREAM}. - */ - @Deprecated - public NullOutputStream() { - } - - /** - * The singleton. - */ - public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream(); - - /** - * Does nothing - output to {@code /dev/null}. - * - * @param b The bytes to write - * @param off The start offset - * @param len The number of bytes to write - */ - @Override - public void write(final byte[] b, final int off, final int len) { - // To /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * - * @param b The byte to write - */ - @Override - public void write(final int b) { - // To /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * - * @param b The bytes to write - * @throws IOException never - */ - @Override - public void write(final byte[] b) throws IOException { - // To /dev/null - } - -} diff --git a/src/org/apache/commons/io/output/NullPrintStream.java b/src/org/apache/commons/io/output/NullPrintStream.java deleted file mode 100644 index c9165843..00000000 --- a/src/org/apache/commons/io/output/NullPrintStream.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.output; - -import java.io.PrintStream; - -/** - * Writes all data to the famous /dev/null. - *

- * This print stream has no destination (file/socket etc.) and all bytes written to it are ignored and lost. - *

- * - * @since 2.7 - */ -public class NullPrintStream extends PrintStream { - - /** - * The singleton instance. - */ - public static final NullPrintStream NULL_PRINT_STREAM = new NullPrintStream(); - - /** - * Constructs an instance. - */ - public NullPrintStream() { - // Relies on the default charset which is OK since we are not actually writing. - super(NullOutputStream.NULL_OUTPUT_STREAM); - } - -} diff --git a/src/org/apache/commons/io/output/NullWriter.java b/src/org/apache/commons/io/output/NullWriter.java deleted file mode 100644 index 4c6f4051..00000000 --- a/src/org/apache/commons/io/output/NullWriter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.Writer; - -/** - * Writes all data to the famous /dev/null. - *

- * This {@code Writer} has no destination (file/socket etc.) and all characters written to it are ignored and lost. - *

- */ -public class NullWriter extends Writer { - - /** - * A singleton. - */ - public static final NullWriter NULL_WRITER = new NullWriter(); - - /** - * Constructs a new NullWriter. - */ - public NullWriter() { - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param c The character to write - * @return this writer - * @since 2.0 - */ - @Override - public Writer append(final char c) { - //to /dev/null - return this; - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param csq The character sequence to write - * @param start The index of the first character to write - * @param end The index of the first character to write (exclusive) - * @return this writer - * @since 2.0 - */ - @Override - public Writer append(final CharSequence csq, final int start, final int end) { - //to /dev/null - return this; - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param csq The character sequence to write - * @return this writer - * @since 2.0 - */ - @Override - public Writer append(final CharSequence csq) { - //to /dev/null - return this; - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param idx The character to write - */ - @Override - public void write(final int idx) { - //to /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param chr The characters to write - */ - @Override - public void write(final char[] chr) { - //to /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param chr The characters to write - * @param st The start offset - * @param end The number of characters to write - */ - @Override - public void write(final char[] chr, final int st, final int end) { - //to /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param str The string to write - */ - @Override - public void write(final String str) { - //to /dev/null - } - - /** - * Does nothing - output to {@code /dev/null}. - * @param str The string to write - * @param st The start offset - * @param end The number of characters to write - */ - @Override - public void write(final String str, final int st, final int end) { - //to /dev/null - } - - /** @see java.io.Writer#flush() */ - @Override - public void flush() { - //to /dev/null - } - - /** @see java.io.Writer#close() */ - @Override - public void close() { - //to /dev/null - } - -} diff --git a/src/org/apache/commons/io/output/ProxyCollectionWriter.java b/src/org/apache/commons/io/output/ProxyCollectionWriter.java deleted file mode 100644 index 91fab36e..00000000 --- a/src/org/apache/commons/io/output/ProxyCollectionWriter.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; -import java.util.Collection; - -import org.apache.commons.io.IOUtils; - -/** - * A Proxy stream collection which acts as expected, that is it passes the method calls on to the proxied streams and - * doesn't change which methods are being called. It is an alternative base class to {@link FilterWriter} and - * {@link FilterCollectionWriter} to increase reusability, because FilterWriter changes the methods being called, such - * as {@code write(char[])} to {@code write(char[], int, int)} and {@code write(String)} to - * {@code write(String, int, int)}. This is in contrast to {@link ProxyWriter} which is backed by a single - * {@link Writer}. - * - * @since 2.7 - */ -public class ProxyCollectionWriter extends FilterCollectionWriter { - - /** - * Creates a new proxy collection writer. - * - * @param writers Writers object to provide the underlying targets. - */ - public ProxyCollectionWriter(final Collection writers) { - super(writers); - } - - /** - * Creates a new proxy collection writer. - * - * @param writers Writers to provide the underlying targets. - */ - public ProxyCollectionWriter(final Writer... writers) { - super(writers); - } - - /** - * Invoked by the write methods after the proxied call has returned successfully. The number of chars written (1 for - * the {@link #write(int)} method, buffer length for {@link #write(char[])}, etc.) is given as an argument. - *

- * Subclasses can override this method to add common post-processing functionality without having to override all - * the write methods. The default implementation does nothing. - *

- * - * @param n number of chars written - * @throws IOException if the post-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void afterWrite(final int n) throws IOException { - // noop - } - - /** - * Invokes the delegates' {@code append(char)} methods. - * - * @param c The character to write - * @return this writer - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - @Override - public Writer append(final char c) throws IOException { - try { - beforeWrite(1); - super.append(c); - afterWrite(1); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invokes the delegates' {@code append(CharSequence)} methods. - * - * @param csq The character sequence to write - * @return this writer - * @throws IOException if an I/O error occurs. - */ - @Override - public Writer append(final CharSequence csq) throws IOException { - try { - final int len = IOUtils.length(csq); - beforeWrite(len); - super.append(csq); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invokes the delegates' {@code append(CharSequence, int, int)} methods. - * - * @param csq The character sequence to write - * @param start The index of the first character to write - * @param end The index of the first character to write (exclusive) - * @return this writer - * @throws IOException if an I/O error occurs. - */ - @Override - public Writer append(final CharSequence csq, final int start, final int end) throws IOException { - try { - beforeWrite(end - start); - super.append(csq, start, end); - afterWrite(end - start); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invoked by the write methods before the call is proxied. The number of chars to be written (1 for the - * {@link #write(int)} method, buffer length for {@link #write(char[])}, etc.) is given as an argument. - *

- * Subclasses can override this method to add common pre-processing functionality without having to override all the - * write methods. The default implementation does nothing. - *

- * - * @param n number of chars to be written - * @throws IOException if the pre-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void beforeWrite(final int n) throws IOException { - // noop - } - - /** - * Invokes the delegate's {@code close()} method. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - try { - super.close(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code flush()} method. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - try { - super.flush(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Handle any IOExceptions thrown. - *

- * This method provides a point to implement custom exception handling. The default behavior is to re-throw the - * exception. - *

- * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - */ - protected void handleIOException(final IOException e) throws IOException { - throw e; - } - - /** - * Invokes the delegate's {@code write(char[])} method. - * - * @param cbuf the characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf) throws IOException { - try { - final int len = IOUtils.length(cbuf); - beforeWrite(len); - super.write(cbuf); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(char[], int, int)} method. - * - * @param cbuf the characters to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - try { - beforeWrite(len); - super.write(cbuf, off, len); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(int)} method. - * - * @param c the character to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int c) throws IOException { - try { - beforeWrite(1); - super.write(c); - afterWrite(1); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(String)} method. - * - * @param str the string to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str) throws IOException { - try { - final int len = IOUtils.length(str); - beforeWrite(len); - super.write(str); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(String)} method. - * - * @param str the string to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str, final int off, final int len) throws IOException { - try { - beforeWrite(len); - super.write(str, off, len); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - -} diff --git a/src/org/apache/commons/io/output/ProxyOutputStream.java b/src/org/apache/commons/io/output/ProxyOutputStream.java deleted file mode 100644 index 16791149..00000000 --- a/src/org/apache/commons/io/output/ProxyOutputStream.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.io.IOUtils; - -/** - * A Proxy stream which acts as expected, that is it passes the method - * calls on to the proxied stream and doesn't change which methods are - * being called. It is an alternative base class to FilterOutputStream - * to increase reusability. - *

- * See the protected methods for ways in which a subclass can easily decorate - * a stream with custom pre-, post- or error processing functionality. - *

- * - */ -public class ProxyOutputStream extends FilterOutputStream { - - /** - * Constructs a new ProxyOutputStream. - * - * @param proxy the OutputStream to delegate to - */ - public ProxyOutputStream(final OutputStream proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'out' - } - - /** - * Invokes the delegate's {@code write(int)} method. - * @param idx the byte to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int idx) throws IOException { - try { - beforeWrite(1); - out.write(idx); - afterWrite(1); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(byte[])} method. - * @param bts the bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final byte[] bts) throws IOException { - try { - final int len = IOUtils.length(bts); - beforeWrite(len); - out.write(bts); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(byte[])} method. - * @param bts the bytes to write - * @param st The start offset - * @param end The number of bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final byte[] bts, final int st, final int end) throws IOException { - try { - beforeWrite(end); - out.write(bts, st, end); - afterWrite(end); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code flush()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - try { - out.flush(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code close()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - IOUtils.close(out, this::handleIOException); - } - - /** - * Invoked by the write methods before the call is proxied. The number - * of bytes to be written (1 for the {@link #write(int)} method, buffer - * length for {@link #write(byte[])}, etc.) is given as an argument. - *

- * Subclasses can override this method to add common pre-processing - * functionality without having to override all the write methods. - * The default implementation does nothing. - * - * @since 2.0 - * @param n number of bytes to be written - * @throws IOException if the pre-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void beforeWrite(final int n) throws IOException { - // noop - } - - /** - * Invoked by the write methods after the proxied call has returned - * successfully. The number of bytes written (1 for the - * {@link #write(int)} method, buffer length for {@link #write(byte[])}, - * etc.) is given as an argument. - *

- * Subclasses can override this method to add common post-processing - * functionality without having to override all the write methods. - * The default implementation does nothing. - * - * @since 2.0 - * @param n number of bytes written - * @throws IOException if the post-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void afterWrite(final int n) throws IOException { - // noop - } - - /** - * Handle any IOExceptions thrown. - *

- * This method provides a point to implement custom exception - * handling. The default behavior is to re-throw the exception. - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - protected void handleIOException(final IOException e) throws IOException { - throw e; - } - -} diff --git a/src/org/apache/commons/io/output/ProxyWriter.java b/src/org/apache/commons/io/output/ProxyWriter.java deleted file mode 100644 index 1d50e97d..00000000 --- a/src/org/apache/commons/io/output/ProxyWriter.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; - -import org.apache.commons.io.IOUtils; - -/** - * A Proxy stream which acts as expected, that is it passes the method calls on to the proxied stream and doesn't - * change which methods are being called. It is an alternative base class to FilterWriter to increase reusability, - * because FilterWriter changes the methods being called, such as {@code write(char[]) to write(char[], int, int)} - * and {@code write(String) to write(String, int, int)}. - */ -public class ProxyWriter extends FilterWriter { - - /** - * Constructs a new ProxyWriter. - * - * @param proxy the Writer to delegate to - */ - public ProxyWriter(final Writer proxy) { - super(proxy); - // the proxy is stored in a protected superclass variable named 'out' - } - - /** - * Invokes the delegate's {@code append(char)} method. - * @param c The character to write - * @return this writer - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - @Override - public Writer append(final char c) throws IOException { - try { - beforeWrite(1); - out.append(c); - afterWrite(1); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invokes the delegate's {@code append(CharSequence, int, int)} method. - * @param csq The character sequence to write - * @param start The index of the first character to write - * @param end The index of the first character to write (exclusive) - * @return this writer - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - @Override - public Writer append(final CharSequence csq, final int start, final int end) throws IOException { - try { - beforeWrite(end - start); - out.append(csq, start, end); - afterWrite(end - start); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invokes the delegate's {@code append(CharSequence)} method. - * @param csq The character sequence to write - * @return this writer - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - @Override - public Writer append(final CharSequence csq) throws IOException { - try { - final int len = IOUtils.length(csq); - beforeWrite(len); - out.append(csq); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - return this; - } - - /** - * Invokes the delegate's {@code write(int)} method. - * @param c the character to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int c) throws IOException { - try { - beforeWrite(1); - out.write(c); - afterWrite(1); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(char[])} method. - * @param cbuf the characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf) throws IOException { - try { - final int len = IOUtils.length(cbuf); - beforeWrite(len); - out.write(cbuf); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(char[], int, int)} method. - * @param cbuf the characters to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - try { - beforeWrite(len); - out.write(cbuf, off, len); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(String)} method. - * @param str the string to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str) throws IOException { - try { - final int len = IOUtils.length(str); - beforeWrite(len); - out.write(str); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code write(String)} method. - * @param str the string to write - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final String str, final int off, final int len) throws IOException { - try { - beforeWrite(len); - out.write(str, off, len); - afterWrite(len); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code flush()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - try { - out.flush(); - } catch (final IOException e) { - handleIOException(e); - } - } - - /** - * Invokes the delegate's {@code close()} method. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - IOUtils.close(out, this::handleIOException); - } - - /** - * Invoked by the write methods before the call is proxied. The number - * of chars to be written (1 for the {@link #write(int)} method, buffer - * length for {@link #write(char[])}, etc.) is given as an argument. - *

- * Subclasses can override this method to add common pre-processing - * functionality without having to override all the write methods. - * The default implementation does nothing. - *

- * - * @since 2.0 - * @param n number of chars to be written - * @throws IOException if the pre-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void beforeWrite(final int n) throws IOException { - // noop - } - - /** - * Invoked by the write methods after the proxied call has returned - * successfully. The number of chars written (1 for the - * {@link #write(int)} method, buffer length for {@link #write(char[])}, - * etc.) is given as an argument. - *

- * Subclasses can override this method to add common post-processing - * functionality without having to override all the write methods. - * The default implementation does nothing. - *

- * - * @since 2.0 - * @param n number of chars written - * @throws IOException if the post-processing fails - */ - @SuppressWarnings("unused") // Possibly thrown from subclasses. - protected void afterWrite(final int n) throws IOException { - // noop - } - - /** - * Handle any IOExceptions thrown. - *

- * This method provides a point to implement custom exception - * handling. The default behavior is to re-throw the exception. - *

- * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - protected void handleIOException(final IOException e) throws IOException { - throw e; - } - -} diff --git a/src/org/apache/commons/io/output/QueueOutputStream.java b/src/org/apache/commons/io/output/QueueOutputStream.java deleted file mode 100644 index b5968d65..00000000 --- a/src/org/apache/commons/io/output/QueueOutputStream.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import org.apache.commons.io.input.QueueInputStream; - -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.util.Objects; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Simple alternative to JDK {@link java.io.PipedOutputStream}; queue input stream provides what's written in queue - * output stream. - *

- * Example usage: - *

- * - *
- * QueueOutputStream outputStream = new QueueOutputStream();
- * QueueInputStream inputStream = outputStream.newPipeInputStream();
- *
- * outputStream.write("hello world".getBytes(UTF_8));
- * inputStream.read();
- * 
- * - * Unlike JDK {@link PipedInputStream} and {@link PipedOutputStream}, queue input/output streams may be used safely in a - * single thread or multiple threads. Also, unlike JDK classes, no special meaning is attached to initial or current - * thread. Instances can be used longer after initial threads exited. - *

- * Closing a {@code QueueOutputStream} has no effect. The methods in this class can be called after the stream has been - * closed without generating an {@code IOException}. - *

- * - * @see QueueInputStream - * @since 2.9.0 - */ -public class QueueOutputStream extends OutputStream { - - private final BlockingQueue blockingQueue; - - /** - * Constructs a new instance with no limit to internal buffer size. - */ - public QueueOutputStream() { - this(new LinkedBlockingQueue<>()); - } - - /** - * Constructs a new instance with given buffer. - * - * @param blockingQueue backing queue for the stream - */ - public QueueOutputStream(final BlockingQueue blockingQueue) { - this.blockingQueue = Objects.requireNonNull(blockingQueue, "blockingQueue"); - } - - /** - * Creates a new QueueInputStream instance connected to this. Writes to this output stream will be visible to the - * input stream. - * - * @return QueueInputStream connected to this stream - */ - public QueueInputStream newQueueInputStream() { - return new QueueInputStream(blockingQueue); - } - - /** - * Writes a single byte. - * - * @throws InterruptedIOException if the thread is interrupted while writing to the queue. - */ - @Override - public void write(final int b) throws InterruptedIOException { - try { - blockingQueue.put(0xFF & b); - } catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - final InterruptedIOException interruptedIoException = new InterruptedIOException(); - interruptedIoException.initCause(e); - throw interruptedIoException; - } - } -} diff --git a/src/org/apache/commons/io/output/StringBuilderWriter.java b/src/org/apache/commons/io/output/StringBuilderWriter.java deleted file mode 100644 index 261714ec..00000000 --- a/src/org/apache/commons/io/output/StringBuilderWriter.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.Serializable; -import java.io.Writer; - -/** - * {@link Writer} implementation that outputs to a {@link StringBuilder}. - *

- * NOTE: This implementation, as an alternative to - * {@code java.io.StringWriter}, provides an un-synchronized - * (i.e. for use in a single thread) implementation for better performance. - * For safe usage with multiple {@link Thread}s then - * {@code java.io.StringWriter} should be used. - *

- * - * @since 2.0 - */ -public class StringBuilderWriter extends Writer implements Serializable { - - private static final long serialVersionUID = -146927496096066153L; - private final StringBuilder builder; - - /** - * Constructs a new {@link StringBuilder} instance with default capacity. - */ - public StringBuilderWriter() { - this.builder = new StringBuilder(); - } - - /** - * Constructs a new {@link StringBuilder} instance with the specified capacity. - * - * @param capacity The initial capacity of the underlying {@link StringBuilder} - */ - public StringBuilderWriter(final int capacity) { - this.builder = new StringBuilder(capacity); - } - - /** - * Constructs a new instance with the specified {@link StringBuilder}. - * - *

If {@code builder} is null a new instance with default capacity will be created.

- * - * @param builder The String builder. May be null. - */ - public StringBuilderWriter(final StringBuilder builder) { - this.builder = builder != null ? builder : new StringBuilder(); - } - - /** - * Appends a single character to this Writer. - * - * @param value The character to append - * @return This writer instance - */ - @Override - public Writer append(final char value) { - builder.append(value); - return this; - } - - /** - * Appends a character sequence to this Writer. - * - * @param value The character to append - * @return This writer instance - */ - @Override - public Writer append(final CharSequence value) { - builder.append(value); - return this; - } - - /** - * Appends a portion of a character sequence to the {@link StringBuilder}. - * - * @param value The character to append - * @param start The index of the first character - * @param end The index of the last character + 1 - * @return This writer instance - */ - @Override - public Writer append(final CharSequence value, final int start, final int end) { - builder.append(value, start, end); - return this; - } - - /** - * Closing this writer has no effect. - */ - @Override - public void close() { - // no-op - } - - /** - * Flushing this writer has no effect. - */ - @Override - public void flush() { - // no-op - } - - - /** - * Writes a String to the {@link StringBuilder}. - * - * @param value The value to write - */ - @Override - public void write(final String value) { - if (value != null) { - builder.append(value); - } - } - - /** - * Writes a portion of a character array to the {@link StringBuilder}. - * - * @param value The value to write - * @param offset The index of the first character - * @param length The number of characters to write - */ - @Override - public void write(final char[] value, final int offset, final int length) { - if (value != null) { - builder.append(value, offset, length); - } - } - - /** - * Returns the underlying builder. - * - * @return The underlying builder - */ - public StringBuilder getBuilder() { - return builder; - } - - /** - * Returns {@link StringBuilder#toString()}. - * - * @return The contents of the String builder. - */ - @Override - public String toString() { - return builder.toString(); - } -} diff --git a/src/org/apache/commons/io/output/TaggedOutputStream.java b/src/org/apache/commons/io/output/TaggedOutputStream.java deleted file mode 100644 index 50f373ff..00000000 --- a/src/org/apache/commons/io/output/TaggedOutputStream.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.UUID; - -import org.apache.commons.io.TaggedIOException; - -/** - * An output stream decorator that tags potential exceptions so that the - * stream that caused the exception can easily be identified. This is - * done by using the {@link TaggedIOException} class to wrap all thrown - * {@link IOException}s. See below for an example of using this class. - *
- * TaggedOutputStream stream = new TaggedOutputStream(...);
- * try {
- *     // Processing that may throw an IOException either from this stream
- *     // or from some other IO activity like temporary files, etc.
- *     writeToStream(stream);
- * } catch (IOException e) {
- *     if (stream.isCauseOf(e)) {
- *         // The exception was caused by this stream.
- *         // Use e.getCause() to get the original exception.
- *     } else {
- *         // The exception was caused by something else.
- *     }
- * }
- * 
- *

- * Alternatively, the {@link #throwIfCauseOf(Exception)} method can be - * used to let higher levels of code handle the exception caused by this - * stream while other processing errors are being taken care of at this - * lower level. - *

- *
- * TaggedOutputStream stream = new TaggedOutputStream(...);
- * try {
- *     writeToStream(stream);
- * } catch (IOException e) {
- *     stream.throwIfCauseOf(e);
- *     // ... or process the exception that was caused by something else
- * }
- * 
- * - * @see TaggedIOException - * @since 2.0 - */ -public class TaggedOutputStream extends ProxyOutputStream { - - /** - * The unique tag associated with exceptions from stream. - */ - private final Serializable tag = UUID.randomUUID(); - - /** - * Creates a tagging decorator for the given output stream. - * - * @param proxy output stream to be decorated - */ - public TaggedOutputStream(final OutputStream proxy) { - super(proxy); - } - - /** - * Tests if the given exception was caused by this stream. - * - * @param exception an exception - * @return {@code true} if the exception was thrown by this stream, - * {@code false} otherwise - */ - public boolean isCauseOf(final Exception exception) { - return TaggedIOException.isTaggedWith(exception, tag); - } - - /** - * Re-throws the original exception thrown by this stream. This method - * first checks whether the given exception is a {@link TaggedIOException} - * wrapper created by this decorator, and then unwraps and throws the - * original wrapped exception. Returns normally if the exception was - * not thrown by this stream. - * - * @param exception an exception - * @throws IOException original exception, if any, thrown by this stream - */ - public void throwIfCauseOf(final Exception exception) throws IOException { - TaggedIOException.throwCauseIfTaggedWith(exception, tag); - } - - /** - * Tags any IOExceptions thrown, wrapping and re-throwing. - * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - */ - @Override - protected void handleIOException(final IOException e) throws IOException { - throw new TaggedIOException(e, tag); - } - -} diff --git a/src/org/apache/commons/io/output/TaggedWriter.java b/src/org/apache/commons/io/output/TaggedWriter.java deleted file mode 100644 index 00f9f03d..00000000 --- a/src/org/apache/commons/io/output/TaggedWriter.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.util.UUID; - -import org.apache.commons.io.TaggedIOException; - -/** - * A writer decorator that tags potential exceptions so that the - * reader that caused the exception can easily be identified. This is - * done by using the {@link TaggedIOException} class to wrap all thrown - * {@link IOException}s. See below for an example of using this class. - *
- * TaggedReader reader = new TaggedReader(...);
- * try {
- *     // Processing that may throw an IOException either from this reader
- *     // or from some other IO activity like temporary files, etc.
- *     writeToWriter(writer);
- * } catch (IOException e) {
- *     if (writer.isCauseOf(e)) {
- *         // The exception was caused by this writer.
- *         // Use e.getCause() to get the original exception.
- *     } else {
- *         // The exception was caused by something else.
- *     }
- * }
- * 
- *

- * Alternatively, the {@link #throwIfCauseOf(Exception)} method can be - * used to let higher levels of code handle the exception caused by this - * writer while other processing errors are being taken care of at this - * lower level. - *

- *
- * TaggedWriter writer = new TaggedWriter(...);
- * try {
- *     writeToWriter(writer);
- * } catch (IOException e) {
- *     writer.throwIfCauseOf(e);
- *     // ... or process the exception that was caused by something else
- * }
- * 
- * - * @see TaggedIOException - * @since 2.0 - */ -public class TaggedWriter extends ProxyWriter { - - /** - * The unique tag associated with exceptions from writer. - */ - private final Serializable tag = UUID.randomUUID(); - - /** - * Creates a tagging decorator for the given writer. - * - * @param proxy writer to be decorated - */ - public TaggedWriter(final Writer proxy) { - super(proxy); - } - - /** - * Tests if the given exception was caused by this writer. - * - * @param exception an exception - * @return {@code true} if the exception was thrown by this writer, - * {@code false} otherwise - */ - public boolean isCauseOf(final Exception exception) { - return TaggedIOException.isTaggedWith(exception, tag); - } - - /** - * Re-throws the original exception thrown by this writer. This method - * first checks whether the given exception is a {@link TaggedIOException} - * wrapper created by this decorator, and then unwraps and throws the - * original wrapped exception. Returns normally if the exception was - * not thrown by this writer. - * - * @param exception an exception - * @throws IOException original exception, if any, thrown by this writer - */ - public void throwIfCauseOf(final Exception exception) throws IOException { - TaggedIOException.throwCauseIfTaggedWith(exception, tag); - } - - /** - * Tags any IOExceptions thrown, wrapping and re-throwing. - * - * @param e The IOException thrown - * @throws IOException if an I/O error occurs. - */ - @Override - protected void handleIOException(final IOException e) throws IOException { - throw new TaggedIOException(e, tag); - } - -} diff --git a/src/org/apache/commons/io/output/TeeOutputStream.java b/src/org/apache/commons/io/output/TeeOutputStream.java deleted file mode 100644 index dc70af87..00000000 --- a/src/org/apache/commons/io/output/TeeOutputStream.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Classic splitter of {@link OutputStream}. Named after the Unix 'tee' command. It allows a stream to be branched off - * so there are now two streams. - */ -public class TeeOutputStream extends ProxyOutputStream { - - /** - * The second OutputStream to write to. - * - * TODO Make private and final in 3.0. - */ - protected OutputStream branch; - - /** - * Constructs a TeeOutputStream. - * - * @param out the main OutputStream - * @param branch the second OutputStream - */ - public TeeOutputStream(final OutputStream out, final OutputStream branch) { - super(out); - this.branch = branch; - } - - /** - * Writes the bytes to both streams. - * - * @param b the bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void write(final byte[] b) throws IOException { - super.write(b); - this.branch.write(b); - } - - /** - * Writes the specified bytes to both streams. - * - * @param b the bytes to write - * @param off The start offset - * @param len The number of bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void write(final byte[] b, final int off, final int len) throws IOException { - super.write(b, off, len); - this.branch.write(b, off, len); - } - - /** - * Writes a byte to both streams. - * - * @param b the byte to write - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void write(final int b) throws IOException { - super.write(b); - this.branch.write(b); - } - - /** - * Flushes both streams. - * - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - super.flush(); - this.branch.flush(); - } - - /** - * Closes both output streams. - *

- * If closing the main output stream throws an exception, attempt to close the branch output stream. - *

- * - *

- * If closing the main and branch output streams both throw exceptions, which exceptions is thrown by this method is - * currently unspecified and subject to change. - *

- * - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - try { - super.close(); - } finally { - this.branch.close(); - } - } - -} diff --git a/src/org/apache/commons/io/output/TeeWriter.java b/src/org/apache/commons/io/output/TeeWriter.java deleted file mode 100644 index e373bc1d..00000000 --- a/src/org/apache/commons/io/output/TeeWriter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.io.output; - -import java.io.Writer; -import java.util.Collection; - -/** - * Classic splitter of {@link Writer}. Named after the Unix 'tee' command. It allows a stream to be branched off so - * there are now two streams. - *

- * This currently a only convenience class with the proper name "TeeWriter". - *

- * - * @since 2.7 - */ -public class TeeWriter extends ProxyCollectionWriter { - - /** - * Creates a new filtered collection writer. - * - * @param writers Writers to provide the underlying targets. - */ - public TeeWriter(final Collection writers) { - super(writers); - } - - /** - * Creates a new filtered collection writer. - * - * @param writers Writers to provide the underlying targets. - */ - public TeeWriter(final Writer... writers) { - super(writers); - } -} diff --git a/src/org/apache/commons/io/output/ThresholdingOutputStream.java b/src/org/apache/commons/io/output/ThresholdingOutputStream.java deleted file mode 100644 index 4791f8e2..00000000 --- a/src/org/apache/commons/io/output/ThresholdingOutputStream.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.commons.io.function.IOConsumer; -import org.apache.commons.io.function.IOFunction; - -/** - * An output stream which triggers an event when a specified number of bytes of data have been written to it. The event - * can be used, for example, to throw an exception if a maximum has been reached, or to switch the underlying stream - * type when the threshold is exceeded. - *

- * This class overrides all {@code OutputStream} methods. However, these overrides ultimately call the corresponding - * methods in the underlying output stream implementation. - *

- *

- * NOTE: This implementation may trigger the event before the threshold is actually reached, since it triggers - * when a pending write operation would cause the threshold to be exceeded. - *

- */ -public class ThresholdingOutputStream extends OutputStream { - - /** - * Noop output stream getter function. - */ - private static final IOFunction NOOP_OS_GETTER = os -> NullOutputStream.NULL_OUTPUT_STREAM; - - /** - * The threshold at which the event will be triggered. - */ - private final int threshold; - - /** - * Accepts reaching the threshold. - */ - private final IOConsumer thresholdConsumer; - - /** - * Gets the output stream. - */ - private final IOFunction outputStreamGetter; - - /** - * The number of bytes written to the output stream. - */ - private long written; - - /** - * Whether or not the configured threshold has been exceeded. - */ - private boolean thresholdExceeded; - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold. - * - * @param threshold The number of bytes at which to trigger an event. - */ - public ThresholdingOutputStream(final int threshold) { - this(threshold, IOConsumer.noop(), NOOP_OS_GETTER); - } - - /** - * Constructs an instance of this class which will trigger an event at the specified threshold. - * - * @param threshold The number of bytes at which to trigger an event. - * @param thresholdConsumer Accepts reaching the threshold. - * @param outputStreamGetter Gets the output stream. - * @since 2.9.0 - */ - public ThresholdingOutputStream(final int threshold, final IOConsumer thresholdConsumer, - final IOFunction outputStreamGetter) { - this.threshold = threshold; - this.thresholdConsumer = thresholdConsumer == null ? IOConsumer.noop() : thresholdConsumer; - this.outputStreamGetter = outputStreamGetter == null ? NOOP_OS_GETTER : outputStreamGetter; - } - - /** - * Checks to see if writing the specified number of bytes would cause the configured threshold to be exceeded. If - * so, triggers an event to allow a concrete implementation to take action on this. - * - * @param count The number of bytes about to be written to the underlying output stream. - * - * @throws IOException if an error occurs. - */ - protected void checkThreshold(final int count) throws IOException { - if (!thresholdExceeded && written + count > threshold) { - thresholdExceeded = true; - thresholdReached(); - } - } - - /** - * Closes this output stream and releases any system resources associated with this stream. - * - * @throws IOException if an error occurs. - */ - @Override - public void close() throws IOException { - try { - flush(); - } catch (final IOException ignored) { - // ignore - } - getStream().close(); - } - - /** - * Flushes this output stream and forces any buffered output bytes to be written out. - * - * @throws IOException if an error occurs. - */ - @SuppressWarnings("resource") // the underlying stream is managed by a subclass. - @Override - public void flush() throws IOException { - getStream().flush(); - } - - /** - * Returns the number of bytes that have been written to this output stream. - * - * @return The number of bytes written. - */ - public long getByteCount() { - return written; - } - - /** - * Returns the underlying output stream, to which the corresponding {@code OutputStream} methods in this class will - * ultimately delegate. - * - * @return The underlying output stream. - * - * @throws IOException if an error occurs. - */ - protected OutputStream getStream() throws IOException { - return outputStreamGetter.apply(this); - } - - /** - * Returns the threshold, in bytes, at which an event will be triggered. - * - * @return The threshold point, in bytes. - */ - public int getThreshold() { - return threshold; - } - - /** - * Determines whether or not the configured threshold has been exceeded for this output stream. - * - * @return {@code true} if the threshold has been reached; {@code false} otherwise. - */ - public boolean isThresholdExceeded() { - return written > threshold; - } - - /** - * Resets the byteCount to zero. You can call this from {@link #thresholdReached()} if you want the event to be - * triggered again. - */ - protected void resetByteCount() { - this.thresholdExceeded = false; - this.written = 0; - } - - /** - * Sets the byteCount to count. Useful for re-opening an output stream that has previously been written to. - * - * @param count The number of bytes that have already been written to the output stream - * - * @since 2.5 - */ - protected void setByteCount(final long count) { - this.written = count; - } - - /** - * Indicates that the configured threshold has been reached, and that a subclass should take whatever action - * necessary on this event. This may include changing the underlying output stream. - * - * @throws IOException if an error occurs. - */ - protected void thresholdReached() throws IOException { - thresholdConsumer.accept(this); - } - - /** - * Writes {@code b.length} bytes from the specified byte array to this output stream. - * - * @param b The array of bytes to be written. - * - * @throws IOException if an error occurs. - */ - @SuppressWarnings("resource") // the underlying stream is managed by a subclass. - @Override - public void write(final byte[] b) throws IOException { - checkThreshold(b.length); - getStream().write(b); - written += b.length; - } - - /** - * Writes {@code len} bytes from the specified byte array starting at offset {@code off} to this output stream. - * - * @param b The byte array from which the data will be written. - * @param off The start offset in the byte array. - * @param len The number of bytes to write. - * - * @throws IOException if an error occurs. - */ - @SuppressWarnings("resource") // the underlying stream is managed by a subclass. - @Override - public void write(final byte[] b, final int off, final int len) throws IOException { - checkThreshold(len); - getStream().write(b, off, len); - written += len; - } - - /** - * Writes the specified byte to this output stream. - * - * @param b The byte to be written. - * - * @throws IOException if an error occurs. - */ - @SuppressWarnings("resource") // the underlying stream is managed by a subclass. - @Override - public void write(final int b) throws IOException { - checkThreshold(1); - getStream().write(b); - written++; - } -} diff --git a/src/org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream.java b/src/org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream.java deleted file mode 100644 index dbf2e1bd..00000000 --- a/src/org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Implements a version of {@link AbstractByteArrayOutputStream} without any concurrent thread safety. - * - * @since 2.7 - */ -//@NotThreadSafe -public final class UnsynchronizedByteArrayOutputStream extends AbstractByteArrayOutputStream { - - /** - * Creates a new byte array output stream. The buffer capacity is initially - * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary. - */ - public UnsynchronizedByteArrayOutputStream() { - this(DEFAULT_SIZE); - } - - /** - * Creates a new byte array output stream, with a buffer capacity of the specified size, in bytes. - * - * @param size the initial size - * @throws IllegalArgumentException if size is negative - */ - public UnsynchronizedByteArrayOutputStream(final int size) { - if (size < 0) { - throw new IllegalArgumentException("Negative initial size: " + size); - } - needNewBuffer(size); - } - - @Override - public void write(final byte[] b, final int off, final int len) { - if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(String.format("offset=%,d, length=%,d", off, len)); - } - if (len == 0) { - return; - } - writeImpl(b, off, len); - } - - @Override - public void write(final int b) { - writeImpl(b); - } - - @Override - public int write(final InputStream in) throws IOException { - return writeImpl(in); - } - - @Override - public int size() { - return count; - } - - /** - * @see java.io.ByteArrayOutputStream#reset() - */ - @Override - public void reset() { - resetImpl(); - } - - @Override - public void writeTo(final OutputStream out) throws IOException { - writeToImpl(out); - } - - /** - * Fetches entire contents of an {@code InputStream} and represent same data as result InputStream. - *

- * This method is useful where, - *

- *
    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - */ - public static InputStream toBufferedInputStream(final InputStream input) throws IOException { - return toBufferedInputStream(input, DEFAULT_SIZE); - } - - /** - * Fetches entire contents of an {@code InputStream} and represent same data as result InputStream. - *

- * This method is useful where, - *

- *
    - *
  • Source InputStream is slow.
  • - *
  • It has network resources associated, so we cannot keep it open for long time.
  • - *
  • It has network timeout associated.
  • - *
- * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].
- * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. - * - * @param input Stream to be fully buffered. - * @param size the initial buffer size - * @return A fully buffered stream. - * @throws IOException if an I/O error occurs. - */ - public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException { - // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op - try (final UnsynchronizedByteArrayOutputStream output = new UnsynchronizedByteArrayOutputStream(size)) { - output.write(input); - return output.toInputStream(); - } - } - - @Override - public InputStream toInputStream() { - return toInputStream(UnsynchronizedByteArrayInputStream::new); - } - - @Override - public byte[] toByteArray() { - return toByteArrayImpl(); - } -} diff --git a/src/org/apache/commons/io/output/WriterOutputStream.java b/src/org/apache/commons/io/output/WriterOutputStream.java deleted file mode 100644 index 1a306122..00000000 --- a/src/org/apache/commons/io/output/WriterOutputStream.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; - -/** - * {@link OutputStream} implementation that transforms a byte stream to a - * character stream using a specified charset encoding and writes the resulting - * stream to a {@link Writer}. The stream is transformed using a - * {@link CharsetDecoder} object, guaranteeing that all charset - * encodings supported by the JRE are handled correctly. - *

- * The output of the {@link CharsetDecoder} is buffered using a fixed size buffer. - * This implies that the data is written to the underlying {@link Writer} in chunks - * that are no larger than the size of this buffer. By default, the buffer is - * flushed only when it overflows or when {@link #flush()} or {@link #close()} - * is called. In general there is therefore no need to wrap the underlying {@link Writer} - * in a {@link java.io.BufferedWriter}. {@link WriterOutputStream} can also - * be instructed to flush the buffer after each write operation. In this case, all - * available data is written immediately to the underlying {@link Writer}, implying that - * the current position of the {@link Writer} is correlated to the current position - * of the {@link WriterOutputStream}. - *

- * {@link WriterOutputStream} implements the inverse transformation of {@link java.io.OutputStreamWriter}; - * in the following example, writing to {@code out2} would have the same result as writing to - * {@code out} directly (provided that the byte sequence is legal with respect to the - * charset encoding): - *

- * OutputStream out = ...
- * Charset cs = ...
- * OutputStreamWriter writer = new OutputStreamWriter(out, cs);
- * WriterOutputStream out2 = new WriterOutputStream(writer, cs);
- * {@link WriterOutputStream} implements the same transformation as {@link java.io.InputStreamReader}, - * except that the control flow is reversed: both classes transform a byte stream - * into a character stream, but {@link java.io.InputStreamReader} pulls data from the underlying stream, - * while {@link WriterOutputStream} pushes it to the underlying stream. - *

- * Note that while there are use cases where there is no alternative to using - * this class, very often the need to use this class is an indication of a flaw - * in the design of the code. This class is typically used in situations where an existing - * API only accepts an {@link OutputStream} object, but where the stream is known to represent - * character data that must be decoded for further use. - *

- *

- * Instances of {@link WriterOutputStream} are not thread safe. - *

- * - * @see org.apache.commons.io.input.ReaderInputStream - * @since 2.0 - */ -public class WriterOutputStream extends OutputStream { - private static final int BUFFER_SIZE = 1024; - - private final Writer writer; - private final CharsetDecoder decoder; - private final boolean writeImmediately; - - /** - * ByteBuffer used as input for the decoder. This buffer can be small - * as it is used only to transfer the received data to the - * decoder. - */ - private final ByteBuffer decoderIn = ByteBuffer.allocate(128); - - /** - * CharBuffer used as output for the decoder. It should be - * somewhat larger as we write from this buffer to the - * underlying Writer. - */ - private final CharBuffer decoderOut; - - /** - * Constructs a new {@link WriterOutputStream} with a default output buffer size of {@value #BUFFER_SIZE} - * characters. The output buffer will only be flushed when it overflows or when {@link #flush()} or {@link #close()} - * is called. - * - * @param writer the target {@link Writer} - * @param decoder the charset decoder - * @since 2.1 - */ - public WriterOutputStream(final Writer writer, final CharsetDecoder decoder) { - this(writer, decoder, BUFFER_SIZE, false); - } - - /** - * Constructs a new {@link WriterOutputStream}. - * - * @param writer the target {@link Writer} - * @param decoder the charset decoder - * @param bufferSize the size of the output buffer in number of characters - * @param writeImmediately If {@code true} the output buffer will be flushed after each - * write operation, i.e. all available data will be written to the - * underlying {@link Writer} immediately. If {@code false}, the - * output buffer will only be flushed when it overflows or when - * {@link #flush()} or {@link #close()} is called. - * @since 2.1 - */ - public WriterOutputStream(final Writer writer, final CharsetDecoder decoder, final int bufferSize, - final boolean writeImmediately) { - checkIbmJdkWithBrokenUTF16( decoder.charset()); - this.writer = writer; - this.decoder = decoder; - this.writeImmediately = writeImmediately; - decoderOut = CharBuffer.allocate(bufferSize); - } - - /** - * Constructs a new {@link WriterOutputStream}. - * - * @param writer the target {@link Writer} - * @param charset the charset encoding - * @param bufferSize the size of the output buffer in number of characters - * @param writeImmediately If {@code true} the output buffer will be flushed after each - * write operation, i.e. all available data will be written to the - * underlying {@link Writer} immediately. If {@code false}, the - * output buffer will only be flushed when it overflows or when - * {@link #flush()} or {@link #close()} is called. - */ - public WriterOutputStream(final Writer writer, final Charset charset, final int bufferSize, - final boolean writeImmediately) { - this(writer, - charset.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .replaceWith("?"), - bufferSize, - writeImmediately); - } - - /** - * Constructs a new {@link WriterOutputStream} with a default output buffer size of {@value #BUFFER_SIZE} - * characters. The output buffer will only be flushed when it overflows or when {@link #flush()} or {@link #close()} - * is called. - * - * @param writer the target {@link Writer} - * @param charset the charset encoding - */ - public WriterOutputStream(final Writer writer, final Charset charset) { - this(writer, charset, BUFFER_SIZE, false); - } - - /** - * Constructs a new {@link WriterOutputStream}. - * - * @param writer the target {@link Writer} - * @param charsetName the name of the charset encoding - * @param bufferSize the size of the output buffer in number of characters - * @param writeImmediately If {@code true} the output buffer will be flushed after each - * write operation, i.e. all available data will be written to the - * underlying {@link Writer} immediately. If {@code false}, the - * output buffer will only be flushed when it overflows or when - * {@link #flush()} or {@link #close()} is called. - */ - public WriterOutputStream(final Writer writer, final String charsetName, final int bufferSize, - final boolean writeImmediately) { - this(writer, Charset.forName(charsetName), bufferSize, writeImmediately); - } - - /** - * Constructs a new {@link WriterOutputStream} with a default output buffer size of {@value #BUFFER_SIZE} - * characters. The output buffer will only be flushed when it overflows or when {@link #flush()} or {@link #close()} - * is called. - * - * @param writer the target {@link Writer} - * @param charsetName the name of the charset encoding - */ - public WriterOutputStream(final Writer writer, final String charsetName) { - this(writer, charsetName, BUFFER_SIZE, false); - } - - /** - * Constructs a new {@link WriterOutputStream} that uses the default character encoding and with a default output - * buffer size of {@value #BUFFER_SIZE} characters. The output buffer will only be flushed when it overflows or when - * {@link #flush()} or {@link #close()} is called. - * - * @param writer the target {@link Writer} - * @deprecated 2.5 use {@link #WriterOutputStream(Writer, Charset)} instead - */ - @Deprecated - public WriterOutputStream(final Writer writer) { - this(writer, Charset.defaultCharset(), BUFFER_SIZE, false); - } - - /** - * Write bytes from the specified byte array to the stream. - * - * @param b the byte array containing the bytes to write - * @param off the start offset in the byte array - * @param len the number of bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final byte[] b, int off, int len) throws IOException { - while (len > 0) { - final int c = Math.min(len, decoderIn.remaining()); - decoderIn.put(b, off, c); - processInput(false); - len -= c; - off += c; - } - if (writeImmediately) { - flushOutput(); - } - } - - /** - * Write bytes from the specified byte array to the stream. - * - * @param b the byte array containing the bytes to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final byte[] b) throws IOException { - write(b, 0, b.length); - } - - /** - * Write a single byte to the stream. - * - * @param b the byte to write - * @throws IOException if an I/O error occurs. - */ - @Override - public void write(final int b) throws IOException { - write(new byte[] {(byte) b}, 0, 1); - } - - /** - * Flush the stream. Any remaining content accumulated in the output buffer - * will be written to the underlying {@link Writer}. After that - * {@link Writer#flush()} will be called. - * @throws IOException if an I/O error occurs. - */ - @Override - public void flush() throws IOException { - flushOutput(); - writer.flush(); - } - - /** - * Close the stream. Any remaining content accumulated in the output buffer - * will be written to the underlying {@link Writer}. After that - * {@link Writer#close()} will be called. - * @throws IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - processInput(true); - flushOutput(); - writer.close(); - } - - /** - * Decode the contents of the input ByteBuffer into a CharBuffer. - * - * @param endOfInput indicates end of input - * @throws IOException if an I/O error occurs. - */ - private void processInput(final boolean endOfInput) throws IOException { - // Prepare decoderIn for reading - decoderIn.flip(); - CoderResult coderResult; - while (true) { - coderResult = decoder.decode(decoderIn, decoderOut, endOfInput); - if (coderResult.isOverflow()) { - flushOutput(); - } else if (coderResult.isUnderflow()) { - break; - } else { - // The decoder is configured to replace malformed input and unmappable characters, - // so we should not get here. - throw new IOException("Unexpected coder result"); - } - } - // Discard the bytes that have been read - decoderIn.compact(); - } - - /** - * Flush the output. - * - * @throws IOException if an I/O error occurs. - */ - private void flushOutput() throws IOException { - if (decoderOut.position() > 0) { - writer.write(decoderOut.array(), 0, decoderOut.position()); - decoderOut.rewind(); - } - } - - /** - * Check if the JDK in use properly supports the given charset. - * - * @param charset the charset to check the support for - */ - private static void checkIbmJdkWithBrokenUTF16(final Charset charset){ - if (!"UTF-16".equals(charset.name())) { - return; - } - final String TEST_STRING_2 = "v\u00e9s"; - final byte[] bytes = TEST_STRING_2.getBytes(charset); - - final CharsetDecoder charsetDecoder2 = charset.newDecoder(); - final ByteBuffer bb2 = ByteBuffer.allocate(16); - final CharBuffer cb2 = CharBuffer.allocate(TEST_STRING_2.length()); - final int len = bytes.length; - for (int i = 0; i < len; i++) { - bb2.put(bytes[i]); - bb2.flip(); - try { - charsetDecoder2.decode(bb2, cb2, i == (len - 1)); - } catch ( final IllegalArgumentException e){ - throw new UnsupportedOperationException("UTF-16 requested when running on an IBM JDK with broken UTF-16 support. " + - "Please find a JDK that supports UTF-16 if you intend to use UF-16 with WriterOutputStream"); - } - bb2.compact(); - } - cb2.rewind(); - if (!TEST_STRING_2.equals(cb2.toString())){ - throw new UnsupportedOperationException("UTF-16 requested when running on an IBM JDK with broken UTF-16 support. " + - "Please find a JDK that supports UTF-16 if you intend to use UF-16 with WriterOutputStream"); - } - - } -} diff --git a/src/org/apache/commons/io/output/XmlStreamWriter.java b/src/org/apache/commons/io/output/XmlStreamWriter.java deleted file mode 100644 index 881f1d70..00000000 --- a/src/org/apache/commons/io/output/XmlStreamWriter.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.io.output; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.input.XmlStreamReader; - -/** - * Character stream that handles all the necessary Voodoo to figure out the - * charset encoding of the XML document written to the stream. - * - * @see XmlStreamReader - * @since 2.0 - */ -public class XmlStreamWriter extends Writer { - private static final int BUFFER_SIZE = IOUtils.DEFAULT_BUFFER_SIZE; - - private final OutputStream out; - - private final String defaultEncoding; - - private StringWriter xmlPrologWriter = new StringWriter(BUFFER_SIZE); - - private Writer writer; - - private String encoding; - - /** - * Constructs a new XML stream writer for the specified output stream - * with a default encoding of UTF-8. - * - * @param out The output stream - */ - public XmlStreamWriter(final OutputStream out) { - this(out, null); - } - - /** - * Constructs a new XML stream writer for the specified output stream - * with the specified default encoding. - * - * @param out The output stream - * @param defaultEncoding The default encoding if not encoding could be detected - */ - public XmlStreamWriter(final OutputStream out, final String defaultEncoding) { - this.out = out; - this.defaultEncoding = defaultEncoding != null ? defaultEncoding : "UTF-8"; - } - - /** - * Constructs a new XML stream writer for the specified file - * with a default encoding of UTF-8. - * - * @param file The file to write to - * @throws FileNotFoundException if there is an error creating or - * opening the file - */ - public XmlStreamWriter(final File file) throws FileNotFoundException { - this(file, null); - } - - /** - * Constructs a new XML stream writer for the specified file - * with the specified default encoding. - * - * @param file The file to write to - * @param defaultEncoding The default encoding if not encoding could be detected - * @throws FileNotFoundException if there is an error creating or - * opening the file - */ - @SuppressWarnings("resource") - public XmlStreamWriter(final File file, final String defaultEncoding) throws FileNotFoundException { - this(new FileOutputStream(file), defaultEncoding); - } - - /** - * Returns the detected encoding. - * - * @return the detected encoding - */ - public String getEncoding() { - return encoding; - } - - /** - * Returns the default encoding. - * - * @return the default encoding - */ - public String getDefaultEncoding() { - return defaultEncoding; - } - - /** - * Closes the underlying writer. - * - * @throws IOException if an error occurs closing the underlying writer - */ - @Override - public void close() throws IOException { - if (writer == null) { - encoding = defaultEncoding; - writer = new OutputStreamWriter(out, encoding); - writer.write(xmlPrologWriter.toString()); - } - writer.close(); - } - - /** - * Flushes the underlying writer. - * - * @throws IOException if an error occurs flushing the underlying writer - */ - @Override - public void flush() throws IOException { - if (writer != null) { - writer.flush(); - } - } - - /** - * Detects the encoding. - * - * @param cbuf the buffer to write the characters from - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an error occurs detecting the encoding - */ - private void detectEncoding(final char[] cbuf, final int off, final int len) - throws IOException { - int size = len; - final StringBuffer xmlProlog = xmlPrologWriter.getBuffer(); - if (xmlProlog.length() + len > BUFFER_SIZE) { - size = BUFFER_SIZE - xmlProlog.length(); - } - xmlPrologWriter.write(cbuf, off, size); - - // try to determine encoding - if (xmlProlog.length() >= 5) { - if (xmlProlog.substring(0, 5).equals(""); - if (xmlPrologEnd > 0) { - // ok, full XML prolog written: let's extract encoding - final Matcher m = ENCODING_PATTERN.matcher(xmlProlog.substring(0, - xmlPrologEnd)); - if (m.find()) { - encoding = m.group(1).toUpperCase(Locale.ROOT); - encoding = encoding.substring(1, encoding.length() - 1); - } else { - // no encoding found in XML prolog: using default - // encoding - encoding = defaultEncoding; - } - } else if (xmlProlog.length() >= BUFFER_SIZE) { - // no encoding found in first characters: using default - // encoding - encoding = defaultEncoding; - } - } else { - // no XML prolog: using default encoding - encoding = defaultEncoding; - } - if (encoding != null) { - // encoding has been chosen: let's do it - xmlPrologWriter = null; - writer = new OutputStreamWriter(out, encoding); - writer.write(xmlProlog.toString()); - if (len > size) { - writer.write(cbuf, off + size, len - size); - } - } - } - } - - /** - * Writes the characters to the underlying writer, detecting encoding. - * - * @param cbuf the buffer to write the characters from - * @param off The start offset - * @param len The number of characters to write - * @throws IOException if an error occurs detecting the encoding - */ - @Override - public void write(final char[] cbuf, final int off, final int len) throws IOException { - if (xmlPrologWriter != null) { - detectEncoding(cbuf, off, len); - } else { - writer.write(cbuf, off, len); - } - } - - static final Pattern ENCODING_PATTERN = XmlStreamReader.ENCODING_PATTERN; -} diff --git a/src/org/apache/commons/io/output/package.html b/src/org/apache/commons/io/output/package.html deleted file mode 100644 index 44156133..00000000 --- a/src/org/apache/commons/io/output/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - -

-This package provides implementations of output classes, such as -OutputStream and Writer. -

- - diff --git a/src/org/apache/commons/io/overview.html b/src/org/apache/commons/io/overview.html deleted file mode 100644 index 5f2ff1e7..00000000 --- a/src/org/apache/commons/io/overview.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - -

-The commons-io component contains utility classes, -filters, streams, readers and writers. -

-

-These classes aim to add to the standard JDK IO classes. -The utilities provide convenience wrappers around the JDK, simplifying -various operations into pre-tested units of code. -The filters and streams provide useful implementations that perhaps should -be in the JDK itself. -

- - diff --git a/src/org/apache/commons/io/package.html b/src/org/apache/commons/io/package.html deleted file mode 100644 index 914a0a60..00000000 --- a/src/org/apache/commons/io/package.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - -

-This package defines utility classes for working with streams, readers, -writers and files. The most commonly used classes are described here: -

-

-IOUtils is the most frequently used class. -It provides operations to read, write, copy and close streams. -

-

-FileUtils provides operations based around the JDK File class. -These include reading, writing, copying, comparing and deleting. -

-

-FilenameUtils provides utilities based on filenames. -This utility class manipulates filenames without using File objects. -It aims to simplify the transition between Windows and Unix. -Before using this class however, you should consider whether you should -be using File objects. -

-

-FileSystemUtils allows access to the filing system in ways the JDK -does not support. At present this allows you to get the free space on a drive. -

-

-EndianUtils swaps data between Big-Endian and Little-Endian formats. -

- - diff --git a/src/org/apache/commons/net/DatagramSocketClient.java b/src/org/apache/commons/net/DatagramSocketClient.java deleted file mode 100644 index 0bd0b4a9..00000000 --- a/src/org/apache/commons/net/DatagramSocketClient.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.nio.charset.Charset; - -/** - * The DatagramSocketClient provides the basic operations that are required - * of client objects accessing datagram sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } - * method, which allows you to control the type of DatagramSocket the - * DatagramSocketClient creates for network communications. This is - * especially useful for adding things like proxy support as well as better - * support for applets. For - * example, you could create a - * {@link org.apache.commons.net.DatagramSocketFactory} - * that - * requests browser security capabilities before creating a socket. - * All classes derived from DatagramSocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create DatagramSocket instances rather than instantiating - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - * - * - * @see DatagramSocketFactory - */ - -public abstract class DatagramSocketClient -{ - /** - * The default DatagramSocketFactory shared by all DatagramSocketClient - * instances. - */ - private static final DatagramSocketFactory DEFAULT_SOCKET_FACTORY = - new DefaultDatagramSocketFactory(); - - /** - * Charset to use for byte IO. - */ - private Charset charset = Charset.defaultCharset(); - - /** The timeout to use after opening a socket. */ - protected int _timeout_; - - /** The datagram socket used for the connection. */ - protected DatagramSocket _socket_; - - /** - * A status variable indicating if the client's socket is currently open. - */ - protected boolean _isOpen_; - - /** The datagram socket's DatagramSocketFactory. */ - protected DatagramSocketFactory _socketFactory_; - - /** - * Default constructor for DatagramSocketClient. Initializes - * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. - */ - public DatagramSocketClient() - { - _socket_ = null; - _timeout_ = 0; - _isOpen_ = false; - _socketFactory_ = DEFAULT_SOCKET_FACTORY; - } - - - /** - * Opens a DatagramSocket on the local host at the first available port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - */ - public void open() throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - /** - * Opens a DatagramSocket on the local host at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @param port The port to use for the socket. - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - */ - public void open(final int port) throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(port); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - /** - * Opens a DatagramSocket at the specified address on the local host - * at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - */ - public void open(final int port, final InetAddress laddr) throws SocketException - { - _socket_ = _socketFactory_.createDatagramSocket(port, laddr); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - - - /** - * Closes the DatagramSocket used for the connection. - * You should call this method after you've finished using the class - * instance and also before you call {@link #open open() } - * again. _isOpen_ is set to false and _socket_ is set to null. - */ - public void close() - { - if (_socket_ != null) { - _socket_.close(); - } - _socket_ = null; - _isOpen_ = false; - } - - - /** - * Returns true if the client has a currently open socket. - * - * @return True if the client has a currently open socket, false otherwise. - */ - public boolean isOpen() - { - return _isOpen_; - } - - - /** - * Set the default timeout in milliseconds to use when opening a socket. - * After a call to open, the timeout for the socket is set using this value. - * This method should be used prior to a call to {@link #open open()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on the currently open socket. _timeout_ contains - * the new timeout value. - * - * @param timeout The timeout in milliseconds to use for the datagram socket - * connection. - */ - public void setDefaultTimeout(final int timeout) - { - _timeout_ = timeout; - } - - - /** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - * - * @return The default timeout in milliseconds that is used when - * opening a socket. - */ - public int getDefaultTimeout() - { - return _timeout_; - } - - - /** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #open open()}. - * - * @param timeout The timeout in milliseconds to use for the currently - * open datagram socket connection. - * @throws SocketException if an error setting the timeout - */ - public void setSoTimeout(final int timeout) throws SocketException - { - _socket_.setSoTimeout(timeout); - } - - - /** - * Returns the timeout in milliseconds of the currently opened socket. - * If you call this method when the client socket is not open, - * a NullPointerException is thrown. - * - * @return The timeout in milliseconds of the currently opened socket. - * @throws SocketException if an error getting the timeout - */ - public int getSoTimeout() throws SocketException - { - return _socket_.getSoTimeout(); - } - - - /** - * Returns the port number of the open socket on the local host used - * for the connection. If you call this method when the client socket - * is not open, a NullPointerException is thrown. - * - * @return The port number of the open socket on the local host used - * for the connection. - */ - public int getLocalPort() - { - return _socket_.getLocalPort(); - } - - - /** - * Returns the local address to which the client's socket is bound. - * If you call this method when the client socket is not open, a - * NullPointerException is thrown. - * - * @return The local address to which the client's socket is bound. - */ - public InetAddress getLocalAddress() - { - return _socket_.getLocalAddress(); - } - - - /** - * Sets the DatagramSocketFactory used by the DatagramSocketClient - * to open DatagramSockets. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - * - * @param factory The new DatagramSocketFactory the DatagramSocketClient - * should use. - */ - public void setDatagramSocketFactory(final DatagramSocketFactory factory) - { - if (factory == null) { - _socketFactory_ = DEFAULT_SOCKET_FACTORY; - } else { - _socketFactory_ = factory; - } - } - - /** - * Gets the charset name. - * - * @return the charset name. - * @since 3.3 - * @deprecated Use {@link #getCharset()} instead - */ - @Deprecated - public String getCharsetName() { - return charset.name(); - } - - /** - * Gets the charset. - * - * @return the charset. - * @since 3.3 - */ - public Charset getCharset() { - return charset; - } - - /** - * Sets the charset. - * - * @param charset the charset. - * @since 3.3 - */ - public void setCharset(final Charset charset) { - this.charset = charset; - } -} diff --git a/src/org/apache/commons/net/DatagramSocketFactory.java b/src/org/apache/commons/net/DatagramSocketFactory.java deleted file mode 100644 index e58071f4..00000000 --- a/src/org/apache/commons/net/DatagramSocketFactory.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/** - * The DatagramSocketFactory interface provides a means for the - * programmer to control the creation of datagram sockets and - * provide his own DatagramSocket implementations for use by all - * classes derived from - * {@link org.apache.commons.net.DatagramSocketClient} - * . - * This allows you to provide your own DatagramSocket implementations and - * to perform security checks or browser capability requests before - * creating a DatagramSocket. - * - * - */ - -public interface DatagramSocketFactory -{ - - /** - * Creates a DatagramSocket on the local host at the first available port. - * @return the socket - * - * @throws SocketException If the socket could not be created. - */ - DatagramSocket createDatagramSocket() throws SocketException; - - /** - * Creates a DatagramSocket on the local host at a specified port. - * - * @param port The port to use for the socket. - * @return the socket - * @throws SocketException If the socket could not be created. - */ - DatagramSocket createDatagramSocket(int port) throws SocketException; - - /** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @return the socket - * @throws SocketException If the socket could not be created. - */ - DatagramSocket createDatagramSocket(int port, InetAddress laddr) - throws SocketException; -} diff --git a/src/org/apache/commons/net/DefaultDatagramSocketFactory.java b/src/org/apache/commons/net/DefaultDatagramSocketFactory.java deleted file mode 100644 index c4ce3f95..00000000 --- a/src/org/apache/commons/net/DefaultDatagramSocketFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/** - * DefaultDatagramSocketFactory implements the DatagramSocketFactory - * interface by simply wrapping the java.net.DatagramSocket - * constructors. It is the default DatagramSocketFactory used by - * {@link org.apache.commons.net.DatagramSocketClient} - * implementations. - * - * - * @see DatagramSocketFactory - * @see DatagramSocketClient - * @see DatagramSocketClient#setDatagramSocketFactory - */ - -public class DefaultDatagramSocketFactory implements DatagramSocketFactory -{ - - /** - * Creates a DatagramSocket on the local host at the first available port. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - */ - @Override - public DatagramSocket createDatagramSocket() throws SocketException - { - return new DatagramSocket(); - } - - /** - * Creates a DatagramSocket on the local host at a specified port. - * - * @param port The port to use for the socket. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - */ - @Override - public DatagramSocket createDatagramSocket(final int port) throws SocketException - { - return new DatagramSocket(port); - } - - /** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - */ - @Override - public DatagramSocket createDatagramSocket(final int port, final InetAddress laddr) - throws SocketException - { - return new DatagramSocket(port, laddr); - } -} diff --git a/src/org/apache/commons/net/DefaultSocketFactory.java b/src/org/apache/commons/net/DefaultSocketFactory.java deleted file mode 100644 index 1a114ad7..00000000 --- a/src/org/apache/commons/net/DefaultSocketFactory.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; - -/** - * DefaultSocketFactory implements the SocketFactory interface by - * simply wrapping the java.net.Socket and java.net.ServerSocket - * constructors. It is the default SocketFactory used by - * {@link org.apache.commons.net.SocketClient} - * implementations. - * - * - * @see SocketFactory - * @see SocketClient - * @see SocketClient#setSocketFactory - */ - -public class DefaultSocketFactory extends SocketFactory -{ - /** The proxy to use when creating new sockets. */ - private final Proxy connProxy; - - /** - * The default constructor. - */ - public DefaultSocketFactory() - { - this(null); - } - - /** - * A constructor for sockets with proxy support. - * - * @param proxy The Proxy to use when creating new Sockets. - * @since 3.2 - */ - public DefaultSocketFactory(final Proxy proxy) - { - connProxy = proxy; - } - - /** - * Creates an unconnected Socket. - * - * @return A new unconnected Socket. - * @throws IOException If an I/O error occurs while creating the Socket. - * @since 3.2 - */ - @Override - public Socket createSocket() throws IOException - { - if (connProxy != null) - { - return new Socket(connProxy); - } - return new Socket(); - } - - /** - * Creates a Socket connected to the given host and port. - * - * @param host The hostname to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @throws UnknownHostException If the hostname cannot be resolved. - * @throws IOException If an I/O error occurs while creating the Socket. - */ - @Override - public Socket createSocket(final String host, final int port) - throws UnknownHostException, IOException - { - if (connProxy != null) - { - final Socket s = new Socket(connProxy); - s.connect(new InetSocketAddress(host, port)); - return s; - } - return new Socket(host, port); - } - - /** - * Creates a Socket connected to the given host and port. - * - * @param address The address of the host to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @throws IOException If an I/O error occurs while creating the Socket. - */ - @Override - public Socket createSocket(final InetAddress address, final int port) - throws IOException - { - if (connProxy != null) - { - final Socket s = new Socket(connProxy); - s.connect(new InetSocketAddress(address, port)); - return s; - } - return new Socket(address, port); - } - - /** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - * - * @param host The hostname to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @throws UnknownHostException If the hostname cannot be resolved. - * @throws IOException If an I/O error occurs while creating the Socket. - */ - @Override - public Socket createSocket(final String host, final int port, - final InetAddress localAddr, final int localPort) - throws UnknownHostException, IOException - { - if (connProxy != null) - { - final Socket s = new Socket(connProxy); - s.bind(new InetSocketAddress(localAddr, localPort)); - s.connect(new InetSocketAddress(host, port)); - return s; - } - return new Socket(host, port, localAddr, localPort); - } - - /** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - * - * @param address The address of the host to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @throws IOException If an I/O error occurs while creating the Socket. - */ - @Override - public Socket createSocket(final InetAddress address, final int port, - final InetAddress localAddr, final int localPort) - throws IOException - { - if (connProxy != null) - { - final Socket s = new Socket(connProxy); - s.bind(new InetSocketAddress(localAddr, localPort)); - s.connect(new InetSocketAddress(address, port)); - return s; - } - return new Socket(address, port, localAddr, localPort); - } - - /** - * Creates a ServerSocket bound to a specified port. A port - * of 0 will create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - */ - public ServerSocket createServerSocket(final int port) throws IOException - { - return new ServerSocket(port); - } - - /** - * Creates a ServerSocket bound to a specified port with a given - * maximum queue length for incoming connections. A port of 0 will - * create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - */ - public ServerSocket createServerSocket(final int port, final int backlog) - throws IOException - { - return new ServerSocket(port, backlog); - } - - /** - * Creates a ServerSocket bound to a specified port on a given local - * address with a given maximum queue length for incoming connections. - * A port of 0 will - * create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @param bindAddr The local address to which the ServerSocket should bind. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - */ - public ServerSocket createServerSocket(final int port, final int backlog, - final InetAddress bindAddr) - throws IOException - { - return new ServerSocket(port, backlog, bindAddr); - } -} diff --git a/src/org/apache/commons/net/MalformedServerReplyException.java b/src/org/apache/commons/net/MalformedServerReplyException.java deleted file mode 100644 index 4e4d7862..00000000 --- a/src/org/apache/commons/net/MalformedServerReplyException.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.IOException; - -/** - * This exception is used to indicate that the reply from a server - * could not be interpreted. Most of the NetComponents classes attempt - * to be as lenient as possible when receiving server replies. Many - * server implementations deviate from IETF protocol specifications, making - * it necessary to be as flexible as possible. However, there will be - * certain situations where it is not possible to continue an operation - * because the server reply could not be interpreted in a meaningful manner. - * In these cases, a MalformedServerReplyException should be thrown. - * - * - */ - -public class MalformedServerReplyException extends IOException -{ - - private static final long serialVersionUID = 6006765264250543945L; - - /** Constructs a MalformedServerReplyException with no message */ - public MalformedServerReplyException() - { - } - - /** - * Constructs a MalformedServerReplyException with a specified message. - * - * @param message The message explaining the reason for the exception. - */ - public MalformedServerReplyException(final String message) - { - super(message); - } - -} diff --git a/src/org/apache/commons/net/PrintCommandListener.java b/src/org/apache/commons/net/PrintCommandListener.java deleted file mode 100644 index 6a844767..00000000 --- a/src/org/apache/commons/net/PrintCommandListener.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * This is a support class for some of the example programs. It is - * a sample implementation of the ProtocolCommandListener interface - * which just prints out to a specified stream all command/reply traffic. - * - * @since 2.0 - */ - -public class PrintCommandListener implements ProtocolCommandListener -{ - private final PrintWriter writer; - private final boolean nologin; - private final char eolMarker; - private final boolean directionMarker; - - /** - * Create the default instance which prints everything. - * - * @param stream where to write the commands and responses - * e.g. System.out - * @since 3.0 - */ - public PrintCommandListener(final PrintStream stream) - { - this(new PrintWriter(stream)); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * - * @since 3.0 - */ - public PrintCommandListener(final PrintStream stream, final boolean suppressLogin) { - this(new PrintWriter(stream), suppressLogin); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * - * @since 3.0 - */ - public PrintCommandListener(final PrintStream stream, final boolean suppressLogin, final char eolMarker) { - this(new PrintWriter(stream), suppressLogin, eolMarker); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the output - * - * @since 3.0 - */ - public PrintCommandListener(final PrintStream stream, final boolean suppressLogin, final char eolMarker, - final boolean showDirection) { - this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection); - } - - /** - * Create the default instance which prints everything. - * - * @param writer where to write the commands and responses - */ - public PrintCommandListener(final PrintWriter writer) - { - this(writer, false); - } - - /** - * Create an instance which optionally suppresses login command text. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * - * @since 3.0 - */ - public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin) - { - this(writer, suppressLogin, (char) 0); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * - * @since 3.0 - */ - public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin, final char eolMarker) - { - this(writer, suppressLogin, eolMarker, false); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the output - * - * @since 3.0 - */ - public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin, final char eolMarker, - final boolean showDirection) { - this.writer = writer; - this.nologin = suppressLogin; - this.eolMarker = eolMarker; - this.directionMarker = showDirection; - } - - @Override - public void protocolCommandSent(final ProtocolCommandEvent event) - { - if (directionMarker) { - writer.print("> "); - } - if (nologin) { - final String cmd = event.getCommand(); - if ("PASS".equalsIgnoreCase(cmd) || "USER".equalsIgnoreCase(cmd)) { - writer.print(cmd); - writer.println(" *******"); // Don't bother with EOL marker for this! - } else { - final String IMAP_LOGIN = "LOGIN"; - if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP - String msg = event.getMessage(); - msg=msg.substring(0, msg.indexOf(IMAP_LOGIN)+IMAP_LOGIN.length()); - writer.print(msg); - writer.println(" *******"); // Don't bother with EOL marker for this! - } else { - writer.print(getPrintableString(event.getMessage())); - } - } - } else { - writer.print(getPrintableString(event.getMessage())); - } - writer.flush(); - } - - private String getPrintableString(final String msg){ - if (eolMarker == 0) { - return msg; - } - final int pos = msg.indexOf(SocketClient.NETASCII_EOL); - if (pos > 0) { - final StringBuilder sb = new StringBuilder(); - sb.append(msg.substring(0,pos)); - sb.append(eolMarker); - sb.append(msg.substring(pos)); - return sb.toString(); - } - return msg; - } - - @Override - public void protocolReplyReceived(final ProtocolCommandEvent event) - { - if (directionMarker) { - writer.print("< "); - } - writer.print(event.getMessage()); - writer.flush(); - } -} - diff --git a/src/org/apache/commons/net/ProtocolCommandEvent.java b/src/org/apache/commons/net/ProtocolCommandEvent.java deleted file mode 100644 index f1ae28ee..00000000 --- a/src/org/apache/commons/net/ProtocolCommandEvent.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; -import java.util.EventObject; - -/** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandEvent class coupled with the - * {@link org.apache.commons.net.ProtocolCommandListener} - * interface facilitate this process. - * - * - * @see ProtocolCommandListener - * @see ProtocolCommandSupport - */ - -public class ProtocolCommandEvent extends EventObject -{ - private static final long serialVersionUID = 403743538418947240L; - - private final int replyCode; - private final boolean isCommand; - private final String message, command; - - /** - * Creates a ProtocolCommandEvent signalling a command was sent to - * the server. ProtocolCommandEvents created with this constructor - * should only be sent after a command has been sent, but before the - * reply has been received. - * - * @param source The source of the event. - * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - */ - public ProtocolCommandEvent(final Object source, final String command, final String message) - { - super(source); - this.replyCode = 0; - this.message = message; - this.isCommand = true; - this.command = command; - } - - - /** - * Creates a ProtocolCommandEvent signalling a reply to a command was - * received. ProtocolCommandEvents created with this constructor - * should only be sent after a complete command reply has been received - * fromt a server. - * - * @param source The source of the event. - * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - */ - public ProtocolCommandEvent(final Object source, final int replyCode, final String message) - { - super(source); - this.replyCode = replyCode; - this.message = message; - this.isCommand = false; - this.command = null; - } - - /** - * Returns the string representation of the command type sent (e.g., "STAT" - * or "GET"). If the ProtocolCommandEvent is a reply event, then null - * is returned. - * - * @return The string representation of the command type sent, or null - * if this is a reply event. - */ - public String getCommand() - { - return command; - } - - - /** - * Returns the reply code of the received server reply. Undefined if - * this is not a reply event. - * - * @return The reply code of the received server reply. Undefined if - * not a reply event. - */ - public int getReplyCode() - { - return replyCode; - } - - /** - * Returns true if the ProtocolCommandEvent was generated as a result - * of sending a command. - * - * @return true If the ProtocolCommandEvent was generated as a result - * of sending a command. False otherwise. - */ - public boolean isCommand() - { - return isCommand; - } - - /** - * Returns true if the ProtocolCommandEvent was generated as a result - * of receiving a reply. - * - * @return true If the ProtocolCommandEvent was generated as a result - * of receiving a reply. False otherwise. - */ - public boolean isReply() - { - return !isCommand(); - } - - /** - * Returns the entire message sent to or received from the server. - * Includes the line terminator. - * - * @return The entire message sent to or received from the server. - */ - public String getMessage() - { - return message; - } -} diff --git a/src/org/apache/commons/net/ProtocolCommandListener.java b/src/org/apache/commons/net/ProtocolCommandListener.java deleted file mode 100644 index c6696a90..00000000 --- a/src/org/apache/commons/net/ProtocolCommandListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; -import java.util.EventListener; - -/** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandListener interface coupled with the - * {@link ProtocolCommandEvent} class facilitate this process. - *

- * To receive ProtocolCommandEvents, you merely implement the - * ProtocolCommandListener interface and register the class as a listener - * with a ProtocolCommandEvent source such as - * {@link org.apache.commons.net.ftp.FTPClient}. - * - * - * @see ProtocolCommandEvent - * @see ProtocolCommandSupport - */ - -public interface ProtocolCommandListener extends EventListener -{ - - /** - * This method is invoked by a ProtocolCommandEvent source after - * sending a protocol command to a server. - * - * @param event The ProtocolCommandEvent fired. - */ - void protocolCommandSent(ProtocolCommandEvent event); - - /** - * This method is invoked by a ProtocolCommandEvent source after - * receiving a reply from a server. - * - * @param event The ProtocolCommandEvent fired. - */ - void protocolReplyReceived(ProtocolCommandEvent event); - -} diff --git a/src/org/apache/commons/net/ProtocolCommandSupport.java b/src/org/apache/commons/net/ProtocolCommandSupport.java deleted file mode 100644 index b86d3db6..00000000 --- a/src/org/apache/commons/net/ProtocolCommandSupport.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.Serializable; -import java.util.EventListener; - -import org.apache.commons.net.util.ListenerList; - -/** - * ProtocolCommandSupport is a convenience class for managing a list of - * ProtocolCommandListeners and firing ProtocolCommandEvents. You can - * simply delegate ProtocolCommandEvent firing and listener - * registering/unregistering tasks to this class. - * - * - * @see ProtocolCommandEvent - * @see ProtocolCommandListener - */ - -public class ProtocolCommandSupport implements Serializable -{ - private static final long serialVersionUID = -8017692739988399978L; - - private final Object source; - private final ListenerList listeners; - - /** - * Creates a ProtocolCommandSupport instance using the indicated source - * as the source of ProtocolCommandEvents. - * - * @param source The source to use for all generated ProtocolCommandEvents. - */ - public ProtocolCommandSupport(final Object source) - { - this.listeners = new ListenerList(); - this.source = source; - } - - - /** - * Fires a ProtocolCommandEvent signalling the sending of a command to all - * registered listeners, invoking their - * {@link org.apache.commons.net.ProtocolCommandListener#protocolCommandSent protocolCommandSent() } - * methods. - * - * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - */ - public void fireCommandSent(final String command, final String message) - { - final ProtocolCommandEvent event; - - event = new ProtocolCommandEvent(source, command, message); - - for (final EventListener listener : listeners) - { - ((ProtocolCommandListener)listener).protocolCommandSent(event); - } - } - - /** - * Fires a ProtocolCommandEvent signalling the reception of a command reply - * to all registered listeners, invoking their - * {@link org.apache.commons.net.ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } - * methods. - * - * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - */ - public void fireReplyReceived(final int replyCode, final String message) - { - final ProtocolCommandEvent event; - event = new ProtocolCommandEvent(source, replyCode, message); - - for (final EventListener listener : listeners) - { - ((ProtocolCommandListener)listener).protocolReplyReceived(event); - } - } - - /** - * Adds a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to add. - */ - public void addProtocolCommandListener(final ProtocolCommandListener listener) - { - listeners.addListener(listener); - } - - /** - * Removes a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to remove. - */ - public void removeProtocolCommandListener(final ProtocolCommandListener listener) - { - listeners.removeListener(listener); - } - - - /** - * Returns the number of ProtocolCommandListeners currently registered. - * - * @return The number of ProtocolCommandListeners currently registered. - */ - public int getListenerCount() - { - return listeners.getListenerCount(); - } - -} - diff --git a/src/org/apache/commons/net/SocketClient.java b/src/org/apache/commons/net/SocketClient.java deleted file mode 100644 index c3bb3a0d..00000000 --- a/src/org/apache/commons/net/SocketClient.java +++ /dev/null @@ -1,900 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.Socket; -import java.net.SocketException; -import java.nio.charset.Charset; - -import javax.net.ServerSocketFactory; -import javax.net.SocketFactory; - - -/** - * The SocketClient provides the basic operations that are required of - * client objects accessing sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setSocketFactory setSocketFactory } - * method, which allows you to control the type of Socket the SocketClient - * creates for initiating network connections. This is especially useful - * for adding SSL or proxy support as well as better support for applets. For - * example, you could create a - * {@link javax.net.SocketFactory} that - * requests browser security capabilities before creating a socket. - * All classes derived from SocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create Socket and ServerSocket instances rather than instantiating - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - * @see SocketFactory - */ -public abstract class SocketClient -{ - /** - * The end of line character sequence used by most IETF protocols. That - * is a carriage return followed by a newline: "\r\n" - */ - public static final String NETASCII_EOL = "\r\n"; - - /** The default SocketFactory shared by all SocketClient instances. */ - private static final SocketFactory DEFAULT_SOCKET_FACTORY = - SocketFactory.getDefault(); - - /** The default {@link ServerSocketFactory} */ - private static final ServerSocketFactory DEFAULT_SERVER_SOCKET_FACTORY = - ServerSocketFactory.getDefault(); - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and the firing of ProtocolCommandEvents. - */ - private ProtocolCommandSupport commandSupport; - - /** The timeout to use after opening a socket. */ - protected int _timeout_; - - /** The socket used for the connection. */ - protected Socket _socket_; - - /** The hostname used for the connection (null = no hostname supplied). */ - protected String _hostname_; - - /** The default port the client should connect to. */ - protected int _defaultPort_; - - /** The socket's InputStream. */ - protected InputStream _input_; - - /** The socket's OutputStream. */ - protected OutputStream _output_; - - /** The socket's SocketFactory. */ - protected SocketFactory _socketFactory_; - - /** The socket's ServerSocket Factory. */ - protected ServerSocketFactory _serverSocketFactory_; - - /** The socket's connect timeout (0 = infinite timeout) */ - private static final int DEFAULT_CONNECT_TIMEOUT = 60000; - - protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; - - /** Hint for SO_RCVBUF size */ - private int receiveBufferSize = -1; - - /** Hint for SO_SNDBUF size */ - private int sendBufferSize = -1; - - /** The proxy to use when connecting. */ - private Proxy connProxy; - - /** - * Charset to use for byte IO. - */ - private Charset charset = Charset.defaultCharset(); - - /** - * Default constructor for SocketClient. Initializes - * _socket_ to null, _timeout_ to 0, _defaultPort to 0, - * _isConnected_ to false, charset to {@code Charset.defaultCharset()} - * and _socketFactory_ to a shared instance of - * {@link org.apache.commons.net.DefaultSocketFactory}. - */ - public SocketClient() - { - _socket_ = null; - _hostname_ = null; - _input_ = null; - _output_ = null; - _timeout_ = 0; - _defaultPort_ = 0; - _socketFactory_ = DEFAULT_SOCKET_FACTORY; - _serverSocketFactory_ = DEFAULT_SERVER_SOCKET_FACTORY; - } - - - /** - * Because there are so many connect() methods, the _connectAction_() - * method is provided as a means of performing some action immediately - * after establishing a connection, rather than reimplementing all - * of the connect() methods. The last action performed by every - * connect() method after opening a socket is to call this method. - *

- * This method sets the timeout on the just opened socket to the default - * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, - * sets _input_ and _output_ to the socket's InputStream and OutputStream - * respectively, and sets _isConnected_ to true. - *

- * Subclasses overriding this method should start by calling - * super._connectAction_() first to ensure the - * initialization of the aforementioned protected variables. - * @throws IOException (SocketException) if a problem occurs with the socket - */ - protected void _connectAction_() throws IOException - { - applySocketAttributes(); - _input_ = _socket_.getInputStream(); - _output_ = _socket_.getOutputStream(); - } - - /** - * Applies socket attributes. - * - * @throws SocketException if there is an error in the underlying protocol, such as a TCP error. - * @since 3.8.0 - */ - protected void applySocketAttributes() throws SocketException { - _socket_.setSoTimeout(_timeout_); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(final InetAddress host, final int port) - throws SocketException, IOException - { - _hostname_ = null; - _connect(host, port, null, -1); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(final String hostname, final int port) - throws SocketException, IOException - { - _hostname_ = hostname; - _connect(InetAddress.getByName(hostname), port, null, -1); - } - - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(final InetAddress host, final int port, - final InetAddress localAddr, final int localPort) - throws SocketException, IOException - { - _hostname_ = null; - _connect(host, port, localAddr, localPort); - } - - // helper method to allow code to be shared with connect(String,...) methods - private void _connect(final InetAddress host, final int port, final InetAddress localAddr, final int localPort) - throws SocketException, IOException - { - _socket_ = _socketFactory_.createSocket(); - if (receiveBufferSize != -1) { - _socket_.setReceiveBufferSize(receiveBufferSize); - } - if (sendBufferSize != -1) { - _socket_.setSendBufferSize(sendBufferSize); - } - if (localAddr != null) { - _socket_.bind(new InetSocketAddress(localAddr, localPort)); - } - _socket_.connect(new InetSocketAddress(host, port), connectTimeout); - _connectAction_(); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(final String hostname, final int port, - final InetAddress localAddr, final int localPort) - throws SocketException, IOException - { - _hostname_ = hostname; - _connect(InetAddress.getByName(hostname), port, localAddr, localPort); - } - - - /** - * Opens a Socket connected to a remote host at the current default port - * and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param host The remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(final InetAddress host) throws SocketException, IOException - { - _hostname_ = null; - connect(host, _defaultPort_); - } - - - /** - * Opens a Socket connected to a remote host at the current default - * port and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * @param hostname The name of the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(final String hostname) throws SocketException, IOException - { - connect(hostname, _defaultPort_); - } - - - /** - * Disconnects the socket connection. - * You should call this method after you've finished using the class - * instance and also before you call - * {@link #connect connect() } - * again. _isConnected_ is set to false, _socket_ is set to null, - * _input_ is set to null, and _output_ is set to null. - *

- * @throws IOException If there is an error closing the socket. - */ - public void disconnect() throws IOException - { - closeQuietly(_socket_); - closeQuietly(_input_); - closeQuietly(_output_); - _socket_ = null; - _hostname_ = null; - _input_ = null; - _output_ = null; - } - - private void closeQuietly(final Socket socket) { - if (socket != null){ - try { - socket.close(); - } catch (final IOException e) { - // Ignored - } - } - } - - private void closeQuietly(final Closeable close){ - if (close != null){ - try { - close.close(); - } catch (final IOException e) { - // Ignored - } - } - } - /** - * Returns true if the client is currently connected to a server. - *

- * Delegates to {@link Socket#isConnected()} - * @return True if the client is currently connected to a server, - * false otherwise. - */ - public boolean isConnected() - { - if (_socket_ == null) { - return false; - } - - return _socket_.isConnected(); - } - - /** - * Make various checks on the socket to test if it is available for use. - * Note that the only sure test is to use it, but these checks may help - * in some cases. - * @see NET-350 - * @return {@code true} if the socket appears to be available for use - * @since 3.0 - */ - @SuppressWarnings("resource") - public boolean isAvailable(){ - if (isConnected()) { - try - { - if (_socket_.getInetAddress() == null) { - return false; - } - if (_socket_.getPort() == 0) { - return false; - } - if (_socket_.getRemoteSocketAddress() == null) { - return false; - } - if (_socket_.isClosed()) { - return false; - } - /* these aren't exact checks (a Socket can be half-open), - but since we usually require two-way data transfer, - we check these here too: */ - if (_socket_.isInputShutdown()) { - return false; - } - if (_socket_.isOutputShutdown()) { - return false; - } - /* ignore the result, catch exceptions: */ - // No need to close - _socket_.getInputStream(); - // No need to close - _socket_.getOutputStream(); - } - catch (final IOException ioex) - { - return false; - } - return true; - } - return false; - } - - /** - * Sets the default port the SocketClient should connect to when a port - * is not specified. The {@link #_defaultPort_ _defaultPort_ } - * variable stores this value. If never set, the default port is equal - * to zero. - *

- * @param port The default port to set. - */ - public void setDefaultPort(final int port) - { - _defaultPort_ = port; - } - - /** - * Returns the current value of the default port (stored in - * {@link #_defaultPort_ _defaultPort_ }). - *

- * @return The current value of the default port. - */ - public int getDefaultPort() - { - return _defaultPort_; - } - - - /** - * Set the default timeout in milliseconds to use when opening a socket. - * This value is only used previous to a call to - * {@link #connect connect()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on an the currently opened socket. _timeout_ contains - * the new timeout value. - *

- * @param timeout The timeout in milliseconds to use for the socket - * connection. - */ - public void setDefaultTimeout(final int timeout) - { - _timeout_ = timeout; - } - - - /** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - *

- * @return The default timeout in milliseconds that is used when - * opening a socket. - */ - public int getDefaultTimeout() - { - return _timeout_; - } - - - /** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #connect connect()}. - *

- * To set the initial timeout, use {@link #setDefaultTimeout(int)} instead. - * - * @param timeout The timeout in milliseconds to use for the currently - * open socket connection. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setSoTimeout(final int timeout) throws SocketException - { - _socket_.setSoTimeout(timeout); - } - - - /** - * Set the underlying socket send buffer size. - *

- * @param size The size of the buffer in bytes. - * @throws SocketException never thrown, but subclasses might want to do so - * @since 2.0 - */ - public void setSendBufferSize(final int size) throws SocketException { - sendBufferSize = size; - } - - /** - * Get the current sendBuffer size - * @return the size, or -1 if not initialized - * @since 3.0 - */ - protected int getSendBufferSize(){ - return sendBufferSize; - } - - /** - * Sets the underlying socket receive buffer size. - *

- * @param size The size of the buffer in bytes. - * @throws SocketException never (but subclasses may wish to do so) - * @since 2.0 - */ - public void setReceiveBufferSize(final int size) throws SocketException { - receiveBufferSize = size; - } - - /** - * Get the current receivedBuffer size - * @return the size, or -1 if not initialized - * @since 3.0 - */ - protected int getReceiveBufferSize(){ - return receiveBufferSize; - } - - /** - * Returns the timeout in milliseconds of the currently opened socket. - *

- * @return The timeout in milliseconds of the currently opened socket. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public int getSoTimeout() throws SocketException - { - return _socket_.getSoTimeout(); - } - - /** - * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the - * currently opened socket. - *

- * @param on True if Nagle's algorithm is to be enabled, false if not. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setTcpNoDelay(final boolean on) throws SocketException - { - _socket_.setTcpNoDelay(on); - } - - - /** - * Returns true if Nagle's algorithm is enabled on the currently opened - * socket. - *

- * @return True if Nagle's algorithm is enabled on the currently opened - * socket, false otherwise. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public boolean getTcpNoDelay() throws SocketException - { - return _socket_.getTcpNoDelay(); - } - - /** - * Sets the SO_KEEPALIVE flag on the currently opened socket. - * - * From the Javadocs, the default keepalive time is 2 hours (although this is - * implementation dependent). It looks as though the Windows WSA sockets implementation - * allows a specific keepalive value to be set, although this seems not to be the case on - * other systems. - * @param keepAlive If true, keepAlive is turned on - * @throws SocketException if there is a problem with the socket - * @throws NullPointerException if the socket is not currently open - * @since 2.2 - */ - public void setKeepAlive(final boolean keepAlive) throws SocketException { - _socket_.setKeepAlive(keepAlive); - } - - /** - * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. - * Delegates to {@link Socket#getKeepAlive()} - * @return True if SO_KEEPALIVE is enabled. - * @throws SocketException if there is a problem with the socket - * @throws NullPointerException if the socket is not currently open - * @since 2.2 - */ - public boolean getKeepAlive() throws SocketException { - return _socket_.getKeepAlive(); - } - - /** - * Sets the SO_LINGER timeout on the currently opened socket. - *

- * @param on True if linger is to be enabled, false if not. - * @param val The linger timeout (in hundredths of a second?) - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setSoLinger(final boolean on, final int val) throws SocketException - { - _socket_.setSoLinger(on, val); - } - - - /** - * Returns the current SO_LINGER timeout of the currently opened socket. - *

- * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns - * -1. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public int getSoLinger() throws SocketException - { - return _socket_.getSoLinger(); - } - - - /** - * Returns the port number of the open socket on the local host used - * for the connection. - * Delegates to {@link Socket#getLocalPort()} - *

- * @return The port number of the open socket on the local host used - * for the connection. - * @throws NullPointerException if the socket is not currently open - */ - public int getLocalPort() - { - return _socket_.getLocalPort(); - } - - - /** - * Returns the local address to which the client's socket is bound. - * Delegates to {@link Socket#getLocalAddress()} - *

- * @return The local address to which the client's socket is bound. - * @throws NullPointerException if the socket is not currently open - */ - public InetAddress getLocalAddress() - { - return _socket_.getLocalAddress(); - } - - /** - * Returns the port number of the remote host to which the client is - * connected. - * Delegates to {@link Socket#getPort()} - *

- * @return The port number of the remote host to which the client is - * connected. - * @throws NullPointerException if the socket is not currently open - */ - public int getRemotePort() - { - return _socket_.getPort(); - } - - - /** - * @return The remote address to which the client is connected. - * Delegates to {@link Socket#getInetAddress()} - * @throws NullPointerException if the socket is not currently open - */ - public InetAddress getRemoteAddress() - { - return _socket_.getInetAddress(); - } - - - /** - * Verifies that the remote end of the given socket is connected to the - * the same host that the SocketClient is currently connected to. This - * is useful for doing a quick security check when a client needs to - * accept a connection from a server, such as an FTP data connection or - * a BSD R command standard error stream. - *

- * @param socket the item to check against - * @return True if the remote hosts are the same, false if not. - */ - public boolean verifyRemote(final Socket socket) - { - final InetAddress host1; - final InetAddress host2; - - host1 = socket.getInetAddress(); - host2 = getRemoteAddress(); - - return host1.equals(host2); - } - - - /** - * Sets the SocketFactory used by the SocketClient to open socket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - * Any proxy setting is discarded. - *

- * @param factory The new SocketFactory the SocketClient should use. - */ - public void setSocketFactory(final SocketFactory factory) - { - if (factory == null) { - _socketFactory_ = DEFAULT_SOCKET_FACTORY; - } else { - _socketFactory_ = factory; - } - // re-setting the socket factory makes the proxy setting useless, - // so set the field to null so that getProxy() doesn't return a - // Proxy that we're actually not using. - connProxy = null; - } - - /** - * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - *

- * @param factory The new ServerSocketFactory the SocketClient should use. - * @since 2.0 - */ - public void setServerSocketFactory(final ServerSocketFactory factory) { - if (factory == null) { - _serverSocketFactory_ = DEFAULT_SERVER_SOCKET_FACTORY; - } else { - _serverSocketFactory_ = factory; - } - } - - /** - * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's - * connect() method. - * @param connectTimeout The connection timeout to use (in ms) - * @since 2.0 - */ - public void setConnectTimeout(final int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - /** - * Get the underlying socket connection timeout. - * @return timeout (in ms) - * @since 2.0 - */ - public int getConnectTimeout() { - return connectTimeout; - } - - /** - * Get the underlying {@link ServerSocketFactory} - * @return The server socket factory - * @since 2.2 - */ - public ServerSocketFactory getServerSocketFactory() { - return _serverSocketFactory_; - } - - - /** - * Adds a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to add. - * @since 3.0 - */ - public void addProtocolCommandListener(final ProtocolCommandListener listener) { - getCommandSupport().addProtocolCommandListener(listener); - } - - /** - * Removes a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to remove. - * @since 3.0 - */ - public void removeProtocolCommandListener(final ProtocolCommandListener listener) { - getCommandSupport().removeProtocolCommandListener(listener); - } - - /** - * If there are any listeners, send them the reply details. - * - * @param replyCode the code extracted from the reply - * @param reply the full reply text - * @since 3.0 - */ - protected void fireReplyReceived(final int replyCode, final String reply) { - if (getCommandSupport().getListenerCount() > 0) { - getCommandSupport().fireReplyReceived(replyCode, reply); - } - } - - /** - * If there are any listeners, send them the command details. - * - * @param command the command name - * @param message the complete message, including command name - * @since 3.0 - */ - protected void fireCommandSent(final String command, final String message) { - if (getCommandSupport().getListenerCount() > 0) { - getCommandSupport().fireCommandSent(command, message); - } - } - - /** - * Create the CommandSupport instance if required - */ - protected void createCommandSupport(){ - commandSupport = new ProtocolCommandSupport(this); - } - - /** - * Subclasses can override this if they need to provide their own - * instance field for backwards compatibilty. - * - * @return the CommandSupport instance, may be {@code null} - * @since 3.0 - */ - protected ProtocolCommandSupport getCommandSupport() { - return commandSupport; - } - - /** - * Sets the proxy for use with all the connections. - * The proxy is used for connections established after the - * call to this method. - * - * @param proxy the new proxy for connections. - * @since 3.2 - */ - public void setProxy(final Proxy proxy) { - setSocketFactory(new DefaultSocketFactory(proxy)); - connProxy = proxy; - } - - /** - * Gets the proxy for use with all the connections. - * @return the current proxy for connections. - */ - public Proxy getProxy() { - return connProxy; - } - - /** - * Gets the charset name. - * - * @return the charset. - * @since 3.3 - * @deprecated Since the code now requires Java 1.6 as a mininmum - */ - @Deprecated - public String getCharsetName() { - return charset.name(); - } - - /** - * Gets the charset. - * - * @return the charset. - * @since 3.3 - */ - public Charset getCharset() { - return charset; - } - - /** - * Sets the charset. - * - * @param charset the charset. - * @since 3.3 - */ - public void setCharset(final Charset charset) { - this.charset = charset; - } - - /* - * N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility, - * so the abstract method is needed to pass the instance to the methods which were moved here. - */ -} - - diff --git a/src/org/apache/commons/net/ftp/Configurable.java b/src/org/apache/commons/net/ftp/Configurable.java deleted file mode 100644 index 71277ddc..00000000 --- a/src/org/apache/commons/net/ftp/Configurable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - - -/** - * This interface adds the aspect of configurability by means of - * a supplied FTPClientConfig object to other classes in the - * system, especially listing parsers. - */ -public interface Configurable { - - /** - * @param config the object containing the configuration data - * @throws IllegalArgumentException if the elements of the - * config are somehow inadequate to configure the - * Configurable object. - */ - void configure(FTPClientConfig config); -} diff --git a/src/org/apache/commons/net/ftp/FTP.java b/src/org/apache/commons/net/ftp/FTP.java deleted file mode 100644 index 8f268931..00000000 --- a/src/org/apache/commons/net/ftp/FTP.java +++ /dev/null @@ -1,1923 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.ArrayList; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.NetConstants; - -/** - * FTP provides the basic the functionality necessary to implement your - * own FTP client. It extends org.apache.commons.net.SocketClient since - * extending TelnetClient was causing unwanted behavior (like connections - * that did not time out properly). - *

- * To derive the full benefits of the FTP class requires some knowledge - * of the FTP protocol defined in RFC 959. However, there is no reason - * why you should have to use the FTP class. The - * {@link org.apache.commons.net.ftp.FTPClient} class, - * derived from FTP, - * implements all the functionality required of an FTP client. The - * FTP class is made public to provide access to various FTP constants - * and to make it easier for adventurous programmers (or those with - * special needs) to interact with the FTP protocol and implement their - * own clients. A set of methods with names corresponding to the FTP - * command names are provided to facilitate this interaction. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTP class will detect a - * premature FTP server connection closing when it receives a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * . FTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTP. Before disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode }, - * {@link #getReplyString getReplyString }, - * and {@link #getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodicaly sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * @see FTPClient - * @see FTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - */ - -public class FTP extends SocketClient -{ - /** The default FTP data port (20). */ - public static final int DEFAULT_DATA_PORT = 20; - /** The default FTP control port (21). */ - public static final int DEFAULT_PORT = 21; - - /** - * A constant used to indicate the file(s) being transferred should - * be treated as ASCII. This is the default file type. All constants - * ending in FILE_TYPE are used to indicate file types. - */ - public static final int ASCII_FILE_TYPE = 0; - - /** - * A constant used to indicate the file(s) being transferred should - * be treated as EBCDIC. Note however that there are several different - * EBCDIC formats. All constants ending in FILE_TYPE - * are used to indicate file types. - */ - public static final int EBCDIC_FILE_TYPE = 1; - - - /** - * A constant used to indicate the file(s) being transferred should - * be treated as a binary image, i.e., no translations should be - * performed. All constants ending in FILE_TYPE are used to - * indicate file types. - */ - public static final int BINARY_FILE_TYPE = 2; - - /** - * A constant used to indicate the file(s) being transferred should - * be treated as a local type. All constants ending in - * FILE_TYPE are used to indicate file types. - */ - public static final int LOCAL_FILE_TYPE = 3; - - /** - * A constant used for text files to indicate a non-print text format. - * This is the default format. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - */ - public static final int NON_PRINT_TEXT_FORMAT = 4; - - /** - * A constant used to indicate a text file contains format vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - */ - public static final int TELNET_TEXT_FORMAT = 5; - - /** - * A constant used to indicate a text file contains ASA vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - */ - public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6; - - /** - * A constant used to indicate a file is to be treated as a continuous - * sequence of bytes. This is the default structure. All constants ending - * in _STRUCTURE are used to indicate file structure for - * file transfers. - */ - public static final int FILE_STRUCTURE = 7; - - /** - * A constant used to indicate a file is to be treated as a sequence - * of records. All constants ending in _STRUCTURE - * are used to indicate file structure for file transfers. - */ - public static final int RECORD_STRUCTURE = 8; - - /** - * A constant used to indicate a file is to be treated as a set of - * independent indexed pages. All constants ending in - * _STRUCTURE are used to indicate file structure for file - * transfers. - */ - public static final int PAGE_STRUCTURE = 9; - - /** - * A constant used to indicate a file is to be transferred as a stream - * of bytes. This is the default transfer mode. All constants ending - * in TRANSFER_MODE are used to indicate file transfer - * modes. - */ - public static final int STREAM_TRANSFER_MODE = 10; - - /** - * A constant used to indicate a file is to be transferred as a series - * of blocks. All constants ending in TRANSFER_MODE are used - * to indicate file transfer modes. - */ - public static final int BLOCK_TRANSFER_MODE = 11; - - /** - * A constant used to indicate a file is to be transferred as FTP - * compressed data. All constants ending in TRANSFER_MODE - * are used to indicate file transfer modes. - */ - public static final int COMPRESSED_TRANSFER_MODE = 12; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - /** - * The default character encoding used for communicating over an - * FTP control connection. The default encoding is an - * ASCII-compatible encoding. Some FTP servers expect other - * encodings. You can change the encoding used by an FTP instance - * with {@link #setControlEncoding setControlEncoding}. - */ - public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; - - /** Length of the FTP reply code (3 alphanumerics) */ - public static final int REPLY_CODE_LEN = 3; - - private static final String modes = "AEILNTCFRPSBC"; - protected int _replyCode; - protected ArrayList _replyLines; - protected boolean _newReplyString; - protected String _replyString; - protected String _controlEncoding; - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and the firing of ProtocolCommandEvents. - */ - protected ProtocolCommandSupport _commandSupport_; - - /** - * This is used to signal whether a block of multiline responses beginning - * with xxx must be terminated by the same numeric code xxx - * See section 4.2 of RFC 959 for details. - */ - protected boolean strictMultilineParsing; - - /** - * If this is true, then non-multiline replies must have the format: - * 3 digit code - * If false, then the 3 digit code does not have to be followed by space - * See section 4.2 of RFC 959 for details. - */ - private boolean strictReplyParsing = true; - - /** - * Wraps SocketClient._input_ to facilitate the reading of text - * from the FTP control connection. Do not access the control - * connection via SocketClient._input_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedReader _controlInput_; - - /** - * Wraps SocketClient._output_ to facilitate the writing of text - * to the FTP control connection. Do not access the control - * connection via SocketClient._output_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedWriter _controlOutput_; - - /** - * The default FTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving FTP reply information. - */ - public FTP() - { - setDefaultPort(DEFAULT_PORT); - _replyLines = new ArrayList<>(); - _newReplyString = false; - _replyString = null; - _controlEncoding = DEFAULT_CONTROL_ENCODING; - _commandSupport_ = new ProtocolCommandSupport(this); - } - - // The RFC-compliant multiline termination check - private boolean strictCheck(final String line, final String code) { - return !(line.startsWith(code) && line.charAt(REPLY_CODE_LEN) == ' '); - } - - // The strict check is too strong a condition because of non-conforming ftp - // servers like ftp.funet.fi which sent 226 as the last line of a - // 426 multi-line reply in response to ls /. We relax the condition to - // test that the line starts with a digit rather than starting with - // the code. - private boolean lenientCheck(final String line) { - return !(line.length() > REPLY_CODE_LEN&& line.charAt(REPLY_CODE_LEN) != '-' && - Character.isDigit(line.charAt(0))); - } - - /** - * Get the reply, but don't pass it to command listeners. - * Used for keep-alive processing only. - * @since 3.0 - * @throws IOException on error - */ - protected void __getReplyNoReport() throws IOException - { - getReply(false); - } - - private int getReply(final boolean reportReply) throws IOException - { - final int length; - - _newReplyString = true; - _replyLines.clear(); - - String line = _controlInput_.readLine(); - - if (line == null) { - throw new FTPConnectionClosedException( - "Connection closed without indication."); - } - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - length = line.length(); - if (length < REPLY_CODE_LEN) { - throw new MalformedServerReplyException( - "Truncated server reply: " + line); - } - - String code = null; - try - { - code = line.substring(0, REPLY_CODE_LEN); - _replyCode = Integer.parseInt(code); - } - catch (final NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + line); - } - - _replyLines.add(line); - - // Check the server reply type - if (length > REPLY_CODE_LEN) { - final char sep = line.charAt(REPLY_CODE_LEN); - // Get extra lines if message continues. - if (sep == '-') { - do - { - line = _controlInput_.readLine(); - - if (line == null) { - throw new FTPConnectionClosedException( - "Connection closed without indication."); - } - - _replyLines.add(line); - - // The length() check handles problems that could arise from readLine() - // returning too soon after encountering a naked CR or some other - // anomaly. - } - while ( isStrictMultilineParsing() ? strictCheck(line, code) : lenientCheck(line)); - - } else if (isStrictReplyParsing()) { - if (length == REPLY_CODE_LEN + 1) { // expecting some text - throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); - } else if (sep != ' ') { - throw new MalformedServerReplyException("Invalid server reply: '" + line +"'"); - } - } - } else if (isStrictReplyParsing()) { - throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); - } - - if (reportReply) { - fireReplyReceived(_replyCode, getReplyString()); - } - - if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { - throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); - } - return _replyCode; - } - - /** - * Initiates control connections and gets initial reply. - * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. - */ - @Override - protected void _connectAction_() throws IOException - { - _connectAction_(null); - } - - - /** - * Initiates control connections and gets initial reply. - * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. - * - * @param socketIsReader the reader to reuse (if non-null) - * @throws IOException on error - * @since 3.4 - */ - protected void _connectAction_(final Reader socketIsReader) throws IOException { - super._connectAction_(); // sets up _input_ and _output_ - if(socketIsReader == null) { - _controlInput_ = - new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding())); - } else { - _controlInput_ = new CRLFLineReader(socketIsReader); - } - _controlOutput_ = - new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding())); - if (connectTimeout > 0) { // NET-385 - final int original = _socket_.getSoTimeout(); - _socket_.setSoTimeout(connectTimeout); - try { - getReply(); - // If we received code 120, we have to fetch completion reply. - if (FTPReply.isPositivePreliminary(_replyCode)) { - getReply(); - } - } catch (final SocketTimeoutException e) { - final IOException ioe = new IOException("Timed out waiting for initial connect reply"); - ioe.initCause(e); - throw ioe; - } finally { - _socket_.setSoTimeout(original); - } - } else { - getReply(); - // If we received code 120, we have to fetch completion reply. - if (FTPReply.isPositivePreliminary(_replyCode)) { - getReply(); - } - } - } - - - /** - * Saves the character encoding to be used by the FTP control connection. - * Some FTP servers require that commands be issued in a non-ASCII - * encoding like UTF-8 so that file names with multi-byte character - * representations (e.g, Big 8) can be specified. - *

- * Please note that this has to be set before the connection is established. - * - * @param encoding The new character encoding for the control connection. - */ - public void setControlEncoding(final String encoding) { - _controlEncoding = encoding; - } - - - /** - * @return The character encoding used to communicate over the - * control connection. - */ - public String getControlEncoding() { - return _controlEncoding; - } - - - /** - * Closes the control connection to the FTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - * Also sets {@link #_controlInput_} and {@link #_controlOutput_} to null. - * - * @throws IOException If an error occurs while disconnecting. - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _controlInput_ = null; - _controlOutput_ = null; - _newReplyString = false; - _replyString = null; - } - - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The text representation of the FTP command to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final String command, final String args) throws IOException - { - if (_controlOutput_ == null) { - throw new IOException("Connection is not open"); - } - - final String message = buildMessage(command, args); - - send(message); - - fireCommandSent(command, message); - - return getReply(); - } - - private String buildMessage(final String command, final String args) { - final StringBuilder __commandBuffer = new StringBuilder(); - - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - return __commandBuffer.toString(); - } - - private void send(final String message) throws IOException, - FTPConnectionClosedException, SocketException { - try{ - _controlOutput_.write(message); - _controlOutput_.flush(); - } - catch (final SocketException e) - { - if (!isConnected()) - { - throw new FTPConnectionClosedException("Connection unexpectedly closed."); - } - throw e; - } - } - - /** - * Send a noop and get the reply without reporting to the command listener. - * Intended for use with keep-alive. - * - * @throws IOException on error - * @since 3.0 - */ - protected void __noop() throws IOException { - final String msg = buildMessage(FTPCmd.NOOP.getCommand(), null); - send(msg); - __getReplyNoReport(); // This may timeout - } - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead - */ - @Deprecated - public int sendCommand(final int command, final String args) throws IOException - { - return sendCommand(FTPCommand.getCommand(command), args); - } - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCmd enum corresponding to the FTP command - * to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.3 - */ - public int sendCommand(final FTPCmd command) throws IOException{ - return sendCommand(command, null); - } - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCmd enum corresponding to the FTP command - * to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.3 - */ - public int sendCommand(final FTPCmd command, final String args) throws IOException{ - return sendCommand(command.getCommand(), args); - } - - /** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The text representation of the FTP command to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final String command) throws IOException - { - return sendCommand(command, null); - } - - - /** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final int command) throws IOException - { - return sendCommand(command, null); - } - - - /** - * Returns the integer value of the reply code of the last FTP reply. - * You will usually only use this method after you connect to the - * FTP server to check that the connection was successful since - * connect is of type void. - * - * @return The integer value of the reply code of the last FTP reply. - */ - public int getReplyCode() - { - return _replyCode; - } - - /** - * Fetches a reply from the FTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from either calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. Only use this - * method if you are implementing your own FTP client or if you need to - * fetch a secondary response from the FTP server. - * - * @return The integer value of the reply code of the fetched FTP reply. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while receiving the - * server reply. - */ - public int getReply() throws IOException - { - return getReply(true); - } - - - /** - * Returns the lines of text from the last FTP server response as an array - * of strings, one entry per line. The end of line markers of each are - * stripped from each line. - * - * @return The lines of text from the last FTP response as an array. - */ - public String[] getReplyStrings() - { - return _replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - - /** - * Returns the nth line of text from the last FTP server response as a string. The end of line markers of each are - * stripped from the line. - * - * @param index The index of the line to return, 0-based. - * - * @return The lines of text from the last FTP response as an array. - */ - String getReplyString(final int index) - { - return _replyLines.get(index); - } - - /** - * Returns the entire text of the last FTP server response exactly - * as it was received, including all end of line markers in NETASCII - * format. - * - * @return The entire text from the last FTP response as a String. - */ - public String getReplyString() - { - final StringBuilder buffer; - - if (!_newReplyString) { - return _replyString; - } - - buffer = new StringBuilder(256); - - for (final String line : _replyLines) { - buffer.append(line); - buffer.append(SocketClient.NETASCII_EOL); - } - - _newReplyString = false; - - return _replyString = buffer.toString(); - } - - - /** - * A convenience method to send the FTP USER command to the server, - * receive the reply, and return the reply code. - * - * @param username The username to login under. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int user(final String username) throws IOException - { - return sendCommand(FTPCmd.USER, username); - } - - /** - * A convenience method to send the FTP PASS command to the server, - * receive the reply, and return the reply code. - * @param password The plain text password of the username being logged into. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int pass(final String password) throws IOException - { - return sendCommand(FTPCmd.PASS, password); - } - - /** - * A convenience method to send the FTP ACCT command to the server, - * receive the reply, and return the reply code. - * - * @param account The account name to access. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int acct(final String account) throws IOException - { - return sendCommand(FTPCmd.ACCT, account); - } - - - /** - * A convenience method to send the FTP ABOR command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int abor() throws IOException - { - return sendCommand(FTPCmd.ABOR); - } - - /** - * A convenience method to send the FTP CWD command to the server, - * receive the reply, and return the reply code. - * - * @param directory The new working directory. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int cwd(final String directory) throws IOException - { - return sendCommand(FTPCmd.CWD, directory); - } - - /** - * A convenience method to send the FTP CDUP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int cdup() throws IOException - { - return sendCommand(FTPCmd.CDUP); - } - - /** - * A convenience method to send the FTP QUIT command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int quit() throws IOException - { - return sendCommand(FTPCmd.QUIT); - } - - /** - * A convenience method to send the FTP REIN command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rein() throws IOException - { - return sendCommand(FTPCmd.REIN); - } - - /** - * A convenience method to send the FTP SMNT command to the server, - * receive the reply, and return the reply code. - * - * @param dir The directory name. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int smnt(final String dir) throws IOException - { - return sendCommand(FTPCmd.SMNT, dir); - } - - /** - * A convenience method to send the FTP PORT command to the server, - * receive the reply, and return the reply code. - * - * @param host The host owning the port. - * @param port The new port. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int port(final InetAddress host, final int port) throws IOException - { - int num; - final StringBuilder info = new StringBuilder(24); - - info.append(host.getHostAddress().replace('.', ',')); - num = port >>> 8; - info.append(','); - info.append(num); - info.append(','); - num = port & 0xff; - info.append(num); - - return sendCommand(FTPCmd.PORT, info.toString()); - } - - /** - * A convenience method to send the FTP EPRT command to the server, - * receive the reply, and return the reply code. - * - * Examples: - *

    - *
  • EPRT |1|132.235.1.2|6275|
  • - *
  • EPRT |2|1080::8:800:200C:417A|5282|
  • - *
- * - * @see "http://www.faqs.org/rfcs/rfc2428.html" - * - * @param host The host owning the port. - * @param port The new port. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - */ - public int eprt(final InetAddress host, final int port) throws IOException - { - final int num; - final StringBuilder info = new StringBuilder(); - String h; - - // If IPv6, trim the zone index - h = host.getHostAddress(); - num = h.indexOf('%'); - if (num > 0) { - h = h.substring(0, num); - } - - info.append("|"); - - if (host instanceof Inet4Address) { - info.append("1"); - } else if (host instanceof Inet6Address) { - info.append("2"); - } - info.append("|"); - info.append(h); - info.append("|"); - info.append(port); - info.append("|"); - - return sendCommand(FTPCmd.EPRT, info.toString()); - } - - /** - * A convenience method to send the FTP PASV command to the server, - * receive the reply, and return the reply code. Remember, it's up - * to you to interpret the reply string containing the host/port - * information. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int pasv() throws IOException - { - return sendCommand(FTPCmd.PASV); - } - - /** - * A convenience method to send the FTP EPSV command to the server, - * receive the reply, and return the reply code. Remember, it's up - * to you to interpret the reply string containing the host/port - * information. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - */ - public int epsv() throws IOException - { - return sendCommand(FTPCmd.EPSV); - } - - /** - * A convenience method to send the FTP TYPE command for text files - * to the server, receive the reply, and return the reply code. - * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(final int fileType, final int formatOrByteSize) throws IOException - { - final StringBuilder arg = new StringBuilder(); - - arg.append(modes.charAt(fileType)); - arg.append(' '); - if (fileType == LOCAL_FILE_TYPE) { - arg.append(formatOrByteSize); - } else { - arg.append(modes.charAt(formatOrByteSize)); - } - - return sendCommand(FTPCmd.TYPE, arg.toString()); - } - - - /** - * A convenience method to send the FTP TYPE command to the server, - * receive the reply, and return the reply code. - * - * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(final int fileType) throws IOException - { - return sendCommand(FTPCmd.TYPE, - modes.substring(fileType, fileType + 1)); - } - - /** - * A convenience method to send the FTP STRU command to the server, - * receive the reply, and return the reply code. - * - * @param structure The structure of the file (one of the - * _STRUCTURE constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stru(final int structure) throws IOException - { - return sendCommand(FTPCmd.STRU, - modes.substring(structure, structure + 1)); - } - - /** - * A convenience method to send the FTP MODE command to the server, - * receive the reply, and return the reply code. - * - * @param mode The transfer mode to use (one of the - * TRANSFER_MODE constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int mode(final int mode) throws IOException - { - return sendCommand(FTPCmd.MODE, - modes.substring(mode, mode + 1)); - } - - /** - * A convenience method to send the FTP RETR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname of the file to retrieve. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int retr(final String pathname) throws IOException - { - return sendCommand(FTPCmd.RETR, pathname); - } - - /** - * A convenience method to send the FTP STOR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stor(final String pathname) throws IOException - { - return sendCommand(FTPCmd.STOR, pathname); - } - - /** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stou() throws IOException - { - return sendCommand(FTPCmd.STOU); - } - - /** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * @param pathname The base pathname to use for the file when stored at - * the remote end of the transfer. Some FTP servers - * require this. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stou(final String pathname) throws IOException - { - return sendCommand(FTPCmd.STOU, pathname); - } - - /** - * A convenience method to send the FTP APPE command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int appe(final String pathname) throws IOException - { - return sendCommand(FTPCmd.APPE, pathname); - } - - /** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int allo(final int bytes) throws IOException - { - return sendCommand(FTPCmd.ALLO, Integer.toString(bytes)); - } - - /** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int allo(final long bytes) throws IOException - { - return sendCommand(FTPCmd.ALLO, Long.toString(bytes)); - } - - /** - * A convenience method to send the FTP FEAT command to the server, receive the reply, - * and return the reply code. - * @return The reply code received by the server - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - */ - public int feat() throws IOException - { - return sendCommand(FTPCmd.FEAT); - } - - /** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @param recordSize The size of a record. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int allo(final int bytes, final int recordSize) throws IOException - { - return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + - Integer.toString(recordSize)); - } - - /** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @param recordSize The size of a record. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int allo(final long bytes, final int recordSize) throws IOException - { - return sendCommand(FTPCmd.ALLO, Long.toString(bytes) + " R " + - Integer.toString(recordSize)); - } - - /** - * A convenience method to send the FTP REST command to the server, - * receive the reply, and return the reply code. - * - * @param marker The marker at which to restart a transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rest(final String marker) throws IOException - { - return sendCommand(FTPCmd.REST, marker); - } - - - /** - * Sends the MDTM command for the given file. - * - * @param file name of file - * @return the status - * @throws IOException on error - * @since 2.0 - **/ - public int mdtm(final String file) throws IOException - { - return sendCommand(FTPCmd.MDTM, file); - } - - - /** - * A convenience method to send the FTP MFMT command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname for which mtime is to be changed - * @param timeval Timestamp in YYYYMMDDhhmmss format - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - * @see http://tools.ietf.org/html/draft-somers-ftp-mfxx-04 - **/ - public int mfmt(final String pathname, final String timeval) throws IOException - { - return sendCommand(FTPCmd.MFMT, timeval + " " + pathname); - } - - - /** - * A convenience method to send the FTP RNFR command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to rename from. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rnfr(final String pathname) throws IOException - { - return sendCommand(FTPCmd.RNFR, pathname); - } - - /** - * A convenience method to send the FTP RNTO command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to rename to - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rnto(final String pathname) throws IOException - { - return sendCommand(FTPCmd.RNTO, pathname); - } - - /** - * A convenience method to send the FTP DELE command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to delete. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int dele(final String pathname) throws IOException - { - return sendCommand(FTPCmd.DELE, pathname); - } - - /** - * A convenience method to send the FTP RMD command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname of the directory to remove. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rmd(final String pathname) throws IOException - { - return sendCommand(FTPCmd.RMD, pathname); - } - - /** - * A convenience method to send the FTP MKD command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname of the new directory to create. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int mkd(final String pathname) throws IOException - { - return sendCommand(FTPCmd.MKD, pathname); - } - - /** - * A convenience method to send the FTP PWD command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int pwd() throws IOException - { - return sendCommand(FTPCmd.PWD); - } - - /** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int list() throws IOException - { - return sendCommand(FTPCmd.LIST); - } - - /** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to list, - * may be {@code null} in which case the command is sent with no parameters - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int list(final String pathname) throws IOException - { - return sendCommand(FTPCmd.LIST, pathname); - } - - /** - * A convenience method to send the FTP MLSD command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlsd() throws IOException - { - return sendCommand(FTPCmd.MLSD); - } - - /** - * A convenience method to send the FTP MLSD command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param path the path to report on - * @return The reply code received from the server, - * may be {@code null} in which case the command is sent with no parameters - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlsd(final String path) throws IOException - { - return sendCommand(FTPCmd.MLSD, path); - } - - /** - * A convenience method to send the FTP MLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlst() throws IOException - { - return sendCommand(FTPCmd.MLST); - } - - /** - * A convenience method to send the FTP MLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param path the path to report on - * @return The reply code received from the server, - * may be {@code null} in which case the command is sent with no parameters - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlst(final String path) throws IOException - { - return sendCommand(FTPCmd.MLST, path); - } - - /** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int nlst() throws IOException - { - return sendCommand(FTPCmd.NLST); - } - - /** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link org.apache.commons.net.ftp.FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to list, - * may be {@code null} in which case the command is sent with no parameters - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int nlst(final String pathname) throws IOException - { - return sendCommand(FTPCmd.NLST, pathname); - } - - /** - * A convenience method to send the FTP SITE command to the server, - * receive the reply, and return the reply code. - * - * @param parameters The site parameters to send. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int site(final String parameters) throws IOException - { - return sendCommand(FTPCmd.SITE, parameters); - } - - /** - * A convenience method to send the FTP SIZE command to the server, - * receive the reply, and return the reply code. - * - * @param parameters The site parameters to send. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.7 - */ - public int size(final String parameters) throws IOException - { - return sendCommand(FTPCmd.SIZE, parameters); - } - - /** - * A convenience method to send the FTP SYST command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int syst() throws IOException - { - return sendCommand(FTPCmd.SYST); - } - - /** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stat() throws IOException - { - return sendCommand(FTPCmd.STAT); - } - - /** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - * - * @param pathname A pathname to list. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stat(final String pathname) throws IOException - { - return sendCommand(FTPCmd.STAT, pathname); - } - - /** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int help() throws IOException - { - return sendCommand(FTPCmd.HELP); - } - - /** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - * - * @param command The command name on which to request help. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int help(final String command) throws IOException - { - return sendCommand(FTPCmd.HELP, command); - } - - /** - * A convenience method to send the FTP NOOP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int noop() throws IOException - { - return sendCommand(FTPCmd.NOOP); - } - - /** - * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2. - * @return True if strict, false if lenient - * @since 2.0 - */ - public boolean isStrictMultilineParsing() { - return strictMultilineParsing; - } - - /** - * Set strict multiline parsing. - * @param strictMultilineParsing the setting - * @since 2.0 - */ - public void setStrictMultilineParsing(final boolean strictMultilineParsing) { - this.strictMultilineParsing = strictMultilineParsing; - } - - /** - * Return whether strict non-multiline parsing is enabled, as per RFC 959, section 4.2. - *

- * The default is true, which requires the 3 digit code be followed by space and some text. - *
- * If false, only the 3 digit code is required (as was the case for versions up to 3.5) - *
- * @return True if strict (default), false if additional checks are not made - * @since 3.6 - */ - public boolean isStrictReplyParsing() { - return strictReplyParsing; - } - - /** - * Set strict non-multiline parsing. - *

- * If true, it requires the 3 digit code be followed by space and some text. - *
- * If false, only the 3 digit code is required (as was the case for versions up to 3.5) - *

- * This should not be required by a well-behaved FTP server - *
- * @param strictReplyParsing the setting - * @since 3.6 - */ - public void setStrictReplyParsing(final boolean strictReplyParsing) { - this.strictReplyParsing = strictReplyParsing; - } - - /** - * Provide command support to super-class - */ - @Override - protected ProtocolCommandSupport getCommandSupport() { - return _commandSupport_; - } -} diff --git a/src/org/apache/commons/net/ftp/FTPClient.java b/src/org/apache/commons/net/ftp/FTPClient.java deleted file mode 100644 index 19a4ee1b..00000000 --- a/src/org/apache/commons/net/ftp/FTPClient.java +++ /dev/null @@ -1,4034 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.net.ftp; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Properties; -import java.util.Random; -import java.util.Set; -import java.util.regex.Matcher; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; -import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; -import org.apache.commons.net.ftp.parser.MLSxEntryParser; -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.io.CopyStreamAdapter; -import org.apache.commons.net.io.CopyStreamEvent; -import org.apache.commons.net.io.CopyStreamListener; -import org.apache.commons.net.io.FromNetASCIIInputStream; -import org.apache.commons.net.io.SocketOutputStream; -import org.apache.commons.net.io.ToNetASCIIOutputStream; -import org.apache.commons.net.io.Util; -import org.apache.commons.net.util.NetConstants; - -/** - * FTPClient encapsulates all the functionality necessary to store and - * retrieve files from an FTP server. This class takes care of all - * low level details of interacting with an FTP server and provides - * a convenient higher level interface. As with all classes derived - * from {@link org.apache.commons.net.SocketClient}, - * you must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before doing anything, and finally - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after you're completely finished interacting with the server. - * Then you need to check the FTP reply code to see if the connection - * was successful. For example: - *

- *    FTPClient ftp = new FTPClient();
- *    FTPClientConfig config = new FTPClientConfig();
- *    config.setXXX(YYY); // change required options
- *    // for example config.setServerTimeZoneId("Pacific/Pitcairn")
- *    ftp.configure(config );
- *    boolean error = false;
- *    try {
- *      int reply;
- *      String server = "ftp.example.com";
- *      ftp.connect(server);
- *      System.out.println("Connected to " + server + ".");
- *      System.out.print(ftp.getReplyString());
- *
- *      // After connection attempt, you should check the reply code to verify
- *      // success.
- *      reply = ftp.getReplyCode();
- *
- *      if(!FTPReply.isPositiveCompletion(reply)) {
- *        ftp.disconnect();
- *        System.err.println("FTP server refused connection.");
- *        System.exit(1);
- *      }
- *      ... // transfer files
- *      ftp.logout();
- *    } catch(IOException e) {
- *      error = true;
- *      e.printStackTrace();
- *    } finally {
- *      if(ftp.isConnected()) {
- *        try {
- *          ftp.disconnect();
- *        } catch(IOException ioe) {
- *          // do nothing
- *        }
- *      }
- *      System.exit(error ? 1 : 0);
- *    }
- * 
- *

- * Immediately after connecting is the only real time you need to check the - * reply code (because connect is of type void). The convention for all the - * FTP command methods in FTPClient is such that they either return a - * boolean value or some other value. - * The boolean methods return true on a successful completion reply from - * the FTP server and false on a reply resulting in an error condition or - * failure. The methods returning a value other than boolean return a value - * containing the higher level data produced by the FTP command, or null if a - * reply resulted in an error condition or failure. If you want to access - * the exact FTP reply code causing a success or failure, you must call - * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after - * a success or failure. - *

- * The default settings for FTPClient are for it to use - * FTP.ASCII_FILE_TYPE , - * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE . The only file types directly supported - * are FTP.ASCII_FILE_TYPE and - * FTP.BINARY_FILE_TYPE . Because there are at least 4 - * different EBCDIC encodings, we have opted not to provide direct support - * for EBCDIC. To transfer EBCDIC and other unsupported file types you - * must create your own filter InputStreams and OutputStreams and wrap - * them around the streams returned or required by the FTPClient methods. - * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} - * filter streams to provide transparent handling of ASCII files. We will - * consider incorporating EBCDIC support if there is enough demand. - *

- * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE are the only supported formats, - * transfer modes, and file structures. - *

- * Because the handling of sockets on different platforms can differ - * significantly, the FTPClient automatically issues a new PORT (or EPRT) command - * prior to every transfer requiring that the server connect to the client's - * data port. This ensures identical problem-free behavior on Windows, Unix, - * and Macintosh platforms. Additionally, it relieves programmers from - * having to issue the PORT (or EPRT) command themselves and dealing with platform - * dependent issues. - *

- * Additionally, for security purposes, all data connections to the - * client are verified to ensure that they originated from the intended - * party (host and port). If a data connection is initiated by an unexpected - * party, the command will close the socket and throw an IOException. You - * may disable this behavior with - * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTPClient class will detect a - * premature FTP server connection closing when it receives a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * . - * FTPConnectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTPClient. Before disconnecting, you may check the - * last reply code and text with - * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode }, - * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, - * and - * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodically sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- * Listing API Examples - * Both paged and unpaged examples of directory listings are available, - * as follows: - *

- * Unpaged (whole list) access, using a parser accessible by auto-detect: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles(directory);
- * 
- *

- * Paged access, using a parser not accessible by auto-detect. The class - * defined in the first parameter of initateListParsing should be derived - * from org.apache.commons.net.FTPFileEntryParser: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * Paged access, using a parser accessible by auto-detect: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For examples of using FTPClient on servers whose directory listings - *

    - *
  • use languages other than English
  • - *
  • use date formats other than the American English "standard" MM d yyyy
  • - *
  • are in different time zones and you need accurate timestamps for dependency checking - * as in Ant
  • - *
see {@link FTPClientConfig FTPClientConfig}. - *

- * Control channel keep-alive feature: - *

- * Please note: this does not apply to the methods where the user is responsible for writing or reading - * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} - * and the other xxxFileStream methods - *

- * During file transfers, the data connection is busy, but the control connection is idle. - * FTP servers know that the control connection is in use, so won't close it through lack of activity, - * but it's a lot harder for network routers to know that the control and data connections are associated - * with each other. - * Some routers may treat the control connection as idle, and disconnect it if the transfer over the data - * connection takes longer than the allowable idle time for the router. - *
- * One solution to this is to send a safe command (i.e. NOOP) over the control connection to reset the router's - * idle timer. This is enabled as follows: - *

- *     ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes
- * 
- * This will cause the file upload/download methods to send a NOOP approximately every 5 minutes. - * The following public methods support this: - *
    - *
  • {@link #retrieveFile(String, OutputStream)}
  • - *
  • {@link #appendFile(String, InputStream)}
  • - *
  • {@link #storeFile(String, InputStream)}
  • - *
  • {@link #storeUniqueFile(InputStream)}
  • - *
  • {@link #storeUniqueFileStream(String)}
  • - *
- * This feature does not apply to the methods where the user is responsible for writing or reading - * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} - * and the other xxxFileStream methods. - * In such cases, the user is responsible for keeping the control connection alive if necessary. - *

- * The implementation currently uses a {@link CopyStreamListener} which is passed to the - * {@link Util#copyStream(InputStream, OutputStream, int, long, CopyStreamListener, boolean)} - * method, so the timing is partially dependent on how long each block transfer takes. - *

- * This keep-alive feature is optional; if it does not help or causes problems then don't use it. - * - * @see #FTP_SYSTEM_TYPE - * @see #SYSTEM_TYPE_PROPERTIES - * @see FTP - * @see FTPConnectionClosedException - * @see FTPFileEntryParser - * @see FTPFileEntryParserFactory - * @see DefaultFTPFileEntryParserFactory - * @see FTPClientConfig - * - * @see org.apache.commons.net.MalformedServerReplyException - */ -public class FTPClient extends FTP implements Configurable { - // @since 3.0 - private static class CSL implements CopyStreamListener { - - private final FTPClient parent; - private final long idleMillis; - private final int currentSoTimeoutMillis; - - private long timeMillis = System.currentTimeMillis(); - private int notAcked; - private int acksAcked; - private int ioErrors; - - CSL(final FTPClient parent, final long idleTimeMillis, final int maxWaitMillis) throws SocketException { - this.idleMillis = idleTimeMillis; - this.parent = parent; - this.currentSoTimeoutMillis = parent.getSoTimeout(); - parent.setSoTimeout(maxWaitMillis); - } - - @Override - public void bytesTransferred(final CopyStreamEvent event) { - bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize()); - } - - @Override - public void bytesTransferred(final long totalBytesTransferred, - final int bytesTransferred, final long streamSize) { - final long nowMillis = System.currentTimeMillis(); - if (nowMillis - timeMillis > idleMillis) { - try { - parent.__noop(); - acksAcked++; - } catch (final SocketTimeoutException e) { - notAcked++; - } catch (final IOException e) { - ioErrors++; - // Ignored - } - timeMillis = nowMillis; - } - } - - int[] cleanUp() throws IOException { - final int remain = notAcked; - try { - while(notAcked > 0) { - parent.getReply(); // we do want to see these - notAcked--; // only decrement if actually received - } - } catch (final SocketTimeoutException e) { // NET-584 - // ignored - } finally { - parent.setSoTimeout(currentSoTimeoutMillis); - } - return new int [] {acksAcked, remain, notAcked, ioErrors}; // debug counts - } - - } - - /** - * Strategy interface for updating host names received from FTP server - * for passive NAT workaround. - * - * @since 3.6 - */ - public interface HostnameResolver { - String resolve(String hostname) throws UnknownHostException; - } - - /** - * Default strategy for passive NAT workaround (site-local - * replies are replaced.) - * @since 3.6 - */ - public static class NatServerResolverImpl implements HostnameResolver { - private final FTPClient client; - - public NatServerResolverImpl(final FTPClient client) { - this.client = client; - } - - @Override - public String resolve(final String hostname) throws UnknownHostException { - String newHostname = hostname; - final InetAddress host = InetAddress.getByName(newHostname); - // reply is a local address, but target is not - assume NAT box changed the PASV reply - if (host.isSiteLocalAddress()) { - final InetAddress remote = this.client.getRemoteAddress(); - if (!remote.isSiteLocalAddress()){ - newHostname = remote.getHostAddress(); - } - } - return newHostname; - } - } - - private static class PropertiesSingleton { - - static final Properties PROPERTIES; - - static { - final InputStream resourceAsStream = FTPClient.class.getResourceAsStream(SYSTEM_TYPE_PROPERTIES); - Properties p = null; - if (resourceAsStream != null) { - p = new Properties(); - try { - p.load(resourceAsStream); - } catch (final IOException e) { - // Ignored - } finally { - try { - resourceAsStream.close(); - } catch (final IOException e) { - // Ignored - } - } - } - PROPERTIES = p; - } - - } - - /** - * The system property ({@value}) which can be used to override the system type.
- * If defined, the value will be used to create any automatically created parsers. - * - * @since 3.0 - */ - public static final String FTP_SYSTEM_TYPE = "org.apache.commons.net.ftp.systemType"; - - /** - * The system property ({@value}) which can be used as the default system type.
- * If defined, the value will be used if the SYST command fails. - * - * @since 3.1 - */ - public static final String FTP_SYSTEM_TYPE_DEFAULT = "org.apache.commons.net.ftp.systemType.default"; - - /** - * The name of an optional systemType properties file ({@value}), which is loaded - * using {@link Class#getResourceAsStream(String)}.
- * The entries are the systemType (as determined by {@link FTPClient#getSystemType}) - * and the values are the replacement type or parserClass, which is passed to - * {@link FTPFileEntryParserFactory#createFileEntryParser(String)}.
- * For example: - *

-     * Plan 9=Unix
-     * OS410=org.apache.commons.net.ftp.parser.OS400FTPEntryParser
-     * 
- * - * @since 3.0 - */ - public static final String SYSTEM_TYPE_PROPERTIES = "/systemType.properties"; - - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * should connect to the client's data port to initiate a data transfer. - * This is the default data connection mode when and FTPClient instance - * is created. - */ - public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; - - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to should connect to the other server's - * data port to initiate a data transfer. - */ - public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; - - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * is in passive mode, requiring the client to connect to the - * server's data port to initiate a transfer. - */ - public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; - - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to is in passive mode, requiring the other - * server to connect to the first server's data port to initiate a data - * transfer. - */ - public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; - - /** Pattern for PASV mode responses. Groups: (n,n,n,n),(n),(n) */ - private static final java.util.regex.Pattern PARMS_PAT; - - static { - PARMS_PAT = java.util.regex.Pattern.compile( - "(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})"); - } - - private static Properties getOverrideProperties() { - return PropertiesSingleton.PROPERTIES; - } - - /** - * Parse the pathname from a CWD reply. - *

- * According to RFC959 (http://www.ietf.org/rfc/rfc959.txt), - * it should be the same as for MKD i.e. - * {@code 257""[commentary]} - * where any double-quotes in {@code } are doubled. - * Unlike MKD, the commentary is optional. - *

- * However, see NET-442 for an exception. - * - * @param reply - * @return the pathname, without enclosing quotes, - * or the full string after the reply code and space if the syntax is invalid - * (i.e. enclosing quotes are missing or embedded quotes are not doubled) - */ - // package protected for access by test cases - static String parsePathname(final String reply) - { - final String param = reply.substring(REPLY_CODE_LEN + 1); - if (param.startsWith("\"")) { - final StringBuilder sb = new StringBuilder(); - boolean quoteSeen = false; - // start after initial quote - for(int i=1; i < param.length(); i++) { - final char ch = param.charAt(i); - if (ch=='"') { - if (quoteSeen) { - sb.append(ch); - quoteSeen=false; - } else { - // don't output yet, in case doubled - quoteSeen=true; - } - } else { - if (quoteSeen) { // found lone trailing quote within string - return sb.toString(); - } - sb.append(ch); // just another character - } - } - if (quoteSeen) { // found lone trailing quote at end of string - return sb.toString(); - } - } - // malformed reply, return all after reply code and space - return param; - } - - private int dataConnectionMode; - private int dataTimeoutMillis; - - private int passivePort; - private String passiveHost; - private final Random random; - private int activeMinPort; - private int activeMaxPort; - private InetAddress activeExternalHost; - - /** overrides __activeExternalHost in EPRT/PORT commands. */ - private InetAddress reportActiveExternalHost; - - /** The address to bind to on passive connections, if necessary. */ - private InetAddress passiveLocalHost; - private int fileType; - @SuppressWarnings("unused") // fields are written, but currently not read - private int fileFormat; - @SuppressWarnings("unused") // field is written, but currently not read - private int fileStructure; - @SuppressWarnings("unused") // field is written, but currently not read - private int fileTransferMode; - - private boolean remoteVerificationEnabled; - - private long restartOffset; - - private FTPFileEntryParserFactory parserFactory; - - private int bufferSize; // buffersize for buffered data streams - - private int sendDataSocketBufferSize; - - private int receiveDataSocketBufferSize; - - private boolean listHiddenFiles; - - private boolean useEPSVwithIPv4; // whether to attempt EPSV with an IPv4 connection - - // __systemName is a cached value that should not be referenced directly - // except when assigned in getSystemName and __initDefaults. - private String systemName; - - // __entryParser is a cached value that should not be referenced directly - // except when assigned in listFiles(String, String) and __initDefaults. - private FTPFileEntryParser entryParser; - - // Key used to create the parser; necessary to ensure that the parser type is not ignored - private String entryParserKey; - - private FTPClientConfig configuration; - - // Listener used by store/retrieve methods to handle keepalive - private CopyStreamListener copyStreamListener; - - // How long to wait before sending another control keep-alive message - private long controlKeepAliveTimeoutMillis; - // How long to wait (millis) for keepalive message replies before continuing - // Most FTP servers don't seem to support concurrent control and data connection usage - private int controlKeepAliveReplyTimeoutMillis = 1000; - - // Debug counts for NOOP acks - private int[] cslDebug; - - - /** - * Enable or disable replacement of internal IP in passive mode. Default enabled - * using {code NatServerResolverImpl}. - */ - private HostnameResolver passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); - - /** Controls the automatic server encoding detection (only UTF-8 supported). */ - private boolean autodetectEncoding = false; - - /** Map of FEAT responses. If null, has not been initialized. */ - private HashMap> featuresMap; - - /** - * Default FTPClient constructor. Creates a new FTPClient instance - * with the data connection mode set to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE , the file type - * set to FTP.ASCII_FILE_TYPE , the - * file format set to FTP.NON_PRINT_TEXT_FORMAT , - * the file structure set to FTP.FILE_STRUCTURE , and - * the transfer mode set to FTP.STREAM_TRANSFER_MODE . - *

- * The list parsing auto-detect feature can be configured to use lenient future - * dates (short dates may be up to one day in the future) as follows: - *

-     * FTPClient ftp = new FTPClient();
-     * FTPClientConfig config = new FTPClientConfig();
-     * config.setLenientFutureDates(true);
-     * ftp.configure(config );
-     * 
- */ - public FTPClient() - { - initDefaults(); - dataTimeoutMillis = -1; - remoteVerificationEnabled = true; - parserFactory = new DefaultFTPFileEntryParserFactory(); - configuration = null; - listHiddenFiles = false; - useEPSVwithIPv4 = false; - random = new Random(); - passiveLocalHost = null; - } - - @Override - protected void _connectAction_() throws IOException { - _connectAction_(null); - } - - /** - * @param socketIsReader the reader to reuse (if non-null) - * @throws IOException on error - * @since 3.4 - */ - @Override - protected void _connectAction_(final Reader socketIsReader) throws IOException { - super._connectAction_(socketIsReader); // sets up _input_ and _output_ - initDefaults(); - // must be after super._connectAction_(), because otherwise we get an - // Exception claiming we're not connected - if (autodetectEncoding) { - final ArrayList oldReplyLines = new ArrayList<>(_replyLines); - final int oldReplyCode = _replyCode; - if (hasFeature("UTF8") || hasFeature("UTF-8")) // UTF8 appears to be the default - { - setControlEncoding("UTF-8"); - _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding())); - _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding())); - } - // restore the original reply (server greeting) - _replyLines.clear(); - _replyLines.addAll(oldReplyLines); - _replyCode = oldReplyCode; - _newReplyString = true; - } - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.3 - */ - protected Socket _openDataConnection_(final FTPCmd command, final String arg) - throws IOException - { - return _openDataConnection_(command.getCommand(), arg); - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead - */ - @Deprecated - protected Socket _openDataConnection_(final int command, final String arg) throws IOException { - return _openDataConnection_(FTPCommand.getCommand(command), arg); - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The text representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.1 - */ - protected Socket _openDataConnection_(final String command, final String arg) - throws IOException - { - if (dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE && - dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { - return null; - } - - final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; - - final Socket socket; - - if (dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) - { - // if no activePortRange was set (correctly) -> getActivePort() = 0 - // -> new ServerSocket(0) -> bind to any free local port - try (final ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress())) { - // Try EPRT only if remote server is over IPv6, if not use PORT, - // because EPRT has no advantage over PORT on IPv4. - // It could even have the disadvantage, - // that EPRT will make the data connection fail, because - // today's intelligent NAT Firewalls are able to - // substitute IP addresses in the PORT command, - // but might not be able to recognize the EPRT command. - if (isInet6Address) { - if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) { - return null; - } - } else { - if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) { - return null; - } - } - - if ((restartOffset > 0) && !restart(restartOffset)) { - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { - return null; - } - - // For now, let's just use the data timeout value for waiting for - // the data connection. It may be desirable to let this be a - // separately configurable value. In any case, we really want - // to allow preventing the accept from blocking indefinitely. - if (dataTimeoutMillis >= 0) { - server.setSoTimeout(dataTimeoutMillis); - } - socket = server.accept(); - - // Ensure the timeout is set before any commands are issued on the new socket - if (dataTimeoutMillis >= 0) { - socket.setSoTimeout(dataTimeoutMillis); - } - if (receiveDataSocketBufferSize > 0) { - socket.setReceiveBufferSize(receiveDataSocketBufferSize); - } - if (sendDataSocketBufferSize > 0) { - socket.setSendBufferSize(sendDataSocketBufferSize); - } - } - } - else - { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE - - // Try EPSV command first on IPv6 - and IPv4 if enabled. - // When using IPv4 with NAT it has the advantage - // to work with more rare configurations. - // E.g. if FTP server has a static PASV address (external network) - // and the client is coming from another internal network. - // In that case the data connection after PASV command would fail, - // while EPSV would make the client succeed by taking just the port. - final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; - if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) - { - _parseExtendedPassiveModeReply(_replyLines.get(0)); - } - else - { - if (isInet6Address) { - return null; // Must use EPSV for IPV6 - } - // If EPSV failed on IPV4, revert to PASV - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return null; - } - _parsePassiveModeReply(_replyLines.get(0)); - } - - socket = _socketFactory_.createSocket(); - if (receiveDataSocketBufferSize > 0) { - socket.setReceiveBufferSize(receiveDataSocketBufferSize); - } - if (sendDataSocketBufferSize > 0) { - socket.setSendBufferSize(sendDataSocketBufferSize); - } - if (passiveLocalHost != null) { - socket.bind(new InetSocketAddress(passiveLocalHost, 0)); - } - - // For now, let's just use the data timeout value for waiting for - // the data connection. It may be desirable to let this be a - // separately configurable value. In any case, we really want - // to allow preventing the accept from blocking indefinitely. - if (dataTimeoutMillis >= 0) { - socket.setSoTimeout(dataTimeoutMillis); - } - - socket.connect(new InetSocketAddress(passiveHost, passivePort), connectTimeout); - if ((restartOffset > 0) && !restart(restartOffset)) - { - socket.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) - { - socket.close(); - return null; - } - } - - if (remoteVerificationEnabled && !verifyRemote(socket)) - { - // Grab the host before we close the socket to avoid NET-663 - final InetAddress socketHost = socket.getInetAddress(); - - socket.close(); - - throw new IOException( - "Host attempting data connection " + socketHost.getHostAddress() + - " is not same as server " + getRemoteAddress().getHostAddress()); - } - - return socket; - } - - protected void _parseExtendedPassiveModeReply(String reply) throws MalformedServerReplyException { - reply = reply.substring(reply.indexOf('(') + 1, reply.indexOf(')')).trim(); - - final char delim1 = reply.charAt(0); - final char delim2 = reply.charAt(1); - final char delim3 = reply.charAt(2); - final char delim4 = reply.charAt(reply.length() - 1); - - if ((delim1 != delim2) || (delim2 != delim3) || (delim3 != delim4)) { - throw new MalformedServerReplyException( - "Could not parse extended passive host information.\nServer Reply: " + reply); - } - - final int port; - try { - port = Integer.parseInt(reply.substring(3, reply.length() - 1)); - } catch (final NumberFormatException e) { - throw new MalformedServerReplyException( - "Could not parse extended passive host information.\nServer Reply: " + reply); - } - - // in EPSV mode, the passive host address is implicit - this.passiveHost = getRemoteAddress().getHostAddress(); - this.passivePort = port; - } - - /** - * @since 3.1 - * @param reply the reply to parse - * @throws MalformedServerReplyException if the server reply does not match (n,n,n,n),(n),(n) - */ - protected void _parsePassiveModeReply(final String reply) throws MalformedServerReplyException { - final Matcher m = PARMS_PAT.matcher(reply); - if (!m.find()) { - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - - this.passiveHost = "0,0,0,0".equals(m.group(1)) ? _socket_.getInetAddress().getHostAddress() - : m.group(1).replace(',', '.'); // Fix up to look like IP address - - try { - final int oct1 = Integer.parseInt(m.group(2)); - final int oct2 = Integer.parseInt(m.group(3)); - passivePort = (oct1 << 8) | oct2; - } catch (final NumberFormatException e) { - throw new MalformedServerReplyException( - "Could not parse passive port information.\nServer Reply: " + reply); - } - - if (passiveNatWorkaroundStrategy != null) { - try { - final String newPassiveHost = passiveNatWorkaroundStrategy.resolve(this.passiveHost); - if (!this.passiveHost.equals(newPassiveHost)) { - fireReplyReceived(0, - "[Replacing PASV mode reply address " + this.passiveHost + " with " + newPassiveHost + "]\n"); - this.passiveHost = newPassiveHost; - } - } catch (final UnknownHostException e) { // Should not happen as we are passing in an IP address - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - } - } - - /** - * @param command the command to get - * @param remote the remote file name - * @param local The local OutputStream to which to write the file. - * @return true if successful - * @throws IOException on error - * @since 3.1 - */ - protected boolean _retrieveFile(final String command, final String remote, final OutputStream local) - throws IOException - { - final Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return false; - } - - InputStream input = null; - CSL csl = null; - try { - try { - if (fileType == ASCII_FILE_TYPE) { - input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); - } else { - input = getBufferedInputStream(socket.getInputStream()); - } - - if (controlKeepAliveTimeoutMillis > 0) { - csl = new CSL(this, controlKeepAliveTimeoutMillis, controlKeepAliveReplyTimeoutMillis); - } - - // Treat everything else as binary for now - Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl), - false); - } finally { - Util.closeQuietly(input); - } - // Get the transfer response - return completePendingCommand(); - } finally { - Util.closeQuietly(socket); - if (csl != null) { - cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies - } - } - } - - - /** - * @param command the command to send - * @param remote the remote file name - * @return the stream from which to read the file - * @throws IOException on error - * @since 3.1 - */ - protected InputStream _retrieveFileStream(final String command, final String remote) - throws IOException - { - final Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return null; - } - - final InputStream input; - if (fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between FromNetASCIIOutputSream and the underlying - // socket input stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketInputStream we return - // for file types other than ASCII. - input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); - } else { - input = socket.getInputStream(); - } - return new org.apache.commons.net.io.SocketInputStream(socket, input); - } - - - /** - * @since 3.1 - * @param command the command to send - * @param remote the remote file name - * @param local The local InputStream from which to read the data to - * be written/appended to the remote file. - * @return true if successful - * @throws IOException on error - */ - protected boolean _storeFile(final String command, final String remote, final InputStream local) - throws IOException - { - final Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return false; - } - - final OutputStream output; - - if (fileType == ASCII_FILE_TYPE) { - output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); - } else { - output = getBufferedOutputStream(socket.getOutputStream()); - } - - CSL csl = null; - if (controlKeepAliveTimeoutMillis > 0) { - csl = new CSL(this, controlKeepAliveTimeoutMillis, controlKeepAliveReplyTimeoutMillis); - } - - // Treat everything else as binary for now - try - { - Util.copyStream(local, output, getBufferSize(), - CopyStreamEvent.UNKNOWN_STREAM_SIZE, mergeListeners(csl), - false); - output.close(); // ensure the file is fully written - socket.close(); // done writing the file - - // Get the transfer response - return completePendingCommand(); - } - catch (final IOException e) - { - Util.closeQuietly(output); // ignore close errors here - Util.closeQuietly(socket); // ignore close errors here - throw e; - } finally { - if (csl != null) { - cslDebug = csl.cleanUp(); // fetch any outstanding keepalive replies - } - } - } - - /** - * @param command the command to send - * @param remote the remote file name - * @return the output stream to write to - * @throws IOException on error - * @since 3.1 - */ - protected OutputStream _storeFileStream(final String command, final String remote) - throws IOException - { - final Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return null; - } - - final OutputStream output; - if (fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between ToNetASCIIOutputSream and the underlying - // socket output stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketOutputStream we return - // for file types other than ASCII. - output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); - } else { - output = socket.getOutputStream(); - } - return new SocketOutputStream(socket, output); - } - - /** - * Abort a transfer in progress. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean abort() throws IOException - { - return FTPReply.isPositiveCompletion(abor()); - } - - /** - * Reserve a number of bytes on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(final int bytes) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes)); - } - - /** - * Reserve space on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @param recordSize The size of a file record. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(final int bytes, final int recordSize) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); - } - - /** - * Reserve a number of bytes on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(final long bytes) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes)); - } - - /** - * Reserve space on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @param recordSize The size of a file record. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(final long bytes, final int recordSize) throws IOException - { - return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); - } - - /** - * Appends to a file on the server with the given name, taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name of the remote file. - * @param local The local InputStream from which to read the data to - * be appended to the remote file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws org.apache.commons.net.io.CopyStreamException - * If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean appendFile(final String remote, final InputStream local) - throws IOException - { - return storeFile(FTPCmd.APPE, remote, local); - } - - /** - * Returns an OutputStream through which data can be written to append - * to a file on the server with the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name of the remote file. - * @return An OutputStream through which the remote file can be appended. - * If the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream appendFileStream(final String remote) throws IOException - { - return storeFileStream(FTPCmd.APPE, remote); - } - - - /** - * Change to the parent directory of the current working directory. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean changeToParentDirectory() throws IOException - { - return FTPReply.isPositiveCompletion(cdup()); - } - - - /** - * Change the current working directory of the FTP session. - * - * @param pathname The new current working directory. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean changeWorkingDirectory(final String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(cwd(pathname)); - } - - /** - * There are a few FTPClient methods that do not complete the - * entire sequence of FTP commands to complete a transaction. These - * commands require some action by the programmer after the reception - * of a positive intermediate command. After the programmer's code - * completes its actions, it must call this method to receive - * the completion reply from the server and verify the success of the - * entire transaction. - *

- * For example, - *

-     * InputStream input;
-     * OutputStream output;
-     * input  = new FileInputStream("foobaz.txt");
-     * output = ftp.storeFileStream("foobar.txt")
-     * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
-     *     input.close();
-     *     output.close();
-     *     ftp.logout();
-     *     ftp.disconnect();
-     *     System.err.println("File transfer failed.");
-     *     System.exit(1);
-     * }
-     * Util.copyStream(input, output);
-     * input.close();
-     * output.close();
-     * // Must call completePendingCommand() to finish command.
-     * if(!ftp.completePendingCommand()) {
-     *     ftp.logout();
-     *     ftp.disconnect();
-     *     System.err.println("File transfer failed.");
-     *     System.exit(1);
-     * }
-     * 
- * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean completePendingCommand() throws IOException - { - return FTPReply.isPositiveCompletion(getReply()); - } - - /** - * Implementation of the {@link Configurable Configurable} interface. - * In the case of this class, configuring merely makes the config object available for the - * factory methods that construct parsers. - * @param config {@link FTPClientConfig FTPClientConfig} object used to - * provide non-standard configurations to the parser. - * @since 1.4 - */ - @Override - public void configure(final FTPClientConfig config) { - this.configuration = config; - } - - // package access for test purposes - void createParser(final String parserKey) throws IOException { - // We cache the value to avoid creation of a new object every - // time a file listing is generated. - // Note: we don't check against a null parserKey (NET-544) - if(entryParser == null || (parserKey != null && ! entryParserKey.equals(parserKey))) { - if (null != parserKey) { - // if a parser key was supplied in the parameters, - // use that to create the parser - entryParser = - parserFactory.createFileEntryParser(parserKey); - entryParserKey = parserKey; - - } else { - // if no parserKey was supplied, check for a configuration - // in the params, and if it has a non-empty system type, use that. - if (null != configuration && configuration.getServerSystemKey().length() > 0) { - entryParser = - parserFactory.createFileEntryParser(configuration); - entryParserKey = configuration.getServerSystemKey(); - } else { - // if a parserKey hasn't been supplied, and a configuration - // hasn't been supplied, and the override property is not set - // then autodetect by calling - // the SYST command and use that to choose the parser. - String systemType = System.getProperty(FTP_SYSTEM_TYPE); - if (systemType == null) { - systemType = getSystemType(); // cannot be null - final Properties override = getOverrideProperties(); - if (override != null) { - final String newType = override.getProperty(systemType); - if (newType != null) { - systemType = newType; - } - } - } - if (null != configuration) { // system type must have been empty above - entryParser = parserFactory.createFileEntryParser(new FTPClientConfig(systemType, configuration)); - } else { - entryParser = parserFactory.createFileEntryParser(systemType); - } - entryParserKey = systemType; - } - } - } - } - - /** - * Deletes a file on the FTP server. - * - * @param pathname The pathname of the file to be deleted. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean deleteFile(final String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(dele(pathname)); - } - - /** - * Closes the connection to the FTP server and restores - * connection parameters to the default values. - * - * @throws IOException If an error occurs while disconnecting. - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - initDefaults(); - } - - /** - * Issue a command and wait for the reply. - *

- * Should only be used with commands that return replies on the - * command channel - do not use for LIST, NLST, MLSD etc. - * - * @param command The command to invoke - * @param params The parameters string, may be {@code null} - * @return True if successfully completed, false if not, in which case - * call {@link #getReplyCode()} or {@link #getReplyString()} - * to get the reason. - * - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.0 - */ - public boolean doCommand(final String command, final String params) throws IOException - { - return FTPReply.isPositiveCompletion(sendCommand(command, params)); - } - - /** - * Issue a command and wait for the reply, returning it as an array of strings. - *

- * Should only be used with commands that return replies on the - * command channel - do not use for LIST, NLST, MLSD etc. - * - * @param command The command to invoke - * @param params The parameters string, may be {@code null} - * @return The array of replies, or {@code null} if the command failed, in which case - * call {@link #getReplyCode()} or {@link #getReplyString()} - * to get the reason. - * - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.0 - */ - public String[] doCommandAsStrings(final String command, final String params) throws IOException - { - final boolean success = FTPReply.isPositiveCompletion(sendCommand(command, params)); - if (success){ - return getReplyStrings(); - } - return null; - } - - /** - * Set the current data connection mode to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE. No communication - * with the FTP server is conducted, but this causes all future data - * transfers to require the FTP server to connect to the client's - * data port. Additionally, to accommodate differences between socket - * implementations on different platforms, this method causes the - * client to issue a PORT command before every data transfer. - */ - public void enterLocalActiveMode() - { - dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - passiveHost = null; - passivePort = -1; - } - - /** - * Set the current data connection mode to - * PASSIVE_LOCAL_DATA_CONNECTION_MODE . Use this - * method only for data transfers between the client and server. - * This method causes a PASV (or EPSV) command to be issued to the server - * before the opening of every data connection, telling the server to - * open a data port to which the client will connect to conduct - * data transfers. The FTPClient will stay in - * PASSIVE_LOCAL_DATA_CONNECTION_MODE until the - * mode is changed by calling some other method such as - * {@link #enterLocalActiveMode enterLocalActiveMode() } - *

- * N.B. currently calling any connect method will reset the mode to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE. - */ - public void enterLocalPassiveMode() - { - dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; - // These will be set when just before a data connection is opened - // in _openDataConnection_() - passiveHost = null; - passivePort = -1; - } - - /** - * Set the current data connection mode to - * ACTIVE_REMOTE_DATA_CONNECTION . Use this method only - * for server to server data transfers. This method issues a PORT - * command to the server, indicating the other server and port to which - * it should connect for data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PORT commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - * - * @param host The passive mode server accepting connections for data - * transfers. - * @param port The passive mode server's data port. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean enterRemoteActiveMode(final InetAddress host, final int port) - throws IOException - { - if (FTPReply.isPositiveCompletion(port(host, port))) - { - dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; - passiveHost = null; - passivePort = -1; - return true; - } - return false; - } - - /** - * Set the current data connection mode to - * PASSIVE_REMOTE_DATA_CONNECTION_MODE . Use this - * method only for server to server data transfers. - * This method issues a PASV command to the server, telling it to - * open a data port to which the active server will connect to conduct - * data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PASV commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean enterRemotePassiveMode() throws IOException - { - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return false; - } - - dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; - _parsePassiveModeReply(_replyLines.get(0)); - - return true; - } - - /** - * Queries the server for supported features. The server may reply with a list of server-supported extensions. - * For example, a typical client-server interaction might be (from RFC 2389): - *

-        C> feat
-        S> 211-Extensions supported:
-        S>  MLST size*;create;modify*;perm;media-type
-        S>  SIZE
-        S>  COMPRESSION
-        S>  MDTM
-        S> 211 END
-     * 
- * @see http://www.faqs.org/rfcs/rfc2389.html - * @return True if successfully completed, false if not. - * @throws IOException on error - * @since 2.2 - */ - public boolean features() throws IOException { - return FTPReply.isPositiveCompletion(feat()); - } - - /** - * Queries the server for a supported feature, and returns the its value (if any). - * Caches the parsed response to avoid resending the command repeatedly. - * @param feature the feature to check - * - * @return if the feature is present, returns the feature value or the empty string - * if the feature exists but has no value. - * Returns {@code null} if the feature is not found or the command failed. - * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. - * @throws IOException on error - * @since 3.0 - */ - public String featureValue(final String feature) throws IOException { - final String [] values = featureValues(feature); - if (values != null) { - return values[0]; - } - return null; - } - - /** - * Queries the server for a supported feature, and returns its values (if any). - * Caches the parsed response to avoid resending the command repeatedly. - * @param feature the feature to check - * - * @return if the feature is present, returns the feature values (empty array if none) - * Returns {@code null} if the feature is not found or the command failed. - * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. - * @throws IOException on error - * @since 3.0 - */ - public String[] featureValues(final String feature) throws IOException { - if (!initFeatureMap()) { - return null; - } - final Set entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); - if (entries != null) { - return entries.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - return null; - } - - /** - * Get the client port for active mode. - * - * @return The client port for active mode. - */ - private int getActivePort() - { - if (activeMinPort > 0 && activeMaxPort >= activeMinPort) - { - if (activeMaxPort == activeMinPort) { - return activeMaxPort; - } - // Get a random port between the min and max port range - return random.nextInt(activeMaxPort - activeMinPort + 1) + activeMinPort; - } - // default port - return 0; - } - - /** - * Tells if automatic server encoding detection is enabled or disabled. - * @return true, if automatic server encoding detection is enabled. - */ - public boolean getAutodetectUTF8() - { - return autodetectEncoding; - } - - private InputStream getBufferedInputStream(final InputStream inputStream) { - if (bufferSize > 0) { - return new BufferedInputStream(inputStream, bufferSize); - } - return new BufferedInputStream(inputStream); - } - - private OutputStream getBufferedOutputStream(final OutputStream outputStream) { - if (bufferSize > 0) { - return new BufferedOutputStream(outputStream, bufferSize); - } - return new BufferedOutputStream(outputStream); - } - - /** - * Retrieve the current internal buffer size for buffered data streams. - * @return The current buffer size. - */ - public int getBufferSize() { - return bufferSize; - } - - /** - * Gets how long to wait for control keep-alive message replies. - * @return wait time in milliseconds. - * @since 3.0 - */ - public int getControlKeepAliveReplyTimeout() { - return controlKeepAliveReplyTimeoutMillis; - } - - /** - * Gets the time to wait between sending control connection keepalive messages - * when processing file upload or download. - *

- * See the class Javadoc section "Control channel keep-alive feature:" - * - * @return the number of seconds between keepalive messages. - * @since 3.0 - */ - public long getControlKeepAliveTimeout() { - return controlKeepAliveTimeoutMillis / 1000; - } - - /** - * Obtain the currently active listener. - * - * @return the listener, may be {@code null} - * @since 3.0 - */ - public CopyStreamListener getCopyStreamListener(){ - return copyStreamListener; - } - - /** - * Get the CSL debug array. - *

- * For debug use only - *

- * Currently contains: - *

    - *
  • successfully acked NOOPs at end of transfer
  • - *
  • unanswered NOOPs at end of transfer
  • - *
  • unanswered NOOPs after fetching additional replies
  • - *
  • Number of IOErrors ignored
  • - *
- * @return the debug array - * @deprecated 3.7 For testing only; may be dropped or changed at any time - */ - @Deprecated // only for use in testing - public int[] getCslDebug() { - return cslDebug; - } - - /** - * Returns the current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - * - * @return The current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - */ - public int getDataConnectionMode() - { - return dataConnectionMode; - } - - // Method for use by unit test code only - FTPFileEntryParser getEntryParser() { - return entryParser; - } - - /** - * Get the host address for active mode; allows the local address to be overridden. - * - * @return __activeExternalHost if non-null, else getLocalAddress() - * @see #setActiveExternalIPAddress(String) - */ - private InetAddress getHostAddress() - { - if (activeExternalHost != null) - { - return activeExternalHost; - } - // default local address - return getLocalAddress(); - } - - /** - * @param pathname the initial pathname - * @return the adjusted string with "-a" added if necessary - * @since 2.0 - */ - protected String getListArguments(final String pathname) { - if (getListHiddenFiles()) - { - if (pathname != null) - { - final StringBuilder sb = new StringBuilder(pathname.length() + 3); - sb.append("-a "); - sb.append(pathname); - return sb.toString(); - } - return "-a"; - } - - return pathname; - } - - /** - * @see #setListHiddenFiles(boolean) - * @return the current state - * @since 2.0 - */ - public boolean getListHiddenFiles() { - return this.listHiddenFiles; - } - - /** - * Issue the FTP MDTM command (not supported by all servers) to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honor this. - * - * @param pathname The file path to query. - * @return A string representing the last file modification time in YYYYMMDDhhmmss format. - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - public String getModificationTime(final String pathname) throws IOException { - if (FTPReply.isPositiveCompletion(mdtm(pathname))) { - // skip the return code (e.g. 213) and the space - return getReplyString(0).substring(4); - } - return null; - } - - /** - * Returns the hostname or IP address (in the form of a string) returned - * by the server when entering passive mode. If not in passive mode, - * returns null. This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * - * @return The passive host name if in passive mode, otherwise null. - */ - public String getPassiveHost() - { - return passiveHost; - } - - /** - * Set the local IP address in passive mode. - * Useful when there are multiple network cards. - * - * @return The local IP address in passive mode. - */ - public InetAddress getPassiveLocalIPAddress() - { - return this.passiveLocalHost; - } - - /** - * If in passive mode, returns the data port of the passive host. - * This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * - * @return The data port of the passive server. If not in passive - * mode, undefined. - */ - public int getPassivePort() - { - return passivePort; - } - - /** - * Retrieve the value to be used for the data socket SO_RCVBUF option. - * @return The current buffer size. - * @since 3.3 - */ - public int getReceiveDataSocketBufferSize() { - return receiveDataSocketBufferSize; - } - - /** - * Get the reported host address for active mode EPRT/PORT commands; - * allows override of {@link #getHostAddress()}. - * - * Useful for FTP Client behind Firewall NAT. - * - * @return __reportActiveExternalHost if non-null, else getHostAddress(); - */ - private InetAddress getReportHostAddress() { - if (reportActiveExternalHost != null) { - return reportActiveExternalHost ; - } - return getHostAddress(); - } - - /** - * Fetches the restart offset. - * - * @return offset The offset into the remote file at which to start the - * next file transfer. - */ - public long getRestartOffset() - { - return restartOffset; - } - - /** - * Retrieve the value to be used for the data socket SO_SNDBUF option. - * @return The current buffer size. - * @since 3.3 - */ - public int getSendDataSocketBufferSize() { - return sendDataSocketBufferSize; - } - - /** - * Issue the FTP SIZE command to the server for a given pathname. - * This should produce the size of the file. - * - * @param pathname the file name - * - * @return The size information returned by the server; {@code null} if there was an error - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.7 - */ - public String getSize(final String pathname) throws IOException - { - if (FTPReply.isPositiveCompletion(size(pathname))) { - return getReplyString(0).substring(4); // skip the return code (e.g. 213) and the space - } - return null; - } - - /** - * Issue the FTP STAT command to the server. - * - * @return The status information returned by the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String getStatus() throws IOException - { - if (FTPReply.isPositiveCompletion(stat())) { - return getReplyString(); - } - return null; - } - - /** - * Issue the FTP STAT command to the server for a given pathname. This - * should produce a listing of the file or directory. - * @param pathname the file name - * - * @return The status information returned by the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String getStatus(final String pathname) throws IOException - { - if (FTPReply.isPositiveCompletion(stat(pathname))) { - return getReplyString(); - } - return null; - } - - /** - * @return the name - * @throws IOException on error - * @deprecated use {@link #getSystemType()} instead - */ - @Deprecated - public String getSystemName() throws IOException - { - if (systemName == null && FTPReply.isPositiveCompletion(syst())) { - systemName = _replyLines.get(_replyLines.size() - 1).substring(4); - } - return systemName; - } - - /** - * Fetches the system type from the server and returns the string. - * This value is cached for the duration of the connection after the - * first call to this method. In other words, only the first time - * that you invoke this method will it issue a SYST command to the - * FTP server. FTPClient will remember the value and return the - * cached value until a call to disconnect. - *

- * If the SYST command fails, and the system property - * {@link #FTP_SYSTEM_TYPE_DEFAULT} is defined, then this is used instead. - * @return The system type obtained from the server. Never null. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server (and the default - * system type property is not defined) - * @since 2.2 - */ - public String getSystemType() throws IOException - { - //if (syst() == FTPReply.NAME_SYSTEM_TYPE) - // Technically, we should expect a NAME_SYSTEM_TYPE response, but - // in practice FTP servers deviate, so we soften the condition to - // a positive completion. - if (systemName == null){ - if (FTPReply.isPositiveCompletion(syst())) { - // Assume that response is not empty here (cannot be null) - systemName = _replyLines.get(_replyLines.size() - 1).substring(4); - } else { - // Check if the user has provided a default for when the SYST command fails - final String systDefault = System.getProperty(FTP_SYSTEM_TYPE_DEFAULT); - if (systDefault != null) { - systemName = systDefault; - } else { - throw new IOException("Unable to determine system type - response: " + getReplyString()); - } - } - } - return systemName; - } - - /** - * Queries the server for a supported feature. - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the name of the feature; it is converted to upper case. - * @return {@code true} if the feature is present, {@code false} if the feature is not present - * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()} - * if it is necessary to distinguish these cases. - * - * @throws IOException on error - * @since 3.8.0 - */ - public boolean hasFeature(final FTPCmd feature) throws IOException { - return hasFeature(feature.name()); - } - - /** - * Queries the server for a supported feature. - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the name of the feature; it is converted to upper case. - * @return {@code true} if the feature is present, {@code false} if the feature is not present - * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()} - * if it is necessary to distinguish these cases. - * - * @throws IOException on error - * @since 3.0 - */ - public boolean hasFeature(final String feature) throws IOException { - if (!initFeatureMap()) { - return false; - } - return featuresMap.containsKey(feature.toUpperCase(Locale.ENGLISH)); - } - - /** - * Queries the server for a supported feature with particular value, - * for example "AUTH SSL" or "AUTH TLS". - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the name of the feature; it is converted to upper case. - * @param value the value to find. - * - * @return {@code true} if the feature is present, {@code false} if the feature is not present - * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()} - * if it is necessary to distinguish these cases. - * - * @throws IOException on error - * @since 3.0 - */ - public boolean hasFeature(final String feature, final String value) throws IOException { - if (!initFeatureMap()) { - return false; - } - final Set entries = featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); - if (entries != null) { - return entries.contains(value); - } - return false; - } - - private void initDefaults() - { - dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - passiveHost = null; - passivePort = -1; - activeExternalHost = null; - reportActiveExternalHost = null; - activeMinPort = 0; - activeMaxPort = 0; - fileType = FTP.ASCII_FILE_TYPE; - fileStructure = FTP.FILE_STRUCTURE; - fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - fileTransferMode = FTP.STREAM_TRANSFER_MODE; - restartOffset = 0; - systemName = null; - entryParser = null; - entryParserKey = ""; - featuresMap = null; - } - - /* - * Create the feature map if not already created. - */ - private boolean initFeatureMap() throws IOException { - if (featuresMap == null) { - // Don't create map here, because next line may throw exception - final int replyCode = feat(); - if (replyCode == FTPReply.NOT_LOGGED_IN) { // 503 - return false; // NET-518; don't create empy map - } - final boolean success = FTPReply.isPositiveCompletion(replyCode); - // we init the map here, so we don't keep trying if we know the command will fail - featuresMap = new HashMap<>(); - if (!success) { - return false; - } - for (final String line : _replyLines) { - if (line.startsWith(" ")) { // it's a FEAT entry - String key; - String value = ""; - final int varsep = line.indexOf(' ', 1); - if (varsep > 0) { - key = line.substring(1, varsep); - value = line.substring(varsep + 1); - } else { - key = line.substring(1); - } - key = key.toUpperCase(Locale.ENGLISH); - Set entries = featuresMap.get(key); - if (entries == null) { - entries = new HashSet<>(); - featuresMap.put(key, entries); - } - entries.add(value); - } - } - } - return true; - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the current working - * directory on the server - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing() - throws IOException - { - return initiateListParsing((String) null); - } - - /** - * private method through which all listFiles() and - * initiateListParsing methods pass once a parser is determined. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @see FTPListParseEngine - */ - private FTPListParseEngine initiateListParsing( - final FTPFileEntryParser parser, final String pathname) - throws IOException - { - final Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname)); - - final FTPListParseEngine engine = new FTPListParseEngine(parser, configuration); - if (socket == null) - { - return engine; - } - - try { - engine.readServerList(socket.getInputStream(), getControlEncoding()); - } - finally { - Util.closeQuietly(socket); - } - - completePendingCommand(); - return engine; - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - *

-     *    FTPClient f=FTPClient();
-     *    f.connect(server);
-     *    f.login(username, password);
-     *    FTPListParseEngine engine = f.initiateListParsing(directory);
-     *
-     *    while (engine.hasNext()) {
-     *       FTPFile[] files = engine.getNext(25);  // "page size" you want
-     *       //do whatever you want with these files, display them, etc.
-     *       //expensive FTPFile objects not created until needed.
-     *    }
-     * 
- * @param pathname the starting directory - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing(final String pathname) - throws IOException - { - return initiateListParsing((String) null, pathname); - } - - /** - * Using the supplied parser key, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @param parserKey A string representing a designated code or fully-qualified - * class name of an FTPFileEntryParser that should be - * used to parse each server file listing. - * May be {@code null}, in which case the code checks first - * the system property {@link #FTP_SYSTEM_TYPE}, and if that is - * not defined the SYST command is used to provide the value. - * To allow for arbitrary system types, the return from the - * SYST command is used to look up an alias for the type in the - * {@link #SYSTEM_TYPE_PROPERTIES} properties file if it is available. - * @param pathname the starting directory - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing( - final String parserKey, final String pathname) - throws IOException - { - createParser(parserKey); // create and cache parser - return initiateListParsing(entryParser, pathname); - } - - /** - * Initiate list parsing for MLSD listings in the current working directory. - * - * @return the engine - * @throws IOException on error - */ - public FTPListParseEngine initiateMListParsing() throws IOException - { - return initiateMListParsing(null); - } - - /** - * Initiate list parsing for MLSD listings. - * - * @param pathname the path from where to MLSD. - * @return the engine. - * @throws IOException on error - */ - public FTPListParseEngine initiateMListParsing(final String pathname) throws IOException - { - final Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname); - final FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance(), configuration); - if (socket == null) - { - return engine; - } - - try { - engine.readServerList(socket.getInputStream(), getControlEncoding()); - } - finally { - Util.closeQuietly(socket); - completePendingCommand(); - } - return engine; - } - - /** - * Return whether or not verification of the remote host participating - * in data connections is enabled. The default behavior is for - * verification to be enabled. - * - * @return True if verification is enabled, false if not. - */ - public boolean isRemoteVerificationEnabled() - { - return remoteVerificationEnabled; - } - - /** - * Whether should attempt to use EPSV with IPv4. - * Default (if not set) is false - * @return true if should attempt EPSV - * @since 2.2 - */ - public boolean isUseEPSVwithIPv4() { - return useEPSVwithIPv4; - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of directories contained in the current working directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @return The list of directories contained in the current directory - * in the format determined by the autodetection mechanism. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - * @since 3.0 - */ - public FTPFile[] listDirectories() throws IOException { - return listDirectories((String) null); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of directories contained in the specified directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * @param parent the starting directory - * - * @return The list of directories contained in the specified directory - * in the format determined by the autodetection mechanism. - * - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - * @since 3.0 - */ - public FTPFile[] listDirectories(final String parent) throws IOException { - return listFiles(parent, FTPFileFilters.DIRECTORIES); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @return The list of file information contained in the current directory - * in the format determined by the autodetection mechanism. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - */ - public FTPFile[] listFiles() - throws IOException - { - return listFiles((String) null); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory - * or for just a single file. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @param pathname The file or directory to list. Since the server may - * or may not expand glob expressions, using them here - * is not recommended and may well cause this method to - * fail. - * Also, some servers treat a leading '-' as being an option. - * To avoid this interpretation, use an absolute pathname - * or prefix the pathname with ./ (unix style servers). - * Some servers may support "--" as meaning end of options, - * in which case "-- -xyz" should work. - * - * @return The list of file information contained in the given path in - * the format determined by the autodetection mechanism - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException - * If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws org.apache.commons.net.ftp.parser.ParserInitializationException - * Thrown if the parserKey parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * org.apache.commons.net.ftp.FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.FTPFileEntryParser - */ - public FTPFile[] listFiles(final String pathname) throws IOException { - return initiateListParsing((String) null, pathname).getFiles(); - } - - /** - * Version of {@link #listFiles(String)} which allows a filter to be provided. - * For example: listFiles("site", FTPFileFilters.DIRECTORY); - * @param pathname the initial path, may be null - * @param filter the filter, non-null - * @return the list of FTPFile entries. - * @throws IOException on error - * @since 2.2 - */ - public FTPFile[] listFiles(final String pathname, final FTPFileFilter filter) throws IOException { - return initiateListParsing((String) null, pathname).getFiles(filter); - } - - /** - * Fetches the system help information from the server and returns the - * full string. - * - * @return The system help string obtained from the server. null if the - * information could not be obtained. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp() throws IOException { - return FTPReply.isPositiveCompletion(help()) ? getReplyString() : null; - } - - /** - * Fetches the help information for a given command from the server and - * returns the full string. - * @param command The command on which to ask for help. - * @return The command help string obtained from the server. null if the - * information could not be obtained. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp(final String command) throws IOException { - return FTPReply.isPositiveCompletion(help(command)) ? getReplyString() : null; - } - - /** - * Obtain a list of file names in the current working directory - * This information is obtained through the NLST command. If the current - * directory contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise, - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of file names in the directory is - * returned. - * - * @return The list of file names contained in the current working - * directory. null if the list could not be obtained. - * If there are no file names in the directory, a zero-length array - * is returned. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String[] listNames() throws IOException - { - return listNames(null); - } - - /** - * Obtain a list of file names in a directory (or just the name of a given - * file, which is not particularly useful). This information is obtained - * through the NLST command. If the given pathname is a directory and - * contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of file names in the directory is - * returned. If the pathname corresponds - * to a file, only that file will be listed. The server may or may not - * expand glob expressions. - * - * @param pathname The file or directory to list. - * Warning: the server may treat a leading '-' as an - * option introducer. If so, try using an absolute path, - * or prefix the path with ./ (unix style servers). - * Some servers may support "--" as meaning end of options, - * in which case "-- -xyz" should work. - * @return The list of file names contained in the given path. null if - * the list could not be obtained. If there are no file names in - * the directory, a zero-length array is returned. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String[] listNames(final String pathname) throws IOException - { - final ArrayList results = new ArrayList<>(); - try (final Socket socket = _openDataConnection_(FTPCmd.NLST, getListArguments(pathname))) { - - if (socket == null) { - return null; - } - - try (final BufferedReader reader = new BufferedReader( - new InputStreamReader(socket.getInputStream(), getControlEncoding()))) { - - String line; - while ((line = reader.readLine()) != null) { - results.add(line); - } - } - } - - if (completePendingCommand()) { - return results.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - - return null; - } - - /** - * Login to the FTP server using the provided username and password. - * - * @param username The username to login under. - * @param password The password to use. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login(final String username, final String password) throws IOException - { - - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - return FTPReply.isPositiveCompletion(pass(password)); - } - - /** - * Login to the FTP server using the provided username, password, - * and account. If no account is required by the server, only - * the username and password, the account information is not used. - * - * @param username The username to login under. - * @param password The password to use. - * @param account The account to use. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login(final String username, final String password, final String account) - throws IOException - { - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - pass(password); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - return FTPReply.isPositiveCompletion(acct(account)); - } - - /** - * Logout of the FTP server by sending the QUIT command. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean logout() throws IOException - { - return FTPReply.isPositiveCompletion(quit()); - } - - /** - * Creates a new subdirectory on the FTP server in the current directory - * (if a relative pathname is given) or where specified (if an absolute - * pathname is given). - * - * @param pathname The pathname of the directory to create. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean makeDirectory(final String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(mkd(pathname)); - } - - /** - * Issue the FTP MDTM command (not supported by all servers) to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honor this. - * - * @param pathname The file path to query. - * @return A Calendar representing the last file modification time, may be {@code null}. - * The Calendar timestamp will be null if a parse error occurs. - * @throws IOException if an I/O error occurs. - * @since 3.8.0 - */ - public Calendar mdtmCalendar(final String pathname) throws IOException { - final String modificationTime = getModificationTime(pathname); - if (modificationTime != null) { - return MLSxEntryParser.parseGMTdateTime(modificationTime); - } - return null; - } - - /** - * Issue the FTP MDTM command (not supported by all servers) to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honor this. - * - * @param pathname The file path to query. - * @return A FTPFile representing the last file modification time, may be {@code null}. - * The FTPFile timestamp will be null if a parse error occurs. - * @throws IOException if an I/O error occurs. - * @since 3.4 - */ - public FTPFile mdtmFile(final String pathname) throws IOException { - final String modificationTime = getModificationTime(pathname); - if (modificationTime != null) { - final FTPFile file = new FTPFile(); - file.setName(pathname); - file.setRawListing(modificationTime); - file.setTimestamp(MLSxEntryParser.parseGMTdateTime(modificationTime)); - return file; - } - return null; - } - - /** - * Merge two copystream listeners, either or both of which may be null. - * - * @param local the listener used by this class, may be null - * @return a merged listener or a single listener or null - * @since 3.0 - */ - private CopyStreamListener mergeListeners(final CopyStreamListener local) { - if (local == null) { - return copyStreamListener; - } - if (copyStreamListener == null) { - return local; - } - // Both are non-null - final CopyStreamAdapter merged = new CopyStreamAdapter(); - merged.addCopyStreamListener(local); - merged.addCopyStreamListener(copyStreamListener); - return merged; - } - - /** - * Generate a directory listing for the current directory using the MLSD command. - * - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir() throws IOException - { - return mlistDir(null); - } - - /** - * Generate a directory listing using the MLSD command. - * - * @param pathname the directory name, may be {@code null} - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir(final String pathname) throws IOException { - return initiateMListParsing(pathname).getFiles(); - } - - /** - * Generate a directory listing using the MLSD command. - * - * @param pathname the directory name, may be {@code null} - * @param filter the filter to apply to the responses - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir(final String pathname, final FTPFileFilter filter) throws IOException { - return initiateMListParsing(pathname).getFiles(filter); - } - - /** - * Get file details using the MLST command - * - * @param pathname the file or directory to list, may be {@code null} - * @return the file details, may be {@code null} - * @throws IOException on error - * @since 3.0 - */ - public FTPFile mlistFile(final String pathname) throws IOException - { - final boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname)); - if (success){ - String reply = getReplyString(1); - // some FTP server reply not contains space before fact(s) - if(reply.charAt(0) != ' ') { reply = " " + reply; } - /* check the response makes sense. - * Must have space before fact(s) and between fact(s) and file name - * Fact(s) can be absent, so at least 3 chars are needed. - */ - if (reply.length() < 3) { - throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'"); - } - // some FTP server reply contains more than one space before fact(s) - final String entry = reply.replaceAll("^\\s+", ""); // skip leading space for parser - return MLSxEntryParser.parseEntry(entry); - } - return null; - } - - /** - * Returns the pathname of the current working directory. - * - * @return The pathname of the current working directory. If it cannot - * be obtained, returns null. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String printWorkingDirectory() throws IOException - { - if (pwd() != FTPReply.PATHNAME_CREATED) { - return null; - } - - return parsePathname(_replyLines.get( _replyLines.size() - 1)); - } - - /** - * Reinitialize the FTP session. Not all FTP servers support this - * command, which issues the FTP REIN command. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.4 (made public) - */ - public boolean reinitialize() throws IOException - { - rein(); - - if (FTPReply.isPositiveCompletion(_replyCode) || - (FTPReply.isPositivePreliminary(_replyCode) && - FTPReply.isPositiveCompletion(getReply()))) - { - - initDefaults(); - - return true; - } - - return false; - } - - // For server to server transfers - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to append to a given file on - * the other server. The other server must have had a - * remoteRetrieve issued to it by another FTPClient. - * - * @param fileName The name of the file to be appended to, or if the - * file does not exist, the name to call the file being stored. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteAppend(final String fileName) throws IOException - { - if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(appe(fileName)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to retrieve a given file from - * the other server. - * - * @param fileName The name of the file to retrieve. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteRetrieve(final String fileName) throws IOException - { - if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(retr(fileName)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using the given file name. The other server must - * have had a remoteRetrieve issued to it by another - * FTPClient. - * - * @param fileName The name to call the file that is to be stored. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStore(final String fileName) throws IOException - { - if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stor(fileName)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique file name. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. Many FTP servers require that a base - * file name be given from which the unique file name can be derived. For - * those servers use the other version of remoteStoreUnique - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStoreUnique() throws IOException - { - if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stou()); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique file name based on the given file name. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. - * - * @param fileName The name on which to base the file name of the file - * that is to be stored. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStoreUnique(final String fileName) throws IOException - { - if (dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE || - dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stou(fileName)); - } - return false; - } - - /** - * Removes a directory on the FTP server (if empty). - * - * @param pathname The pathname of the directory to remove. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean removeDirectory(final String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(rmd(pathname)); - } - - /** - * Renames a remote file. - * - * @param from The name of the remote file to rename. - * @param to The new name of the remote file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean rename(final String from, final String to) throws IOException - { - if (!FTPReply.isPositiveIntermediate(rnfr(from))) { - return false; - } - - return FTPReply.isPositiveCompletion(rnto(to)); - } - - /** - * Restart a STREAM_TRANSFER_MODE file transfer starting - * from the given offset. This will only work on FTP servers supporting - * the REST comand for the stream transfer mode. However, most FTP - * servers support this. Any subsequent file transfer will start - * reading or writing the remote file from the indicated offset. - * - * @param offset The offset into the remote file at which to start the - * next file transfer. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.1 (changed from private to protected) - */ - protected boolean restart(final long offset) throws IOException - { - restartOffset = 0; - return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); - } - - /** - * Retrieves a named file from the server and writes it to the given - * OutputStream. This method does NOT close the given OutputStream. - * If the current file type is ASCII, line separators in the file are - * converted to the local representation. - *

- * Note: if you have used {@link #setRestartOffset(long)}, - * the file data will start from the selected offset. - * @param remote The name of the remote file. - * @param local The local OutputStream to which to write the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws org.apache.commons.net.io.CopyStreamException - * If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean retrieveFile(final String remote, final OutputStream local) - throws IOException - { - return _retrieveFile(FTPCmd.RETR.getCommand(), remote, local); - } - - /** - * Returns an InputStream from which a named file from the server - * can be read. If the current file type is ASCII, the returned - * InputStream will convert line separators in the file to - * the local representation. You must close the InputStream when you - * finish reading from it. The InputStream itself will take care of - * closing the parent data connection socket upon being closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - *

- * Note: if you have used {@link #setRestartOffset(long)}, - * the file data will start from the selected offset. - * - * @param remote The name of the remote file. - * @return An InputStream from which the remote file can be read. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public InputStream retrieveFileStream(final String remote) throws IOException - { - return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote); - } - - - /** - * Sends a NOOP command to the FTP server. This is useful for preventing - * server timeouts. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendNoOp() throws IOException - { - return FTPReply.isPositiveCompletion(noop()); - } - - /** - * Send a site specific command. - * @param arguments The site specific command and arguments. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendSiteCommand(final String arguments) throws IOException - { - return FTPReply.isPositiveCompletion(site(arguments)); - } - - /** - * Set the external IP address in active mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The external IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - * @since 2.2 - */ - public void setActiveExternalIPAddress(final String ipAddress) throws UnknownHostException - { - this.activeExternalHost = InetAddress.getByName(ipAddress); - } - - /** - * Set the client side port range in active mode. - * - * @param minPort The lowest available port (inclusive). - * @param maxPort The highest available port (inclusive). - * @since 2.2 - */ - public void setActivePortRange(final int minPort, final int maxPort) - { - this.activeMinPort = minPort; - this.activeMaxPort = maxPort; - } - - /** - * Enables or disables automatic server encoding detection (only UTF-8 supported). - *

- * Does not affect existing connections; must be invoked before a connection is established. - * - * @param autodetect If true, automatic server encoding detection will be enabled. - */ - public void setAutodetectUTF8(final boolean autodetect) - { - autodetectEncoding = autodetect; - } - - /** - * Set the internal buffer size for buffered data streams. - * - * @param bufSize The size of the buffer. Use a non-positive value to use the default. - */ - public void setBufferSize(final int bufSize) { - bufferSize = bufSize; - } - - /** - * Sets how long to wait for control keep-alive message replies. - * - * @param timeoutMillis number of milliseconds to wait (defaults to 1000) - * @since 3.0 - * @see #setControlKeepAliveTimeout(long) - */ - public void setControlKeepAliveReplyTimeout(final int timeoutMillis) { - controlKeepAliveReplyTimeoutMillis = timeoutMillis; - } - - /** - * Set the time to wait between sending control connection keepalive messages - * when processing file upload or download. - *

- * See the class Javadoc section "Control channel keep-alive feature:" - * - * @param controlIdleSeconds the wait (in seconds) between keepalive messages. Zero (or less) disables. - * @since 3.0 - * @see #setControlKeepAliveReplyTimeout(int) - */ - public void setControlKeepAliveTimeout(final long controlIdleSeconds){ - controlKeepAliveTimeoutMillis = controlIdleSeconds * 1000; - } - - /** - * Set the listener to be used when performing store/retrieve operations. - * The default value (if not set) is {@code null}. - * - * @param listener to be used, may be {@code null} to disable - * @since 3.0 - */ - public void setCopyStreamListener(final CopyStreamListener listener){ - copyStreamListener = listener; - } - - /** - * Sets the timeout in milliseconds to use when reading from the - * data connection. This timeout will be set immediately after - * opening the data connection, provided that the value is ≥ 0. - *

- * Note: the timeout will also be applied when calling accept() - * whilst establishing an active local data connection. - * @param timeoutMillis The default timeout in milliseconds that is used when - * opening a data connection socket. The value 0 means an infinite timeout. - */ - public void setDataTimeout(final int timeoutMillis) - { - dataTimeoutMillis = timeoutMillis; - } - - /** - * Sets the file structure. The default structure is - * FTP.FILE_STRUCTURE if this method is never called - * or if a connect method is called. - * - * @param structure The structure of the file (one of the FTP class - * _STRUCTURE constants). - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileStructure(final int structure) throws IOException - { - if (FTPReply.isPositiveCompletion(stru(structure))) - { - fileStructure = structure; - return true; - } - return false; - } - - /** - * Sets the transfer mode. The default transfer mode - * FTP.STREAM_TRANSFER_MODE if this method is never called - * or if a connect method is called. - * - * @param mode The new transfer mode to use (one of the FTP class - * _TRANSFER_MODE constants). - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileTransferMode(final int mode) throws IOException - { - if (FTPReply.isPositiveCompletion(mode(mode))) - { - fileTransferMode = mode; - return true; - } - return false; - } - - /** - * Sets the file type to be transferred. This should be one of - * FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, - * etc. The file type only needs to be set when you want to change the - * type. After changing it, the new type stays in effect until you change - * it again. The default file type is FTP.ASCII_FILE_TYPE - * if this method is never called. - *
- * The server default is supposed to be ASCII (see RFC 959), however many - * ftp servers default to BINARY. To ensure correct operation with all servers, - * always specify the appropriate file type after connecting to the server. - *
- *

- * N.B. currently calling any connect method will reset the type to - * FTP.ASCII_FILE_TYPE. - * @param fileType The _FILE_TYPE constant indicating the - * type of file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileType(final int fileType) throws IOException - { - if (FTPReply.isPositiveCompletion(type(fileType))) - { - this.fileType = fileType; - this.fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - return true; - } - return false; - } - - /** - * Sets the file type to be transferred and the format. The type should be - * one of FTP.ASCII_FILE_TYPE , - * FTP.BINARY_FILE_TYPE , etc. The file type only needs to - * be set when you want to change the type. After changing it, the new - * type stays in effect until you change it again. The default file type - * is FTP.ASCII_FILE_TYPE if this method is never called. - *
- * The server default is supposed to be ASCII (see RFC 959), however many - * ftp servers default to BINARY. To ensure correct operation with all servers, - * always specify the appropriate file type after connecting to the server. - *
- * The format should be one of the FTP class TEXT_FORMAT - * constants, or if the type is FTP.LOCAL_FILE_TYPE , the - * format should be the byte size for that type. The default format - * is FTP.NON_PRINT_TEXT_FORMAT if this method is never - * called. - *

- * N.B. currently calling any connect method will reset the type to - * FTP.ASCII_FILE_TYPE and the formatOrByteSize to FTP.NON_PRINT_TEXT_FORMAT. - * - * @param fileType The _FILE_TYPE constant indicating the - * type of file. - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileType(final int fileType, final int formatOrByteSize) - throws IOException - { - if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) - { - this.fileType = fileType; - this.fileFormat = formatOrByteSize; - return true; - } - return false; - } - - /** - * You can set this to true if you would like to get hidden files when {@link #listFiles} too. - * A LIST -a will be issued to the ftp server. - * It depends on your ftp server if you need to call this method, also dont expect to get rid - * of hidden files if you call this method with "false". - * - * @param listHiddenFiles true if hidden files should be listed - * @since 2.0 - */ - public void setListHiddenFiles(final boolean listHiddenFiles) { - this.listHiddenFiles = listHiddenFiles; - } - - /** - * Issue the FTP MFMT command (not supported by all servers) which sets the last - * modified time of a file. - * - * The timestamp should be in the form YYYYMMDDhhmmss. It should also - * be in GMT, but not all servers honor this. - * - * An FTP server would indicate its support of this feature by including "MFMT" - * in its response to the FEAT command, which may be retrieved by FTPClient.features() - * - * @param pathname The file path for which last modified time is to be changed. - * @param timeval The timestamp to set to, in YYYYMMDDhhmmss format. - * @return true if successfully set, false if not - * @throws IOException if an I/O error occurs. - * @since 2.2 - * @see http://tools.ietf.org/html/draft-somers-ftp-mfxx-04 - */ - public boolean setModificationTime(final String pathname, final String timeval) throws IOException { - return (FTPReply.isPositiveCompletion(mfmt(pathname, timeval))); - } - - /** - * set the factory used for parser creation to the supplied factory object. - * - * @param parserFactory - * factory object used to create FTPFileEntryParsers - * - * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ - public void setParserFactory(final FTPFileEntryParserFactory parserFactory) { - this.parserFactory = parserFactory; - } - - /** - * Set the local IP address to use in passive mode. - * Useful when there are multiple network cards. - * - * @param inetAddress The local IP address of this machine. - */ - public void setPassiveLocalIPAddress(final InetAddress inetAddress) - { - this.passiveLocalHost = inetAddress; - } - - /** - * Set the local IP address to use in passive mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The local IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - */ - public void setPassiveLocalIPAddress(final String ipAddress) throws UnknownHostException - { - this.passiveLocalHost = InetAddress.getByName(ipAddress); - } - - /** - * Enables or disables passive mode NAT workaround. - * If enabled, a site-local PASV mode reply address will be replaced with the - * remote host address to which the PASV mode request was sent - * (unless that is also a site local address). - * This gets around the problem that some NAT boxes may change the - * reply. - * - * The default is true, i.e. site-local replies are replaced. - * @param enabled true to enable replacing internal IP's in passive - * mode. - * @deprecated (3.6) use {@link #setPassiveNatWorkaroundStrategy(HostnameResolver)} instead - */ - @Deprecated - public void setPassiveNatWorkaround(final boolean enabled) { - if (enabled) { - this.passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); - } else { - this.passiveNatWorkaroundStrategy = null; - } - } - - /** - * Set the workaround strategy to replace the PASV mode reply addresses. - * This gets around the problem that some NAT boxes may change the reply. - * - * The default implementation is {@code NatServerResolverImpl}, i.e. site-local - * replies are replaced. - * @param resolver strategy to replace internal IP's in passive mode - * or null to disable the workaround (i.e. use PASV mode reply address.) - * @since 3.6 - */ - public void setPassiveNatWorkaroundStrategy(final HostnameResolver resolver) { - this.passiveNatWorkaroundStrategy = resolver; - } - - /** - * Sets the value to be used for the data socket SO_RCVBUF option. - * If the value is positive, the option will be set when the data socket has been created. - * - * @param bufSize The size of the buffer, zero or negative means the value is ignored. - * @since 3.3 - */ - public void setReceieveDataSocketBufferSize(final int bufSize) { - receiveDataSocketBufferSize = bufSize; - } - - /** - * Enable or disable verification that the remote host taking part - * of a data connection is the same as the host to which the control - * connection is attached. The default is for verification to be - * enabled. You may set this value at any time, whether the - * FTPClient is currently connected or not. - * - * @param enable True to enable verification, false to disable verification. - */ - public void setRemoteVerificationEnabled(final boolean enable) - { - remoteVerificationEnabled = enable; - } - - /** - * Set the external IP address to report in EPRT/PORT commands in active mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The external IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - * @since 3.1 - * @see #getReportHostAddress() - */ - public void setReportActiveExternalIPAddress(final String ipAddress) throws UnknownHostException - { - this.reportActiveExternalHost = InetAddress.getByName(ipAddress); - } - - /** - * Sets the restart offset for file transfers. - *

- * The restart command is not sent to the server immediately. - * It is sent when a data connection is created as part of a - * subsequent command. - * The restart marker is reset to zero after use. - *

- *

- * Note: This method should only be invoked immediately prior to - * the transfer to which it applies. - * - * @param offset The offset into the remote file at which to start the - * next file transfer. This must be a value greater than or - * equal to zero. - */ - public void setRestartOffset(final long offset) - { - if (offset >= 0) { - restartOffset = offset; - } - } - - /** - * Sets the value to be used for the data socket SO_SNDBUF option. - * If the value is positive, the option will be set when the data socket has been created. - * - * @param bufSize The size of the buffer, zero or negative means the value is ignored. - * @since 3.3 - */ - public void setSendDataSocketBufferSize(final int bufSize) { - sendDataSocketBufferSize = bufSize; - } - - /** - * Set whether to use EPSV with IPv4. - * Might be worth enabling in some circumstances. - * - * For example, when using IPv4 with NAT it - * may work with some rare configurations. - * E.g. if FTP server has a static PASV address (external network) - * and the client is coming from another internal network. - * In that case the data connection after PASV command would fail, - * while EPSV would make the client succeed by taking just the port. - * - * @param selected value to set. - * @since 2.2 - */ - public void setUseEPSVwithIPv4(final boolean selected) { - this.useEPSVwithIPv4 = selected; - } - - private boolean storeFile(final FTPCmd command, final String remote, final InputStream local) - throws IOException - { - return _storeFile(command.getCommand(), remote, local); - } - - /** - * Stores a file on the server using the given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name to give the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws org.apache.commons.net.io.CopyStreamException - * If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeFile(final String remote, final InputStream local) - throws IOException - { - return storeFile(FTPCmd.STOR, remote, local); - } - - private OutputStream storeFileStream(final FTPCmd command, final String remote) - throws IOException - { - return _storeFileStream(command.getCommand(), remote); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name to give the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeFileStream(final String remote) throws IOException - { - return storeFileStream(FTPCmd.STOR, remote); - } - - /** - * Stores a file on the server using a unique name assigned by the - * server and taking input from the given InputStream. This method does - * NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws org.apache.commons.net.io.CopyStreamException - * If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeUniqueFile(final InputStream local) throws IOException - { - return storeFile(FTPCmd.STOU, null, local); - } - - /** - * Stores a file on the server using a unique name derived from the - * given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name on which to base the unique name given to - * the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws org.apache.commons.net.io.CopyStreamException - * If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeUniqueFile(final String remote, final InputStream local) - throws IOException - { - return storeFile(FTPCmd.STOU, remote, local); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name assigned by the server. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeUniqueFileStream() throws IOException - { - return storeFileStream(FTPCmd.STOU, null); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name derived from the given name. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name on which to base the unique name given to - * the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeUniqueFileStream(final String remote) throws IOException - { - return storeFileStream(FTPCmd.STOU, remote); - } - - /** - * Issue the FTP SMNT command. - * - * @param pathname The pathname to mount. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean structureMount(final String pathname) throws IOException - { - return FTPReply.isPositiveCompletion(smnt(pathname)); - } -} diff --git a/src/org/apache/commons/net/ftp/FTPClientConfig.java b/src/org/apache/commons/net/ftp/FTPClientConfig.java deleted file mode 100644 index 3cab2cb0..00000000 --- a/src/org/apache/commons/net/ftp/FTPClientConfig.java +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.text.DateFormatSymbols; -import java.util.Collection; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeMap; - -/** - *

- * This class implements an alternate means of configuring the - * {@link org.apache.commons.net.ftp.FTPClient FTPClient} object and - * also subordinate objects which it uses. Any class implementing the - * {@link org.apache.commons.net.ftp.Configurable Configurable } - * interface can be configured by this object. - *

- * In particular this class was designed primarily to support configuration - * of FTP servers which express file timestamps in formats and languages - * other than those for the US locale, which although it is the most common - * is not universal. Unfortunately, nothing in the FTP spec allows this to - * be determined in an automated way, so manual configuration such as this - * is necessary. - *

- * This functionality was designed to allow existing clients to work exactly - * as before without requiring use of this component. This component should - * only need to be explicitly invoked by the user of this package for problem - * cases that previous implementations could not solve. - *

- *

Examples of use of FTPClientConfig

- * Use cases: - * You are trying to access a server that - *
    - *
  • lists files with timestamps that use month names in languages other - * than English
  • - *
  • lists files with timestamps that use date formats other - * than the American English "standard" MM dd yyyy
  • - *
  • is in different time zone and you need accurate timestamps for - * dependency checking as in Ant
  • - *
- *

- * Unpaged (whole list) access on a UNIX server that uses French month names - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("fr");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Paged access on a UNIX server that uses Danish month names - * and "European" date formatting in Denmark's time zone, when you - * are in some other time zone. - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("da");
- *    conf.setDefaultDateFormat("d MMM yyyy");
- *    conf.setRecentDateFormat("d MMM HH:mm");
- *    conf.setTimeZoneId("Europe/Copenhagen");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * Unpaged (whole list) access on a VMS server that uses month names - * in a language not {@link #getSupportedLanguageCodes() supported} by the system. - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS);
- *    conf.setShortMonthNames(
- *        "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Unpaged (whole list) access on a Windows-NT server in a different time zone. - * (Note, since the NT Format uses numeric date formatting, language issues - * are irrelevant here). - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- * Unpaged (whole list) access on a Windows-NT server in a different time zone - * but which has been configured to use a unix-style listing format. - *
- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- * - * @since 1.4 - * @see org.apache.commons.net.ftp.Configurable - * @see org.apache.commons.net.ftp.FTPClient - * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) - * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl - */ -public class FTPClientConfig -{ - - /** - * Identifier by which a unix-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_UNIX = "UNIX"; - - /** - * Identifier for alternate UNIX parser; same as {@link #SYST_UNIX} but leading spaces are - * trimmed from file names. This is to maintain backwards compatibility with - * the original behavior of the parser which ignored multiple spaces between the date - * and the start of the file name. - * @since 3.4 - */ - public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; - - /** - * Identifier by which a vms-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_VMS = "VMS"; - - /** - * Identifier by which a WindowsNT-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_NT = "WINDOWS"; - - /** - * Identifier by which an OS/2-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS2 = "OS/2"; - - /** - * Identifier by which an OS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS400 = "OS/400"; - - /** - * Identifier by which an AS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_AS400 = "AS/400"; - - /** - * Identifier by which an MVS-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_MVS = "MVS"; - - /** - * Some servers return an "UNKNOWN Type: L8" message - * in response to the SYST command. We set these to be a Unix-type system. - * This may happen if the ftpd in question was compiled without system - * information. - * - * NET-230 - Updated to be UPPERCASE so that the check done in - * createFileEntryParser will succeed. - * - * @since 1.5 - */ - public static final String SYST_L8 = "TYPE: L8"; - - /** - * Identifier by which an Netware-based ftp server is known throughout - * the commons-net ftp system. - * - * @since 1.5 - */ - public static final String SYST_NETWARE = "NETWARE"; - - /** - * Identifier by which a Mac pre OS-X -based ftp server is known throughout - * the commons-net ftp system. - * - * @since 3.1 - */ - // Full string is "MACOS Peter's Server"; the substring below should be enough - public static final String SYST_MACOS_PETER = "MACOS PETER"; // NET-436 - - private final String serverSystemKey; - private String defaultDateFormatStr; - private String recentDateFormatStr; - private boolean lenientFutureDates = true; // NET-407 - private String serverLanguageCode; - private String shortMonthNames; - private String serverTimeZoneId; - private boolean saveUnparseableEntries; - - - /** - * The main constructor for an FTPClientConfig object - * @param systemKey key representing system type of the server being - * connected to. See {@link #getServerSystemKey() serverSystemKey} - * If set to the empty string, then FTPClient uses the system type returned by the server. - * However this is not recommended for general use; - * the correct system type should be set if it is known. - */ - public FTPClientConfig(final String systemKey) { - this.serverSystemKey = systemKey; - } - - /** - * Convenience constructor mainly for use in testing. - * Constructs a UNIX configuration. - */ - public FTPClientConfig() { - this(SYST_UNIX); - } - - /** - * Constructor which allows setting of the format string member fields - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @since 3.6 - */ - public FTPClientConfig(final String systemKey, - final String defaultDateFormatStr, - final String recentDateFormatStr) - { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.recentDateFormatStr = recentDateFormatStr; - } - - /** - * Constructor which allows setting of most member fields - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @param serverLanguageCode See - * {@link #setServerLanguageCode(String) serverLanguageCode} - * @param shortMonthNames See - * {@link #setShortMonthNames(String) shortMonthNames} - * @param serverTimeZoneId See - * {@link #setServerTimeZoneId(String) serverTimeZoneId} - */ - public FTPClientConfig(final String systemKey, - final String defaultDateFormatStr, - final String recentDateFormatStr, - final String serverLanguageCode, - final String shortMonthNames, - final String serverTimeZoneId) - { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.recentDateFormatStr = recentDateFormatStr; - this.serverLanguageCode = serverLanguageCode; - this.shortMonthNames = shortMonthNames; - this.serverTimeZoneId = serverTimeZoneId; - } - - /** - * Constructor which allows setting of all member fields - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @param serverLanguageCode See - * {@link #setServerLanguageCode(String) serverLanguageCode} - * @param shortMonthNames See - * {@link #setShortMonthNames(String) shortMonthNames} - * @param serverTimeZoneId See - * {@link #setServerTimeZoneId(String) serverTimeZoneId} - * @param lenientFutureDates See - * {@link #setLenientFutureDates(boolean) lenientFutureDates} - * @param saveUnparseableEntries See - * {@link #setUnparseableEntries(boolean) saveUnparseableEntries} - */ - public FTPClientConfig(final String systemKey, - final String defaultDateFormatStr, - final String recentDateFormatStr, - final String serverLanguageCode, - final String shortMonthNames, - final String serverTimeZoneId, - final boolean lenientFutureDates, - final boolean saveUnparseableEntries) - { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.lenientFutureDates = lenientFutureDates; - this.recentDateFormatStr = recentDateFormatStr; - this.saveUnparseableEntries = saveUnparseableEntries; - this.serverLanguageCode = serverLanguageCode; - this.shortMonthNames = shortMonthNames; - this.serverTimeZoneId = serverTimeZoneId; - } - - // Copy constructor, intended for use by FTPClient only - FTPClientConfig(final String systemKey, final FTPClientConfig config) { - this.serverSystemKey = systemKey; - this.defaultDateFormatStr = config.defaultDateFormatStr; - this.lenientFutureDates = config.lenientFutureDates; - this.recentDateFormatStr = config.recentDateFormatStr; - this.saveUnparseableEntries = config.saveUnparseableEntries; - this.serverLanguageCode = config.serverLanguageCode; - this.serverTimeZoneId = config.serverTimeZoneId; - this.shortMonthNames = config.shortMonthNames; - } - - /** - * Copy constructor - * @param config source - * @since 3.6 - */ - public FTPClientConfig(final FTPClientConfig config) { - this.serverSystemKey = config.serverSystemKey; - this.defaultDateFormatStr = config.defaultDateFormatStr; - this.lenientFutureDates = config.lenientFutureDates; - this.recentDateFormatStr = config.recentDateFormatStr; - this.saveUnparseableEntries = config.saveUnparseableEntries; - this.serverLanguageCode = config.serverLanguageCode; - this.serverTimeZoneId = config.serverTimeZoneId; - this.shortMonthNames = config.shortMonthNames; - } - - private static final Map LANGUAGE_CODE_MAP = new TreeMap<>(); - static { - - // if there are other commonly used month name encodings which - // correspond to particular locales, please add them here. - - - - // many locales code short names for months as all three letters - // these we handle simply. - LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); - LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); - LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); - LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish - LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese - LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish - LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish - LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian - LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch - LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian - LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian - LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian - LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak - LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian - - - // some don't - LANGUAGE_CODE_MAP.put("fr", - "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french - - } - - /** - * Getter for the serverSystemKey property. This property - * specifies the general type of server to which the client connects. - * Should be either one of the FTPClientConfig.SYST_* codes - * or else the fully qualified class name of a parser implementing both - * the FTPFileEntryParser and Configurable - * interfaces. - * @return Returns the serverSystemKey property. - */ - public String getServerSystemKey() { - return serverSystemKey; - } - - /** - * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * property. - * @return Returns the defaultDateFormatStr property. - */ - public String getDefaultDateFormatStr() { - return defaultDateFormatStr; - } - - /** - * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. - * @return Returns the recentDateFormatStr property. - */ - - public String getRecentDateFormatStr() { - return recentDateFormatStr; - } - - /** - * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. - * @return Returns the serverTimeZoneId property. - */ - public String getServerTimeZoneId() { - return serverTimeZoneId; - } - - /** - *

- * getter for the {@link #setShortMonthNames(String) shortMonthNames} - * property. - *

- * @return Returns the shortMonthNames. - */ - public String getShortMonthNames() { - return shortMonthNames; - } - - /** - *

- * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. - *

- * @return Returns the serverLanguageCode property. - */ - public String getServerLanguageCode() { - return serverLanguageCode; - } - - /** - *

- * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. - *

- * @return Returns the lenientFutureDates (default true). - * @since 1.5 - */ - public boolean isLenientFutureDates() { - return lenientFutureDates; - } - /** - *

- * setter for the defaultDateFormatStr property. This property - * specifies the main date format that will be used by a parser configured - * by this configuration to parse file timestamps. If this is not - * specified, such a parser will use as a default value, the most commonly - * used format which will be in as used in en_US locales. - *

- * This should be in the format described for - * java.text.SimpleDateFormat. - * property. - *

- * @param defaultDateFormatStr The defaultDateFormatStr to set. - */ - public void setDefaultDateFormatStr(final String defaultDateFormatStr) { - this.defaultDateFormatStr = defaultDateFormatStr; - } - - /** - *

- * setter for the recentDateFormatStr property. This property - * specifies a secondary date format that will be used by a parser - * configured by this configuration to parse file timestamps, typically - * those less than a year old. If this is not specified, such a parser - * will not attempt to parse using an alternate format. - *

- *

- * This is used primarily in unix-based systems. - *

- *

- * This should be in the format described for - * java.text.SimpleDateFormat. - *

- * @param recentDateFormatStr The recentDateFormatStr to set. - */ - public void setRecentDateFormatStr(final String recentDateFormatStr) { - this.recentDateFormatStr = recentDateFormatStr; - } - - /** - *

- * setter for the lenientFutureDates property. This boolean property - * (default: true) only has meaning when a - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property - * has been set. In that case, if this property is set true, then the - * parser, when it encounters a listing parseable with the recent date - * format, will only consider a date to belong to the previous year if - * it is more than one day in the future. This will allow all - * out-of-synch situations (whether based on "slop" - i.e. servers simply - * out of synch with one another or because of time zone differences - - * but in the latter case it is highly recommended to use the - * {@link #setServerTimeZoneId(String) serverTimeZoneId} property - * instead) to resolve correctly. - *

- * This is used primarily in unix-based systems. - *

- * @param lenientFutureDates set true to compensate for out-of-synch - * conditions. - */ - public void setLenientFutureDates(final boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } - /** - *

- * setter for the serverTimeZoneId property. This property - * allows a time zone to be specified corresponding to that known to be - * used by an FTP server in file listings. This might be particularly - * useful to clients such as Ant that try to use these timestamps for - * dependency checking. - *

- * This should be one of the identifiers used by - * java.util.TimeZone to refer to time zones, for example, - * America/Chicago or Asia/Rangoon. - *

- * @param serverTimeZoneId The serverTimeZoneId to set. - */ - public void setServerTimeZoneId(final String serverTimeZoneId) { - this.serverTimeZoneId = serverTimeZoneId; - } - - /** - *

- * setter for the shortMonthNames property. - * This property allows the user to specify a set of month names - * used by the server that is different from those that may be - * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} - * property. - *

- * This should be a string containing twelve strings each composed of - * three characters, delimited by pipe (|) characters. Currently, - * only 8-bit ASCII characters are known to be supported. For example, - * a set of month names used by a hypothetical Icelandic FTP server might - * conceivably be specified as - * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". - *

- * @param shortMonthNames The value to set to the shortMonthNames property. - */ - public void setShortMonthNames(final String shortMonthNames) { - this.shortMonthNames = shortMonthNames; - } - - /** - *

- * setter for the serverLanguageCode property. This property allows - * user to specify a - * - * two-letter ISO-639 language code that will be used to - * configure the set of month names used by the file timestamp parser. - * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} - * is specified, parsing will assume English month names, which may or - * may not be significant, depending on whether the date format(s) - * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using - * numeric or alphabetic month names. - *

- *

If the code supplied is not supported here, en_US - * month names will be used. We are supporting here those language - * codes which, when a java.util.Locale is constucted - * using it, and a java.text.SimpleDateFormat is - * constructed using that Locale, the array returned by the - * SimpleDateFormat's getShortMonths() method consists - * solely of three 8-bit ASCII character strings. Additionally, - * languages which do not meet this requirement are included if a - * common alternative set of short month names is known to be used. - * This means that users who can tell us of additional such encodings - * may get them added to the list of supported languages by contacting - * the Apache Commons Net team. - *

- *

- * Please note that this attribute will NOT be used to determine a - * locale-based date format for the language. - * Experience has shown that many if not most FTP servers outside the - * United States employ the standard en_US date format - * orderings of MMM d yyyy and MMM d HH:mm - * and attempting to deduce this automatically here would cause more - * problems than it would solve. The date format must be changed - * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. - *

- * @param serverLanguageCode The value to set to the serverLanguageCode property. - */ - public void setServerLanguageCode(final String serverLanguageCode) { - this.serverLanguageCode = serverLanguageCode; - } - - /** - * Looks up the supplied language code in the internally maintained table of - * language codes. Returns a DateFormatSymbols object configured with - * short month names corresponding to the code. If there is no corresponding - * entry in the table, the object returned will be that for - * Locale.US - * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} - * @return a DateFormatSymbols object configured with short month names - * corresponding to the supplied code, or with month names for - * Locale.US if there is no corresponding entry in the internal - * table. - */ - public static DateFormatSymbols lookupDateFormatSymbols(final String languageCode) - { - final Object lang = LANGUAGE_CODE_MAP.get(languageCode); - if (lang != null) { - if (lang instanceof Locale) { - return new DateFormatSymbols((Locale) lang); - } else if (lang instanceof String){ - return getDateFormatSymbols((String) lang); - } - } - return new DateFormatSymbols(Locale.US); - } - - /** - * Returns a DateFormatSymbols object configured with short month names - * as in the supplied string - * @param shortmonths This should be as described in - * {@link #setShortMonthNames(String) shortMonthNames} - * @return a DateFormatSymbols object configured with short month names - * as in the supplied string - */ - public static DateFormatSymbols getDateFormatSymbols(final String shortmonths) - { - final String[] months = splitShortMonthString(shortmonths); - final DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); - dfs.setShortMonths(months); - return dfs; - } - - private static String[] splitShortMonthString(final String shortmonths) { - final StringTokenizer st = new StringTokenizer(shortmonths, "|"); - final int monthcnt = st.countTokens(); - if (12 != monthcnt) { - throw new IllegalArgumentException( - "expecting a pipe-delimited string containing 12 tokens"); - } - final String[] months = new String[13]; - int pos = 0; - while(st.hasMoreTokens()) { - months[pos++] = st.nextToken(); - } - months[pos]=""; - return months; - } - - /** - * Returns a Collection of all the language codes currently supported - * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} - * for a functional descrption of language codes within this system. - * - * @return a Collection of all the language codes currently supported - * by this class - */ - public static Collection getSupportedLanguageCodes() { - return LANGUAGE_CODE_MAP.keySet(); - } - - /** - * Allow list parsing methods to create basic FTPFile entries if parsing fails. - *

- * In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} - * and {@link FTPFile#isValid()} will return {@code false} - * @param saveUnparseable if true, then create FTPFile entries if parsing fails - * @since 3.4 - */ - public void setUnparseableEntries(final boolean saveUnparseable) { - this.saveUnparseableEntries = saveUnparseable; - } - - /** - * @return true if list parsing should return FTPFile entries even for unparseable response lines - *

- * If true, the FTPFile for any unparseable entries will contain only the unparsed entry - * {@link FTPFile#getRawListing()} and {@link FTPFile#isValid()} will return {@code false} - * @since 3.4 - */ - public boolean getUnparseableEntries() { - return this.saveUnparseableEntries; - } - -} diff --git a/src/org/apache/commons/net/ftp/FTPCmd.java b/src/org/apache/commons/net/ftp/FTPCmd.java deleted file mode 100644 index 5ce85bd9..00000000 --- a/src/org/apache/commons/net/ftp/FTPCmd.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.ftp; - -/** -* @since 3.3 - */ -public enum FTPCmd { - ABOR, - ACCT, - ALLO, - APPE, - CDUP, - CWD, - DELE, - EPRT, - EPSV, - FEAT, - HELP, - LIST, - MDTM, - MFMT, - MKD, - MLSD, - MLST, - MODE, - NLST, - NOOP, - PASS, - PASV, - PORT, - PWD, - QUIT, - REIN, - REST, - RETR, - RMD, - RNFR, - RNTO, - SITE, - /** @since 3.7 */ - SIZE, - SMNT, - STAT, - STOR, - STOU, - STRU, - SYST, - TYPE, - USER, - ; - - // Aliases - - public static final FTPCmd ABORT = ABOR; - public static final FTPCmd ACCOUNT = ACCT; - public static final FTPCmd ALLOCATE = ALLO; - public static final FTPCmd APPEND = APPE; - public static final FTPCmd CHANGE_TO_PARENT_DIRECTORY = CDUP; - public static final FTPCmd CHANGE_WORKING_DIRECTORY = CWD; - public static final FTPCmd DATA_PORT = PORT; - public static final FTPCmd DELETE = DELE; - public static final FTPCmd FEATURES = FEAT; - public static final FTPCmd FILE_STRUCTURE = STRU; - public static final FTPCmd GET_MOD_TIME = MDTM; - public static final FTPCmd LOGOUT = QUIT; - public static final FTPCmd MAKE_DIRECTORY = MKD; - public static final FTPCmd MOD_TIME = MDTM; - public static final FTPCmd NAME_LIST = NLST; - public static final FTPCmd PASSIVE = PASV; - public static final FTPCmd PASSWORD = PASS; - public static final FTPCmd PRINT_WORKING_DIRECTORY = PWD; - public static final FTPCmd REINITIALIZE = REIN; - public static final FTPCmd REMOVE_DIRECTORY = RMD; - public static final FTPCmd RENAME_FROM = RNFR; - public static final FTPCmd RENAME_TO = RNTO; - public static final FTPCmd REPRESENTATION_TYPE = TYPE; - public static final FTPCmd RESTART = REST; - public static final FTPCmd RETRIEVE = RETR; - public static final FTPCmd SET_MOD_TIME = MFMT; - public static final FTPCmd SITE_PARAMETERS = SITE; - public static final FTPCmd STATUS = STAT; - public static final FTPCmd STORE = STOR; - public static final FTPCmd STORE_UNIQUE = STOU; - public static final FTPCmd STRUCTURE_MOUNT = SMNT; - public static final FTPCmd SYSTEM = SYST; - public static final FTPCmd TRANSFER_MODE = MODE; - public static final FTPCmd USERNAME = USER; - - /** - * Retrieve the FTP protocol command string corresponding to a specified - * command code. - * - * @return The FTP protcol command string corresponding to a specified - * command code. - */ - public final String getCommand() - { - return this.name(); - } - -} diff --git a/src/org/apache/commons/net/ftp/FTPCommand.java b/src/org/apache/commons/net/ftp/FTPCommand.java deleted file mode 100644 index 65811a65..00000000 --- a/src/org/apache/commons/net/ftp/FTPCommand.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/** - * FTPCommand stores a set of constants for FTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. For those who think in terms of the actual FTP commands, - * a set of constants such as {@link #USER USER } are provided - * where the constant name is the same as the FTP command. - * - * @deprecated use {@link FTPCmd} instead - */ -@Deprecated -public final class FTPCommand -{ - - public static final int USER = 0; - public static final int PASS = 1; - public static final int ACCT = 2; - public static final int CWD = 3; - public static final int CDUP = 4; - public static final int SMNT = 5; - public static final int REIN = 6; - public static final int QUIT = 7; - public static final int PORT = 8; - public static final int PASV = 9; - public static final int TYPE = 10; - public static final int STRU = 11; - public static final int MODE = 12; - public static final int RETR = 13; - public static final int STOR = 14; - public static final int STOU = 15; - public static final int APPE = 16; - public static final int ALLO = 17; - public static final int REST = 18; - public static final int RNFR = 19; - public static final int RNTO = 20; - public static final int ABOR = 21; - public static final int DELE = 22; - public static final int RMD = 23; - public static final int MKD = 24; - public static final int PWD = 25; - public static final int LIST = 26; - public static final int NLST = 27; - public static final int SITE = 28; - public static final int SYST = 29; - public static final int STAT = 30; - public static final int HELP = 31; - public static final int NOOP = 32; - /** @since 2.0 */ - public static final int MDTM = 33; - /** @since 2.2 */ - public static final int FEAT = 34; - /** @since 2.2 */ - public static final int MFMT = 35; - /** @since 2.2 */ - public static final int EPSV = 36; - /** @since 2.2 */ - public static final int EPRT = 37; - - /** - * Machine parseable list for a directory - * @since 3.0 - */ - public static final int MLSD = 38; - - /** - * Machine parseable list for a single file - * @since 3.0 - */ - public static final int MLST = 39; - - // Must agree with final entry above; used to check array size - private static final int LAST = MLST; - - public static final int USERNAME = USER; - public static final int PASSWORD = PASS; - public static final int ACCOUNT = ACCT; - public static final int CHANGE_WORKING_DIRECTORY = CWD; - public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; - public static final int STRUCTURE_MOUNT = SMNT; - public static final int REINITIALIZE = REIN; - public static final int LOGOUT = QUIT; - public static final int DATA_PORT = PORT; - public static final int PASSIVE = PASV; - public static final int REPRESENTATION_TYPE = TYPE; - public static final int FILE_STRUCTURE = STRU; - public static final int TRANSFER_MODE = MODE; - public static final int RETRIEVE = RETR; - public static final int STORE = STOR; - public static final int STORE_UNIQUE = STOU; - public static final int APPEND = APPE; - public static final int ALLOCATE = ALLO; - public static final int RESTART = REST; - public static final int RENAME_FROM = RNFR; - public static final int RENAME_TO = RNTO; - public static final int ABORT = ABOR; - public static final int DELETE = DELE; - public static final int REMOVE_DIRECTORY = RMD; - public static final int MAKE_DIRECTORY = MKD; - public static final int PRINT_WORKING_DIRECTORY = PWD; - // public static final int LIST = LIST; - public static final int NAME_LIST = NLST; - public static final int SITE_PARAMETERS = SITE; - public static final int SYSTEM = SYST; - public static final int STATUS = STAT; - //public static final int HELP = HELP; - //public static final int NOOP = NOOP; - - /** @since 2.0 */ - public static final int MOD_TIME = MDTM; - - /** @since 2.2 */ - public static final int FEATURES = FEAT; - /** @since 2.2 */ - public static final int GET_MOD_TIME = MDTM; - /** @since 2.2 */ - public static final int SET_MOD_TIME = MFMT; - - // Cannot be instantiated - private FTPCommand() - {} - - private static final String[] _commands = { - "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", - "PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", - "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", - "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", - "EPSV", "EPRT", "MLSD", "MLST" }; - - - - // default access needed for Unit test - static void checkArray(){ - final int expectedLength = LAST+1; - if (_commands.length != expectedLength) { - throw new RuntimeException("Incorrect _commands array. Should have length " - +expectedLength+" found "+_commands.length); - } - } - - /** - * Retrieve the FTP protocol command string corresponding to a specified - * command code. - * - * @param command The command code. - * @return The FTP protcol command string corresponding to a specified - * command code. - */ - public static String getCommand(final int command) - { - return _commands[command]; - } -} diff --git a/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java b/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java deleted file mode 100644 index 4306fde2..00000000 --- a/src/org/apache/commons/net/ftp/FTPConnectionClosedException.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.IOException; - -/** - * FTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an FTP connection resulting from a - * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response (FTP reply code 421) to a - * failed FTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * FTPConnectionClosedException. - * - * @see FTP - * @see FTPClient - */ - -public class FTPConnectionClosedException extends IOException -{ - - private static final long serialVersionUID = 3500547241659379952L; - - /** Constructs a FTPConnectionClosedException with no message */ - public FTPConnectionClosedException() - { - } - - /** - * Constructs a FTPConnectionClosedException with a specified message. - * - * @param message The message explaining the reason for the exception. - */ - public FTPConnectionClosedException(final String message) - { - super(message); - } - -} diff --git a/src/org/apache/commons/net/ftp/FTPFile.java b/src/org/apache/commons/net/ftp/FTPFile.java deleted file mode 100644 index 28f64dab..00000000 --- a/src/org/apache/commons/net/ftp/FTPFile.java +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.Serializable; -import java.util.Calendar; -import java.util.Date; -import java.util.Formatter; -import java.util.TimeZone; - -/** - * The FTPFile class is used to represent information about files stored on an FTP server. - * - * @see FTPFileEntryParser - * @see FTPClient#listFiles - */ -public class FTPFile implements Serializable { - - private static final long serialVersionUID = 9010790363003271996L; - - /** A constant indicating an FTPFile is a file. */ - public static final int FILE_TYPE = 0; - - /** A constant indicating an FTPFile is a directory. */ - public static final int DIRECTORY_TYPE = 1; - - /** A constant indicating an FTPFile is a symbolic link. */ - public static final int SYMBOLIC_LINK_TYPE = 2; - - /** A constant indicating an FTPFile is of unknown type. */ - public static final int UNKNOWN_TYPE = 3; - - /** A constant indicating user access permissions. */ - public static final int USER_ACCESS = 0; - - /** A constant indicating group access permissions. */ - public static final int GROUP_ACCESS = 1; - - /** A constant indicating world access permissions. */ - public static final int WORLD_ACCESS = 2; - - /** A constant indicating file/directory read permission. */ - public static final int READ_PERMISSION = 0; - - /** A constant indicating file/directory write permission. */ - public static final int WRITE_PERMISSION = 1; - /** - * A constant indicating file execute permission or directory listing permission. - */ - public static final int EXECUTE_PERMISSION = 2; - - private int type = UNKNOWN_TYPE; - - /** 0 is invalid as a link count. */ - private int hardLinkCount; - - /** 0 is valid, so use -1. */ - private long size = -1; - private String rawListing; - private String user = ""; - private String group = ""; - private String name; - private String link; - private Calendar date; - - /** If this is null, then list entry parsing failed. */ - private final boolean[] permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION] - - /** Creates an empty FTPFile. */ - public FTPFile() { - permissions = new boolean[3][3]; - } - - /** - * Constructor for use by {@link FTPListParseEngine} only. Used to create FTPFile entries for failed parses - * - * @param rawListing line that could not be parsed. - * @since 3.4 - */ - FTPFile(final String rawListing) { - this.permissions = null; // flag that entry is invalid - this.rawListing = rawListing; - } - - private char formatType() { - switch (type) { - case FILE_TYPE: - return '-'; - case DIRECTORY_TYPE: - return 'd'; - case SYMBOLIC_LINK_TYPE: - return 'l'; - default: - return '?'; - } - } - - /** - * Gets the name of the group owning the file. Sometimes this will be a string representation of the group - * number. - * - * @return The name of the group owning the file. - */ - public String getGroup() { - return group; - } - - /** - * Gets the number of hard links to this file. This is not to be confused with symbolic links. - * - * @return The number of hard links to this file. - */ - public int getHardLinkCount() { - return hardLinkCount; - } - - /** - * If the FTPFile is a symbolic link, this method returns the name of the file being pointed to by the symbolic - * link. Otherwise it returns null. - * - * @return The file pointed to by the symbolic link (null if the FTPFile is not a symbolic link). - */ - public String getLink() { - return link; - } - - /** - * Gets the name of the file. - * - * @return The name of the file. - */ - public String getName() { - return name; - } - - /** - * Gets the original FTP server raw listing used to initialize the FTPFile. - * - * @return The original FTP server raw listing used to initialize the FTPFile. - */ - public String getRawListing() { - return rawListing; - } - - /** - * Gets the file size in bytes. - * - * @return The file size in bytes. - */ - public long getSize() { - return size; - } - - /** - * Gets the file timestamp. This usually the last modification time. - * - * @return A Calendar instance representing the file timestamp. - */ - public Calendar getTimestamp() { - return date; - } - - /** - * Gets the type of the file (one of the _TYPE constants), e.g., if it is a directory, a regular - * file, or a symbolic link. - * - * @return The type of the file. - */ - public int getType() { - return type; - } - - /** - * Gets the name of the user owning the file. Sometimes this will be a string representation of the user number. - * - * @return The name of the user owning the file. - */ - public String getUser() { - return user; - } - - /** - * Tests if the given access group (one of the _ACCESS constants) has the given access - * permission (one of the _PERMISSION constants) to the file. - * - * @param access The access group (one of the _ACCESS constants) - * @param permission The access permission (one of the _PERMISSION constants) - * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range - * @return true if {@link #isValid()} is {@code true &&} the associated permission is set; {@code false} otherwise. - */ - public boolean hasPermission(final int access, final int permission) { - if (permissions == null) { - return false; - } - return permissions[access][permission]; - } - - /** - * Tests if the file is a directory. - * - * @return True if the file is of type DIRECTORY_TYPE, false if not. - */ - public boolean isDirectory() { - return type == DIRECTORY_TYPE; - } - - /** - * Tests if the file is a regular file. - * - * @return True if the file is of type FILE_TYPE, false if not. - */ - public boolean isFile() { - return type == FILE_TYPE; - } - - /** - * Tests if the file is a symbolic link. - * - * @return True if the file is of type UNKNOWN_TYPE, false if not. - */ - public boolean isSymbolicLink() { - return type == SYMBOLIC_LINK_TYPE; - } - - /** - * Tests if the type of the file is unknown. - * - * @return True if the file is of type UNKNOWN_TYPE, false if not. - */ - public boolean isUnknown() { - return type == UNKNOWN_TYPE; - } - - /** - * Tests whether an entry is valid or not. If the entry is invalid, only the {@link #getRawListing()} - * method will be useful. Other methods may fail. - * - * Used in conjunction with list parsing that preseverves entries that failed to parse. - * - * @see FTPClientConfig#setUnparseableEntries(boolean) - * @return true if the entry is valid - * @since 3.4 - */ - public boolean isValid() { - return permissions != null; - } - - private String permissionToString(final int access) { - final StringBuilder sb = new StringBuilder(); - if (hasPermission(access, READ_PERMISSION)) { - sb.append('r'); - } else { - sb.append('-'); - } - if (hasPermission(access, WRITE_PERMISSION)) { - sb.append('w'); - } else { - sb.append('-'); - } - if (hasPermission(access, EXECUTE_PERMISSION)) { - sb.append('x'); - } else { - sb.append('-'); - } - return sb.toString(); - } - - /** - * Sets the name of the group owning the file. This may be a string representation of the group number. - * - * @param group The name of the group owning the file. - */ - public void setGroup(final String group) { - this.group = group; - } - - /** - * Sets the number of hard links to this file. This is not to be confused with symbolic links. - * - * @param links The number of hard links to this file. - */ - public void setHardLinkCount(final int links) { - this.hardLinkCount = links; - } - - /** - * If the FTPFile is a symbolic link, use this method to set the name of the file being pointed to by the symbolic - * link. - * - * @param link The file pointed to by the symbolic link. - */ - public void setLink(final String link) { - this.link = link; - } - - /** - * Sets the name of the file. - * - * @param name The name of the file. - */ - public void setName(final String name) { - this.name = name; - } - - /** - * Sets if the given access group (one of the _ACCESS constants) has the given access permission (one - * of the _PERMISSION constants) to the file. - * - * @param access The access group (one of the _ACCESS constants) - * @param permission The access permission (one of the _PERMISSION constants) - * @param value True if permission is allowed, false if not. - * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range - */ - public void setPermission(final int access, final int permission, final boolean value) { - permissions[access][permission] = value; - } - - /** - * Sets the original FTP server raw listing from which the FTPFile was created. - * - * @param rawListing The raw FTP server listing. - */ - public void setRawListing(final String rawListing) { - this.rawListing = rawListing; - } - - /** - * Sets the file size in bytes. - * - * @param size The file size in bytes. - */ - public void setSize(final long size) { - this.size = size; - } - - /** - * Sets the file timestamp. This usually the last modification time. The parameter is not cloned, so do not alter its - * value after calling this method. - * - * @param date A Calendar instance representing the file timestamp. - */ - public void setTimestamp(final Calendar date) { - this.date = date; - } - - /** - * Sets the type of the file (DIRECTORY_TYPE, FILE_TYPE, etc.). - * - * @param type The integer code representing the type of the file. - */ - public void setType(final int type) { - this.type = type; - } - - /** - * Sets the name of the user owning the file. This may be a string representation of the user number; - * - * @param user The name of the user owning the file. - */ - public void setUser(final String user) { - this.user = user; - } - - /** - * Gets a string representation of the FTPFile information. This currently mimics the Unix listing format. This - * method uses the time zone of the Calendar entry, which is the server time zone (if one was provided) otherwise it - * is the local time zone. - *

- * Note: if the instance is not valid {@link #isValid()}, no useful information can be returned. In this case, use - * {@link #getRawListing()} instead. - *

- * - * @return A string representation of the FTPFile information. - * @since 3.0 - */ - public String toFormattedString() { - return toFormattedString(null); - } - - /** - * Gets a string representation of the FTPFile information. This currently mimics the Unix listing format. This - * method allows the Calendar time zone to be overridden. - *

- * Note: if the instance is not valid {@link #isValid()}, no useful information can be returned. In this case, use - * {@link #getRawListing()} instead. - *

- * - * @param timezone the time zone to use for displaying the time stamp If {@code null}, then use the Calendar entry - * - * @return A string representation of the FTPFile information. - * @since 3.4 - */ - public String toFormattedString(final String timezone) { - - if (!isValid()) { - return "[Invalid: could not parse file entry]"; - } - final StringBuilder sb = new StringBuilder(); - try (final Formatter fmt = new Formatter(sb)) { - sb.append(formatType()); - sb.append(permissionToString(USER_ACCESS)); - sb.append(permissionToString(GROUP_ACCESS)); - sb.append(permissionToString(WORLD_ACCESS)); - fmt.format(" %4d", Integer.valueOf(getHardLinkCount())); - fmt.format(" %-8s %-8s", getUser(), getGroup()); - fmt.format(" %8d", Long.valueOf(getSize())); - Calendar timestamp = getTimestamp(); - if (timestamp != null) { - if (timezone != null) { - final TimeZone newZone = TimeZone.getTimeZone(timezone); - if (!newZone.equals(timestamp.getTimeZone())) { - final Date original = timestamp.getTime(); - final Calendar newStamp = Calendar.getInstance(newZone); - newStamp.setTime(original); - timestamp = newStamp; - } - } - fmt.format(" %1$tY-%1$tm-%1$td", timestamp); - // Only display time units if they are present - if (timestamp.isSet(Calendar.HOUR_OF_DAY)) { - fmt.format(" %1$tH", timestamp); - if (timestamp.isSet(Calendar.MINUTE)) { - fmt.format(":%1$tM", timestamp); - if (timestamp.isSet(Calendar.SECOND)) { - fmt.format(":%1$tS", timestamp); - if (timestamp.isSet(Calendar.MILLISECOND)) { - fmt.format(".%1$tL", timestamp); - } - } - } - fmt.format(" %1$tZ", timestamp); - } - } - sb.append(' '); - sb.append(getName()); - } - return sb.toString(); - } - - /** - * Gets a string representation of the FTPFile information. - * - * @return A string representation of the FTPFile information. - */ - @Override - public String toString() { - return getRawListing(); - } -} diff --git a/src/org/apache/commons/net/ftp/FTPFileEntryParser.java b/src/org/apache/commons/net/ftp/FTPFileEntryParser.java deleted file mode 100644 index 58407afb..00000000 --- a/src/org/apache/commons/net/ftp/FTPFileEntryParser.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.List; - -/** - * FTPFileEntryParser defines the interface for parsing a single FTP file - * listing and converting that information into an - * {@link org.apache.commons.net.ftp.FTPFile} instance. - * Sometimes you will want to parse unusual listing formats, in which - * case you would create your own implementation of FTPFileEntryParser and - * if necessary, subclass FTPFile. - *

- * Here are some examples showing how to use one of the classes that - * implement this interface. - *

- * - * The first example uses the FTPClient.listFiles() - * API to pull the whole list from the subfolder subfolder in - * one call, attempting to automatically detect the parser type. This - * method, without a parserKey parameter, indicates that autodection should - * be used. - * - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("subfolder");
- * 
- * - * The second example uses the FTPClient.listFiles() - * API to pull the whole list from the current working directory in one call, - * but specifying by classname the parser to be used. For this particular - * parser class, this approach is necessary since there is no way to - * autodetect this server type. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles(
- *      "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser",
- *      ".");
- * 
- * - * The third example uses the FTPClient.listFiles() - * API to pull a single file listing in an arbitrary directory in one call, - * specifying by KEY the parser to be used, in this case, VMS. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java");
- * 
- * - * For an alternative approach, see the {@link FTPListParseEngine} class - * which provides iterative access. - * - * @see org.apache.commons.net.ftp.FTPFile - * @see org.apache.commons.net.ftp.FTPClient#listFiles() - */ -public interface FTPFileEntryParser -{ - /** - * Parses a line of an FTP server file listing and converts it into a usable - * format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null should be - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param listEntry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - FTPFile parseFTPEntry(String listEntry); - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. Implementors must define - * this for the particular ftp system being parsed. In many but not all - * cases, this can be defined simply by calling BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @throws IOException thrown on any IO Error reading from the reader. - */ - String readNextEntry(BufferedReader reader) throws IOException; - - - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * The default implementation can be a no-op. - * - * @param original Original list after it has been created from the server stream - * - * @return Original list as processed by this method. - */ - List preParse(List original); - - -} diff --git a/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java deleted file mode 100644 index 4fd479b2..00000000 --- a/src/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; -import java.io.BufferedReader; -import java.io.IOException; -import java.util.List; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - * - */ -public abstract class FTPFileEntryParserImpl - implements FTPFileEntryParser -{ - /** - * The constructor for a FTPFileEntryParserImpl object. - */ - public FTPFileEntryParserImpl() - { - } - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delimits one entry from the next. This default implementation - * simply calls BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @throws java.io.IOException thrown on any IO Error reading from the reader. - */ - @Override - public String readNextEntry(final BufferedReader reader) throws IOException - { - return reader.readLine(); - } - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * This default implementation does nothing. - * - * @param original Original list after it has been created from the server stream - * - * @return original unmodified. - */ - @Override - public List preParse(final List original) { - return original; - } -} diff --git a/src/org/apache/commons/net/ftp/FTPFileFilter.java b/src/org/apache/commons/net/ftp/FTPFileFilter.java deleted file mode 100644 index ce2c7638..00000000 --- a/src/org/apache/commons/net/ftp/FTPFileFilter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.ftp; - -/** - * Performs filtering on {@link FTPFile} instances. - * - * @since 2.2 - */ -public interface FTPFileFilter { - - /** - * Checks if an FTPFile entry should be included or not. - * - * @param file entry to be checked for inclusion. May be {@code null}. - * @return {@code true} if the file is to be included, {@code false} otherwise. - */ - boolean accept(FTPFile file); -} diff --git a/src/org/apache/commons/net/ftp/FTPFileFilters.java b/src/org/apache/commons/net/ftp/FTPFileFilters.java deleted file mode 100644 index 9d665f54..00000000 --- a/src/org/apache/commons/net/ftp/FTPFileFilters.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.ftp; - -/** - * Implements some simple FTPFileFilter classes. - * @since 2.2 - */ -public class FTPFileFilters { - - /** - * Accepts all FTPFile entries, including null. - */ - public static final FTPFileFilter ALL = new FTPFileFilter() { - @Override - public boolean accept(final FTPFile file) { - return true; - } - }; - - /** - * Accepts all non-null FTPFile entries. - */ - public static final FTPFileFilter NON_NULL = new FTPFileFilter() { - @Override - public boolean accept(final FTPFile file) { - return file != null; - } - }; - - /** - * Accepts all (non-null) FTPFile directory entries. - */ - public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() { - @Override - public boolean accept(final FTPFile file) { - return file != null && file.isDirectory(); - } - }; - -} diff --git a/src/org/apache/commons/net/ftp/FTPHTTPClient.java b/src/org/apache/commons/net/ftp/FTPHTTPClient.java deleted file mode 100644 index ae72331a..00000000 --- a/src/org/apache/commons/net/ftp/FTPHTTPClient.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.net.Inet6Address; -import java.net.Socket; -import java.net.SocketException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.net.util.Base64; - -/** - * Experimental attempt at FTP client that tunnels over an HTTP proxy connection. - * - * @since 2.2 - */ -public class FTPHTTPClient extends FTPClient { - private final String proxyHost; - private final int proxyPort; - private final String proxyUsername; - private final String proxyPassword; - private final Charset charset; - - private static final byte[] CRLF={'\r', '\n'}; - private final Base64 base64 = new Base64(); - - private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV) - - /** - * Create an instance with the specified encoding - * - * @param proxyHost the hostname to use - * @param proxyPort the port to use - * @param proxyUser the user name for the proxy - * @param proxyPass the password for the proxy - * @param encoding the encoding to use - */ - public FTPHTTPClient(final String proxyHost, final int proxyPort, final String proxyUser, final String proxyPass, - final Charset encoding) { - this.proxyHost = proxyHost; - this.proxyPort = proxyPort; - this.proxyUsername = proxyUser; - this.proxyPassword = proxyPass; - this.tunnelHost = null; - this.charset = encoding; - } - - /** - * Create an instance using the UTF-8 encoding - * - * @param proxyHost the hostname to use - * @param proxyPort the port to use - * @param proxyUser the user name for the proxy - * @param proxyPass the password for the proxy - */ - public FTPHTTPClient(final String proxyHost, final int proxyPort, final String proxyUser, final String proxyPass) { - this(proxyHost, proxyPort, proxyUser, proxyPass, StandardCharsets.UTF_8); - } - - /** - * Create an instance using the UTF-8 encoding, with no proxy credentials. - * - * @param proxyHost the hostname to use - * @param proxyPort the port to use - */ - public FTPHTTPClient(final String proxyHost, final int proxyPort) { - this(proxyHost, proxyPort, null, null); - } - - - /** - * Create an instance using the specified encoding, with no proxy credentials. - * - * @param proxyHost the hostname to use - * @param proxyPort the port to use - * @param encoding the encoding to use - */ - public FTPHTTPClient(final String proxyHost, final int proxyPort, final Charset encoding) { - this(proxyHost, proxyPort, null, null, encoding); - } - - - /** - * {@inheritDoc} - * - * @throws IllegalStateException if connection mode is not passive - * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead - */ - // Kept to maintain binary compatibility - // Not strictly necessary, but Clirr complains even though there is a super-impl - @Override - @Deprecated - protected Socket _openDataConnection_(final int command, final String arg) - throws IOException { - return super._openDataConnection_(command, arg); - } - - /** - * {@inheritDoc} - * - * @throws IllegalStateException if connection mode is not passive - * @since 3.1 - */ - @Override - protected Socket _openDataConnection_(final String command, final String arg) - throws IOException { - //Force local passive mode, active mode not supported by through proxy - if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { - throw new IllegalStateException("Only passive connection mode supported"); - } - - final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; - String passiveHost = null; - - final boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; - if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) { - _parseExtendedPassiveModeReply(_replyLines.get(0)); - passiveHost = this.tunnelHost; - } else { - if (isInet6Address) { - return null; // Must use EPSV for IPV6 - } - // If EPSV failed on IPV4, revert to PASV - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return null; - } - _parsePassiveModeReply(_replyLines.get(0)); - passiveHost = this.getPassiveHost(); - } - - final Socket socket = _socketFactory_.createSocket(proxyHost, proxyPort); - final InputStream is = socket.getInputStream(); - final OutputStream os = socket.getOutputStream(); - tunnelHandshake(passiveHost, this.getPassivePort(), is, os); - if (getRestartOffset() > 0 && !restart(getRestartOffset())) { - socket.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { - socket.close(); - return null; - } - - return socket; - } - - @Override - public void connect(final String host, final int port) throws SocketException, IOException { - - _socket_ = _socketFactory_.createSocket(proxyHost, proxyPort); - _input_ = _socket_.getInputStream(); - _output_ = _socket_.getOutputStream(); - final Reader socketIsReader; - try { - socketIsReader = tunnelHandshake(host, port, _input_, _output_); - } - catch (final Exception e) { - final IOException ioe = new IOException("Could not connect to " + host + " using port " + port); - ioe.initCause(e); - throw ioe; - } - super._connectAction_(socketIsReader); - } - - private BufferedReader tunnelHandshake(final String host, final int port, final InputStream input, - final OutputStream output) throws IOException, UnsupportedEncodingException { - final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; - final String hostString = "Host: " + host + ":" + port; - - this.tunnelHost = host; - output.write(connectString.getBytes(charset)); - output.write(CRLF); - output.write(hostString.getBytes(charset)); - output.write(CRLF); - - if (proxyUsername != null && proxyPassword != null) { - final String auth = proxyUsername + ":" + proxyPassword; - final String header = "Proxy-Authorization: Basic " + base64.encodeToString(auth.getBytes(charset)); - output.write(header.getBytes(charset)); - } - output.write(CRLF); - - final List response = new ArrayList<>(); - final BufferedReader reader = new BufferedReader(new InputStreamReader(input, getCharset())); - - for (String line = reader.readLine(); line != null && !line.isEmpty(); line = reader.readLine()) { - response.add(line); - } - - final int size = response.size(); - if (size == 0) { - throw new IOException("No response from proxy"); - } - - String code = null; - final String resp = response.get(0); - if (resp.startsWith("HTTP/") && resp.length() >= 12) { - code = resp.substring(9, 12); - } else { - throw new IOException("Invalid response from proxy: " + resp); - } - - if (!"200".equals(code)) { - final StringBuilder msg = new StringBuilder(); - msg.append("HTTPTunnelConnector: connection failed\r\n"); - msg.append("Response received from the proxy:\r\n"); - for (final String line : response) { - msg.append(line); - msg.append("\r\n"); - } - throw new IOException(msg.toString()); - } - return reader; - } -} - - diff --git a/src/org/apache/commons/net/ftp/FTPListParseEngine.java b/src/org/apache/commons/net/ftp/FTPListParseEngine.java deleted file mode 100644 index 0c4d2607..00000000 --- a/src/org/apache/commons/net/ftp/FTPListParseEngine.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - -import org.apache.commons.net.util.Charsets; - - -/** - * This class handles the entire process of parsing a listing of - * file entries from the server. - *

- * This object defines a two-part parsing mechanism. - *

- * The first part is comprised of reading the raw input into an internal - * list of strings. Every item in this list corresponds to an actual - * file. All extraneous matter emitted by the server will have been - * removed by the end of this phase. This is accomplished in conjunction - * with the FTPFileEntryParser associated with this engine, by calling - * its methods readNextEntry() - which handles the issue of - * what delimits one entry from another, usually but not always a line - * feed and preParse() - which handles removal of - * extraneous matter such as the preliminary lines of a listing, removal - * of duplicates on versioning systems, etc. - *

- * The second part is composed of the actual parsing, again in conjunction - * with the particular parser used by this engine. This is controlled - * by an iterator over the internal list of strings. This may be done - * either in block mode, by calling the getNext() and - * getPrevious() methods to provide "paged" output of less - * than the whole list at one time, or by calling the - * getFiles() method to return the entire list. - *

- * Examples: - *

- * Paged access: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For unpaged access, simply use FTPClient.listFiles(). That method - * uses this class transparently. - */ -public class FTPListParseEngine { - private List entries = new LinkedList<>(); - private ListIterator internalIterator = entries.listIterator(); - - private final FTPFileEntryParser parser; - // Should invalid files (parse failures) be allowed? - private final boolean saveUnparseableEntries; - - /** - * An empty immutable {@code FTPFile} array. - */ - private static final FTPFile[] EMPTY_FTP_FILE_ARRAY = new FTPFile[0]; - - public FTPListParseEngine(final FTPFileEntryParser parser) { - this(parser, null); - } - - /** - * Intended for use by FTPClient only - * @since 3.4 - */ - FTPListParseEngine(final FTPFileEntryParser parser, final FTPClientConfig configuration) { - this.parser = parser; - if (configuration != null) { - this.saveUnparseableEntries = configuration.getUnparseableEntries(); - } else { - this.saveUnparseableEntries = false; - } - } - - /** - * Reads (and closes) the initial reading and preparsing of the list returned by the server. After this method has - * completed, this object will contain a list of unparsed entries (Strings) each referring to a unique file on the - * server. - * - * @param inputStream input stream provided by the server socket. - * @param charsetName the encoding to be used for reading the stream - * - * @throws IOException thrown on any failure to read from the sever. - */ - public void readServerList(final InputStream inputStream, final String charsetName) throws IOException { - this.entries = new LinkedList<>(); - read(inputStream, charsetName); - this.parser.preParse(this.entries); - resetIterator(); - } - - /** - * Internal method for reading (and closing) the input into the entries list. After this method has - * completed, entries will contain a collection of entries (as defined by - * FTPFileEntryParser.readNextEntry()), but this may contain various non-entry preliminary lines from - * the server output, duplicates, and other data that will not be part of the final listing. - * - * @param inputStream The socket stream on which the input will be read. - * @param charsetName The encoding to use. - * - * @throws IOException thrown on any failure to read the stream - */ - private void read(final InputStream inputStream, final String charsetName) throws IOException { - try (final BufferedReader reader = new BufferedReader( - new InputStreamReader(inputStream, Charsets.toCharset(charsetName)))) { - - String line = this.parser.readNextEntry(reader); - - while (line != null) { - this.entries.add(line); - line = this.parser.readNextEntry(reader); - } - } - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position. - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is advanced - * by a number of positions equal to the size of the array returned. - * - * @param quantityRequested - * the maximum number of entries we want to get. - * - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getNext(final int quantityRequested) { - final List tmpResults = new LinkedList<>(); - int count = quantityRequested; - while (count > 0 && this.internalIterator.hasNext()) { - final String entry = this.internalIterator.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - tmpResults.add(temp); - count--; - } - return tmpResults.toArray(EMPTY_FTP_FILE_ARRAY); - - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position, - * and working back toward the beginning. - * - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is moved - * back by a number of positions equal to the size of the array returned. - * - * @param quantityRequested - * the maximum number of entries we want to get. - * - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. This array will be in the same order - * as the underlying list (not reversed). - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getPrevious(final int quantityRequested) { - final List tmpResults = new LinkedList<>(); - int count = quantityRequested; - while (count > 0 && this.internalIterator.hasPrevious()) { - final String entry = this.internalIterator.previous(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - tmpResults.add(0,temp); - count--; - } - return tmpResults.toArray(EMPTY_FTP_FILE_ARRAY); - } - - /** - * Returns an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * - * @return an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * None of the entries will be null - * @throws IOException - not ever thrown, may be removed in a later release - */ - public FTPFile[] getFiles() - throws IOException // TODO remove; not actually thrown - { - return getFiles(FTPFileFilters.NON_NULL); - } - - /** - * Returns an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * The files are filtered before being added to the array. - * - * @param filter FTPFileFilter, must not be null. - * - * @return an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it, or use the - * a filter such as {@link FTPFileFilters#NON_NULL} which does not - * allow null entries. - * @since 2.2 - * @throws IOException - not ever thrown, may be removed in a later release - */ - public FTPFile[] getFiles(final FTPFileFilter filter) - throws IOException // TODO remove; not actually thrown - { - final List tmpResults = new ArrayList<>(); - final Iterator iter = this.entries.iterator(); - while (iter.hasNext()) { - final String entry = iter.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - if (filter.accept(temp)) { - tmpResults.add(temp); - } - } - return tmpResults.toArray(EMPTY_FTP_FILE_ARRAY); - - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the end of the list. - * - * @return true if internal iterator is not at end of list, false - * otherwise. - */ - public boolean hasNext() { - return internalIterator.hasNext(); - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the beginning of the list. - * - * @return true if internal iterator is not at beginning of list, false - * otherwise. - */ - public boolean hasPrevious() { - return internalIterator.hasPrevious(); - } - - /** - * resets this object's internal iterator to the beginning of the list. - */ - public void resetIterator() { - this.internalIterator = this.entries.listIterator(); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * Do not use. - * @param inputStream the stream from which to read - * @throws IOException on error - * @deprecated use {@link #readServerList(InputStream, String)} instead - */ - @Deprecated - public void readServerList(final InputStream inputStream) throws IOException { - readServerList(inputStream, null); - } - -} diff --git a/src/org/apache/commons/net/ftp/FTPReply.java b/src/org/apache/commons/net/ftp/FTPReply.java deleted file mode 100644 index fbdc9f2d..00000000 --- a/src/org/apache/commons/net/ftp/FTPReply.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/** - * FTPReply stores a set of constants for FTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. - *

- * TODO replace with an enum - */ - -public final class FTPReply -{ - - public static final int RESTART_MARKER = 110; - public static final int SERVICE_NOT_READY = 120; - public static final int DATA_CONNECTION_ALREADY_OPEN = 125; - public static final int FILE_STATUS_OK = 150; - public static final int COMMAND_OK = 200; - public static final int COMMAND_IS_SUPERFLUOUS = 202; - public static final int SYSTEM_STATUS = 211; - public static final int DIRECTORY_STATUS = 212; - public static final int FILE_STATUS = 213; - public static final int HELP_MESSAGE = 214; - public static final int NAME_SYSTEM_TYPE = 215; - public static final int SERVICE_READY = 220; - public static final int SERVICE_CLOSING_CONTROL_CONNECTION = 221; - public static final int DATA_CONNECTION_OPEN = 225; - public static final int CLOSING_DATA_CONNECTION = 226; - public static final int ENTERING_PASSIVE_MODE = 227; - /** @since 2.2 */ - public static final int ENTERING_EPSV_MODE = 229; - public static final int USER_LOGGED_IN = 230; - public static final int FILE_ACTION_OK = 250; - public static final int PATHNAME_CREATED = 257; - public static final int NEED_PASSWORD = 331; - public static final int NEED_ACCOUNT = 332; - public static final int FILE_ACTION_PENDING = 350; - public static final int SERVICE_NOT_AVAILABLE = 421; - public static final int CANNOT_OPEN_DATA_CONNECTION = 425; - public static final int TRANSFER_ABORTED = 426; - public static final int FILE_ACTION_NOT_TAKEN = 450; - public static final int ACTION_ABORTED = 451; - public static final int INSUFFICIENT_STORAGE = 452; - public static final int UNRECOGNIZED_COMMAND = 500; - public static final int SYNTAX_ERROR_IN_ARGUMENTS = 501; - public static final int COMMAND_NOT_IMPLEMENTED = 502; - public static final int BAD_COMMAND_SEQUENCE = 503; - public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = 504; - public static final int NOT_LOGGED_IN = 530; - public static final int NEED_ACCOUNT_FOR_STORING_FILES = 532; - public static final int FILE_UNAVAILABLE = 550; - public static final int PAGE_TYPE_UNKNOWN = 551; - public static final int STORAGE_ALLOCATION_EXCEEDED = 552; - public static final int FILE_NAME_NOT_ALLOWED = 553; - - // FTPS Reply Codes - - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_COMPLETE = 234; - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = 235; - /** @since 2.0 */ - public static final int SECURITY_MECHANISM_IS_OK = 334; - /** @since 2.0 */ - public static final int SECURITY_DATA_IS_ACCEPTABLE = 335; - /** @since 2.0 */ - public static final int UNAVAILABLE_RESOURCE = 431; - /** @since 2.2 */ - public static final int BAD_TLS_NEGOTIATION_OR_DATA_ENCRYPTION_REQUIRED = 522; - /** @since 2.0 */ - public static final int DENIED_FOR_POLICY_REASONS = 533; - /** @since 2.0 */ - public static final int REQUEST_DENIED = 534; - /** @since 2.0 */ - public static final int FAILED_SECURITY_CHECK = 535; - /** @since 2.0 */ - public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = 536; - - // IPv6 error codes - // Note this is also used as an FTPS error code reply - /** @since 2.2 */ - public static final int EXTENDED_PORT_FAILURE = 522; - - // Cannot be instantiated - private FTPReply() - {} - - /** - * Determine if a reply code is a positive preliminary response. All - * codes beginning with a 1 are positive preliminary responses. - * Postitive preliminary responses are used to indicate tentative success. - * No further commands can be issued to the FTP server after a positive - * preliminary response until a follow up response is received from the - * server. - * - * @param reply The reply code to test. - * @return True if a reply code is a positive preliminary response, false - * if not. - */ - public static boolean isPositivePreliminary(final int reply) - { - return reply >= 100 && reply < 200; - } - - /** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The FTP server will send a positive completion response on the final - * successful completion of a command. - * - * @param reply The reply code to test. - * @return True if a reply code is a positive completion response, false - * if not. - */ - public static boolean isPositiveCompletion(final int reply) - { - return reply >= 200 && reply < 300; - } - - /** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The FTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part sequence of - * commands. For example, after a successful USER command, a positive - * intermediate response will be sent to indicate that the server is - * ready for the PASS command. - * - * @param reply The reply code to test. - * @return True if a reply code is a positive intermediate response, false - * if not. - */ - public static boolean isPositiveIntermediate(final int reply) - { - return reply >= 300 && reply < 400; - } - - /** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The FTP server will send a negative transient response on the - * failure of a command that can be reattempted with success. - * - * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - */ - public static boolean isNegativeTransient(final int reply) - { - return reply >= 400 && reply < 500; - } - - /** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The FTP server will send a negative permanent response on the - * failure of a command that cannot be reattempted with success. - * - * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - */ - public static boolean isNegativePermanent(final int reply) - { - return reply >= 500 && reply < 600; - } - - /** - * Determine if a reply code is a protected response. - * @param reply The reply code to test. - * @return True if a reply code is a protected response, false - * if not. - * @since 3.0 - */ - public static boolean isProtectedReplyCode(final int reply) - { - // actually, only 3 protected reply codes are - // defined in RFC 2228: 631, 632 and 633. - return reply >= 600 && reply < 700; - } - - -} diff --git a/src/org/apache/commons/net/ftp/FTPSClient.java b/src/org/apache/commons/net/ftp/FTPSClient.java deleted file mode 100644 index 443e25fe..00000000 --- a/src/org/apache/commons/net/ftp/FTPSClient.java +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.Socket; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.net.util.Base64; -import org.apache.commons.net.util.SSLContextUtils; -import org.apache.commons.net.util.SSLSocketUtils; -import org.apache.commons.net.util.TrustManagerUtils; - -/** - * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to - * see wire-level SSL details. - * - * Warning: the hostname is not verified against the certificate by default, use - * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} - * (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. - * @since 2.0 - */ -public class FTPSClient extends FTPClient { - -// From http://www.iana.org/assignments/port-numbers - -// ftps-data 989/tcp ftp protocol, data, over TLS/SSL -// ftps-data 989/udp ftp protocol, data, over TLS/SSL -// ftps 990/tcp ftp protocol, control, over TLS/SSL -// ftps 990/udp ftp protocol, control, over TLS/SSL - - public static final int DEFAULT_FTPS_DATA_PORT = 989; - public static final int DEFAULT_FTPS_PORT = 990; - - /** The value that I can set in PROT command (C = Clear, P = Protected) */ - private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; - /** Default PROT Command */ - private static final String DEFAULT_PROT = "C"; - /** Default secure socket protocol name, i.e. TLS */ - private static final String DEFAULT_PROTOCOL = "TLS"; - - /** The AUTH (Authentication/Security Mechanism) command. */ - private static final String CMD_AUTH = "AUTH"; - /** The ADAT (Authentication/Security Data) command. */ - private static final String CMD_ADAT = "ADAT"; - /** The PROT (Data Channel Protection Level) command. */ - private static final String CMD_PROT = "PROT"; - /** The PBSZ (Protection Buffer Size) command. */ - private static final String CMD_PBSZ = "PBSZ"; - /** The MIC (Integrity Protected Command) command. */ - private static final String CMD_MIC = "MIC"; - /** The CONF (Confidentiality Protected Command) command. */ - private static final String CMD_CONF = "CONF"; - /** The ENC (Privacy Protected Command) command. */ - private static final String CMD_ENC = "ENC"; - /** The CCC (Clear Command Channel) command. */ - private static final String CMD_CCC = "CCC"; - - /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ - private final boolean isImplicit; - /** The secure socket protocol to be used, e.g. SSL/TLS. */ - private final String protocol; - /** The AUTH Command value */ - private String auth = DEFAULT_PROTOCOL; - /** The context object. */ - private SSLContext context; - /** The socket object. */ - private Socket plainSocket; - /** Controls whether a new SSL session may be established by this socket. Default true. */ - private boolean isCreation = true; - /** The use client mode flag. */ - private boolean isClientMode = true; - /** The need client auth flag. */ - private boolean isNeedClientAuth; - /** The want client auth flag. */ - private boolean isWantClientAuth; - /** The cipher suites */ - private String[] suites; - /** The protocol versions */ - private String[] protocols; - - /** The FTPS {@link TrustManager} implementation, default validate only - * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. - */ - private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); - - /** The {@link KeyManager}, default null (i.e. use system default). */ - private KeyManager keyManager; - - /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ - private HostnameVerifier hostnameVerifier; - - /** Use Java 1.7+ HTTPS Endpoint Identification Algorithm. */ - private boolean tlsEndpointChecking; - - /** - * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. - * - * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false) - */ - public FTPSClient() { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * Calls {@link #FTPSClient(String, boolean)} - * @param isImplicit The security mode (Implicit/Explicit). - */ - public FTPSClient(final boolean isImplicit) { - this(DEFAULT_PROTOCOL, isImplicit); - } - - /** - * Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}. - * - * @param protocol the protocol to use - */ - public FTPSClient(final String protocol) { - this(protocol, false); - } - - /** - * Constructor for FTPSClient allowing specification of protocol - * and security mode. If isImplicit is true, the port is set to - * {@link #DEFAULT_FTPS_PORT} i.e. 990. - * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} - * @param protocol the protocol - * @param isImplicit The security mode(Implicit/Explicit). - */ - public FTPSClient(final String protocol, final boolean isImplicit) { - this.protocol = protocol; - this.isImplicit = isImplicit; - if (isImplicit) { - setDefaultPort(DEFAULT_FTPS_PORT); - } - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} - * @param isImplicit The security mode(Implicit/Explicit). - * @param context A pre-configured SSL Context - */ - public FTPSClient(final boolean isImplicit, final SSLContext context) { - this(DEFAULT_PROTOCOL, isImplicit); - this.context = context; - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * and isImplicit {@code false} - * Calls {@link #FTPSClient(boolean, SSLContext)} - * @param context A pre-configured SSL Context - */ - public FTPSClient(final SSLContext context) { - this(false, context); - } - - - /** - * Set AUTH command use value. - * This processing is done before connected processing. - * @param auth AUTH command use value. - */ - public void setAuthValue(final String auth) { - this.auth = auth; - } - - /** - * Return AUTH command use value. - * @return AUTH command use value. - */ - public String getAuthValue() { - return this.auth; - } - - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * @throws IOException If it throw by _connectAction_. - * @see org.apache.commons.net.SocketClient#_connectAction_() - */ - @Override - protected void _connectAction_() throws IOException { - // Implicit mode. - if (isImplicit) { - applySocketAttributes(); - sslNegotiation(); - } - super._connectAction_(); - // Explicit mode. - if (!isImplicit) { - execAUTH(); - sslNegotiation(); - } - } - - /** - * AUTH command. - * @throws SSLException If it server reply code not equal "234" and "334". - * @throws IOException If an I/O error occurs while either sending - * the command. - */ - protected void execAUTH() throws SSLException, IOException { - final int replyCode = sendCommand(CMD_AUTH, auth); - if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { - // replyCode = 334 - // I carry out an ADAT command. - } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { - throw new SSLException(getReplyString()); - } - } - - /** - * Performs a lazy init of the SSL context - * @throws IOException - */ - private void initSslContext() throws IOException { - if (context == null) { - context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a control - * connection and carries out handshake processing. - * @throws IOException If server negotiation fails - */ - protected void sslNegotiation() throws IOException { - plainSocket = _socket_; - initSslContext(); - final SSLSocket socket = createSSLSocket(_socket_); - socket.setEnableSessionCreation(isCreation); - socket.setUseClientMode(isClientMode); - - // client mode - if (isClientMode) { - if (tlsEndpointChecking) { - SSLSocketUtils.enableEndpointNameVerification(socket); - } - } else { // server mode - socket.setNeedClientAuth(isNeedClientAuth); - socket.setWantClientAuth(isWantClientAuth); - } - - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - if (suites != null) { - socket.setEnabledCipherSuites(suites); - } - socket.startHandshake(); - - // TODO the following setup appears to duplicate that in the super class methods - _socket_ = socket; - _controlInput_ = new BufferedReader(new InputStreamReader( - socket .getInputStream(), getControlEncoding())); - _controlOutput_ = new BufferedWriter(new OutputStreamWriter( - socket.getOutputStream(), getControlEncoding())); - - if (isClientMode) { - if (hostnameVerifier != null && - !hostnameVerifier.verify(_hostname_, socket.getSession())) { - throw new SSLHandshakeException("Hostname doesn't match certificate"); - } - } - } - - /** - * Get the {@link KeyManager} instance. - * @return The {@link KeyManager} instance - */ - private KeyManager getKeyManager() { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use - * - * @param keyManager The KeyManager implementation to set. - * @see org.apache.commons.net.util.KeyManagerUtils - */ - public void setKeyManager(final KeyManager keyManager) { - this.keyManager = keyManager; - } - - /** - * Controls whether a new SSL session may be established by this socket. - * @param isCreation The established socket flag. - */ - public void setEnabledSessionCreation(final boolean isCreation) { - this.isCreation = isCreation; - } - - /** - * Returns true if new SSL sessions may be established by this socket. - * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an - * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, - * this returns False. - * @return true - Indicates that sessions may be created; - * this is the default. - * false - indicates that an existing session must be resumed. - */ - public boolean getEnableSessionCreation() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getEnableSessionCreation(); - } - return false; - } - - /** - * Configures the socket to require client authentication. - * @param isNeedClientAuth The need client auth flag. - */ - public void setNeedClientAuth(final boolean isNeedClientAuth) { - this.isNeedClientAuth = isNeedClientAuth; - } - - /** - * Returns true if the socket will require client authentication. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getNeedClientAuth() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getNeedClientAuth(); - } - return false; - } - - /** - * Configures the socket to request client authentication, - * but only if such a request is appropriate to the cipher - * suite negotiated. - * @param isWantClientAuth The want client auth flag. - */ - public void setWantClientAuth(final boolean isWantClientAuth) { - this.isWantClientAuth = isWantClientAuth; - } - - /** - * Returns true if the socket will request client authentication. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getWantClientAuth() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getWantClientAuth(); - } - return false; - } - - /** - * Configures the socket to use client (or server) mode in its first - * handshake. - * @param isClientMode The use client mode flag. - */ - public void setUseClientMode(final boolean isClientMode) { - this.isClientMode = isClientMode; - } - - /** - * Returns true if the socket is set to use client mode - * in its first handshake. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * @return true - If the socket should start its first handshake - * in "client" mode. - */ - public boolean getUseClientMode() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getUseClientMode(); - } - return false; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. Called before server negotiation. - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(final String[] cipherSuites) { - suites = cipherSuites.clone(); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of cipher suite names, or null - */ - public String[] getEnabledCipherSuites() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getEnabledCipherSuites(); - } - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(final String[] protocolVersions) { - protocols = protocolVersions.clone(); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of protocols, or null - */ - public String[] getEnabledProtocols() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket)_socket_).getEnabledProtocols(); - } - return null; - } - - /** - * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. - * @param pbsz Protection Buffer Size. - * @throws SSLException If the server reply code does not equal "200". - * @throws IOException If an I/O error occurs while sending - * the command. - * @see #parsePBSZ(long) - */ - public void execPBSZ(final long pbsz) throws SSLException, IOException { - if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number - throw new IllegalArgumentException(); - } - final int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); - if (FTPReply.COMMAND_OK != status) { - throw new SSLException(getReplyString()); - } - } - - /** - * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. - * Issues the command and parses the response to return the negotiated value. - * - * @param pbsz Protection Buffer Size. - * @throws SSLException If the server reply code does not equal "200". - * @throws IOException If an I/O error occurs while sending - * the command. - * @return the negotiated value. - * @see #execPBSZ(long) - * @since 3.0 - */ - public long parsePBSZ(final long pbsz) throws SSLException, IOException { - execPBSZ(pbsz); - long minvalue = pbsz; - final String remainder = extractPrefixedData("PBSZ=", getReplyString()); - if (remainder != null) { - final long replysz = Long.parseLong(remainder); - if (replysz < minvalue) { - minvalue = replysz; - } - } - return minvalue; - } - - /** - * PROT command. - *

    - *
  • C - Clear
  • - *
  • S - Safe(SSL protocol only)
  • - *
  • E - Confidential(SSL protocol only)
  • - *
  • P - Private
  • - *
- * N.B. the method calls - * {@link #setSocketFactory(javax.net.SocketFactory)} and - * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} - * - * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. - * @throws SSLException If the server reply code does not equal {@code 200}. - * @throws IOException If an I/O error occurs while sending - * the command. - */ - public void execPROT(String prot) throws SSLException, IOException { - if (prot == null) { - prot = DEFAULT_PROT; - } - if (!checkPROTValue(prot)) { - throw new IllegalArgumentException(); - } - if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { - throw new SSLException(getReplyString()); - } - if (DEFAULT_PROT.equals(prot)) { - setSocketFactory(null); - setServerSocketFactory(null); - } else { - setSocketFactory(new FTPSSocketFactory(context)); - setServerSocketFactory(new FTPSServerSocketFactory(context)); - initSslContext(); - } - } - - /** - * Check the value that can be set in PROT Command value. - * @param prot Data Channel Protection Level. - * @return True - A set point is right / False - A set point is not right - */ - private boolean checkPROTValue(final String prot) { - for (final String element : PROT_COMMAND_VALUE) - { - if (element.equals(prot)) { - return true; - } - } - return false; - } - - /** - * Send an FTP command. - * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} - * instance to be assigned to a plain {@link Socket} - * @param command The FTP command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending the command. - * @throws SSLException if a CCC command fails - * @see org.apache.commons.net.ftp.FTP#sendCommand(java.lang.String) - */ - // Would like to remove this method, but that will break any existing clients that are using CCC - @Override - public int sendCommand(final String command, final String args) throws IOException { - final int repCode = super.sendCommand(command, args); - /* If CCC is issued, restore socket i/o streams to unsecured versions */ - if (CMD_CCC.equals(command)) { - if (FTPReply.COMMAND_OK == repCode) { - _socket_.close(); - _socket_ = plainSocket; - _controlInput_ = new BufferedReader( - new InputStreamReader( - _socket_ .getInputStream(), getControlEncoding())); - _controlOutput_ = new BufferedWriter( - new OutputStreamWriter( - _socket_.getOutputStream(), getControlEncoding())); - } else { - throw new SSLException(getReplyString()); - } - } - return repCode; - } - - /** - * Returns a socket of the data connection. - * Wrapped as an {@link SSLSocket}, which carries out handshake processing. - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. - * If this parameter is set to null, then the command is sent with - * no arguments. - * @return corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at any point - * during the establishment and initialization of the connection. - * @throws IOException If there is any problem with the connection. - * @see FTPClient#_openDataConnection_(int, String) - * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead - */ - @Override - // Strictly speaking this is not needed, but it works round a Clirr bug - // So rather than invoke the parent code, we do it here - @Deprecated - protected Socket _openDataConnection_(final int command, final String arg) - throws IOException { - return _openDataConnection_(FTPCommand.getCommand(command), arg); - } - - /** - * Returns a socket of the data connection. - * Wrapped as an {@link SSLSocket}, which carries out handshake processing. - * @param command The textual representation of the FTP command to send. - * @param arg The arguments to the FTP command. - * If this parameter is set to null, then the command is sent with - * no arguments. - * @return corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at any point - * during the establishment and initialization of the connection. - * @throws IOException If there is any problem with the connection. - * @see FTPClient#_openDataConnection_(int, String) - * @since 3.2 - */ - @Override - protected Socket _openDataConnection_(final String command, final String arg) - throws IOException { - final Socket socket = super._openDataConnection_(command, arg); - _prepareDataSocket_(socket); - if (socket instanceof SSLSocket) { - final SSLSocket sslSocket = (SSLSocket)socket; - - sslSocket.setUseClientMode(isClientMode); - sslSocket.setEnableSessionCreation(isCreation); - - // server mode - if (!isClientMode) { - sslSocket.setNeedClientAuth(isNeedClientAuth); - sslSocket.setWantClientAuth(isWantClientAuth); - } - if (suites != null) { - sslSocket.setEnabledCipherSuites(suites); - } - if (protocols != null) { - sslSocket.setEnabledProtocols(protocols); - } - sslSocket.startHandshake(); - } - - return socket; - } - - /** - * Performs any custom initialization for a newly created SSLSocket (before - * the SSL handshake happens). - * Called by {@link #_openDataConnection_(int, String)} immediately - * after creating the socket. - * The default implementation is a no-op - * @param socket the socket to set up - * @throws IOException on error - * @since 3.1 - */ - protected void _prepareDataSocket_(final Socket socket) - throws IOException { - } - - /** - * Get the currently configured {@link TrustManager}. - * - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use; if set to {@code null}, - * the default TrustManager from the JVM will be used. - * - * @param trustManager The TrustManager implementation to set, may be {@code null} - * @see org.apache.commons.net.util.TrustManagerUtils - */ - public void setTrustManager(final TrustManager trustManager) { - this.trustManager = trustManager; - } - - /** - * Get the currently configured {@link HostnameVerifier}. - * The verifier is only used on client mode connections. - * @return A HostnameVerifier instance. - * @since 3.4 - */ - public HostnameVerifier getHostnameVerifier() - { - return hostnameVerifier; - } - - /** - * Override the default {@link HostnameVerifier} to use. - * The verifier is only used on client mode connections. - * @param newHostnameVerifier The HostnameVerifier implementation to set or null to disable. - * @since 3.4 - */ - public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) - { - hostnameVerifier = newHostnameVerifier; - } - - /** - * Return whether or not endpoint identification using the HTTPS algorithm - * on Java 1.7+ is enabled. The default behavior is for this to be disabled. - * - * This check is only performed on client mode connections. - * - * @return True if enabled, false if not. - * @since 3.4 - */ - public boolean isEndpointCheckingEnabled() - { - return tlsEndpointChecking; - } - - /** - * Automatic endpoint identification checking using the HTTPS algorithm - * is supported on Java 1.7+. The default behavior is for this to be disabled. - * - * This check is only performed on client mode connections. - * - * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. - * @since 3.4 - */ - public void setEndpointCheckingEnabled(final boolean enable) - { - tlsEndpointChecking = enable; - } - - /** - * Closes the connection to the FTP server and restores - * connection parameters to the default values. - *

- * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} - * to reset the factories that may have been changed during the session, - * e.g. by {@link #execPROT(String)} - * @throws IOException If an error occurs while disconnecting. - * @since 3.0 - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - if (plainSocket != null) { - plainSocket.close(); - } - setSocketFactory(null); - setServerSocketFactory(null); - } - - /** - * Send the AUTH command with the specified mechanism. - * @param mechanism The mechanism name to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execAUTH(final String mechanism) throws IOException - { - return sendCommand(CMD_AUTH, mechanism); - } - - /** - * Send the ADAT command with the specified authentication data. - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execADAT(final byte[] data) throws IOException - { - if (data != null) - { - return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); - } - return sendCommand(CMD_ADAT); - } - - /** - * Send the CCC command to the server. - * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned - * to a plain {@link Socket} instances - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execCCC() throws IOException - { - final int repCode = sendCommand(CMD_CCC); -// This will be performed by sendCommand(String, String) -// if (FTPReply.isPositiveCompletion(repCode)) { -// _socket_.close(); -// _socket_ = plainSocket; -// _controlInput_ = new BufferedReader( -// new InputStreamReader( -// _socket_.getInputStream(), getControlEncoding())); -// _controlOutput_ = new BufferedWriter( -// new OutputStreamWriter( -// _socket_.getOutputStream(), getControlEncoding())); -// } - return repCode; - } - - /** - * Send the MIC command with the specified data. - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execMIC(final byte[] data) throws IOException - { - if (data != null) - { - return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); - } - return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? - } - - /** - * Send the CONF command with the specified data. - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execCONF(final byte[] data) throws IOException - { - if (data != null) - { - return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); - } - return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? - } - - /** - * Send the ENC command with the specified data. - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execENC(final byte[] data) throws IOException - { - if (data != null) - { - return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); - } - return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? - } - - /** - * Parses the given ADAT response line and base64-decodes the data. - * @param reply The ADAT reply to parse. - * @return the data in the reply, base64-decoded. - * @since 3.0 - */ - public byte[] parseADATReply(final String reply) - { - if (reply == null) { - return null; - } - return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); - } - - /** - * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 - * @param prefix the prefix to find - * @param reply where to find the prefix - * @return the remainder of the string after the prefix, or null if the prefix was not present. - */ - private String extractPrefixedData(final String prefix, final String reply) { - final int idx = reply.indexOf(prefix); - if (idx == -1) { - return null; - } - // N.B. Cannot use trim before substring as leading space would affect the offset. - return reply.substring(idx+prefix.length()).trim(); - } - - /** - * Create SSL socket from plain socket. - * - * @param socket - * @return SSL Socket - * @throws IOException - */ - private SSLSocket createSSLSocket(final Socket socket) throws IOException { - if (socket != null) { - final SSLSocketFactory f = context.getSocketFactory(); - return (SSLSocket) f.createSocket(socket, _hostname_, socket.getPort(), false); - } - return null; - } - - // DEPRECATED - for API compatibility only - DO NOT USE - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated - public static String KEYSTORE_ALGORITHM; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated - public static String TRUSTSTORE_ALGORITHM; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated - public static String PROVIDER; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated - public static String STORE_TYPE; - -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/ftp/FTPSCommand.java b/src/org/apache/commons/net/ftp/FTPSCommand.java deleted file mode 100644 index fde870b7..00000000 --- a/src/org/apache/commons/net/ftp/FTPSCommand.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -/** - * FTPS-specific commands. - * @since 2.0 - * @deprecated 3.0 DO NOT USE - */ -@Deprecated -public final class FTPSCommand { - public static final int AUTH = 0; - public static final int ADAT = 1; - public static final int PBSZ = 2; - public static final int PROT = 3; - public static final int CCC = 4; - - public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; - public static final int AUTHENTICATION_SECURITY_DATA = ADAT; - public static final int PROTECTION_BUFFER_SIZE = PBSZ; - public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; - public static final int CLEAR_COMMAND_CHANNEL = CCC; - - private static final String[] commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; - - /** - * Retrieve the FTPS command string corresponding to a specified - * command code. - * - * @param command The command code. - * @return The FTPS command string corresponding to a specified - * command code. - */ - public static String getCommand(final int command) { - return commands[command]; - } -} diff --git a/src/org/apache/commons/net/ftp/FTPSServerSocketFactory.java b/src/org/apache/commons/net/ftp/FTPSServerSocketFactory.java deleted file mode 100644 index 87ec5f4e..00000000 --- a/src/org/apache/commons/net/ftp/FTPSServerSocketFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; - -import javax.net.ServerSocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLServerSocketFactory; - -/** - * Server socket factory for FTPS connections. - * - * @since 2.2 - */ -public class FTPSServerSocketFactory extends ServerSocketFactory { - - /** Factory for secure socket factories */ - private final SSLContext sslContext; - - /** - * Constructs a new instance for the given SSL context. - * - * @param sslContext The SSL context. - */ - public FTPSServerSocketFactory(final SSLContext sslContext) { - this.sslContext = sslContext; - } - - @SuppressWarnings("resource") // Factory method. - @Override - public ServerSocket createServerSocket() throws IOException { - return init(getServerSocketFactory().createServerSocket()); - } - - @SuppressWarnings("resource") // Factory method. - @Override - public ServerSocket createServerSocket(final int port) throws IOException { - return init(getServerSocketFactory().createServerSocket(port)); - } - - @SuppressWarnings("resource") // Factory method. - @Override - public ServerSocket createServerSocket(final int port, final int backlog) throws IOException { - return init(getServerSocketFactory().createServerSocket(port, backlog)); - } - - @SuppressWarnings("resource") // Factory method. - @Override - public ServerSocket createServerSocket(final int port, final int backlog, final InetAddress ifAddress) - throws IOException { - return init(getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); - } - - private SSLServerSocketFactory getServerSocketFactory() { - return this.sslContext.getServerSocketFactory(); - } - - /** - * Sets the socket so newly accepted connections will use SSL client mode. - * - * @param socket the SSLServerSocket to initialize - * @return the socket - * @throws ClassCastException if socket is not an instance of SSLServerSocket - */ - public ServerSocket init(final ServerSocket socket) { - ((SSLServerSocket) socket).setUseClientMode(true); - return socket; - } -} diff --git a/src/org/apache/commons/net/ftp/FTPSSocketFactory.java b/src/org/apache/commons/net/ftp/FTPSSocketFactory.java deleted file mode 100644 index 83f22897..00000000 --- a/src/org/apache/commons/net/ftp/FTPSSocketFactory.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; - -/** - * - * Socket factory for FTPS connections. - * - * @since 2.0 - */ -public class FTPSSocketFactory extends SocketFactory { - - private final SSLContext context; - - public FTPSSocketFactory(final SSLContext context) { - this.context = context; - } - - // Override the default implementation - @Override - public Socket createSocket() throws IOException{ - return this.context.getSocketFactory().createSocket(); - } - - @Override - public Socket createSocket(final String address, final int port) throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override - public Socket createSocket(final InetAddress address, final int port) throws IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override - public Socket createSocket(final String address, final int port, final InetAddress localAddress, final int localPort) - throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - @Override - public Socket createSocket(final InetAddress address, final int port, final InetAddress localAddress, - final int localPort) throws IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** @param port the port - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead} */ - @Deprecated - public java.net.ServerSocket createServerSocket(final int port) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port)); - } - - /** @param port the port - * @param backlog the backlog - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead} */ - @Deprecated - public java.net.ServerSocket createServerSocket(final int port, final int backlog) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); - } - - /** @param port the port - * @param backlog the backlog - * @param ifAddress the interface - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress) instead} */ - @Deprecated - public java.net.ServerSocket createServerSocket(final int port, final int backlog, final InetAddress ifAddress) - throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); - } - - /** @param socket the socket - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)} */ - @Deprecated - public java.net.ServerSocket init(final java.net.ServerSocket socket) throws IOException { - ((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true); - return socket; - } - -} diff --git a/src/org/apache/commons/net/ftp/FTPSTrustManager.java b/src/org/apache/commons/net/ftp/FTPSTrustManager.java deleted file mode 100644 index c6399078..00000000 --- a/src/org/apache/commons/net/ftp/FTPSTrustManager.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.X509TrustManager; - -import org.apache.commons.net.util.NetConstants; - -/** - * Do not use. - * @since 2.0 - * @deprecated 3.0 use - * {@link org.apache.commons.net.util.TrustManagerUtils#getValidateServerCertificateTrustManager() - * TrustManagerUtils#getValidateServerCertificateTrustManager()} instead - */ -@Deprecated -public class FTPSTrustManager implements X509TrustManager -{ - /** - * No-op - */ - @Override - public void checkClientTrusted(final X509Certificate[] certificates, final String authType) - { - } - - @Override - public void checkServerTrusted(final X509Certificate[] certificates, final String authType) throws CertificateException - { - for (final X509Certificate certificate : certificates) - { - certificate.checkValidity(); - } - } - - @Override - public X509Certificate[] getAcceptedIssuers() - { - return NetConstants.EMPTY_X509_CERTIFICATE_ARRAY; - } -} diff --git a/src/org/apache/commons/net/ftp/package-info.java b/src/org/apache/commons/net/ftp/package-info.java deleted file mode 100644 index 63a06a01..00000000 --- a/src/org/apache/commons/net/ftp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * FTP and FTPS support classes - */ -package org.apache.commons.net.ftp; \ No newline at end of file diff --git a/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java b/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java deleted file mode 100644 index f21490c7..00000000 --- a/src/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPFileEntryParser; -import org.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * This implementation allows to pack some FileEntryParsers together - * and handle the case where to returned dirstyle isnt clearly defined. - * The matching parser will be cached. - * If the cached parser wont match due to the server changed the dirstyle, - * a new matching parser will be searched. - */ -public class CompositeFileEntryParser extends FTPFileEntryParserImpl -{ - private final FTPFileEntryParser[] ftpFileEntryParsers; - private FTPFileEntryParser cachedFtpFileEntryParser; - - public CompositeFileEntryParser(final FTPFileEntryParser[] ftpFileEntryParsers) - { - this.cachedFtpFileEntryParser = null; - this.ftpFileEntryParsers = ftpFileEntryParsers; - } - - @Override - public FTPFile parseFTPEntry(final String listEntry) - { - if (cachedFtpFileEntryParser != null) - { - final FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) - { - return matched; - } - } - else - { - for (final FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers) - { - final FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) - { - cachedFtpFileEntryParser = ftpFileEntryParser; - return matched; - } - } - } - return null; - } -} diff --git a/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java deleted file mode 100644 index c7ee9a78..00000000 --- a/src/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.Calendar; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; - - -/** - *

- * This abstract class implements the common timestamp parsing - * algorithm for all the concrete parsers. Classes derived from - * this one will parse file listings via a supplied regular expression - * that pulls out the date portion as a separate string which is - * passed to the underlying {@link FTPTimestampParser delegate} to - * handle parsing of the file timestamp. - *

- * This class also implements the {@link Configurable Configurable} - * interface to allow the parser to be configured from the outside. - * - * @since 1.4 - */ -public abstract class ConfigurableFTPFileEntryParserImpl -extends RegexFTPFileEntryParserImpl -implements Configurable -{ - - private final FTPTimestampParser timestampParser; - - /** - * constructor for this abstract class. - * @param regex Regular expression used main parsing of the - * file listing. - */ - public ConfigurableFTPFileEntryParserImpl(final String regex) - { - super(regex); - this.timestampParser = new FTPTimestampParserImpl(); - } - - /** - * constructor for this abstract class. - * @param regex Regular expression used main parsing of the - * file listing. - * @param flags the flags to apply, see - * {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for none. - * @since 3.4 - */ - public ConfigurableFTPFileEntryParserImpl(final String regex, final int flags) - { - super(regex, flags); - this.timestampParser = new FTPTimestampParserImpl(); - } - - /** - * This method is called by the concrete parsers to delegate - * timestamp parsing to the timestamp parser. - * - * @param timestampStr the timestamp string pulled from the - * file listing by the regular expression parser, to be submitted - * to the timestampParser for extracting the timestamp. - * @return a java.util.Calendar containing results of the - * timestamp parse. - * @throws ParseException on parse error - */ - public Calendar parseTimestamp(final String timestampStr) throws ParseException { - return this.timestampParser.parseTimestamp(timestampStr); - } - - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this parser by delegating to the - * underlying Configurable FTPTimestampParser implementation, ' - * passing it the supplied {@link FTPClientConfig FTPClientConfig} - * if that is non-null or a default configuration defined by - * each concrete subclass. - * - * @param config the configuration to be used to configure this parser. - * If it is null, a default configuration defined by - * each concrete subclass is used instead. - */ - @Override - public void configure(final FTPClientConfig config) - { - if (this.timestampParser instanceof Configurable) { - final FTPClientConfig defaultCfg = getDefaultConfiguration(); - if (config != null) { - if (null == config.getDefaultDateFormatStr()) { - config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); - } - if (null == config.getRecentDateFormatStr()) { - config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); - } - ((Configurable)this.timestampParser).configure(config); - } else { - ((Configurable)this.timestampParser).configure(defaultCfg); - } - } - } - - /** - * Each concrete subclass must define this member to create - * a default configuration to be used when that subclass is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for the subclass. - */ - protected abstract FTPClientConfig getDefaultConfiguration(); -} diff --git a/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java b/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java deleted file mode 100644 index 45953bde..00000000 --- a/src/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.util.regex.Pattern; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFileEntryParser; - - -/** - * This is the default implementation of the - * FTPFileEntryParserFactory interface. This is the - * implementation that will be used by - * org.apache.commons.net.ftp.FTPClient.listFiles() - * if no other implementation has been specified. - * - * @see org.apache.commons.net.ftp.FTPClient#listFiles - * @see org.apache.commons.net.ftp.FTPClient#setParserFactory - */ -public class DefaultFTPFileEntryParserFactory - implements FTPFileEntryParserFactory -{ - - // Match a plain Java Identifier - private static final String JAVA_IDENTIFIER = "\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart})*"; - // Match a qualified name, e.g. a.b.c.Name - but don't allow the default package as that would allow "VMS"/"UNIX" etc. - private static final String JAVA_QUALIFIED_NAME = "("+JAVA_IDENTIFIER+"\\.)+"+JAVA_IDENTIFIER; - // Create the pattern, as it will be reused many times - private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME); - - /** - * This default implementation of the FTPFileEntryParserFactory - * interface works according to the following logic: - * First it attempts to interpret the supplied key as a fully - * qualified classname (default package is not allowed) of a class implementing the - * FTPFileEntryParser interface. If that succeeds, a parser - * object of this class is instantiated and is returned; - * otherwise it attempts to interpret the key as an identirier - * commonly used by the FTP SYST command to identify systems. - *

- * If key is not recognized as a fully qualified - * classname known to the system, this method will then attempt - * to see whether it contains a string identifying one of - * the known parsers. This comparison is case-insensitive. - * The intent here is where possible, to select as keys strings - * which are returned by the SYST command on the systems which - * the corresponding parser successfully parses. This enables - * this factory to be used in the auto-detection system. - * - * @param key should be a fully qualified classname corresponding to - * a class implementing the FTPFileEntryParser interface
- * OR
- * a string containing (case-insensitively) one of the - * following keywords: - *

    - *
  • {@link FTPClientConfig#SYST_UNIX UNIX}
  • - *
  • {@link FTPClientConfig#SYST_NT WINDOWS}
  • - *
  • {@link FTPClientConfig#SYST_OS2 OS/2}
  • - *
  • {@link FTPClientConfig#SYST_OS400 OS/400}
  • - *
  • {@link FTPClientConfig#SYST_AS400 AS/400}
  • - *
  • {@link FTPClientConfig#SYST_VMS VMS}
  • - *
  • {@link FTPClientConfig#SYST_MVS MVS}
  • - *
  • {@link FTPClientConfig#SYST_NETWARE NETWARE}
  • - *
  • {@link FTPClientConfig#SYST_L8 TYPE:L8}
  • - *
- * @return the FTPFileEntryParser corresponding to the supplied key. - * @throws ParserInitializationException thrown if for any reason the factory cannot resolve - * the supplied key into an FTPFileEntryParser. - * @see FTPFileEntryParser - */ - @Override - public FTPFileEntryParser createFileEntryParser(final String key) - { - if (key == null) { - throw new ParserInitializationException("Parser key cannot be null"); - } - return createFileEntryParser(key, null); - } - - // Common method to process both key and config parameters. - @SuppressWarnings("deprecation") - private FTPFileEntryParser createFileEntryParser(final String key, final FTPClientConfig config) { - FTPFileEntryParser parser = null; - - // Is the key a possible class name? - if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) { - try - { - final Class parserClass = Class.forName(key); - try { - parser = (FTPFileEntryParser) parserClass.newInstance(); - } catch (final ClassCastException e) { - throw new ParserInitializationException(parserClass.getName() - + " does not implement the interface " - + "org.apache.commons.net.ftp.FTPFileEntryParser.", e); - } catch (final Exception | ExceptionInInitializerError e) { - throw new ParserInitializationException("Error initializing parser", e); - } - } catch (final ClassNotFoundException e) { - // OK, assume it is an alias - } - } - - if (parser == null) { // Now try for aliases - final String ukey = key.toUpperCase(java.util.Locale.ENGLISH); - if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) - { - parser = new UnixFTPEntryParser(config, true); - } - // must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it - else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) - { - parser = new UnixFTPEntryParser(config, false); - } - else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) - { - parser = new VMSVersioningFTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) - { - parser = createNTFTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) - { - parser = new OS2FTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || - ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) - { - parser = createOS400FTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) - { - parser = new MVSFTPEntryParser(); // Does not currently support config parameter - } - else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) - { - parser = new NetwareFTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0) - { - parser = new MacOsPeterFTPEntryParser(config); - } - else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0) - { - // L8 normally means Unix, but move it to the end for some L8 systems that aren't. - // This check should be last! - parser = new UnixFTPEntryParser(config); - } - else - { - throw new ParserInitializationException("Unknown parser type: " + key); - } - } - - if (parser instanceof Configurable) { - ((Configurable)parser).configure(config); - } - return parser; - } - - /** - *

Implementation extracts a key from the supplied - * {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @throws ParserInitializationException - * Thrown on any exception in instantiation - * @throws NullPointerException if {@code config} is {@code null} - * @since 1.4 - */ - @Override - public FTPFileEntryParser createFileEntryParser(final FTPClientConfig config) - throws ParserInitializationException - { - final String key = config.getServerSystemKey(); - return createFileEntryParser(key, config); - } - - - public FTPFileEntryParser createUnixFTPEntryParser() - { - return new UnixFTPEntryParser(); - } - - public FTPFileEntryParser createVMSVersioningFTPEntryParser() - { - return new VMSVersioningFTPEntryParser(); - } - - public FTPFileEntryParser createNetwareFTPEntryParser() { - return new NetwareFTPEntryParser(); - } - - public FTPFileEntryParser createNTFTPEntryParser() - { - return createNTFTPEntryParser(null); - } - - /** - * Creates an NT FTP parser: if the config exists, and the system key equals - * {@link FTPClientConfig#SYST_NT} then a plain {@link NTFTPEntryParser} is used, - * otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used. - * @param config the config to use, may be {@code null} - * @return the parser - */ - private FTPFileEntryParser createNTFTPEntryParser(final FTPClientConfig config) - { - if (config != null && FTPClientConfig.SYST_NT.equals( - config.getServerSystemKey())) - { - return new NTFTPEntryParser(config); - } - // clone the config as it may be changed by the parsers (NET-602) - final FTPClientConfig config2 = config != null ? new FTPClientConfig(config) : null; - return new CompositeFileEntryParser(new FTPFileEntryParser[] - { - new NTFTPEntryParser(config), - new UnixFTPEntryParser(config2, - config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey())) - }); - } - - public FTPFileEntryParser createOS2FTPEntryParser() - { - return new OS2FTPEntryParser(); - } - - public FTPFileEntryParser createOS400FTPEntryParser() - { - return createOS400FTPEntryParser(null); - } - - /** - * Creates an OS400 FTP parser: if the config exists, and the system key equals - * {@link FTPClientConfig#SYST_OS400} then a plain {@link OS400FTPEntryParser} is used, - * otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used. - * @param config the config to use, may be {@code null} - * @return the parser - */ - private FTPFileEntryParser createOS400FTPEntryParser(final FTPClientConfig config) - { - if (config != null && - FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) - { - return new OS400FTPEntryParser(config); - } - // clone the config as it may be changed by the parsers (NET-602) - final FTPClientConfig config2 = config != null ? new FTPClientConfig(config) : null; - return new CompositeFileEntryParser(new FTPFileEntryParser[] - { - new OS400FTPEntryParser(config), - new UnixFTPEntryParser(config2, - config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey())) - }); - } - - public FTPFileEntryParser createMVSEntryParser() - { - return new MVSFTPEntryParser(); - } - -} - diff --git a/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java deleted file mode 100644 index f39e1c3e..00000000 --- a/src/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.util.Calendar; - -import org.apache.commons.net.ftp.FTPFile; - -/** - * Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. - * Here is a sample of the sort of output line this parser processes: - *
- *  "-C--E-----FTP B QUA1I1      18128       41 Aug 12 13:56 QUADTEST"
- * 
- *

- * Note: EnterpriseUnixFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - *

- * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ -public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl -{ - - /** - * months abbreviations looked for by this parser. Also used - * to determine which month has been matched by the parser. - */ - private static final String MONTHS = - "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" - + "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" - + "(\\S*)\\s*" // 12 - + "(\\S+)\\s*" // 13 - + "(\\S*)\\s*" // 14 user - + "(\\d*)\\s*" // 15 group - + "(\\d*)\\s*" // 16 filesize - + MONTHS // 17 month - + "\\s*" // TODO should the space be optional? - // TODO \\d* should be \\d? surely ? Otherwise 01111 is allowed - + "((?:[012]\\d*)|(?:3[01]))\\s*" // 18 date [012]\d* or 3[01] - + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" - // 20 \d\d\d\d = year OR - // 21 [01]\d or 2[0123] hour + ':' - // 22 [012345]\d = minute - + "(\\S*)(\\s*.*)"; // 23 name - - /** - * The sole constructor for a EnterpriseUnixFTPEntryParser object. - * - */ - public EnterpriseUnixFTPEntryParser() - { - super(REGEX); - } - - /** - * Parses a line of a unix FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If - * the file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) - { - - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - - if (matches(entry)) - { - final String usr = group(14); - final String grp = group(15); - final String filesize = group(16); - final String mo = group(17); - final String da = group(18); - final String yr = group(20); - final String hr = group(21); - final String min = group(22); - final String name = group(23); - - file.setType(FTPFile.FILE_TYPE); - file.setUser(usr); - file.setGroup(grp); - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - - final Calendar cal = Calendar.getInstance(); - cal.set(Calendar.MILLISECOND, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.HOUR_OF_DAY, 0); - - final int pos = MONTHS.indexOf(mo); - final int month = pos / 4; - final int missingUnit; // the first missing unit - try - { - - if (yr != null) - { - // it's a year; there are no hours and minutes - cal.set(Calendar.YEAR, Integer.parseInt(yr)); - missingUnit = Calendar.HOUR_OF_DAY; - } - else - { - // it must be hour/minute or we wouldn't have matched - missingUnit = Calendar.SECOND; - int year = cal.get(Calendar.YEAR); - - // if the month we're reading is greater than now, it must - // be last year - if (cal.get(Calendar.MONTH) < month) - { - year--; - } - cal.set(Calendar.YEAR, year); - cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hr)); - cal.set(Calendar.MINUTE, Integer.parseInt(min)); - } - cal.set(Calendar.MONTH, month); - cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da)); - cal.clear(missingUnit); - file.setTimestamp(cal); - } - catch (final NumberFormatException e) - { - // do nothing, date will be uninitialized - } - file.setName(name); - - return file; - } - return null; - } -} diff --git a/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java b/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java deleted file mode 100644 index 5809c3b9..00000000 --- a/src/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFileEntryParser; - -/** - * The interface describes a factory for creating FTPFileEntryParsers. - * @since 1.2 - */ -public interface FTPFileEntryParserFactory -{ - /** - * Implementation should be a method that decodes the - * supplied key and creates an object implementing the - * interface FTPFileEntryParser. - * - * @param key A string that somehow identifies an - * FTPFileEntryParser to be created. - * - * @return the FTPFileEntryParser created. - * @throws ParserInitializationException - * Thrown on any exception in instantiation - */ - FTPFileEntryParser createFileEntryParser(String key) - throws ParserInitializationException; - - /** - *

- * Implementation should be a method that extracts - * a key from the supplied {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * - * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @throws ParserInitializationException - * Thrown on any exception in instantiation - * @since 1.4 - */ - FTPFileEntryParser createFileEntryParser(FTPClientConfig config) - throws ParserInitializationException; - -} diff --git a/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java b/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java deleted file mode 100644 index 400e872c..00000000 --- a/src/org/apache/commons/net/ftp/parser/FTPTimestampParser.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.Calendar; - -/** - * This interface specifies the concept of parsing an FTP server's - * timestamp. - * @since 1.4 - */ -public interface FTPTimestampParser { - - /** - * the default default date format. - */ - String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; - /** - * the default recent date format. - */ - String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; - - /** - * Parses the supplied datestamp parameter. This parameter typically would - * have been pulled from a longer FTP listing via the regular expression - * mechanism - * @param timestampStr - the timestamp portion of the FTP directory listing - * to be parsed - * @return a java.util.Calendar object initialized to the date - * parsed by the parser - * @throws ParseException if none of the parser mechanisms belonging to - * the implementor can parse the input. - */ - Calendar parseTimestamp(String timestampStr) throws ParseException; - -} diff --git a/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java deleted file mode 100644 index b0995ece..00000000 --- a/src/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; - -/** - * Default implementation of the {@link FTPTimestampParser FTPTimestampParser} - * interface also implements the {@link org.apache.commons.net.ftp.Configurable Configurable} - * interface to allow the parsing to be configured from the outside. - * - * @see ConfigurableFTPFileEntryParserImpl - * @since 1.4 - */ -public class FTPTimestampParserImpl implements - FTPTimestampParser, Configurable -{ - - - /** The date format for all dates, except possibly recent dates. Assumed to include the year. */ - private SimpleDateFormat defaultDateFormat; - /* The index in CALENDAR_UNITS of the smallest time unit in defaultDateFormat */ - private int defaultDateSmallestUnitIndex; - - /** The format used for recent dates (which don't have the year). May be null. */ - private SimpleDateFormat recentDateFormat; - /* The index in CALENDAR_UNITS of the smallest time unit in recentDateFormat */ - private int recentDateSmallestUnitIndex; - - private boolean lenientFutureDates; - - /* - * List of units in order of increasing significance. - * This allows the code to clear all units in the Calendar until it - * reaches the least significant unit in the parse string. - * The date formats are analysed to find the least significant - * unit (e.g. Minutes or Milliseconds) and the appropriate index to - * the array is saved. - * This is done by searching the array for the unit specifier, - * and returning the index. When clearing the Calendar units, - * the code loops through the array until the previous entry. - * e.g. for MINUTE it would clear MILLISECOND and SECOND - */ - private static final int[] CALENDAR_UNITS = { - Calendar.MILLISECOND, - Calendar.SECOND, - Calendar.MINUTE, - Calendar.HOUR_OF_DAY, - Calendar.DAY_OF_MONTH, - Calendar.MONTH, - Calendar.YEAR}; - - /* - * Return the index to the array representing the least significant - * unit found in the date format. - * Default is 0 (to avoid dropping precision) - */ - private static int getEntry(final SimpleDateFormat dateFormat) { - if (dateFormat == null) { - return 0; - } - final String FORMAT_CHARS="SsmHdM"; - final String pattern = dateFormat.toPattern(); - for(final char ch : FORMAT_CHARS.toCharArray()) { - if (pattern.indexOf(ch) != -1){ // found the character - switch(ch) { - case 'S': - return indexOf(Calendar.MILLISECOND); - case 's': - return indexOf(Calendar.SECOND); - case 'm': - return indexOf(Calendar.MINUTE); - case 'H': - return indexOf(Calendar.HOUR_OF_DAY); - case 'd': - return indexOf(Calendar.DAY_OF_MONTH); - case 'M': - return indexOf(Calendar.MONTH); - } - } - } - return 0; - } - - /* - * Find the entry in the CALENDAR_UNITS array. - */ - private static int indexOf(final int calendarUnit) { - int i; - for(i = 0; i NET-83) - now.add(Calendar.DAY_OF_MONTH, 1); - } - // The Java SimpleDateFormat class uses the epoch year 1970 if not present in the input - // As 1970 was not a leap year, it cannot parse "Feb 29" correctly. - // Java 1.5+ returns Mar 1 1970 - // Temporarily add the current year to the short date time - // to cope with short-date leap year strings. - // Since Feb 29 is more that 6 months from the end of the year, this should be OK for - // all instances of short dates which are +- 6 months from current date. - // TODO this won't always work for systems that use short dates +0/-12months - // e.g. if today is Jan 1 2001 and the short date is Feb 29 - final String year = Integer.toString(now.get(Calendar.YEAR)); - final String timeStampStrPlusYear = timestampStr + " " + year; - final SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", - recentDateFormat.getDateFormatSymbols()); - hackFormatter.setLenient(false); - hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); - final ParsePosition pp = new ParsePosition(0); - parsed = hackFormatter.parse(timeStampStrPlusYear, pp); - // Check if we parsed the full string, if so it must have been a short date originally - if (parsed != null && pp.getIndex() == timeStampStrPlusYear.length()) { - working.setTime(parsed); - if (working.after(now)) { // must have been last year instead - working.add(Calendar.YEAR, -1); - } - setPrecision(recentDateSmallestUnitIndex, working); - return working; - } - } - - final ParsePosition pp = new ParsePosition(0); - parsed = defaultDateFormat.parse(timestampStr, pp); - // note, length checks are mandatory for us since - // SimpleDateFormat methods will succeed if less than - // full string is matched. They will also accept, - // despite "leniency" setting, a two-digit number as - // a valid year (e.g. 22:04 will parse as 22 A.D.) - // so could mistakenly confuse an hour with a year, - // if we don't insist on full length parsing. - if (parsed != null && pp.getIndex() == timestampStr.length()) { - working.setTime(parsed); - } else { - throw new ParseException( - "Timestamp '"+timestampStr+"' could not be parsed using a server time of " - +serverTime.getTime().toString(), - pp.getErrorIndex()); - } - setPrecision(defaultDateSmallestUnitIndex, working); - return working; - } - - /** - * @return Returns the defaultDateFormat. - */ - public SimpleDateFormat getDefaultDateFormat() { - return defaultDateFormat; - } - /** - * @return Returns the defaultDateFormat pattern string. - */ - public String getDefaultDateFormatString() { - return defaultDateFormat.toPattern(); - } - /** - * @param format The defaultDateFormat to be set. - * @param dfs the symbols to use (may be null) - */ - private void setDefaultDateFormat(final String format, final DateFormatSymbols dfs) { - if (format != null) { - if (dfs != null) { - this.defaultDateFormat = new SimpleDateFormat(format, dfs); - } else { - this.defaultDateFormat = new SimpleDateFormat(format); - } - this.defaultDateFormat.setLenient(false); - } else { - this.defaultDateFormat = null; - } - this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat); - } - /** - * @return Returns the recentDateFormat. - */ - public SimpleDateFormat getRecentDateFormat() { - return recentDateFormat; - } - /** - * @return Returns the recentDateFormat. - */ - public String getRecentDateFormatString() { - return recentDateFormat.toPattern(); - } - /** - * @param format The recentDateFormat to set. - * @param dfs the symbols to use (may be null) - */ - private void setRecentDateFormat(final String format, final DateFormatSymbols dfs) { - if (format != null) { - if (dfs != null) { - this.recentDateFormat = new SimpleDateFormat(format, dfs); - } else { - this.recentDateFormat = new SimpleDateFormat(format); - } - this.recentDateFormat.setLenient(false); - } else { - this.recentDateFormat = null; - } - this.recentDateSmallestUnitIndex = getEntry(this.recentDateFormat); - } - - /** - * @return returns an array of 12 strings representing the short - * month names used by this parse. - */ - public String[] getShortMonths() { - return defaultDateFormat.getDateFormatSymbols().getShortMonths(); - } - - - /** - * @return Returns the serverTimeZone used by this parser. - */ - public TimeZone getServerTimeZone() { - return this.defaultDateFormat.getTimeZone(); - } - /** - * sets a TimeZone represented by the supplied ID string into all - * of the parsers used by this server. - * @param serverTimeZoneId Time Id java.util.TimeZone id used by - * the ftp server. If null the client's local time zone is assumed. - */ - private void setServerTimeZone(final String serverTimeZoneId) { - TimeZone serverTimeZone = TimeZone.getDefault(); - if (serverTimeZoneId != null) { - serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); - } - this.defaultDateFormat.setTimeZone(serverTimeZone); - if (this.recentDateFormat != null) { - this.recentDateFormat.setTimeZone(serverTimeZone); - } - } - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this FTPTimestampParser according - * to the following logic: - *

- * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(java.lang.String) defaultDateFormat} - * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} - * to values supplied in the config based on month names configured as follows: - *

- *
    - *
  • If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} - * has been supplied in the config, use that to parse parse timestamps.
  • - *
  • Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} - * has been supplied in the config, use the month names represented - * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} - * to parse timestamps.
  • - *
  • otherwise use default English month names
  • - *

- * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} - * has been supplied via the config, set that into all date formats that have - * been configured. - *

- */ - @Override - public void configure(final FTPClientConfig config) { - DateFormatSymbols dfs = null; - - final String languageCode = config.getServerLanguageCode(); - final String shortmonths = config.getShortMonthNames(); - if (shortmonths != null) { - dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); - } else if (languageCode != null) { - dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); - } else { - dfs = FTPClientConfig.lookupDateFormatSymbols("en"); - } - - - final String recentFormatString = config.getRecentDateFormatStr(); - setRecentDateFormat(recentFormatString, dfs); - - final String defaultFormatString = config.getDefaultDateFormatStr(); - if (defaultFormatString == null) { - throw new IllegalArgumentException("defaultFormatString cannot be null"); - } - setDefaultDateFormat(defaultFormatString, dfs); - - setServerTimeZone(config.getServerTimeZoneId()); - - this.lenientFutureDates = config.isLenientFutureDates(); - } - /** - * @return Returns the lenientFutureDates. - */ - boolean isLenientFutureDates() { - return lenientFutureDates; - } - /** - * @param lenientFutureDates The lenientFutureDates to set. - */ - void setLenientFutureDates(final boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } -} diff --git a/src/org/apache/commons/net/ftp/parser/MLSxEntryParser.java b/src/org/apache/commons/net/ftp/parser/MLSxEntryParser.java deleted file mode 100644 index 64d46eec..00000000 --- a/src/org/apache/commons/net/ftp/parser/MLSxEntryParser.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Locale; -import java.util.TimeZone; - -import org.apache.commons.net.ftp.FTPFile; -import org.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * Parser class for MSLT and MLSD replies. See RFC 3659. - *

- * Format is as follows: - *

- *
- * entry            = [ facts ] SP pathname
- * facts            = 1*( fact ";" )
- * fact             = factname "=" value
- * factname         = "Size" / "Modify" / "Create" /
- *                    "Type" / "Unique" / "Perm" /
- *                    "Lang" / "Media-Type" / "CharSet" /
- * os-depend-fact / local-fact
- * os-depend-fact   = {IANA assigned OS name} "." token
- * local-fact       = "X." token
- * value            = *SCHAR
- *
- * Sample os-depend-fact:
- * UNIX.group=0;UNIX.mode=0755;UNIX.owner=0;
- * 
- *

- * A single control response entry (MLST) is returned with a leading space; - * multiple (data) entries are returned without any leading spaces. - * The parser requires that the leading space from the MLST entry is removed. - * MLSD entries can begin with a single space if there are no facts. - *

- * - * @since 3.0 - */ -public class MLSxEntryParser extends FTPFileEntryParserImpl -{ - // This class is immutable, so a single instance can be shared. - private static final MLSxEntryParser INSTANCE = new MLSxEntryParser(); - - private static final HashMap TYPE_TO_INT = new HashMap<>(); - static { - TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE)); - TYPE_TO_INT.put("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // listed directory - TYPE_TO_INT.put("pdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // a parent dir - TYPE_TO_INT.put("dir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // dir or sub-dir - } - - private static final int[] UNIX_GROUPS = { // Groups in order of mode digits - FTPFile.USER_ACCESS, - FTPFile.GROUP_ACCESS, - FTPFile.WORLD_ACCESS, - }; - - private static final int[][] UNIX_PERMS = { // perm bits, broken down by octal int value -/* 0 */ {}, -/* 1 */ {FTPFile.EXECUTE_PERMISSION}, -/* 2 */ {FTPFile.WRITE_PERMISSION}, -/* 3 */ {FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION}, -/* 4 */ {FTPFile.READ_PERMISSION}, -/* 5 */ {FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION}, -/* 6 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION}, -/* 7 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION}, - }; - - /** - * Create the parser for MSLT and MSLD listing entries - * This class is immutable, so one can use {@link #getInstance()} instead. - */ - public MLSxEntryParser() - { - } - - @Override - public FTPFile parseFTPEntry(final String entry) { - if (entry.startsWith(" ")) {// leading space means no facts are present - if (entry.length() > 1) { // is there a path name? - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - file.setName(entry.substring(1)); - return file; - } - return null; // Invalid - no pathname - - } - final String parts[] = entry.split(" ",2); // Path may contain space - if (parts.length != 2 || parts[1].isEmpty()) { - return null; // no space found or no file name - } - final String factList = parts[0]; - if (!factList.endsWith(";")) { - return null; - } - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - file.setName(parts[1]); - final String[] facts = factList.split(";"); - final boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode="); - for(final String fact : facts) { - final String []factparts = fact.split("=", -1); // Don't drop empty values -// Sample missing permission -// drwx------ 2 mirror mirror 4096 Mar 13 2010 subversion -// modify=20100313224553;perm=;type=dir;unique=811U282598;UNIX.group=500;UNIX.mode=0700;UNIX.owner=500; subversion - if (factparts.length != 2) { - return null; // invalid - there was no "=" sign - } - final String factname = factparts[0].toLowerCase(Locale.ENGLISH); - final String factvalue = factparts[1]; - if (factvalue.isEmpty()) { - continue; // nothing to see here - } - final String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH); - if ("size".equals(factname) || "sizd".equals(factname)) { - file.setSize(Long.parseLong(factvalue)); - } - else if ("modify".equals(factname)) { - final Calendar parsed = parseGMTdateTime(factvalue); - if (parsed == null) { - return null; - } - file.setTimestamp(parsed); - } - else if ("type".equals(factname)) { - final Integer intType = TYPE_TO_INT.get(valueLowerCase); - if (intType == null) { - file.setType(FTPFile.UNKNOWN_TYPE); - } else { - file.setType(intType.intValue()); - } - } - else if (factname.startsWith("unix.")) { - final String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH); - if ("group".equals(unixfact)){ - file.setGroup(factvalue); - } else if ("owner".equals(unixfact)){ - file.setUser(factvalue); - } else if ("mode".equals(unixfact)){ // e.g. 0[1]755 - final int off = factvalue.length()-3; // only parse last 3 digits - for(int i=0; i < 3; i++){ - final int ch = factvalue.charAt(off+i)-'0'; - if (ch >= 0 && ch <= 7) { // Check it's valid octal - for(final int p : UNIX_PERMS[ch]) { - file.setPermission(UNIX_GROUPS[i], p, true); - } - } else { - // TODO should this cause failure, or can it be reported somehow? - } - } // digits - } // mode - } // unix. - else if (!hasUnixMode && "perm".equals(factname)) { // skip if we have the UNIX.mode - doUnixPerms(file, valueLowerCase); - } // process "perm" - } // each fact - return file; - } - - /** - * Parse a GMT time stamp of the form YYYYMMDDHHMMSS[.sss] - * - * @param timestamp the date-time to parse - * @return a Calendar entry, may be {@code null} - * @since 3.4 - */ - public static Calendar parseGMTdateTime(final String timestamp) { - final SimpleDateFormat sdf; - final boolean hasMillis; - if (timestamp.contains(".")){ - sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); - hasMillis = true; - } else { - sdf = new SimpleDateFormat("yyyyMMddHHmmss"); - hasMillis = false; - } - final TimeZone GMT = TimeZone.getTimeZone("GMT"); - // both time zones need to be set for the parse to work OK - sdf.setTimeZone(GMT); - final GregorianCalendar gc = new GregorianCalendar(GMT); - final ParsePosition pos = new ParsePosition(0); - sdf.setLenient(false); // We want to parse the whole string - final Date parsed = sdf.parse(timestamp, pos); - if (pos.getIndex() != timestamp.length()) { - return null; // did not fully parse the input - } - gc.setTime(parsed); - if (!hasMillis) { - gc.clear(Calendar.MILLISECOND); // flag up missing ms units - } - return gc; - } - - // perm-fact = "Perm" "=" *pvals - // pvals = "a" / "c" / "d" / "e" / "f" / - // "l" / "m" / "p" / "r" / "w" - private void doUnixPerms(final FTPFile file, final String valueLowerCase) { - for(final char c : valueLowerCase.toCharArray()) { - // TODO these are mostly just guesses at present - switch (c) { - case 'a': // (file) may APPEnd - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'c': // (dir) files may be created in the dir - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'd': // deletable - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'e': // (dir) can change to this dir - file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); - break; - case 'f': // (file) renamable - // ?? file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'l': // (dir) can be listed - file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, true); - break; - case 'm': // (dir) can create directory here - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'p': // (dir) entries may be deleted - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'r': // (files) file may be RETRieved - file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); - break; - case 'w': // (files) file may be STORed - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - default: - break; - // ignore unexpected flag for now. - } // switch - } // each char - } - - public static FTPFile parseEntry(final String entry) { - return INSTANCE.parseFTPEntry(entry); - } - - public static MLSxEntryParser getInstance() { - return INSTANCE; - } -} diff --git a/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java deleted file mode 100644 index a73dc938..00000000 --- a/src/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.List; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS - * Systems. - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for - * usage instructions) - */ -public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - static final int UNKNOWN_LIST_TYPE = -1; - static final int FILE_LIST_TYPE = 0; - static final int MEMBER_LIST_TYPE = 1; - static final int UNIX_LIST_TYPE = 2; - static final int JES_LEVEL_1_LIST_TYPE = 3; - static final int JES_LEVEL_2_LIST_TYPE = 4; - - private int isType = UNKNOWN_LIST_TYPE; - - /** - * Fallback parser for Unix-style listings - */ - private UnixFTPEntryParser unixFTPEntryParser; - - /** - * Dates are ignored for file lists, but are used for member lists where - * possible - */ - static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18 - // 13:52 - - /** - * Matches these entries: - * - *
-     *  Volume Unit    Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname
-     *  B10142 3390   2006/03/20  2   31  F       80    80  PS   MDI.OKL.WORK
-     * 
- * - * @see Data - * set record formats - */ - static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume - // ignored - "\\S+\\s+" + // unit - ignored - "\\S+\\s+" + // access date - ignored - "\\S+\\s+" + // extents -ignored - // If the values are too large, the fields may be merged (NET-639) - "(?:\\S+\\s+)?" + // used - ignored - "(?:F|FB|V|VB|U)\\s+" + // recfm - F[B], V[B], U - "\\S+\\s+" + // logical record length -ignored - "\\S+\\s+" + // block size - ignored - "(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist - // but only support: PS, PO, PO-E - "(\\S+)\\s*"; // Dataset Name (file name) - - /** - * Matches these entries: - *
-     *   Name      VV.MM   Created       Changed      Size  Init   Mod   Id
-     *   TBSHELF   01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001
-     * 
- */ - static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name - "\\S+\\s+" + // version, modification (ignored) - "\\S+\\s+" + // create date (ignored) - "(\\S+)\\s+" + // modification date - "(\\S+)\\s+" + // modification time - "\\S+\\s+" + // size in lines (ignored) - "\\S+\\s+" + // size in lines at creation(ignored) - "\\S+\\s+" + // lines modified (ignored) - "\\S+\\s*"; // id of user who modified (ignored) - - /** - * Matches these entries, note: no header: - *
-     *   IBMUSER1  JOB01906  OUTPUT    3 Spool Files
-     *   012345678901234567890123456789012345678901234
-     *             1         2         3         4
-     * 
- */ - static final String JES_LEVEL_1_LIST_REGEX = - "(\\S+)\\s+" + // job name ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) - "(\\S+)\\s+" + // number of spool files - "(\\S+)\\s+" + // Text "Spool" ignored - "(\\S+)\\s*" // Text "Files" ignored - ; - - /** - * JES INTERFACE LEVEL 2 parser - * Matches these entries: - *
-     * JOBNAME  JOBID    OWNER    STATUS CLASS
-     * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000 3 spool files
-     * IBMUSER  TSU01830 IBMUSER  OUTPUT TSU      ABEND=522 3 spool files
-     * 
- * Sample output from FTP session: - *
-     * ftp> quote site filetype=jes
-     * 200 SITE command was accepted
-     * ftp> ls
-     * 200 Port request OK.
-     * 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER
-     * JOBNAME  JOBID    OWNER    STATUS CLASS
-     * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000 3 spool files
-     * IBMUSER  TSU01830 IBMUSER  OUTPUT TSU      ABEND=522 3 spool files
-     * 250 List completed successfully.
-     * ftp> ls job01906
-     * 200 Port request OK.
-     * 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER
-     * JOBNAME  JOBID    OWNER    STATUS CLASS
-     * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000
-     * --------
-     * ID  STEPNAME PROCSTEP C DDNAME   BYTE-COUNT
-     * 001 JES2              A JESMSGLG       858
-     * 002 JES2              A JESJCL         128
-     * 003 JES2              A JESYSMSG       443
-     * 3 spool files
-     * 250 List completed successfully.
-     * 
- */ - - static final String JES_LEVEL_2_LIST_REGEX = - "(\\S+)\\s+" + // job name ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // owner ignored - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored - "(\\S+)\\s+" + // job class ignored - "(\\S+).*" // rest ignored - ; - - /* - * --------------------------------------------------------------------- - * Very brief and incomplete description of the zOS/MVS-file system. (Note: - * "zOS" is the operating system on the mainframe, and is the new name for - * MVS) - * - * The file system on the mainframe does not have hierarchal structure as for - * example the unix file system. For a more comprehensive description, please - * refer to the IBM manuals - * - * @LINK: - * http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS - * - * - * Dataset names ============= - * - * A dataset name consist of a number of qualifiers separated by '.', each - * qualifier can be at most 8 characters, and the total length of a dataset - * can be max 44 characters including the dots. - * - * - * Dataset organisation ==================== - * - * A dataset represents a piece of storage allocated on one or more disks. - * The structure of the storage is described with the field dataset - * organinsation (DSORG). There are a number of dataset organisations, but - * only two are usable for FTP transfer. - * - * DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: - * extended partitioned dataset - * - * The PS file is just a flat file, as you would find it on the unix file - * system. - * - * The PO and PO-E files, can be compared to a single level directory - * structure. A PO file consist of a number of dataset members, or files if - * you will. It is possible to CD into the file, and to retrieve the - * individual members. - * - * - * Dataset record format ===================== - * - * The physical layout of the dataset is described on the dataset itself. - * There are a number of record formats (RECFM), but just a few is relavant - * for the FTP transfer. - * - * Any one beginning with either F or V can safely used by FTP transfer. All - * others should only be used with great care. - * F means a fixed number of records per - * allocated storage, and V means a variable number of records. - * - * - * Other notes =========== - * - * The file system supports automatically backup and retrieval of datasets. - * If a file is backed up, the ftp LIST command will return: ARCIVE Not - * Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST - * - * - * Implementation notes ==================== - * - * Only datasets that have dsorg PS, PO or PO-E and have recfm beginning - * with F or V or U, is fully parsed. - * - * The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. - * FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name - * FTPFile.Timestamp: change time or null - * - * - * - * Additional information ====================== - * - * The MVS ftp server supports a number of features via the FTP interface. - * The features are controlled with the FTP command quote site filetype= - * SEQ is the default and used for normal file transfer JES is used to - * interact with the Job Entry Subsystem (JES) similar to a job scheduler - * DB2 is used to interact with a DB2 subsystem - * - * This parser supports SEQ and JES. - * - * - * - * - * - * - */ - - /** - * The sole constructor for a MVSFTPEntryParser object. - * - */ - public MVSFTPEntryParser() { - super(""); // note the regex is set in preParse. - super.configure(null); // configure parser with default configurations - } - - /** - * Parses a line of an z/OS - MVS FTP server file listing and converts it - * into a usable format in the form of an FTPFile instance. - * If the file listing line doesn't describe a file, then - * null is returned. Otherwise a FTPFile - * instance representing the file is returned. - * - * @param entry - * A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) { - if (isType == FILE_LIST_TYPE) { - return parseFileList(entry); - } else if (isType == MEMBER_LIST_TYPE) { - return parseMemberList(entry); - } else if (isType == UNIX_LIST_TYPE) { - return unixFTPEntryParser.parseFTPEntry(entry); - } else if (isType == JES_LEVEL_1_LIST_TYPE) { - return parseJeslevel1List(entry); - } else if (isType == JES_LEVEL_2_LIST_TYPE) { - return parseJeslevel2List(entry); - } - - return null; - } - - /** - * Parse entries representing a dataset list. Only datasets with DSORG PS or - * PO or PO-E and with RECFM F[B], V[B], U will be parsed. - * - * Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred - * Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 - * 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device - * KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO - * PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB - * - * ----------------------------------- Group within Regex [1] Volume [2] - * Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record - * format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: - * Dataset organisation. Many exists but only support: PS, PO, PO-E [10] - * Dsname: Dataset name - * - * Note: When volume is ARCIVE, it means the dataset is stored somewhere in - * a tape archive. These entries is currently not supported by this parser. - * A null value is returned. - * - * @param entry zosDirectoryEntry - * @return null: entry was not parsed. - */ - private FTPFile parseFileList(final String entry) { - if (matches(entry)) { - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - final String name = group(2); - final String dsorg = group(1); - file.setName(name); - - // DSORG - if ("PS".equals(dsorg)) { - file.setType(FTPFile.FILE_TYPE); - } - else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { - // regex already ruled out anything other than PO or PO-E - file.setType(FTPFile.DIRECTORY_TYPE); - } - else { - return null; - } - - return file; - } - - return null; - } - - /** - * Parse entries within a partitioned dataset. - * - * Format of a memberlist within a PDS: - *
-     *    0         1        2          3        4     5     6      7    8
-     *   Name      VV.MM   Created       Changed      Size  Init   Mod   Id
-     *   TBSHELF   01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001
-     *   TBTOOL    01.12 2002/09/12 2004/11/26 19:54    51    28     0 KIL001
-     *
-     * -------------------------------------------
-     * [1] Name
-     * [2] VV.MM: Version . modification
-     * [3] Created: yyyy / MM / dd
-     * [4,5] Changed: yyyy / MM / dd HH:mm
-     * [6] Size: number of lines
-     * [7] Init: number of lines when first created
-     * [8] Mod: number of modified lines a last save
-     * [9] Id: User id for last update
-     * 
- * - * @param entry zosDirectoryEntry - * @return null: entry was not parsed. - */ - private FTPFile parseMemberList(final String entry) { - final FTPFile file = new FTPFile(); - if (matches(entry)) { - file.setRawListing(entry); - final String name = group(1); - final String datestr = group(2) + " " + group(3); - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - try { - file.setTimestamp(super.parseTimestamp(datestr)); - } catch (final ParseException e) { - // just ignore parsing errors. - // TODO check this is ok - // Drop thru to try simple parser - } - return file; - } - - /* - * Assigns the name to the first word of the entry. Only to be used from a - * safe context, for example from a memberlist, where the regex for some - * reason fails. Then just assign the name field of FTPFile. - */ - if (entry != null && !entry.trim().isEmpty()) { - file.setRawListing(entry); - final String name = entry.split(" ")[0]; - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return file; - } - return null; - } - - /** - * Matches these entries, note: no header: - *
-     * [1]      [2]      [3]   [4] [5]
-     * IBMUSER1 JOB01906 OUTPUT 3 Spool Files
-     * 012345678901234567890123456789012345678901234
-     *           1         2         3         4
-     * -------------------------------------------
-     * Group in regex
-     * [1] Job name
-     * [2] Job number
-     * [3] Job status (INPUT,ACTIVE,OUTPUT)
-     * [4] Number of sysout files
-     * [5] The string "Spool Files"
-     *
- * - * @param entry zosDirectoryEntry - * @return null: entry was not parsed. - */ - private FTPFile parseJeslevel1List(final String entry) { - if (matches(entry)) { - final FTPFile file = new FTPFile(); - if (group(3).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - final String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return file; - } - } - - return null; - } - - /** - * Matches these entries: - *
-     * [1]      [2]      [3]     [4]    [5]
-     * JOBNAME  JOBID    OWNER   STATUS CLASS
-     * IBMUSER1 JOB01906 IBMUSER OUTPUT A       RC=0000 3 spool files
-     * IBMUSER  TSU01830 IBMUSER OUTPUT TSU     ABEND=522 3 spool files
-     * 012345678901234567890123456789012345678901234
-     *           1         2         3         4
-     * -------------------------------------------
-     * Group in regex
-     * [1] Job name
-     * [2] Job number
-     * [3] Owner
-     * [4] Job status (INPUT,ACTIVE,OUTPUT)
-     * [5] Job Class
-     * [6] The rest
-     * 
- * - * @param entry zosDirectoryEntry - * @return null: entry was not parsed. - */ - private FTPFile parseJeslevel2List(final String entry) { - if (matches(entry)) { - final FTPFile file = new FTPFile(); - if (group(4).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - final String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return file; - } - } - - return null; - } - - /** - * preParse is called as part of the interface. Per definition is is called - * before the parsing takes place. - * Three kind of lists is recognize: - * z/OS-MVS File lists - * z/OS-MVS Member lists - * unix file lists - * @since 2.0 - */ - @Override - public List preParse(final List orig) { - // simply remove the header line. Composite logic will take care of the - // two different types of - // list in short order. - if (orig != null && !orig.isEmpty()) { - final String header = orig.get(0); - if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { - setType(FILE_LIST_TYPE); - super.setRegex(FILE_LIST_REGEX); - } else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { - setType(MEMBER_LIST_TYPE); - super.setRegex(MEMBER_LIST_REGEX); - } else if (header.indexOf("total") == 0) { - setType(UNIX_LIST_TYPE); - unixFTPEntryParser = new UnixFTPEntryParser(); - } else if (header.indexOf("Spool Files") >= 30) { - setType(JES_LEVEL_1_LIST_TYPE); - super.setRegex(JES_LEVEL_1_LIST_REGEX); - } else if (header.indexOf("JOBNAME") == 0 - && header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS - setType(JES_LEVEL_2_LIST_TYPE); - super.setRegex(JES_LEVEL_2_LIST_REGEX); - } else { - setType(UNKNOWN_LIST_TYPE); - } - - if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary - orig.remove(0); - } - } - - return orig; - } - - /** - * Explicitly set the type of listing being processed. - * @param type The listing type. - */ - void setType(final int type) { - isType = type; - } - - /* - * @return - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_MVS, - DEFAULT_DATE_FORMAT, null); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java deleted file mode 100644 index 1c9139d0..00000000 --- a/src/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for pre MacOS-X Systems. - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @since 3.1 - */ -public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - static final String DEFAULT_DATE_FORMAT - = "MMM d yyyy"; //Nov 9 2001 - - static final String DEFAULT_RECENT_DATE_FORMAT - = "MMM d HH:mm"; //Nov 9 20:06 - - /** - * this is the regular expression used by this parser. - * - * Permissions: - * r the file is readable - * w the file is writable - * x the file is executable - * - the indicated permission is not granted - * L mandatory locking occurs during access (the set-group-ID bit is - * on and the group execution bit is off) - * s the set-user-ID or set-group-ID bit is on, and the corresponding - * user or group execution bit is also on - * S undefined bit-state (the set-user-ID bit is on and the user - * execution bit is off) - * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and - * execution is on - * T the 1000 bit is turned on, and execution is off (undefined bit- - * state) - * e z/OS external link bit - */ - private static final String REGEX = - "([bcdelfmpSs-])" // type (1) - + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" // permission - + "(" - + "(folder\\s+)" - + "|" - + "((\\d+)\\s+(\\d+)\\s+)" // resource size & data size - + ")" - + "(\\d+)\\s+" // size - /* - * numeric or standard format date: - * yyyy-mm-dd (expecting hh:mm to follow) - * MMM [d]d - * [d]d MMM - * N.B. use non-space for MMM to allow for languages such as German which use - * diacritics (e.g. umlaut) in some abbreviations. - */ - + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S{3}\\s+\\d{1,2})|(?:\\d{1,2}\\s+\\S{3}))\\s+" - /* - year (for non-recent standard format) - yyyy - or time (for numeric or recent standard format) [h]h:mm - */ - + "(\\d+(?::\\d+)?)\\s+" - - + "(\\S*)(\\s*.*)"; // the rest - - - /** - * The default constructor for a UnixFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public MacOsPeterFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public MacOsPeterFTPEntryParser(final FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - /** - * Parses a line of a unix (standard) FTP server file listing and converts - * it into a usable format in the form of an FTPFile - * instance. If the file listing line doesn't describe a file, - * null is returned, otherwise a FTPFile - * instance representing the files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) { - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - final int type; - boolean isDevice = false; - - if (matches(entry)) - { - final String typeStr = group(1); - final String hardLinkCount = "0"; - final String usr = null; - final String grp = null; - final String filesize = group(20); - final String datestr = group(21) + " " + group(22); - String name = group(23); - final String endtoken = group(24); - - try - { - file.setTimestamp(super.parseTimestamp(datestr)); - } - catch (final ParseException e) - { - // intentionally do nothing - } - - // A 'whiteout' file is an ARTIFICIAL entry in any of several types of - // 'translucent' filesystems, of which a 'union' filesystem is one. - - // bcdelfmpSs- - switch (typeStr.charAt(0)) - { - case 'd': - type = FTPFile.DIRECTORY_TYPE; - break; - case 'e': // NET-39 => z/OS external link - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'l': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'b': - case 'c': - isDevice = true; - type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented - break; - case 'f': - case '-': - type = FTPFile.FILE_TYPE; - break; - default: // e.g. ? and w = whiteout - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - int g = 4; - for (int access = 0; access < 3; access++, g += 4) - { - // Use != '-' to avoid having to check for suid and sticky bits - file.setPermission(access, FTPFile.READ_PERMISSION, - (!group(g).equals("-"))); - file.setPermission(access, FTPFile.WRITE_PERMISSION, - (!group(g + 1).equals("-"))); - - final String execPerm = group(g + 2); - if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); - } - else - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); - } - } - - if (!isDevice) - { - try - { - file.setHardLinkCount(Integer.parseInt(hardLinkCount)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - } - - file.setUser(usr); - file.setGroup(grp); - - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - - if (null == endtoken) - { - file.setName(name); - } - else - { - // oddball cases like symbolic links, file names - // with spaces in them. - name += endtoken; - if (type == FTPFile.SYMBOLIC_LINK_TYPE) - { - - final int end = name.indexOf(" -> "); - // Give up if no link indicator is present - if (end == -1) - { - file.setName(name); - } - else - { - file.setName(name.substring(0, end)); - file.setLink(name.substring(end + 4)); - } - - } - else - { - file.setName(name); - } - } - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_UNIX, - DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java deleted file mode 100644 index e564a7ba..00000000 --- a/src/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; -import java.util.regex.Pattern; - -import org.apache.commons.net.ftp.Configurable; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - private static final String DEFAULT_DATE_FORMAT - = "MM-dd-yy hh:mma"; //11-09-01 12:30PM - - private static final String DEFAULT_DATE_FORMAT2 - = "MM-dd-yy kk:mm"; //11-09-01 18:30 - - private final FTPTimestampParser timestampParser; - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(\\S+)\\s+(\\S+)\\s+" // MM-dd-yy whitespace hh:mma|kk:mm; swallow trailing spaces - + "(?:()|([0-9]+))\\s+" // or ddddd; swallow trailing spaces - + "(\\S.*)"; // First non-space followed by rest of line (name) - - /** - * The sole constructor for an NTFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NTFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an NTFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NTFTPEntryParser(final FTPClientConfig config) - { - super(REGEX, Pattern.DOTALL); - configure(config); - final FTPClientConfig config2 = new FTPClientConfig( - FTPClientConfig.SYST_NT, - DEFAULT_DATE_FORMAT2, - null); - config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2); - this.timestampParser = new FTPTimestampParserImpl(); - ((Configurable)this.timestampParser).configure(config2); - } - - /** - * Parses a line of an NT FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) - { - final FTPFile f = new FTPFile(); - f.setRawListing(entry); - - if (matches(entry)) - { - final String datestr = group(1)+" "+group(2); - final String dirString = group(3); - final String size = group(4); - final String name = group(5); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (final ParseException e) - { - // parsing fails, try the other date format - try - { - f.setTimestamp(timestampParser.parseTimestamp(datestr)); - } - catch (final ParseException e2) - { - // intentionally do nothing - } - } - - if (null == name || name.equals(".") || name.equals("..")) - { - return null; - } - f.setName(name); - - - if ("".equals(dirString)) - { - f.setType(FTPFile.DIRECTORY_TYPE); - f.setSize(0); - } - else - { - f.setType(FTPFile.FILE_TYPE); - if (null != size) - { - f.setSize(Long.parseLong(size)); - } - } - return f; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - public FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_NT, - DEFAULT_DATE_FORMAT, - null); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java deleted file mode 100644 index 918e7992..00000000 --- a/src/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary - * extensions for Novell-specific operations are not supported. See - * - * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html - * for more details. - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @since 1.5 - */ -public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - /** - * Default date format is e.g. Feb 22 2006 - */ - private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; - - /** - * Default recent date format is e.g. Feb 22 17:32 - */ - private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; - - /** - * this is the regular expression used by this parser. - * Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 - */ - private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag - + "\\[([-A-Z]+)\\]\\s+" // Attributes RWCEAFMS or - - + "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size - + "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format - + "\\s+(.*)"; // Filename (incl. spaces) - - /** - * The default constructor for a NetwareFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NetwareFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an NetwareFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NetwareFTPEntryParser(final FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an NetwareFTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: - *

    - *
  • S - Supervisor; All rights. - *
  • R - Read; Right to open and read or execute. - *
  • W - Write; Right to open and modify. - *
  • C - Create; Right to create; when assigned to a file, allows a deleted file to be recovered. - *
  • E - Erase; Right to delete. - *
  • M - Modify; Right to rename a file and to change attributes. - *
  • F - File Scan; Right to see directory or file listings. - *
  • A - Access Control; Right to modify trustee assignments and the Inherited Rights Mask. - *
- * - * See - * - * here - * for more details - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) { - - final FTPFile f = new FTPFile(); - if (matches(entry)) { - final String dirString = group(1); - final String attrib = group(2); - final String user = group(3); - final String size = group(4); - final String datestr = group(5); - final String name = group(9); - - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (final ParseException e) { - // intentionally do nothing - } - - //is it a DIR or a file - if (dirString.trim().equals("d")) { - f.setType(FTPFile.DIRECTORY_TYPE); - } else // Should be "-" - { - f.setType(FTPFile.FILE_TYPE); - } - - f.setUser(user); - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - // Now set the permissions (or at least a subset thereof - full permissions would probably require - // subclassing FTPFile and adding extra metainformation there) - if (attrib.indexOf('R') != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, - true); - } - if (attrib.indexOf('W') != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, - true); - } - - return f; - } - return null; - - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, - DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java deleted file mode 100644 index c97ee6c0..00000000 --- a/src/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. - * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl - -{ - - private static final String DEFAULT_DATE_FORMAT - = "MM-dd-yy HH:mm"; //11-09-01 12:30 - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "\\s*([0-9]+)\\s*" - + "(\\s+|[A-Z]+)\\s*" - + "(DIR|\\s+)\\s*" - + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ - + "(\\S.*)"; - - /** - * The default constructor for a OS2FTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS2FTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an OS2FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS2FTPEntryParser(final FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an OS2 FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) - { - - final FTPFile f = new FTPFile(); - if (matches(entry)) - { - final String size = group(1); - final String attrib = group(2); - final String dirString = group(3); - final String datestr = group(4)+" "+group(5); - final String name = group(6); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (final ParseException e) - { - // intentionally do nothing - } - - - //is it a DIR or a file - if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) - { - f.setType(FTPFile.DIRECTORY_TYPE); - } - else - { - f.setType(FTPFile.FILE_TYPE); - } - - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - return f; - } - return null; - - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_OS2, - DEFAULT_DATE_FORMAT, - null); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java deleted file mode 100644 index 55e89e3b..00000000 --- a/src/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.io.File; -import java.text.ParseException; -import java.util.Locale; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - *
- * Example *FILE/*MEM FTP entries, when the current
- * working directory is a file of file system QSYS:
- * ------------------------------------------------
- *
- * $ cwd /qsys.lib/rpgunit.lib/rpgunitc1.file
- *   250-NAMEFMT set to 1.
- *   250 "/QSYS.LIB/RPGUNIT.LIB/RPGUNITC1.FILE" is current directory.
- * $ dir
- *   227 Entering Passive Mode (10,200,36,33,40,249).
- *   125 List started.
- *   QPGMR          135168 22.06.13 13:18:19 *FILE
- *   QPGMR                                   *MEM       MKCMD.MBR
- *   QPGMR                                   *MEM       RUCALLTST.MBR
- *   QPGMR                                   *MEM       RUCMDHLP.MBR
- *   QPGMR                                   *MEM       RUCRTTST.MBR
- *   250 List completed.
- *
- *
- * Example *FILE entry of an OS/400 save file:
- * ---------------------------------------------------
- *
- * $ cwd /qsys.lib/rpgunit.lib
- *   250 "/QSYS.LIB/RPGUNIT.LIB" is current library.
- * $ dir rpgunit.file
- *   227 Entering Passive Mode (10,200,36,33,188,106).
- *   125 List started.
- *   QPGMR        16347136 29.06.13 15:45:09 *FILE      RPGUNIT.SAVF
- *   250 List completed.
- *
- *
- * Example *STMF/*DIR FTP entries, when the
- * current working directory is in file system "root":
- * ---------------------------------------------------
- *
- * $ cwd /home/raddatz
- *   250 "/home/raddatz" is current directory.
- * $ dir test*
- *   227 Entering Passive Mode (10,200,36,33,200,189).
- *   125 List started.
- *   RADDATZ           200 21.05.11 12:31:18 *STMF      TEST_RG_02_CRLF.properties
- *   RADDATZ           187 08.05.11 12:31:40 *STMF      TEST_RG_02_LF.properties
- *   RADDATZ           187 08.05.11 12:31:52 *STMF      TEST_RG_02_CR.properties
- *   RADDATZ          8192 04.07.13 09:04:14 *DIR       testDir1/
- *   RADDATZ          8192 04.07.13 09:04:17 *DIR       testDir2/
- *   250 List completed.
- *
- *
- * Example 1, using ANT to list specific members of a file:
- * --------------------------------------------------------
- *
- *      <echo/>
- *      <echo>Listing members of a file:</echo>
- *
- *      <ftp action="list"
- *           server="${ftp.server}"
- *           userid="${ftp.user}"
- *           password="${ftp.password}"
- *           binary="false"
- *           verbose="true"
- *           remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE"
- *           systemTypeKey="OS/400"
- *           listing="ftp-listing.txt"
- *           >
- *          <fileset dir="./i5-downloads-file" casesensitive="false">
- *              <include name="run*.mbr" />
- *          </fileset>
- *      </ftp>
- *
- * Output:
- * -------
- *
- *   [echo] Listing members of a file:
- *    [ftp] listing files
- *    [ftp] listing RUN.MBR
- *    [ftp] listing RUNNER.MBR
- *    [ftp] listing RUNNERBND.MBR
- *    [ftp] 3 files listed
- *
- *
- * Example 2, using ANT to list specific members of all files of a library:
- * ------------------------------------------------------------------------
- *
- *      <echo/>
- *      <echo>Listing members of all files of a library:</echo>
- *
- *      <ftp action="list"
- *           server="${ftp.server}"
- *           userid="${ftp.user}"
- *           password="${ftp.password}"
- *           binary="false"
- *           verbose="true"
- *           remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *           systemTypeKey="OS/400"
- *           listing="ftp-listing.txt"
- *           >
- *          <fileset dir="./i5-downloads-lib" casesensitive="false">
- *              <include name="**\run*.mbr" />
- *          </fileset>
- *      </ftp>
- *
- * Output:
- * -------
- *
- *   [echo] Listing members of all files of a library:
- *    [ftp] listing files
- *    [ftp] listing RPGUNIT1.FILE\RUN.MBR
- *    [ftp] listing RPGUNIT1.FILE\RUNRMT.MBR
- *    [ftp] listing RPGUNITT1.FILE\RUNT.MBR
- *    [ftp] listing RPGUNITY1.FILE\RUN.MBR
- *    [ftp] listing RPGUNITY1.FILE\RUNNER.MBR
- *    [ftp] listing RPGUNITY1.FILE\RUNNERBND.MBR
- *    [ftp] 6 files listed
- *
- *
- * Example 3, using ANT to download specific members of a file:
- * ------------------------------------------------------------
- *
- *      <echo/>
- *      <echo>Downloading members of a file:</echo>
- *
- *      <ftp action="get"
- *           server="${ftp.server}"
- *           userid="${ftp.user}"
- *           password="${ftp.password}"
- *           binary="false"
- *           verbose="true"
- *           remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE"
- *           systemTypeKey="OS/400"
- *           >
- *          <fileset dir="./i5-downloads-file" casesensitive="false">
- *              <include name="run*.mbr" />
- *          </fileset>
- *      </ftp>
- *
- * Output:
- * -------
- *
- *   [echo] Downloading members of a file:
- *    [ftp] getting files
- *    [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUN.MBR
- *    [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNER.MBR
- *    [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNERBND.MBR
- *    [ftp] 3 files retrieved
- *
- *
- * Example 4, using ANT to download specific members of all files of a library:
- * ----------------------------------------------------------------------------
- *
- *      <echo/>
- *      <echo>Downloading members of all files of a library:</echo>
- *
- *      <ftp action="get"
- *           server="${ftp.server}"
- *           userid="${ftp.user}"
- *           password="${ftp.password}"
- *           binary="false"
- *           verbose="true"
- *           remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *           systemTypeKey="OS/400"
- *           >
- *          <fileset dir="./i5-downloads-lib" casesensitive="false">
- *              <include name="**\run*.mbr" />
- *          </fileset>
- *      </ftp>
- *
- * Output:
- * -------
- *
- *   [echo] Downloading members of all files of a library:
- *    [ftp] getting files
- *    [ftp] transferring RPGUNIT1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR
- *    [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR
- *    [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR
- *    [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR
- *    [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR
- *    [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR
- *    [ftp] 6 files retrieved
- *
- *
- * Example 5, using ANT to download a save file of a library:
- * ----------------------------------------------------------
- *
- *      <ftp action="get"
- *           server="${ftp.server}"
- *           userid="${ftp.user}"
- *           password="${ftp.password}"
- *           binary="true"
- *           verbose="true"
- *           remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *           systemTypeKey="OS/400"
- *           >
- *        <fileset dir="./i5-downloads-savf" casesensitive="false">
- *            <include name="RPGUNIT.SAVF" />
- *        </fileset>
- *      </ftp>
- *
- * Output:
- * -------
- *   [echo] Downloading save file:
- *    [ftp] getting files
- *    [ftp] transferring RPGUNIT.SAVF to C:\workspaces\rdp_080\workspace\net-Test\i5-downloads-lib\RPGUNIT.SAVF
- *    [ftp] 1 files retrieved
- *
- * 
- */ -public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - private static final String DEFAULT_DATE_FORMAT - = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 - - - - private static final String REGEX = - "(\\S+)\\s+" // user - + "(?:(\\d+)\\s+)?" // size, empty for members - + "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members - + "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM - + "(?:(\\S+)\\s*)?"; // file name, missing, when CWD is a *FILE - - - /** - * The default constructor for a OS400FTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS400FTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of an OS400FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS400FTPEntryParser(final FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - - @Override - public FTPFile parseFTPEntry(final String entry) - { - - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - final int type; - - if (matches(entry)) - { - final String usr = group(1); - final String filesize = group(2); - String datestr = ""; - if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) - { - datestr = group(3)+" "+group(4); - } - final String typeStr = group(5); - String name = group(6); - - boolean mustScanForPathSeparator = true; - - try - { - file.setTimestamp(super.parseTimestamp(datestr)); - } - catch (final ParseException e) - { - // intentionally do nothing - } - - - if (typeStr.equalsIgnoreCase("*STMF")) - { - type = FTPFile.FILE_TYPE; - if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) - { - return null; - } - } - else if (typeStr.equalsIgnoreCase("*DIR")) - { - type = FTPFile.DIRECTORY_TYPE; - if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) - { - return null; - } - } - else if (typeStr.equalsIgnoreCase("*FILE")) - { - // File, defines the structure of the data (columns of a row) - // but the data is stored in one or more members. Typically a - // source file contains multiple members whereas it is - // recommended (but not enforced) to use one member per data - // file. - // Save files are a special type of files which are used - // to save objects, e.g. for backups. - if (name != null && name.toUpperCase(Locale.ROOT).endsWith(".SAVF")) - { - mustScanForPathSeparator = false; - type = FTPFile.FILE_TYPE; - } - else - { - return null; - } - } - else if (typeStr.equalsIgnoreCase("*MEM")) - { - mustScanForPathSeparator = false; - type = FTPFile.FILE_TYPE; - - if (isNullOrEmpty(name)) - { - return null; - } - if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) - { - return null; - } - - // Quick and dirty bug fix to make SelectorUtils work. - // Class SelectorUtils uses 'File.separator' to splitt - // a given path into pieces. But actually it had to - // use the separator of the FTP server, which is a forward - // slash in case of an AS/400. - name = name.replace('/', File.separatorChar); - } - else - { - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - file.setUser(usr); - - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - - if (name.endsWith("/")) - { - name = name.substring(0, name.length() - 1); - } - if (mustScanForPathSeparator) - { - final int pos = name.lastIndexOf('/'); - if (pos > -1) - { - name = name.substring(pos + 1); - } - } - - file.setName(name); - - return file; - } - return null; - } - - /** - * - * @param string String value that is checked for null - * or empty. - * @return true for null or empty values, - * else false. - */ - private boolean isNullOrEmpty(final String string) { - if (string == null || string.isEmpty()) { - return true; - } - return false; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_OS400, - DEFAULT_DATE_FORMAT, - null); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java b/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java deleted file mode 100644 index 001179c4..00000000 --- a/src/org/apache/commons/net/ftp/parser/ParserInitializationException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -/** - * This class encapsulates all errors that may be thrown by - * the process of an FTPFileEntryParserFactory creating and - * instantiating an FTPFileEntryParser. - */ -public class ParserInitializationException extends RuntimeException { - - private static final long serialVersionUID = 5563335279583210658L; - - /** - * Constucts a ParserInitializationException with just a message - * - * @param message Exception message - */ - public ParserInitializationException(final String message) { - super(message); - } - - /** - * Constucts a ParserInitializationException with a message - * and a root cause. - * - * @param message Exception message - * @param rootCause root cause throwable that caused - * this to be thrown - */ - public ParserInitializationException(final String message, final Throwable rootCause) { - super(message, rootCause); - } - - /** - * returns the root cause of this exception or null - * if no root cause was specified. - * - * @return the root cause of this exception being thrown - * @deprecated use {@link #getCause()} instead - */ - @Deprecated - public Throwable getRootCause() { - return super.getCause(); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java b/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java deleted file mode 100644 index 2de9470e..00000000 --- a/src/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.commons.net.ftp.parser; - -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - * - * This is the base class for all regular expression based FTPFileEntryParser classes - */ -public abstract class RegexFTPFileEntryParserImpl extends - FTPFileEntryParserImpl { - /** - * internal pattern the matcher tries to match, representing a file - * entry - */ - private Pattern pattern; - - /** - * internal match result used by the parser - */ - private MatchResult result; - - /** - * Internal PatternMatcher object used by the parser. It has protected - * scope in case subclasses want to make use of it for their own purposes. - */ - protected Matcher _matcher_; - - /** - * The constructor for a RegexFTPFileEntryParserImpl object. - * The expression is compiled with flags = 0. - * - * @param regex The regular expression with which this object is - * initialized. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen in - * normal conditions. It it is seen, this is a sign that a subclass has - * been created with a bad regular expression. Since the parser must be - * created before use, this means that any bad parser subclasses created - * from this will bomb very quickly, leading to easy detection. - */ - - public RegexFTPFileEntryParserImpl(final String regex) { - compileRegex(regex, 0); - } - - /** - * The constructor for a RegexFTPFileEntryParserImpl object. - * - * @param regex The regular expression with which this object is - * initialized. - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen in - * normal conditions. It it is seen, this is a sign that a subclass has - * been created with a bad regular expression. Since the parser must be - * created before use, this means that any bad parser subclasses created - * from this will bomb very quickly, leading to easy detection. - * @since 3.4 - */ - public RegexFTPFileEntryParserImpl(final String regex, final int flags) { - compileRegex(regex, flags); - } - - /** - * Convenience method delegates to the internal MatchResult's matches() - * method. - * - * @param s the String to be matched - * @return true if s matches this object's regular expression. - */ - - public boolean matches(final String s) { - this.result = null; - _matcher_ = pattern.matcher(s); - if (_matcher_.matches()) { - this.result = _matcher_.toMatchResult(); - } - return null != this.result; - } - - /** - * Convenience method - * - * @return the number of groups() in the internal MatchResult. - */ - - public int getGroupCnt() { - if (this.result == null) { - return 0; - } - return this.result.groupCount(); - } - - /** - * Convenience method delegates to the internal MatchResult's group() - * method. - * - * @param matchnum match group number to be retrieved - * - * @return the content of the matchnum'th group of the internal - * match or null if this method is called without a match having - * been made. - */ - public String group(final int matchnum) { - if (this.result == null) { - return null; - } - return this.result.group(matchnum); - } - - /** - * For debugging purposes - returns a string shows each match group by - * number. - * - * @return a string shows each match group by number. - */ - - public String getGroupsAsString() { - final StringBuilder b = new StringBuilder(); - for (int i = 1; i <= this.result.groupCount(); i++) { - b.append(i).append(") ").append(this.result.group(i)).append( - System.getProperty("line.separator")); - } - return b.toString(); - } - - /** - * Alter the current regular expression being utilised for entry parsing - * and create a new {@link Pattern} instance. - * @param regex The new regular expression - * @return true - * @since 2.0 - * @throws IllegalArgumentException if the regex cannot be compiled - */ - public boolean setRegex(final String regex) { - compileRegex(regex, 0); - return true; - } - - - /** - * Alter the current regular expression being utilised for entry parsing - * and create a new {@link Pattern} instance. - * @param regex The new regular expression - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * @return true - * @since 3.4 - * @throws IllegalArgumentException if the regex cannot be compiled - */ - public boolean setRegex(final String regex, final int flags) { - compileRegex(regex, flags); - return true; - } - - /** - * Compile the regex and store the {@link Pattern}. - * - * This is an internal method to do the work so the constructor does not - * have to call an overrideable method. - * - * @param regex the expression to compile - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * @throws IllegalArgumentException if the regex cannot be compiled - */ - private void compileRegex(final String regex, final int flags) { - try { - pattern = Pattern.compile(regex, flags); - } catch (final PatternSyntaxException pse) { - throw new IllegalArgumentException("Unparseable regex supplied: " + regex); - } - } -} diff --git a/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java deleted file mode 100644 index 501fbfbd..00000000 --- a/src/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.text.ParseException; -import java.util.List; -import java.util.ListIterator; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for standard - * Unix Systems. - * - * This class is based on the logic of Daniel Savarese's - * DefaultFTPListParser, but adapted to use regular expressions and to fit the - * new FTPFileEntryParser interface. - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - static final String DEFAULT_DATE_FORMAT - = "MMM d yyyy"; //Nov 9 2001 - - static final String DEFAULT_RECENT_DATE_FORMAT - = "MMM d HH:mm"; //Nov 9 20:06 - - static final String NUMERIC_DATE_FORMAT - = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 - - // Suffixes used in Japanese listings after the numeric values - private static final String JA_MONTH = "\u6708"; - private static final String JA_DAY = "\u65e5"; - private static final String JA_YEAR = "\u5e74"; - - private static final String DEFAULT_DATE_FORMAT_JA - = "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年 - - private static final String DEFAULT_RECENT_DATE_FORMAT_JA - = "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10 - - /** - * Some Linux distributions are now shipping an FTP server which formats - * file listing dates in an all-numeric format: - * "yyyy-MM-dd HH:mm. - * This is a very welcome development, and hopefully it will soon become - * the standard. However, since it is so new, for now, and possibly - * forever, we merely accomodate it, but do not make it the default. - *

- * For now end users may specify this format only via - * UnixFTPEntryParser(FTPClientConfig). - * Steve Cohen - 2005-04-17 - */ - public static final FTPClientConfig NUMERIC_DATE_CONFIG = - new FTPClientConfig( - FTPClientConfig.SYST_UNIX, - NUMERIC_DATE_FORMAT, - null); - - /** - * this is the regular expression used by this parser. - * - * Permissions: - * r the file is readable - * w the file is writable - * x the file is executable - * - the indicated permission is not granted - * L mandatory locking occurs during access (the set-group-ID bit is - * on and the group execution bit is off) - * s the set-user-ID or set-group-ID bit is on, and the corresponding - * user or group execution bit is also on - * S undefined bit-state (the set-user-ID bit is on and the user - * execution bit is off) - * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and - * execution is on - * T the 1000 bit is turned on, and execution is off (undefined bit- - * state) - * e z/OS external link bit - * Final letter may be appended: - * + file has extended security attributes (e.g. ACL) - * Note: local listings on MacOSX also use '@'; - * this is not allowed for here as does not appear to be shown by FTP servers - * {@code @} file has extended attributes - */ - private static final String REGEX = - "([bcdelfmpSs-])" // file type - +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions - - + "\\s*" // separator TODO why allow it to be omitted?? - - + "(\\d+)" // link count - - + "\\s+" // separator - - + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces) - + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces) - + "(\\d+(?:,\\s*\\d+)?)" // size or n,m - - + "\\s+" // separator - - /* - * numeric or standard format date: - * yyyy-mm-dd (expecting hh:mm to follow) - * MMM [d]d - * [d]d MMM - * N.B. use non-space for MMM to allow for languages such as German which use - * diacritics (e.g. umlaut) in some abbreviations. - * Japanese uses numeric day and month with suffixes to distinguish them - * [d]dXX [d]dZZ - */ - + "("+ - "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd - "|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d - "|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM - "|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")"+ - ")" - - + "\\s+" // separator - - /* - year (for non-recent standard format) - yyyy - or time (for numeric or recent standard format) [h]h:mm - or Japanese year - yyyyXX - */ - + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20) - - + "\\s" // separator - - + "(.*)"; // the rest (21) - - - // if true, leading spaces are trimmed from file names - // this was the case for the original implementation - final boolean trimLeadingSpaces; // package protected for access from test code - - /** - * The default constructor for a UnixFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public UnixFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public UnixFTPEntryParser(final FTPClientConfig config) - { - this(config, false); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @param trimLeadingSpaces if {@code true}, trim leading spaces from file names - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 3.4 - */ - public UnixFTPEntryParser(final FTPClientConfig config, final boolean trimLeadingSpaces) - { - super(REGEX); - configure(config); - this.trimLeadingSpaces = trimLeadingSpaces; - } - - /** - * Preparse the list to discard "total nnn" lines - */ - @Override - public List preParse(final List original) { - final ListIterator iter = original.listIterator(); - while (iter.hasNext()) { - final String entry = iter.next(); - if (entry.matches("^total \\d+$")) { // NET-389 - iter.remove(); - } - } - return original; - } - - /** - * Parses a line of a unix (standard) FTP server file listing and converts - * it into a usable format in the form of an FTPFile - * instance. If the file listing line doesn't describe a file, - * null is returned, otherwise a FTPFile - * instance representing the files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) { - final FTPFile file = new FTPFile(); - file.setRawListing(entry); - final int type; - boolean isDevice = false; - - if (matches(entry)) - { - final String typeStr = group(1); - final String hardLinkCount = group(15); - final String usr = group(16); - final String grp = group(17); - final String filesize = group(18); - final String datestr = group(19) + " " + group(20); - String name = group(21); - if (trimLeadingSpaces) { - name = name.replaceFirst("^\\s+", ""); - } - - try - { - if (group(19).contains(JA_MONTH)) { // special processing for Japanese format - final FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl(); - jaParser.configure(new FTPClientConfig( - FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA, DEFAULT_RECENT_DATE_FORMAT_JA)); - file.setTimestamp(jaParser.parseTimestamp(datestr)); - } else { - file.setTimestamp(super.parseTimestamp(datestr)); - } - } - catch (final ParseException e) - { - // intentionally do nothing - } - - // A 'whiteout' file is an ARTIFICIAL entry in any of several types of - // 'translucent' filesystems, of which a 'union' filesystem is one. - - // bcdelfmpSs- - switch (typeStr.charAt(0)) - { - case 'd': - type = FTPFile.DIRECTORY_TYPE; - break; - case 'e': // NET-39 => z/OS external link - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'l': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'b': - case 'c': - isDevice = true; - type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented - break; - case 'f': - case '-': - type = FTPFile.FILE_TYPE; - break; - default: // e.g. ? and w = whiteout - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - int g = 4; - for (int access = 0; access < 3; access++, g += 4) - { - // Use != '-' to avoid having to check for suid and sticky bits - file.setPermission(access, FTPFile.READ_PERMISSION, - !group(g).equals("-")); - file.setPermission(access, FTPFile.WRITE_PERMISSION, - !group(g + 1).equals("-")); - - final String execPerm = group(g + 2); - if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); - } - else - { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); - } - } - - if (!isDevice) - { - try - { - file.setHardLinkCount(Integer.parseInt(hardLinkCount)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - } - - file.setUser(usr); - file.setGroup(grp); - - try - { - file.setSize(Long.parseLong(filesize)); - } - catch (final NumberFormatException e) - { - // intentionally do nothing - } - - // oddball cases like symbolic links, file names - // with spaces in them. - if (type == FTPFile.SYMBOLIC_LINK_TYPE) - { - - final int end = name.indexOf(" -> "); - // Give up if no link indicator is present - if (end == -1) - { - file.setName(name); - } - else - { - file.setName(name.substring(0, end)); - file.setLink(name.substring(end + 4)); - } - - } - else - { - file.setName(name); - } - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_UNIX, - DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java deleted file mode 100644 index a5717809..00000000 --- a/src/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; -import java.util.StringTokenizer; - -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.commons.net.ftp.FTPFile; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. - * This is a sample of VMS LIST output - *

- *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- * 
- *

- * Note: VMSFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - *

- * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory - */ -public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl -{ - - private static final String DEFAULT_DATE_FORMAT - = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(.*?;[0-9]+)\\s*" //1 file and version - + "(\\d+)(?:/\\d+)?\\s*" //2 size/allocated - +"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time - + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner - + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; //9,10,11 Permissions (O,G,W) - // TODO - perhaps restrict permissions to [RWED]* ? - - - - /** - * Constructor for a VMSFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a VMSFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSFTPEntryParser(final FTPClientConfig config) - { - super(REGEX); - configure(config); - } - - /** - * Parses a line of a VMS FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override - public FTPFile parseFTPEntry(final String entry) - { - //one block in VMS equals 512 bytes - final long longBlock = 512; - - if (matches(entry)) - { - final FTPFile f = new FTPFile(); - f.setRawListing(entry); - String name = group(1); - final String size = group(2); - final String datestr = group(3)+" "+group(4); - final String owner = group(5); - final String permissions[] = new String[3]; - permissions[0]= group(9); - permissions[1]= group(10); - permissions[2]= group(11); - try - { - f.setTimestamp(super.parseTimestamp(datestr)); - } - catch (final ParseException e) - { - // intentionally do nothing - } - - - final String grp; - final String user; - final StringTokenizer t = new StringTokenizer(owner, ","); - switch (t.countTokens()) { - case 1: - grp = null; - user = t.nextToken(); - break; - case 2: - grp = t.nextToken(); - user = t.nextToken(); - break; - default: - grp = null; - user = null; - } - - if (name.lastIndexOf(".DIR") != -1) - { - f.setType(FTPFile.DIRECTORY_TYPE); - } - else - { - f.setType(FTPFile.FILE_TYPE); - } - //set FTPFile name - //Check also for versions to be returned or not - if (isVersioning()) - { - f.setName(name); - } - else - { - name = name.substring(0, name.lastIndexOf(';')); - f.setName(name); - } - //size is retreived in blocks and needs to be put in bytes - //for us humans and added to the FTPFile array - final long sizeInBytes = Long.parseLong(size) * longBlock; - f.setSize(sizeInBytes); - - f.setGroup(grp); - f.setUser(user); - //set group and owner - - //Set file permission. - //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain - //R (read) W (write) E (execute) D (delete) - - //iterate for OWNER GROUP WORLD permissions - for (int access = 0; access < 3; access++) - { - final String permission = permissions[access]; - - f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); - f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); - f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); - } - - return f; - } - return null; - } - - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. This parser cannot use - * the default implementation of simply calling BufferedReader.readLine(), - * because one entry may span multiple lines. - * - * @param reader The BufferedReader object from which entries are to be - * read. - * - * @return A string representing the next ftp entry or null if none found. - * @throws IOException thrown on any IO Error reading from the reader. - */ - @Override - public String readNextEntry(final BufferedReader reader) throws IOException - { - String line = reader.readLine(); - final StringBuilder entry = new StringBuilder(); - while (line != null) - { - if (line.startsWith("Directory") || line.startsWith("Total")) { - line = reader.readLine(); - continue; - } - - entry.append(line); - if (line.trim().endsWith(")")) - { - break; - } - line = reader.readLine(); - } - return entry.length() == 0 ? null : entry.toString(); - } - - protected boolean isVersioning() { - return false; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * @return the default configuration for this parser. - */ - @Override - protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig( - FTPClientConfig.SYST_VMS, - DEFAULT_DATE_FORMAT, - null); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * DO NOT USE - * @param listStream the stream - * @return the array of files - * @throws IOException on error - * @deprecated (2.2) No other FTPFileEntryParser implementations have this method. - */ - @Deprecated - public FTPFile[] parseFileList(final java.io.InputStream listStream) throws IOException { - final org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this); - engine.readServerList(listStream, null); - return engine.getFiles(); - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java b/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java deleted file mode 100644 index c2af67a2..00000000 --- a/src/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.ftp.parser; - -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.commons.net.ftp.FTPClientConfig; - -/** - * Special implementation VMSFTPEntryParser with versioning turned on. - * This parser removes all duplicates and only leaves the version with the highest - * version number for each file name. - *

- * This is a sample of VMS LIST output - *

- *
- *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
- * 
- * - * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser -{ - - private final Pattern preparsePattern; - private static final String PRE_PARSE_REGEX = - "(.*?);([0-9]+)\\s*.*"; - - /** - * Constructor for a VMSFTPEntryParser object. - * - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSVersioningFTPEntryParser() - { - this(null); - } - - /** - * This constructor allows the creation of a VMSVersioningFTPEntryParser - * object with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException - * Thrown if the regular expression is unparseable. Should not be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSVersioningFTPEntryParser(final FTPClientConfig config) - { - configure(config); - try - { - //_preparse_matcher_ = new Perl5Matcher(); - preparsePattern = Pattern.compile(PRE_PARSE_REGEX); - } - catch (final PatternSyntaxException pse) - { - throw new IllegalArgumentException ( - "Unparseable regex supplied: " + PRE_PARSE_REGEX); - } - - } - - /** - * Implement hook provided for those implementers (such as - * VMSVersioningFTPEntryParser, and possibly others) which return - * multiple files with the same name to remove the duplicates .. - * - * @param original Original list - * - * @return Original list purged of duplicates - */ - @Override - public List preParse(final List original) { - final HashMap existingEntries = new HashMap<>(); - final ListIterator iter = original.listIterator(); - while (iter.hasNext()) { - final String entry = iter.next().trim(); - MatchResult result = null; - final Matcher _preparse_matcher_ = preparsePattern.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - final String name = result.group(1); - final String version = result.group(2); - final Integer nv = Integer.valueOf(version); - final Integer existing = existingEntries.get(name); - if (null != existing) { - if (nv.intValue() < existing.intValue()) { - iter.remove(); // removes older version from original list. - continue; - } - } - existingEntries.put(name, nv); - } - - } - // we've now removed all entries less than with less than the largest - // version number for each name that were listed after the largest. - // we now must remove those with smaller than the largest version number - // for each name that were found before the largest - while (iter.hasPrevious()) { - final String entry = iter.previous().trim(); - MatchResult result = null; - final Matcher _preparse_matcher_ = preparsePattern.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - final String name = result.group(1); - final String version = result.group(2); - final Integer nv = Integer.valueOf(version); - final Integer existing = existingEntries.get(name); - if (null != existing) { - if (nv.intValue() < existing.intValue()) { - iter.remove(); // removes older version from original list. - } - } - } - - } - return original; - } - - - @Override - protected boolean isVersioning() { - return true; - } - -} diff --git a/src/org/apache/commons/net/ftp/parser/package-info.java b/src/org/apache/commons/net/ftp/parser/package-info.java deleted file mode 100644 index d92e3405..00000000 --- a/src/org/apache/commons/net/ftp/parser/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * FTP file listing parser classes - */ -package org.apache.commons.net.ftp.parser; \ No newline at end of file diff --git a/src/org/apache/commons/net/imap/AuthenticatingIMAPClient.java b/src/org/apache/commons/net/imap/AuthenticatingIMAPClient.java deleted file mode 100644 index 95d7818e..00000000 --- a/src/org/apache/commons/net/imap/AuthenticatingIMAPClient.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.SSLContext; - -import org.apache.commons.net.util.Base64; - -/** - * An IMAP Client class with authentication support. - * @see IMAPSClient - */ -public class AuthenticatingIMAPClient extends IMAPSClient -{ - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * Sets security mode to explicit (isImplicit = false). - */ - public AuthenticatingIMAPClient() - { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param implicit The security mode (Implicit/Explicit). - */ - public AuthenticatingIMAPClient(final boolean implicit) - { - this(DEFAULT_PROTOCOL, implicit); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param proto the protocol. - */ - public AuthenticatingIMAPClient(final String proto) - { - this(proto, false); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param proto the protocol. - * @param implicit The security mode(Implicit/Explicit). - */ - public AuthenticatingIMAPClient(final String proto, final boolean implicit) - { - this(proto, implicit, null); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param proto the protocol. - * @param implicit The security mode(Implicit/Explicit). - * @param ctx the context - */ - public AuthenticatingIMAPClient(final String proto, final boolean implicit, final SSLContext ctx) - { - super(proto, implicit, ctx); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param implicit The security mode(Implicit/Explicit). - * @param ctx A pre-configured SSL Context. - */ - public AuthenticatingIMAPClient(final boolean implicit, final SSLContext ctx) - { - this(DEFAULT_PROTOCOL, implicit, ctx); - } - - /** - * Constructor for AuthenticatingIMAPClient that delegates to IMAPSClient. - * @param context A pre-configured SSL Context. - */ - public AuthenticatingIMAPClient(final SSLContext context) - { - this(false, context); - } - - /** - * Authenticate to the IMAP server by sending the AUTHENTICATE command with the - * selected mechanism, using the given username and the given password. - * - * @param method the method name - * @param username user - * @param password password - * @return True if successfully completed, false if not. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws NoSuchAlgorithmException If the CRAM hash algorithm - * cannot be instantiated by the Java runtime system. - * @throws InvalidKeyException If the CRAM hash algorithm - * failed to use the given password. - * @throws InvalidKeySpecException If the CRAM hash algorithm - * failed to use the given password. - */ - public boolean authenticate(final AuthenticatingIMAPClient.AUTH_METHOD method, - final String username, final String password) - throws IOException, NoSuchAlgorithmException, - InvalidKeyException, InvalidKeySpecException - { - return auth(method, username, password); - } - - /** - * Authenticate to the IMAP server by sending the AUTHENTICATE command with the - * selected mechanism, using the given username and the given password. - * - * @param method the method name - * @param username user - * @param password password - * @return True if successfully completed, false if not. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws NoSuchAlgorithmException If the CRAM hash algorithm - * cannot be instantiated by the Java runtime system. - * @throws InvalidKeyException If the CRAM hash algorithm - * failed to use the given password. - * @throws InvalidKeySpecException If the CRAM hash algorithm - * failed to use the given password. - */ - public boolean auth(final AuthenticatingIMAPClient.AUTH_METHOD method, - final String username, final String password) - throws IOException, NoSuchAlgorithmException, - InvalidKeyException, InvalidKeySpecException - { - if (!IMAPReply.isContinuation(sendCommand(IMAPCommand.AUTHENTICATE, method.getAuthName()))) - { - return false; - } - - switch (method) { - case PLAIN: - { - // the server sends an empty response ("+ "), so we don't have to read it. - final int result = sendData( - Base64.encodeBase64StringUnChunked(("\000" + username + "\000" + password) - .getBytes(getCharset()))); - if (result == IMAPReply.OK) - { - setState(IMAP.IMAPState.AUTH_STATE); - } - return result == IMAPReply.OK; - } - case CRAM_MD5: - { - // get the CRAM challenge (after "+ ") - final byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(2).trim()); - // get the Mac instance - final Mac hmac_md5 = Mac.getInstance("HmacMD5"); - hmac_md5.init(new SecretKeySpec(password.getBytes(getCharset()), "HmacMD5")); - // compute the result: - final byte[] hmacResult = convertToHexString(hmac_md5.doFinal(serverChallenge)).getBytes(getCharset()); - // join the byte arrays to form the reply - final byte[] usernameBytes = username.getBytes(getCharset()); - final byte[] toEncode = new byte[usernameBytes.length + 1 /* the space */ + hmacResult.length]; - System.arraycopy(usernameBytes, 0, toEncode, 0, usernameBytes.length); - toEncode[usernameBytes.length] = ' '; - System.arraycopy(hmacResult, 0, toEncode, usernameBytes.length + 1, hmacResult.length); - // send the reply and read the server code: - final int result = sendData(Base64.encodeBase64StringUnChunked(toEncode)); - if (result == IMAPReply.OK) - { - setState(IMAP.IMAPState.AUTH_STATE); - } - return result == IMAPReply.OK; - } - case LOGIN: - { - // the server sends fixed responses (base64("Username") and - // base64("Password")), so we don't have to read them. - if (sendData(Base64.encodeBase64StringUnChunked(username.getBytes(getCharset()))) != IMAPReply.CONT) - { - return false; - } - final int result = sendData(Base64.encodeBase64StringUnChunked(password.getBytes(getCharset()))); - if (result == IMAPReply.OK) - { - setState(IMAP.IMAPState.AUTH_STATE); - } - return result == IMAPReply.OK; - } - case XOAUTH: - case XOAUTH2: - { - final int result = sendData(username); - if (result == IMAPReply.OK) - { - setState(IMAP.IMAPState.AUTH_STATE); - } - return result == IMAPReply.OK; - } - } - return false; // safety check - } - - /** - * Converts the given byte array to a String containing the hex values of the bytes. - * For example, the byte 'A' will be converted to '41', because this is the ASCII code - * (and the byte value) of the capital letter 'A'. - * @param a The byte array to convert. - * @return The resulting String of hex codes. - */ - private String convertToHexString(final byte[] a) - { - final StringBuilder result = new StringBuilder(a.length*2); - for (final byte element : a) - { - if ( (element & 0x0FF) <= 15 ) { - result.append("0"); - } - result.append(Integer.toHexString(element & 0x0FF)); - } - return result.toString(); - } - - /** - * The enumeration of currently-supported authentication methods. - */ - public enum AUTH_METHOD - { - /** The standarised (RFC4616) PLAIN method, which sends the password unencrypted (insecure). */ - PLAIN("PLAIN"), - /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure). */ - CRAM_MD5("CRAM-MD5"), - /** The unstandarised Microsoft LOGIN method, which sends the password unencrypted (insecure). */ - LOGIN("LOGIN"), - /** XOAUTH */ - XOAUTH("XOAUTH"), - /** XOAUTH 2 */ - XOAUTH2("XOAUTH2"); - - private final String authName; - - AUTH_METHOD(final String name){ - this.authName=name; - } - /** - * Gets the name of the given authentication method suitable for the server. - * @return The name of the given authentication method suitable for the server. - */ - public final String getAuthName() - { - return authName; - } - } -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/IMAP.java b/src/org/apache/commons/net/imap/IMAP.java deleted file mode 100644 index 2ef07c49..00000000 --- a/src/org/apache/commons/net/imap/IMAP.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.net.SocketClient; -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.NetConstants; - - -/** - * The IMAP class provides the basic the functionality necessary to implement your - * own IMAP client. - */ -public class IMAP extends SocketClient -{ - /** The default IMAP port (RFC 3501). */ - public static final int DEFAULT_PORT = 143; - - public enum IMAPState - { - /** A constant representing the state where the client is not yet connected to a server. */ - DISCONNECTED_STATE, - /** A constant representing the "not authenticated" state. */ - NOT_AUTH_STATE, - /** A constant representing the "authenticated" state. */ - AUTH_STATE, - /** A constant representing the "logout" state. */ - LOGOUT_STATE - } - - // RFC 3501, section 5.1.3. It should be "modified UTF-7". - /** - * The default control socket encoding. - */ - protected static final String __DEFAULT_ENCODING = "ISO-8859-1"; - - private IMAPState state; - protected BufferedWriter __writer; - - protected BufferedReader _reader; - private int replyCode; - private final List replyLines; - - /** - * Implement this interface and register it via {@link #setChunkListener(IMAPChunkListener)} - * in order to get access to multi-line partial command responses. - * Useful when processing large FETCH responses. - */ - public interface IMAPChunkListener { - /** - * Called when a multi-line partial response has been received. - * @param imap the instance, get the response - * by calling {@link #getReplyString()} or {@link #getReplyStrings()} - * @return {@code true} if the reply buffer is to be cleared on return - */ - boolean chunkReceived(IMAP imap); - } - - /** - *

- * Implementation of IMAPChunkListener that returns {@code true} - * but otherwise does nothing. - *

- *

- * This is intended for use with a suitable ProtocolCommandListener. - * If the IMAP response contains multiple-line data, the protocol listener - * will be called for each multi-line chunk. - * The accumulated reply data will be cleared after calling the listener. - * If the response is very long, this can significantly reduce memory requirements. - * The listener will also start receiving response data earlier, as it does not have - * to wait for the entire response to be read. - *

- *

- * The ProtocolCommandListener must be prepared to accept partial responses. - * This should not be a problem for listeners that just log the input. - *

- * @see #setChunkListener(IMAPChunkListener) - * @since 3.4 - */ - public static final IMAPChunkListener TRUE_CHUNK_LISTENER = new IMAPChunkListener(){ - @Override - public boolean chunkReceived(final IMAP imap) { - return true; - } - - }; - private volatile IMAPChunkListener chunkListener; - - private final char[] initialID = { 'A', 'A', 'A', 'A' }; - - /** - * The default IMAPClient constructor. Initializes the state - * to DISCONNECTED_STATE. - */ - public IMAP() - { - setDefaultPort(DEFAULT_PORT); - state = IMAPState.DISCONNECTED_STATE; - _reader = null; - __writer = null; - replyLines = new ArrayList<>(); - createCommandSupport(); - } - - /** - * Get the reply for a command that expects a tagged response. - * - * @throws IOException - */ - private void getReply() throws IOException - { - getReply(true); // tagged response - } - - /** - * Get the reply for a command, reading the response until the - * reply is found. - * - * @param wantTag {@code true} if the command expects a tagged response. - * @throws IOException - */ - private void getReply(final boolean wantTag) throws IOException - { - replyLines.clear(); - String line = _reader.readLine(); - - if (line == null) { - throw new EOFException("Connection closed without indication."); - } - - replyLines.add(line); - - if (wantTag) { - while(IMAPReply.isUntagged(line)) { - int literalCount = IMAPReply.literalCount(line); - final boolean isMultiLine = literalCount >= 0; - while (literalCount >= 0) { - line=_reader.readLine(); - if (line == null) { - throw new EOFException("Connection closed without indication."); - } - replyLines.add(line); - literalCount -= line.length() + 2; // Allow for CRLF - } - if (isMultiLine) { - final IMAPChunkListener il = chunkListener; - if (il != null) { - final boolean clear = il.chunkReceived(this); - if (clear) { - fireReplyReceived(IMAPReply.PARTIAL, getReplyString()); - replyLines.clear(); - } - } - } - line = _reader.readLine(); // get next chunk or final tag - if (line == null) { - throw new EOFException("Connection closed without indication."); - } - replyLines.add(line); - } - // check the response code on the last line - replyCode = IMAPReply.getReplyCode(line); - } else { - replyCode = IMAPReply.getUntaggedReplyCode(line); - } - - fireReplyReceived(replyCode, getReplyString()); - } - - /** - * Overrides {@link SocketClient#fireReplyReceived(int, String)} so as to - * avoid creating the reply string if there are no listeners to invoke. - * - * @param replyCode passed to the listeners - * @param ignored the string is only created if there are listeners defined. - * @see #getReplyString() - * @since 3.4 - */ - @Override - protected void fireReplyReceived(final int replyCode, final String ignored) { - if (getCommandSupport().getListenerCount() > 0) { - getCommandSupport().fireReplyReceived(replyCode, getReplyString()); - } - } - - /** - * Performs connection initialization and sets state to - * {@link IMAPState#NOT_AUTH_STATE}. - */ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - _reader = - new CRLFLineReader(new InputStreamReader(_input_, - __DEFAULT_ENCODING)); - __writer = - new BufferedWriter(new OutputStreamWriter(_output_, - __DEFAULT_ENCODING)); - final int tmo = getSoTimeout(); - if (tmo <= 0) { // none set currently - setSoTimeout(connectTimeout); // use connect timeout to ensure we don't block forever - } - getReply(false); // untagged response - if (tmo <= 0) { - setSoTimeout(tmo); // restore the original value - } - setState(IMAPState.NOT_AUTH_STATE); - } - - /** - * Sets IMAP client state. This must be one of the - * _STATE constants. - * - * @param state The new state. - */ - protected void setState(final IMAP.IMAPState state) - { - this.state = state; - } - - - /** - * Returns the current IMAP client state. - * - * @return The current IMAP client state. - */ - public IMAP.IMAPState getState() - { - return state; - } - - /** - * Disconnects the client from the server, and sets the state to - * DISCONNECTED_STATE . The reply text information - * from the last issued command is voided to allow garbage collection - * of the memory used to store that information. - * - * @throws IOException If there is an error in disconnecting. - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - _reader = null; - __writer = null; - replyLines.clear(); - setState(IMAPState.DISCONNECTED_STATE); - } - - - /** - * Sends a command an arguments to the server and returns the reply code. - * - * @param commandID The ID (tag) of the command. - * @param command The IMAP command to send. - * @param args The command arguments. - * @return The server reply code (either IMAPReply.OK, IMAPReply.NO or IMAPReply.BAD). - */ - private int sendCommandWithID(final String commandID, final String command, final String args) throws IOException - { - final StringBuilder __commandBuffer = new StringBuilder(); - if (commandID != null) - { - __commandBuffer.append(commandID); - __commandBuffer.append(' '); - } - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - - final String message = __commandBuffer.toString(); - __writer.write(message); - __writer.flush(); - - fireCommandSent(command, message); - - getReply(); - return replyCode; - } - - /** - * Sends a command an arguments to the server and returns the reply code. - * - * @param command The IMAP command to send. - * @param args The command arguments. - * @return The server reply code (see IMAPReply). - * @throws IOException on error - */ - public int sendCommand(final String command, final String args) throws IOException - { - return sendCommandWithID(generateCommandID(), command, args); - } - - /** - * Sends a command with no arguments to the server and returns the - * reply code. - * - * @param command The IMAP command to send. - * @return The server reply code (see IMAPReply). - * @throws IOException on error - */ - public int sendCommand(final String command) throws IOException - { - return sendCommand(command, null); - } - - /** - * Sends a command and arguments to the server and returns the reply code. - * - * @param command The IMAP command to send - * (one of the IMAPCommand constants). - * @param args The command arguments. - * @return The server reply code (see IMAPReply). - * @throws IOException on error - */ - public int sendCommand(final IMAPCommand command, final String args) throws IOException - { - return sendCommand(command.getIMAPCommand(), args); - } - - /** - * Sends a command and arguments to the server and return whether successful. - * - * @param command The IMAP command to send - * (one of the IMAPCommand constants). - * @param args The command arguments. - * @return {@code true} if the command was successful - * @throws IOException on error - */ - public boolean doCommand(final IMAPCommand command, final String args) throws IOException - { - return IMAPReply.isSuccess(sendCommand(command, args)); - } - - /** - * Sends a command with no arguments to the server and returns the - * reply code. - * - * @param command The IMAP command to send - * (one of the IMAPCommand constants). - * @return The server reply code (see IMAPReply). - * @throws IOException on error - **/ - public int sendCommand(final IMAPCommand command) throws IOException - { - return sendCommand(command, null); - } - - /** - * Sends a command to the server and return whether successful. - * - * @param command The IMAP command to send - * (one of the IMAPCommand constants). - * @return {@code true} if the command was successful - * @throws IOException on error - */ - public boolean doCommand(final IMAPCommand command) throws IOException - { - return IMAPReply.isSuccess(sendCommand(command)); - } - - /** - * Sends data to the server and returns the reply code. - * - * @param command The IMAP command to send. - * @return The server reply code (see IMAPReply). - * @throws IOException on error - */ - public int sendData(final String command) throws IOException - { - return sendCommandWithID(null, command, null); - } - - /** - * Returns an array of lines received as a reply to the last command - * sent to the server. The lines have end of lines truncated. - * @return The last server response. - */ - public String[] getReplyStrings() - { - return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - - /** - * Returns the reply to the last command sent to the server. - * The value is a single string containing all the reply lines including - * newlines. - * - * @return The last server response. - */ - public String getReplyString() - { - final StringBuilder buffer = new StringBuilder(256); - for (final String s : replyLines) - { - buffer.append(s); - buffer.append(SocketClient.NETASCII_EOL); - } - - return buffer.toString(); - } - - /** - * Sets the current chunk listener. - * If a listener is registered and the implementation returns true, - * then any registered - * {@link org.apache.commons.net.PrintCommandListener PrintCommandListener} - * instances will be invoked with the partial response and a status of - * {@link IMAPReply#PARTIAL} to indicate that the final reply code is not yet known. - * @param listener the class to use, or {@code null} to disable - * @see #TRUE_CHUNK_LISTENER - * @since 3.4 - */ - public void setChunkListener(final IMAPChunkListener listener) { - chunkListener = listener; - } - - /** - * Generates a new command ID (tag) for a command. - * @return a new command ID (tag) for an IMAP command. - */ - protected String generateCommandID() - { - final String res = new String (initialID); - // "increase" the ID for the next call - boolean carry = true; // want to increment initially - for (int i = initialID.length-1; carry && i>=0; i--) - { - if (initialID[i] == 'Z') - { - initialID[i] = 'A'; - } - else - { - initialID[i]++; - carry = false; // did not wrap round - } - } - return res; - } - - /** - * Quote an input string if necessary. - * If the string is enclosed in double-quotes it is assumed - * to be quoted already and is returned unchanged. - * If it is the empty string, "" is returned. - * If it contains a space - * then it is enclosed in double quotes, escaping the - * characters backslash and double-quote. - * - * @param input the value to be quoted, may be null - * @return the quoted value - */ - static String quoteMailboxName(final String input) { - if (input == null) { // Don't throw NPE here - return null; - } - if (input.isEmpty()) { - return "\"\""; // return the string "" - } - // Length check is necessary to ensure a lone double-quote is quoted - if (input.length() > 1 && input.startsWith("\"") && input.endsWith("\"")) { - return input; // Assume already quoted - } - if (input.contains(" ")) { - // quoted strings must escape \ and " - return "\"" + input.replaceAll("([\\\\\"])", "\\\\$1") + "\""; - } - return input; - - } -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/IMAPClient.java b/src/org/apache/commons/net/imap/IMAPClient.java deleted file mode 100644 index 1afe2937..00000000 --- a/src/org/apache/commons/net/imap/IMAPClient.java +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -import java.io.IOException; - -/** - * The IMAPClient class provides the basic functionalities found in an - * IMAP client. - */ -public class IMAPClient extends IMAP -{ - - private static final char DQUOTE = '"'; - private static final String DQUOTE_S = "\""; - - // --------- commands available in all states - - /** - * Send a CAPABILITY command to the server. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs - */ - public boolean capability() throws IOException - { - return doCommand (IMAPCommand.CAPABILITY); - } - - /** - * Send a NOOP command to the server. This is useful for keeping - * a connection alive since most IMAP servers will timeout after 10 - * minutes of inactivity. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean noop() throws IOException - { - return doCommand (IMAPCommand.NOOP); - } - - /** - * Send a LOGOUT command to the server. To fully disconnect from the server - * you must call disconnect(). - * A logout attempt is valid in any state. If - * the client is in the not authenticated or authenticated state, it enters the - * logout on a successful logout. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean logout() throws IOException - { - return doCommand (IMAPCommand.LOGOUT); - } - - // --------- commands available in the not-authenticated state - // STARTTLS skipped - see IMAPSClient. - // AUTHENTICATE skipped - see AuthenticatingIMAPClient. - - /** - * Login to the IMAP server with the given username and password. You - * must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before attempting to login. A login attempt is only valid if - * the client is in the NOT_AUTH_STATE. - * After logging in, the client enters the AUTH_STATE. - * - * @param username The account name being logged in to. - * @param password The plain text password of the account. - * @return True if the login attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * logging in. - */ - public boolean login(final String username, final String password) throws IOException - { - if (getState() != IMAP.IMAPState.NOT_AUTH_STATE) - { - return false; - } - - if (!doCommand(IMAPCommand.LOGIN, username + " " + password)) - { - return false; - } - - setState(IMAP.IMAPState.AUTH_STATE); - - return true; - } - - // --------- commands available in the authenticated state - - /** - * Send a SELECT command to the server. - * @param mailboxName The mailbox name to select. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean select(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.SELECT, quoteMailboxName(mailboxName)); - } - - /** - * Send an EXAMINE command to the server. - * @param mailboxName The mailbox name to examine. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean examine(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.EXAMINE, quoteMailboxName(mailboxName)); - } - - /** - * Send a CREATE command to the server. - * @param mailboxName The mailbox name to create. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean create(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.CREATE, quoteMailboxName(mailboxName)); - } - - /** - * Send a DELETE command to the server. - * @param mailboxName The mailbox name to delete. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean delete(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.DELETE, quoteMailboxName(mailboxName)); - } - - /** - * Send a RENAME command to the server. - * @param oldMailboxName The existing mailbox name to rename. - * @param newMailboxName The new mailbox name. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean rename(final String oldMailboxName, final String newMailboxName) throws IOException - { - return doCommand (IMAPCommand.RENAME, quoteMailboxName(oldMailboxName) + " " + quoteMailboxName(newMailboxName)); - } - - /** - * Send a SUBSCRIBE command to the server. - * @param mailboxName The mailbox name to subscribe to. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean subscribe(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.SUBSCRIBE, quoteMailboxName(mailboxName)); - } - - /** - * Send a UNSUBSCRIBE command to the server. - * @param mailboxName The mailbox name to unsubscribe from. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean unsubscribe(final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.UNSUBSCRIBE, quoteMailboxName(mailboxName)); - } - - /** - * Send a LIST command to the server. - * Quotes the parameters if necessary. - * @param refName The reference name - * If empty, indicates that the mailbox name is interpreted as by SELECT. - * @param mailboxName The mailbox name. - * If empty, this is a special request to - * return the hierarchy delimiter and the root name of the name given - * in the reference - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean list(final String refName, final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.LIST, quoteMailboxName(refName) + " " + quoteMailboxName(mailboxName)); - } - - /** - * Send an LSUB command to the server. - * Quotes the parameters if necessary. - * @param refName The reference name. - * @param mailboxName The mailbox name. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean lsub(final String refName, final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.LSUB, quoteMailboxName(refName) + " " + quoteMailboxName(mailboxName)); - } - - /** - * Send a STATUS command to the server. - * @param mailboxName The reference name. - * @param itemNames The status data item names. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean status(final String mailboxName, final String[] itemNames) throws IOException - { - if (itemNames == null || itemNames.length < 1) { - throw new IllegalArgumentException("STATUS command requires at least one data item name"); - } - - final StringBuilder sb = new StringBuilder(); - sb.append(quoteMailboxName(mailboxName)); - - sb.append(" ("); - for ( int i = 0; i < itemNames.length; i++ ) - { - if (i > 0) { - sb.append(" "); - } - sb.append(itemNames[i]); - } - sb.append(")"); - - return doCommand (IMAPCommand.STATUS, sb.toString()); - } - - /** - * Send an APPEND command to the server. - * @param mailboxName The mailbox name. - * @param flags The flag parenthesized list (optional). - * @param datetime The date/time string (optional). - * @param message The message to append. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - * @since 3.4 - */ - public boolean append(final String mailboxName, final String flags, final String datetime, final String message) - throws IOException { - final StringBuilder args = new StringBuilder(quoteMailboxName(mailboxName)); - if (flags != null) { - args.append(" ").append(flags); - } - if (datetime != null) { - args.append(" "); - if (datetime.charAt(0) == DQUOTE) { - args.append(datetime); - } else { - args.append(DQUOTE).append(datetime).append(DQUOTE); - } - } - args.append(" "); - // String literal (probably not used much - if at all) - if (message.startsWith(DQUOTE_S) && message.endsWith(DQUOTE_S)) { - args.append(message); - return doCommand(IMAPCommand.APPEND, args.toString()); - } - args.append('{').append(message.getBytes(IMAP.__DEFAULT_ENCODING).length).append('}'); // length of message - final int status = sendCommand(IMAPCommand.APPEND, args.toString()); - return IMAPReply.isContinuation(status) // expecting continuation response - && IMAPReply.isSuccess(sendData(message)); // if so, send the data - } - - /** - * Send an APPEND command to the server. - * @param mailboxName The mailbox name. - * @param flags The flag parenthesized list (optional). - * @param datetime The date/time string (optional). - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - * @deprecated (3.4) Does not work; the message body is not optional. - * Use {@link #append(String, String, String, String)} instead. - */ - @Deprecated - public boolean append(final String mailboxName, final String flags, final String datetime) throws IOException - { - String args = mailboxName; - if (flags != null) { - args += " " + flags; - } - if (datetime != null) { - if (datetime.charAt(0) == '{') { - args += " " + datetime; - } else { - args += " {" + datetime + "}"; - } - } - return doCommand (IMAPCommand.APPEND, args); - } - - /** - * Send an APPEND command to the server. - * @param mailboxName The mailbox name. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - * @deprecated (3.4) Does not work; the message body is not optional. - * Use {@link #append(String, String, String, String)} instead. - */ - @Deprecated - public boolean append(final String mailboxName) throws IOException - { - return append(mailboxName, null, null); - } - - // --------- commands available in the selected state - - /** - * Send a CHECK command to the server. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean check() throws IOException - { - return doCommand (IMAPCommand.CHECK); - } - - /** - * Send a CLOSE command to the server. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean close() throws IOException - { - return doCommand (IMAPCommand.CLOSE); - } - - /** - * Send an EXPUNGE command to the server. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean expunge() throws IOException - { - return doCommand (IMAPCommand.EXPUNGE); - } - - /** - * Send a SEARCH command to the server. - * @param charset The charset (optional). - * @param criteria The search criteria. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean search(final String charset, final String criteria) throws IOException - { - String args = ""; - if (charset != null) { - args += "CHARSET " + charset; - } - args += criteria; - return doCommand (IMAPCommand.SEARCH, args); - } - - /** - * Send a SEARCH command to the server. - * @param criteria The search criteria. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean search(final String criteria) throws IOException - { - return search(null, criteria); - } - - /** - * Send a FETCH command to the server. - * - * @param sequenceSet The sequence set to fetch (e.g. 1:4,6,11,100:*) - * @param itemNames The item names for the FETCH command. (e.g. BODY.PEEK[HEADER.FIELDS (SUBJECT)]) - * If multiple item names are requested, these must be enclosed in parentheses, e.g. "(UID FLAGS BODY.PEEK[])" - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - * @see #getReplyString() - * @see #getReplyStrings() - */ - public boolean fetch(final String sequenceSet, final String itemNames) throws IOException - { - return doCommand (IMAPCommand.FETCH, sequenceSet + " " + itemNames); - } - - /** - * Send a STORE command to the server. - * @param sequenceSet The sequence set to update (e.g. 2:5) - * @param itemNames The item name for the STORE command (i.e. [+|-]FLAGS[.SILENT]) - * @param itemValues The item values for the STORE command. (e.g. (\Deleted) ) - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean store(final String sequenceSet, final String itemNames, final String itemValues) - throws IOException - { - return doCommand (IMAPCommand.STORE, sequenceSet + " " + itemNames + " " + itemValues); - } - - /** - * Send a COPY command to the server. - * @param sequenceSet The sequence set to fetch. - * @param mailboxName The mailbox name. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean copy(final String sequenceSet, final String mailboxName) throws IOException - { - return doCommand (IMAPCommand.COPY, sequenceSet + " " + quoteMailboxName(mailboxName)); - } - - /** - * Send a UID command to the server. - * @param command The command for UID. - * @param commandArgs The arguments for the command. - * @return {@code true} if the command was successful,{@code false} if not. - * @throws IOException If a network I/O error occurs. - */ - public boolean uid(final String command, final String commandArgs) throws IOException - { - return doCommand (IMAPCommand.UID, command + " " + commandArgs); - } - - /** - * The status data items defined in RFC 3501. - */ - public enum STATUS_DATA_ITEMS - { - /** The number of messages in the mailbox. */ - MESSAGES, - /** The number of messages with the \Recent flag set. */ - RECENT, - /** The next unique identifier value of the mailbox. */ - UIDNEXT, - /** The unique identifier validity value of the mailbox. */ - UIDVALIDITY, - /** The number of messages which do not have the \Seen flag set. */ - UNSEEN - } - - /** - * The search criteria defined in RFC 3501. - */ - public enum SEARCH_CRITERIA - { - /** All messages in the mailbox. */ - ALL, - /** Messages with the \Answered flag set. */ - ANSWERED, - /** - * Messages that contain the specified string in the envelope - * structure's BCC field. - */ - BCC, - /** - * Messages whose internal date (disregarding time and time zone) - * is earlier than the specified date. - */ - BEFORE, - /** - * Messages that contain the specified string in the body of the - * message. - */ - BODY, - /** - * Messages that contain the specified string in the envelope - * structure's CC field. - */ - CC, - /** Messages with the \Deleted flag set. */ - DELETED, - /** Messages with the \Draft flag set. */ - DRAFT, - /** Messages with the \Flagged flag set. */ - FLAGGED, - /** - * Messages that contain the specified string in the envelope - * structure's FROM field. - */ - FROM, - /** - * Messages that have a header with the specified field-name (as - * defined in [RFC-2822]) and that contains the specified string - * in the text of the header (what comes after the colon). If the - * string to search is zero-length, this matches all messages that - * have a header line with the specified field-name regardless of - * the contents. - */ - HEADER, - /** Messages with the specified keyword flag set. */ - KEYWORD, - /** - * Messages with an [RFC-2822] size larger than the specified - * number of octets. - */ - LARGER, - /** - * Messages that have the \Recent flag set but not the \Seen flag. - * This is functionally equivalent to "(RECENT UNSEEN)". - */ - NEW, - /** Messages that do not match the specified search key. */ - NOT, - /** - * Messages that do not have the \Recent flag set. This is - * functionally equivalent to "NOT RECENT" (as opposed to "NOT - * NEW"). - */ - OLD, - /** - * Messages whose internal date (disregarding time and time zone) - * is within the specified date. - */ - ON, - /** Messages that match either search key. */ - OR, - /** Messages that have the \Recent flag set. */ - RECENT, - /** Messages that have the \Seen flag set. */ - SEEN, - /** - * Messages whose [RFC-2822] Date: header (disregarding time and - * time zone) is earlier than the specified date. - */ - SENTBEFORE, - /** - * Messages whose [RFC-2822] Date: header (disregarding time and - * time zone) is within the specified date. - */ - SENTON, - /** - * Messages whose [RFC-2822] Date: header (disregarding time and - * time zone) is within or later than the specified date. - */ - SENTSINCE, - /** - * Messages whose internal date (disregarding time and time zone) - * is within or later than the specified date. - */ - SINCE, - /** - * Messages with an [RFC-2822] size smaller than the specified - * number of octets. - */ - SMALLER, - /** - * Messages that contain the specified string in the envelope - * structure's SUBJECT field. - */ - SUBJECT, - /** - * Messages that contain the specified string in the header or - * body of the message. - */ - TEXT, - /** - * Messages that contain the specified string in the envelope - * structure's TO field. - */ - TO, - /** - * Messages with unique identifiers corresponding to the specified - * unique identifier set. Sequence set ranges are permitted. - */ - UID, - /** Messages that do not have the \Answered flag set. */ - UNANSWERED, - /** Messages that do not have the \Deleted flag set. */ - UNDELETED, - /** Messages that do not have the \Draft flag set. */ - UNDRAFT, - /** Messages that do not have the \Flagged flag set. */ - UNFLAGGED, - /** Messages that do not have the specified keyword flag set. */ - UNKEYWORD, - /** Messages that do not have the \Seen flag set. */ - UNSEEN - } - - /** - * The message data item names for the FETCH command defined in RFC 3501. - */ - public enum FETCH_ITEM_NAMES - { - /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE). */ - ALL, - /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE). */ - FAST, - /** Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY). */ - FULL, - /** Non-extensible form of BODYSTRUCTURE or the text of a particular body section. */ - BODY, - /** The [MIME-IMB] body structure of the message. */ - BODYSTRUCTURE, - /** The envelope structure of the message. */ - ENVELOPE, - /** The flags that are set for this message. */ - FLAGS, - /** The internal date of the message. */ - INTERNALDATE, - /** A prefix for RFC-822 item names. */ - RFC822, - /** The unique identifier for the message. */ - UID - } - -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/IMAPCommand.java b/src/org/apache/commons/net/imap/IMAPCommand.java deleted file mode 100644 index 564c6ca4..00000000 --- a/src/org/apache/commons/net/imap/IMAPCommand.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -/** - * IMAPCommand stores IMAP command codes. - */ -public enum IMAPCommand -{ - // These enums must either use the same name as the IMAP command - // or must provide the correct string as the parameter. - - // Commands valid in any state: - - CAPABILITY(0), - NOOP(0), - LOGOUT(0), - - // Commands valid in Not Authenticated state - STARTTLS(0), - AUTHENTICATE(1), - LOGIN(2), - - XOAUTH(1), - - // commands valid in authenticated state - SELECT(1), - EXAMINE(1), - CREATE(1), - DELETE(1), - RENAME(2), - SUBSCRIBE(1), - UNSUBSCRIBE(1), - LIST(2), - LSUB(2), - STATUS(2), // P2 = list in () - APPEND(2,4), // mbox [(flags)] [date-time] literal - - // commands valid in selected state (substate of authenticated) - CHECK(0), - CLOSE(0), - EXPUNGE(0), - SEARCH(1, Integer.MAX_VALUE), - FETCH(2), - STORE(3), - COPY(2), - UID(2, Integer.MAX_VALUE), - ; - - private final String imapCommand; - - @SuppressWarnings("unused") // not yet used - private final int minParamCount; - @SuppressWarnings("unused") // not yet used - private final int maxParamCount; - - IMAPCommand(){ - this(null); - } - - IMAPCommand(final String name){ - this(name, 0); - } - - IMAPCommand(final int paramCount){ - this(null, paramCount, paramCount); - } - - IMAPCommand(final int minCount, final int maxCount){ - this(null, minCount, maxCount); - } - - IMAPCommand(final String name, final int paramCount){ - this(name, paramCount, paramCount); - } - - IMAPCommand(final String name, final int minCount, final int maxCount){ - this.imapCommand = name; - this.minParamCount = minCount; - this.maxParamCount = maxCount; - } - - /** - * Get the IMAP protocol string command corresponding to a command code. - * - * @param command the IMAPCommand whose command string is required. - * @return The IMAP protocol string command corresponding to a command code. - */ - public static final String getCommand(final IMAPCommand command) { - return command.getIMAPCommand(); - } - - /** - * Get the IMAP protocol string command for this command - * - * @return The IMAP protocol string command corresponding to this command - */ - public String getIMAPCommand() { - return imapCommand != null ? imapCommand : name(); - } - -} - -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/IMAPReply.java b/src/org/apache/commons/net/imap/IMAPReply.java deleted file mode 100644 index fd433756..00000000 --- a/src/org/apache/commons/net/imap/IMAPReply.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.net.MalformedServerReplyException; - -/** - * IMAPReply stores IMAP reply code constants. - */ - -public final class IMAPReply -{ - /** The reply code indicating success of an operation. */ - public static final int OK = 0; - - /** The reply code indicating failure of an operation. */ - public static final int NO = 1; - - /** The reply code indicating command rejection. */ - public static final int BAD = 2; - - /** The reply code indicating command continuation. */ - public static final int CONT = 3; - - /** - * The reply code indicating a partial response. - * This is used when a chunk listener is registered and the listener - * requests that the reply lines are cleared on return. - * @since 3.4 - */ - public static final int PARTIAL = 3; - - /** The IMAP reply String indicating success of an operation. */ - private static final String IMAP_OK = "OK"; - - /** The IMAP reply String indicating failure of an operation. */ - private static final String IMAP_NO = "NO"; - - /** The IMAP reply String indicating command rejection. */ - private static final String IMAP_BAD = "BAD"; - - // Start of line for untagged replies - private static final String IMAP_UNTAGGED_PREFIX = "* "; - - // Start of line for continuation replies - private static final String IMAP_CONTINUATION_PREFIX = "+"; - - // Cannot be instantiated. - private IMAPReply() - {} - - /** - * Checks if the reply line is untagged - e.g. "* OK ..." - * @param line to be checked - * @return {@code true} if the line is untagged - */ - public static boolean isUntagged(final String line) { - return line.startsWith(IMAP_UNTAGGED_PREFIX); - } - - /** - * Checks if the reply line is a continuation, i.e. starts with "+" - * @param line the line to be checked - * @return {@code true} if the line is untagged - */ - public static boolean isContinuation(final String line) { - return line.startsWith(IMAP_CONTINUATION_PREFIX); - } - - private static final String TAGGED_RESPONSE = "^\\w+ (\\S+).*"; // TODO perhaps be less strict on tag match? - // tag cannot contain: + ( ) { SP CTL % * " \ ] - private static final Pattern TAGGED_PATTERN = Pattern.compile(TAGGED_RESPONSE); - - /** - * Intepret the String reply code - OK, NO, BAD - in a tagged response as a integer. - * - * @param line the tagged line to be checked - * @return {@link #OK} or {@link #NO} or {@link #BAD} or {@link #CONT} - * @throws IOException if the input has an unexpected format - */ - public static int getReplyCode(final String line) throws IOException { - return getReplyCode(line, TAGGED_PATTERN); - } - - private static final String UNTAGGED_RESPONSE = "^\\* (\\S+).*"; - private static final Pattern UNTAGGED_PATTERN = Pattern.compile(UNTAGGED_RESPONSE); - - private static final Pattern LITERAL_PATTERN = Pattern.compile("\\{(\\d+)\\}$"); // {dd} - - /** - * Checks if the line introduces a literal, i.e. ends with {dd} - * @param line the line to check - * - * @return the literal count, or -1 if there was no literal. - */ - public static int literalCount(final String line) { - final Matcher m = LITERAL_PATTERN.matcher(line); - if (m.find()) { - return Integer.parseInt(m.group(1)); // Should always parse because we matched \d+ - } - return -1; - } - - /** - * Intepret the String reply code - OK, NO, BAD - in an untagged response as a integer. - * - * @param line the untagged line to be checked - * @return {@link #OK} or {@link #NO} or {@link #BAD} or {@link #CONT} - * @throws IOException if the input has an unexpected format - */ - public static int getUntaggedReplyCode(final String line) throws IOException { - return getReplyCode(line, UNTAGGED_PATTERN); - } - - // Helper method to process both tagged and untagged replies. - private static int getReplyCode(final String line, final Pattern pattern) throws IOException{ - if (isContinuation(line)) { - return CONT; - } - final Matcher m = pattern.matcher(line); - if (m.matches()) { // TODO would lookingAt() be more efficient? If so, then drop trailing .* from patterns - final String code = m.group(1); - if (code.equals(IMAP_OK)) { - return OK; - } - if (code.equals(IMAP_BAD)) { - return BAD; - } - if (code.equals(IMAP_NO)) { - return NO; - } - } - throw new MalformedServerReplyException( - "Received unexpected IMAP protocol response from server: '" + line + "'."); - } - - /** - * Checks whether the reply code indicates success or not - * - * @param replyCode the code to check - * @return {@code true} if the code equals {@link #OK} - */ - public static boolean isSuccess(final int replyCode) { - return replyCode == OK; - } - /** - * Checks if the reply line is a continuation, i.e. starts with "+" - * @param replyCode the code to be checked - * @return {@code true} if the response was a continuation - */ - public static boolean isContinuation(final int replyCode) { - return replyCode == CONT; - } - -} - -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/IMAPSClient.java b/src/org/apache/commons/net/imap/IMAPSClient.java deleted file mode 100644 index 3662d77a..00000000 --- a/src/org/apache/commons/net/imap/IMAPSClient.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.imap; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.SSLContextUtils; -import org.apache.commons.net.util.SSLSocketUtils; - -/** - * The IMAPSClient class provides SSL/TLS connection encryption to IMAPClient. - * Copied from - * - * FTPSClient and modified to suit IMAP. - * If implicit mode is selected (NOT the default), SSL/TLS negotiation starts right - * after the connection has been established. In explicit mode (the default), SSL/TLS - * negotiation starts when the user calls execTLS() and the server accepts the command. - * - *
- * {@code
- * //Implicit usage:
- *
- *               IMAPSClient c = new IMAPSClient(true);
- *               c.connect("127.0.0.1", 993);
- *
- * //Explicit usage:
- *
- *               IMAPSClient c = new IMAPSClient();
- *               c.connect("127.0.0.1", 143);
- *               if (c.execTLS()) { /rest of the commands here/ }
- * }
- * 
- * Warning: the hostname is not verified against the certificate by default, use - * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} - * (on Java 1.7+) to enable verification. - */ -public class IMAPSClient extends IMAPClient -{ - /** The default IMAP over SSL port. */ - public static final int DEFAULT_IMAPS_PORT = 993; - - /** Default secure socket protocol name. */ - public static final String DEFAULT_PROTOCOL = "TLS"; - - /** The security mode. True - Implicit Mode / False - Explicit Mode. */ - private final boolean isImplicit; - /** The secure socket protocol to be used, like SSL/TLS. */ - private final String protocol; - /** The context object. */ - private SSLContext context; - /** The cipher suites. SSLSockets have a default set of these anyway, - so no initialization required. */ - private String[] suites; - /** The protocol versions. */ - private String[] protocols //null; - ;//{"SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "SSLv2Hello"}; - - /** The IMAPS {@link TrustManager} implementation, default null. */ - private TrustManager trustManager; - - /** The {@link KeyManager}, default null. */ - private KeyManager keyManager; - - /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ - private HostnameVerifier hostnameVerifier; - - /** Use Java 1.7+ HTTPS Endpoint Identification Algorithim. */ - private boolean tlsEndpointChecking; - - /** - * Constructor for IMAPSClient. - * Sets security mode to explicit (isImplicit = false). - */ - public IMAPSClient() - { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for IMAPSClient. - * @param implicit The security mode (Implicit/Explicit). - */ - public IMAPSClient(final boolean implicit) - { - this(DEFAULT_PROTOCOL, implicit); - } - - /** - * Constructor for IMAPSClient. - * @param proto the protocol. - */ - public IMAPSClient(final String proto) - { - this(proto, false); - } - - /** - * Constructor for IMAPSClient. - * @param proto the protocol. - * @param implicit The security mode(Implicit/Explicit). - */ - public IMAPSClient(final String proto, final boolean implicit) - { - this(proto, implicit, null); - } - - /** - * Constructor for IMAPSClient. - * @param proto the protocol. - * @param implicit The security mode(Implicit/Explicit). - * @param ctx the SSL context - */ - public IMAPSClient(final String proto, final boolean implicit, final SSLContext ctx) - { - setDefaultPort(DEFAULT_IMAPS_PORT); - protocol = proto; - isImplicit = implicit; - context = ctx; - } - - /** - * Constructor for IMAPSClient. - * @param implicit The security mode(Implicit/Explicit). - * @param ctx A pre-configured SSL Context. - */ - public IMAPSClient(final boolean implicit, final SSLContext ctx) - { - this(DEFAULT_PROTOCOL, implicit, ctx); - } - - /** - * Constructor for IMAPSClient. - * @param context A pre-configured SSL Context. - */ - public IMAPSClient(final SSLContext context) - { - this(false, context); - } - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * @throws IOException If it is thrown by _connectAction_(). - * @see org.apache.commons.net.SocketClient#_connectAction_() - */ - @Override - protected void _connectAction_() throws IOException - { - // Implicit mode. - if (isImplicit) { - performSSLNegotiation(); - } - super._connectAction_(); - // Explicit mode - don't do anything. The user calls execTLS() - } - - /** - * Performs a lazy init of the SSL context. - * @throws IOException When could not initialize the SSL context. - */ - private void initSSLContext() throws IOException - { - if (context == null) - { - context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a - * connection and carries out handshake processing. - * @throws IOException If server negotiation fails. - */ - private void performSSLNegotiation() throws IOException - { - initSSLContext(); - - final SSLSocketFactory ssf = context.getSocketFactory(); - final String host = _hostname_ != null ? _hostname_ : getRemoteAddress().getHostAddress(); - final int port = getRemotePort(); - final SSLSocket socket = - (SSLSocket) ssf.createSocket(_socket_, host, port, true); - socket.setEnableSessionCreation(true); - socket.setUseClientMode(true); - - if (tlsEndpointChecking) { - SSLSocketUtils.enableEndpointNameVerification(socket); - } - - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - if (suites != null) { - socket.setEnabledCipherSuites(suites); - } - socket.startHandshake(); - - // TODO the following setup appears to duplicate that in the super class methods - _socket_ = socket; - _input_ = socket.getInputStream(); - _output_ = socket.getOutputStream(); - _reader = - new CRLFLineReader(new InputStreamReader(_input_, - __DEFAULT_ENCODING)); - __writer = - new BufferedWriter(new OutputStreamWriter(_output_, - __DEFAULT_ENCODING)); - - if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { - throw new SSLHandshakeException("Hostname doesn't match certificate"); - } - } - - /** - * Get the {@link KeyManager} instance. - * @return The current {@link KeyManager} instance. - */ - private KeyManager getKeyManager() - { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use. - * @param newKeyManager The KeyManager implementation to set. - * @see org.apache.commons.net.util.KeyManagerUtils - */ - public void setKeyManager(final KeyManager newKeyManager) - { - keyManager = newKeyManager; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. Called before server negotiation. - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(final String[] cipherSuites) - { - suites = cipherSuites.clone(); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of cipher suite names, or null. - */ - public String[] getEnabledCipherSuites() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledCipherSuites(); - } - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(final String[] protocolVersions) - { - protocols = protocolVersions.clone(); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of protocols, or null. - */ - public String[] getEnabledProtocols() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledProtocols(); - } - return null; - } - - /** - * The TLS command execution. - * @throws SSLException If the server reply code is not positive. - * @throws IOException If an I/O error occurs while sending - * the command or performing the negotiation. - * @return TRUE if the command and negotiation succeeded. - */ - public boolean execTLS() throws SSLException, IOException - { - if (sendCommand(IMAPCommand.getCommand(IMAPCommand.STARTTLS)) != IMAPReply.OK) - { - return false; - //throw new SSLException(getReplyString()); - } - performSSLNegotiation(); - return true; - } - - /** - * Get the currently configured {@link TrustManager}. - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() - { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use. - * @param newTrustManager The TrustManager implementation to set. - * @see org.apache.commons.net.util.TrustManagerUtils - */ - public void setTrustManager(final TrustManager newTrustManager) - { - trustManager = newTrustManager; - } - - /** - * Get the currently configured {@link HostnameVerifier}. - * @return A HostnameVerifier instance. - * @since 3.4 - */ - public HostnameVerifier getHostnameVerifier() - { - return hostnameVerifier; - } - - /** - * Override the default {@link HostnameVerifier} to use. - * @param newHostnameVerifier The HostnameVerifier implementation to set or null to disable. - * @since 3.4 - */ - public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) - { - hostnameVerifier = newHostnameVerifier; - } - - /** - * Return whether or not endpoint identification using the HTTPS algorithm - * on Java 1.7+ is enabled. The default behavior is for this to be disabled. - * - * @return True if enabled, false if not. - * @since 3.4 - */ - public boolean isEndpointCheckingEnabled() - { - return tlsEndpointChecking; - } - - /** - * Automatic endpoint identification checking using the HTTPS algorithm - * is supported on Java 1.7+. The default behavior is for this to be disabled. - * - * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. - * @since 3.4 - */ - public void setEndpointCheckingEnabled(final boolean enable) - { - tlsEndpointChecking = enable; - } -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/imap/package-info.java b/src/org/apache/commons/net/imap/package-info.java deleted file mode 100644 index 2e86b332..00000000 --- a/src/org/apache/commons/net/imap/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Basic IMAP and IMAPS support classes - */ -package org.apache.commons.net.imap; \ No newline at end of file diff --git a/src/org/apache/commons/net/io/CRLFLineReader.java b/src/org/apache/commons/net/io/CRLFLineReader.java deleted file mode 100644 index d7ccc416..00000000 --- a/src/org/apache/commons/net/io/CRLFLineReader.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * CRLFLineReader implements a readLine() method that requires - * exactly CRLF to terminate an input line. - * This is required for IMAP, which allows bare CR and LF. - * - * @since 3.0 - */ -public final class CRLFLineReader extends BufferedReader -{ - private static final char LF = '\n'; - private static final char CR = '\r'; - - /** - * Creates a CRLFLineReader that wraps an existing Reader - * input source. - * @param reader The Reader input source. - */ - public CRLFLineReader(final Reader reader) - { - super(reader); - } - - /** - * Read a line of text. - * A line is considered to be terminated by carriage return followed immediately by a linefeed. - * This contrasts with BufferedReader which also allows other combinations. - * @since 3.0 - */ - @Override - public String readLine() throws IOException { - final StringBuilder sb = new StringBuilder(); - int intch; - boolean prevWasCR = false; - synchronized(lock) { // make thread-safe (hopefully!) - while((intch = read()) != -1) - { - if (prevWasCR && intch == LF) { - return sb.substring(0, sb.length()-1); - } - if (intch == CR) { - prevWasCR = true; - } else { - prevWasCR = false; - } - sb.append((char) intch); - } - } - final String string = sb.toString(); - if (string.isEmpty()) { // immediate EOF - return null; - } - return string; - } -} diff --git a/src/org/apache/commons/net/io/CopyStreamAdapter.java b/src/org/apache/commons/net/io/CopyStreamAdapter.java deleted file mode 100644 index 489ae155..00000000 --- a/src/org/apache/commons/net/io/CopyStreamAdapter.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventListener; - -import org.apache.commons.net.util.ListenerList; - -/** - * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners - * when either of its bytesTransferred() methods are called. Its purpose - * is to facilitate the notification of the progress of a copy operation - * performed by one of the static copyStream() methods in - * org.apache.commons.io.Util to multiple listeners. The static - * copyStream() methods invoke the - * bytesTransfered(long, int) of a CopyStreamListener for performance - * reasons and also because multiple listeners cannot be registered given - * that the methods are static. - * - * - * @see CopyStreamEvent - * @see CopyStreamListener - * @see Util - */ -public class CopyStreamAdapter implements CopyStreamListener -{ - private final ListenerList internalListeners; - - /** - * Creates a new copyStreamAdapter. - */ - public CopyStreamAdapter() - { - internalListeners = new ListenerList(); - } - - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. The CopyStreamAdapater will relay - * the event to all of its registered listeners, listing itself as the - * source of the event. - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - @Override - public void bytesTransferred(final CopyStreamEvent event) - { - for (final EventListener listener : internalListeners) - { - ((CopyStreamListener) listener).bytesTransferred(event); - } - } - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. The CopyStreamAdapater will create a CopyStreamEvent - * from the arguments and relay the event to all of its registered - * listeners, listing itself as the source of the event. - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - @Override - public void bytesTransferred(final long totalBytesTransferred, - final int bytesTransferred, final long streamSize) - { - for (final EventListener listener : internalListeners) - { - ((CopyStreamListener) listener).bytesTransferred( - totalBytesTransferred, bytesTransferred, streamSize); - } - } - - /** - * Registers a CopyStreamListener to receive CopyStreamEvents. - * Although this method is not declared to be synchronized, it is - * implemented in a thread safe manner. - * @param listener The CopyStreamlistener to register. - */ - public void addCopyStreamListener(final CopyStreamListener listener) - { - internalListeners.addListener(listener); - } - - /** - * Unregisters a CopyStreamListener. Although this method is not - * synchronized, it is implemented in a thread safe manner. - * @param listener The CopyStreamlistener to unregister. - */ - public void removeCopyStreamListener(final CopyStreamListener listener) - { - internalListeners.removeListener(listener); - } -} diff --git a/src/org/apache/commons/net/io/CopyStreamEvent.java b/src/org/apache/commons/net/io/CopyStreamEvent.java deleted file mode 100644 index bdca364c..00000000 --- a/src/org/apache/commons/net/io/CopyStreamEvent.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventObject; - -/** - * A CopyStreamEvent is triggered after every write performed by a - * stream copying operation. The event stores the number of bytes - * transferred by the write triggering the event as well as the total - * number of bytes transferred so far by the copy operation. - * - * - * @see CopyStreamListener - * @see CopyStreamAdapter - * @see Util - */ -public class CopyStreamEvent extends EventObject -{ - private static final long serialVersionUID = -964927635655051867L; - - /** - * Constant used to indicate the stream size is unknown. - */ - public static final long UNKNOWN_STREAM_SIZE = -1; - - private final int bytesTransferred; - private final long totalBytesTransferred; - private final long streamSize; - - /** - * Creates a new CopyStreamEvent instance. - * @param source The source of the event. - * @param totalBytesTransferred The total number of bytes transferred so - * far during a copy operation. - * @param bytesTransferred The number of bytes transferred during the - * write that triggered the CopyStreamEvent. - * @param streamSize The number of bytes in the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - */ - public CopyStreamEvent(final Object source, final long totalBytesTransferred, - final int bytesTransferred, final long streamSize) - { - super(source); - this.bytesTransferred = bytesTransferred; - this.totalBytesTransferred = totalBytesTransferred; - this.streamSize = streamSize; - } - - /** - * Returns the number of bytes transferred by the write that triggered - * the event. - * @return The number of bytes transferred by the write that triggered - * the vent. - */ - public int getBytesTransferred() - { - return bytesTransferred; - } - - /** - * Returns the total number of bytes transferred so far by the copy - * operation. - * @return The total number of bytes transferred so far by the copy - * operation. - */ - public long getTotalBytesTransferred() - { - return totalBytesTransferred; - } - - /** - * Returns the size of the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - * @return The size of the stream being copied. - */ - public long getStreamSize() - { - return streamSize; - } - - /** - * @since 3.0 - */ - @Override - public String toString(){ - return getClass().getName() + "[source=" + source - + ", total=" + totalBytesTransferred - + ", bytes=" + bytesTransferred - + ", size=" + streamSize - + "]"; - } -} diff --git a/src/org/apache/commons/net/io/CopyStreamException.java b/src/org/apache/commons/net/io/CopyStreamException.java deleted file mode 100644 index 459a9fd0..00000000 --- a/src/org/apache/commons/net/io/CopyStreamException.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; - -/** - * The CopyStreamException class is thrown by the org.apache.commons.io.Util - * copyStream() methods. It stores the number of bytes confirmed to - * have been transferred before an I/O error as well as the IOException - * responsible for the failure of a copy operation. - * @see Util - */ -public class CopyStreamException extends IOException -{ - private static final long serialVersionUID = -2602899129433221532L; - - private final long totalBytesTransferred; - - /** - * Creates a new CopyStreamException instance. - * @param message A message describing the error. - * @param bytesTransferred The total number of bytes transferred before - * an exception was thrown in a copy operation. - * @param exception The IOException thrown during a copy operation. - */ - public CopyStreamException(final String message, - final long bytesTransferred, - final IOException exception) - { - super(message); - initCause(exception); // merge this into super() call once we need 1.6+ - totalBytesTransferred = bytesTransferred; - } - - /** - * Returns the total number of bytes confirmed to have - * been transferred by a failed copy operation. - * @return The total number of bytes confirmed to have - * been transferred by a failed copy operation. - */ - public long getTotalBytesTransferred() - { - return totalBytesTransferred; - } - - /** - * Returns the IOException responsible for the failure of a copy operation. - * @return The IOException responsible for the failure of a copy operation. - */ - public IOException getIOException() - { - return (IOException) getCause(); // cast is OK because it was initialized with an IOException - } -} diff --git a/src/org/apache/commons/net/io/CopyStreamListener.java b/src/org/apache/commons/net/io/CopyStreamListener.java deleted file mode 100644 index 00ac9760..00000000 --- a/src/org/apache/commons/net/io/CopyStreamListener.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.util.EventListener; - -/** - * The CopyStreamListener class can accept CopyStreamEvents to keep track - * of the progress of a stream copying operation. However, it is currently - * not used that way within NetComponents for performance reasons. Rather - * the bytesTransferred(long, int) method is called directly rather than - * passing an event to bytesTransferred(CopyStreamEvent), saving the creation - * of a CopyStreamEvent instance. Also, the only place where - * CopyStreamListener is currently used within NetComponents is in the - * static methods of the uninstantiable org.apache.commons.io.Util class, which - * would preclude the use of addCopyStreamListener and - * removeCopyStreamListener methods. However, future additions may use the - * JavaBean event model, which is why the hooks have been included from the - * beginning. - * - * - * @see CopyStreamEvent - * @see CopyStreamAdapter - * @see Util - */ -public interface CopyStreamListener extends EventListener -{ - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - void bytesTransferred(CopyStreamEvent event); - - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - void bytesTransferred(long totalBytesTransferred, - int bytesTransferred, - long streamSize); -} diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageReader.java b/src/org/apache/commons/net/io/DotTerminatedMessageReader.java deleted file mode 100644 index 08683395..00000000 --- a/src/org/apache/commons/net/io/DotTerminatedMessageReader.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * DotTerminatedMessageReader is a class used to read messages from a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles stripping of the duplicate period at the beginning - * of lines starting with a period, and ensures you cannot read past the end of the message. - *

- * Note: versions since 3.0 extend BufferedReader rather than Reader, - * and no longer change the CRLF into the local EOL. Also only DOT CR LF - * acts as EOF. - */ -public final class DotTerminatedMessageReader extends BufferedReader -{ - private static final char LF = '\n'; - private static final char CR = '\r'; - private static final int DOT = '.'; - - private boolean atBeginning; - private boolean eof; - private boolean seenCR; // was last character CR? - - /** - * Creates a DotTerminatedMessageReader that wraps an existing Reader - * input source. - * @param reader The Reader input source containing the message. - */ - public DotTerminatedMessageReader(final Reader reader) - { - super(reader); - // Assumes input is at start of message - atBeginning = true; - eof = false; - } - - /** - * Reads and returns the next character in the message. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream to decode - * the message properly (removing doubled dots and so on). All of - * this is transparent to the programmer and is only mentioned for - * completeness. - * @return The next character in the message. Returns -1 if the end of the - * message has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read() throws IOException { - synchronized (lock) { - if (eof) { - return -1; // Don't allow read past EOF - } - int chint = super.read(); - if (chint == -1) { // True EOF - eof = true; - return -1; - } - if (atBeginning) { - atBeginning = false; - if (chint == DOT) { // Have DOT - mark(2); // need to check for CR LF or DOT - chint = super.read(); - if (chint == -1) { // Should not happen - // new Throwable("Trailing DOT").printStackTrace(); - eof = true; - return DOT; // return the trailing DOT - } - if (chint == DOT) { // Have DOT DOT - // no need to reset as we want to lose the first DOT - return chint; // i.e. DOT - } - if (chint == CR) { // Have DOT CR - chint = super.read(); - if (chint == -1) { // Still only DOT CR - should not happen - //new Throwable("Trailing DOT CR").printStackTrace(); - reset(); // So CR is picked up next time - return DOT; // return the trailing DOT - } - if (chint == LF) { // DOT CR LF - atBeginning = true; - eof = true; - // Do we need to clear the mark somehow? - return -1; - } - } - // Should not happen - lone DOT at beginning - //new Throwable("Lone DOT followed by "+(char)chint).printStackTrace(); - reset(); - return DOT; - } // have DOT - } // atBeginning - - // Handle CRLF in normal flow - if (seenCR) { - seenCR = false; - if (chint == LF) { - atBeginning = true; - } - } - if (chint == CR) { - seenCR = true; - } - return chint; - } - } - - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. - * @param buffer The character array in which to store the characters. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(final char[] buffer) throws IOException - { - return read(buffer, 0, buffer.length); - } - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * @param buffer The character array in which to store the characters. - * @param offset The offset into the array at which to start storing - * characters. - * @param length The number of characters to read. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(final char[] buffer, int offset, int length) throws IOException - { - if (length < 1) - { - return 0; - } - int ch; - synchronized (lock) - { - if ((ch = read()) == -1) - { - return -1; - } - - final int off = offset; - - do - { - buffer[offset++] = (char) ch; - } - while (--length > 0 && (ch = read()) != -1); - - return offset - off; - } - } - - /** - * Closes the message for reading. This doesn't actually close the - * underlying stream. The underlying stream may still be used for - * communicating with the server and therefore is not closed. - *

- * If the end of the message has not yet been reached, this method - * will read the remainder of the message until it reaches the end, - * so that the underlying stream may continue to be used properly - * for communicating with the server. If you do not fully read - * a message, you MUST close it, otherwise your program will likely - * hang or behave improperly. - * @throws IOException If an error occurs while reading the - * underlying stream. - */ - @Override - public void close() throws IOException - { - synchronized (lock) - { - if (!eof) - { - while (read() != -1) - { - // read to EOF - } - } - eof = true; - atBeginning = false; - } - } - - /** - * Read a line of text. - * A line is considered to be terminated by carriage return followed immediately by a linefeed. - * This contrasts with BufferedReader which also allows other combinations. - * @since 3.0 - */ - @Override - public String readLine() throws IOException { - final StringBuilder sb = new StringBuilder(); - int intch; - synchronized(lock) { // make thread-safe (hopefully!) - while((intch = read()) != -1) - { - if (intch == LF && atBeginning) { - return sb.substring(0, sb.length()-1); - } - sb.append((char) intch); - } - } - final String string = sb.toString(); - if (string.isEmpty()) { // immediate EOF - return null; - } - // Should not happen - EOF without CRLF - //new Throwable(string).printStackTrace(); - return string; - } -} diff --git a/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java b/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java deleted file mode 100644 index 4eb20234..00000000 --- a/src/org/apache/commons/net/io/DotTerminatedMessageWriter.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.Writer; - -/** - * DotTerminatedMessageWriter is a class used to write messages to a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles the doubling of line-starting periods, - * converts single linefeeds to NETASCII newlines, and on closing - * will send the final message terminator dot and NETASCII newline - * sequence. - * - * - */ - -public final class DotTerminatedMessageWriter extends Writer -{ - private static final int NOTHING_SPECIAL_STATE = 0; - private static final int LAST_WAS_CR_STATE = 1; - private static final int LAST_WAS_NL_STATE = 2; - - private int state; - private Writer output; - - - /** - * Creates a DotTerminatedMessageWriter that wraps an existing Writer - * output destination. - * - * @param output The Writer output destination to write the message. - */ - public DotTerminatedMessageWriter(final Writer output) - { - super(output); - this.output = output; - this.state = NOTHING_SPECIAL_STATE; - } - - - /** - * Writes a character to the output. Note that a call to this method - * may result in multiple writes to the underling Writer in order to - * convert naked linefeeds to NETASCII line separators and to double - * line-leading periods. This is transparent to the programmer and - * is only mentioned for completeness. - * - * @param ch The character to write. - * @throws IOException If an error occurs while writing to the - * underlying output. - */ - @Override - public void write(final int ch) throws IOException - { - synchronized (lock) - { - switch (ch) - { - case '\r': - state = LAST_WAS_CR_STATE; - output.write('\r'); - return ; - case '\n': - if (state != LAST_WAS_CR_STATE) { - output.write('\r'); - } - output.write('\n'); - state = LAST_WAS_NL_STATE; - return ; - case '.': - // Double the dot at the beginning of a line - if (state == LAST_WAS_NL_STATE) { - output.write('.'); - } - //$FALL-THROUGH$ - default: - state = NOTHING_SPECIAL_STATE; - output.write(ch); - } - } - } - - - /** - * Writes a number of characters from a character array to the output - * starting from a given offset. - * - * @param buffer The character array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of characters to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - */ - @Override - public void write(final char[] buffer, int offset, int length) throws IOException - { - synchronized (lock) - { - while (length-- > 0) { - write(buffer[offset++]); - } - } - } - - - /** - * Writes a character array to the output. - * - * @param buffer The character array to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - */ - @Override - public void write(final char[] buffer) throws IOException - { - write(buffer, 0, buffer.length); - } - - - /** - * Writes a String to the output. - * - * @param string The String to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - */ - @Override - public void write(final String string) throws IOException - { - write(string.toCharArray()); - } - - - /** - * Writes part of a String to the output starting from a given offset. - * - * @param string The String to write. - * @param offset The offset into the String at which to start copying data. - * @param length The number of characters to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - */ - @Override - public void write(final String string, final int offset, final int length) throws IOException - { - write(string.toCharArray(), offset, length); - } - - - /** - * Flushes the underlying output, writing all buffered output. - * - * @throws IOException If an error occurs while writing to the underlying - * output. - */ - @Override - public void flush() throws IOException - { - synchronized (lock) - { - output.flush(); - } - } - - - /** - * Flushes the underlying output, writing all buffered output, but doesn't - * actually close the underlying stream. The underlying stream may still - * be used for communicating with the server and therefore is not closed. - * - * @throws IOException If an error occurs while writing to the underlying - * output or closing the Writer. - */ - @Override - public void close() throws IOException - { - synchronized (lock) - { - if (output == null) { - return ; - } - - if (state == LAST_WAS_CR_STATE) { - output.write('\n'); - } else if (state != LAST_WAS_NL_STATE) { - output.write("\r\n"); - } - - output.write(".\r\n"); - - output.flush(); - output = null; - } - } - -} diff --git a/src/org/apache/commons/net/io/FromNetASCIIInputStream.java b/src/org/apache/commons/net/io/FromNetASCIIInputStream.java deleted file mode 100644 index 2474b784..00000000 --- a/src/org/apache/commons/net/io/FromNetASCIIInputStream.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.nio.charset.StandardCharsets; - -/** - * This class wraps an input stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - * - * - */ - -public final class FromNetASCIIInputStream extends PushbackInputStream -{ - static final boolean _noConversionRequired; - static final String _lineSeparator; - static final byte[] _lineSeparatorBytes; - - static { - _lineSeparator = System.getProperty("line.separator"); - _noConversionRequired = _lineSeparator.equals("\r\n"); - _lineSeparatorBytes = _lineSeparator.getBytes(StandardCharsets.US_ASCII); - } - - private int length; - - /** - * Returns true if the NetASCII line separator differs from the system - * line separator, false if they are the same. This method is useful - * to determine whether or not you need to instantiate a - * FromNetASCIIInputStream object. - * - * @return True if the NETASCII line separator differs from the local - * system line separator, false if they are the same. - */ - public static boolean isConversionRequired() - { - return !_noConversionRequired; - } - - /** - * Creates a FromNetASCIIInputStream instance that wraps an existing - * InputStream. - * @param input the stream to wrap - */ - public FromNetASCIIInputStream(final InputStream input) - { - super(input, _lineSeparatorBytes.length + 1); - } - - - private int readInt() throws IOException - { - int ch; - - ch = super.read(); - - if (ch == '\r') - { - ch = super.read(); - if (ch == '\n') - { - unread(_lineSeparatorBytes); - ch = super.read(); - // This is a kluge for read(byte[], ...) to read the right amount - --length; - } - else - { - if (ch != -1) { - unread(ch); - } - return '\r'; - } - } - - return ch; - } - - - /** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream in order - * to convert NETASCII line separators to the local line separator format. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read() throws IOException - { - if (_noConversionRequired) { - return super.read(); - } - - return readInt(); - } - - - /** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - * - * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(final byte buffer[]) throws IOException - { - return read(buffer, 0, buffer.length); - } - - - /** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * - * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read(final byte buffer[], int offset, final int length) throws IOException - { - if (_noConversionRequired) { - return super.read(buffer, offset, length); - } - - if (length < 1) { - return 0; - } - - int ch; - final int off; - - ch = available(); - - this.length = length > ch ? ch : length; - - // If nothing is available, block to read only one character - if (this.length < 1) { - this.length = 1; - } - - - if ((ch = readInt()) == -1) { - return -1; - } - - off = offset; - - do - { - buffer[offset++] = (byte)ch; - } - while (--this.length > 0 && (ch = readInt()) != -1); - - - return offset - off; - } - - - // PushbackInputStream in JDK 1.1.3 returns the wrong thing - // TODO - can we delete this override now? - /** - * Returns the number of bytes that can be read without blocking EXCEPT - * when newline conversions have to be made somewhere within the - * available block of bytes. In other words, you really should not - * rely on the value returned by this method if you are trying to avoid - * blocking. - */ - @Override - public int available() throws IOException - { - if (in == null) { - throw new IOException("Stream closed"); - } - return buf.length - pos + in.available(); - } - -} diff --git a/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java b/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java deleted file mode 100644 index 896bf509..00000000 --- a/src/org/apache/commons/net/io/FromNetASCIIOutputStream.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * This class wraps an output stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - *

- * Because of the translation process, a call to flush() will - * not flush the last byte written if that byte was a carriage - * return. A call to {@link #close close() }, however, will - * flush the carriage return. - * - * - */ - -public final class FromNetASCIIOutputStream extends FilterOutputStream -{ - private boolean lastWasCR; - - /** - * Creates a FromNetASCIIOutputStream instance that wraps an existing - * OutputStream. - * - * @param output The OutputStream to wrap. - */ - public FromNetASCIIOutputStream(final OutputStream output) - { - super(output); - lastWasCR = false; - } - - - private void writeInt(final int ch) throws IOException - { - switch (ch) - { - case '\r': - lastWasCR = true; - // Don't write anything. We need to see if next one is linefeed - break; - case '\n': - if (lastWasCR) - { - out.write(FromNetASCIIInputStream._lineSeparatorBytes); - lastWasCR = false; - break; - } - lastWasCR = false; - out.write('\n'); - break; - default: - if (lastWasCR) - { - out.write('\r'); - lastWasCR = false; - } - out.write(ch); - break; - } - } - - - /** - * Writes a byte to the stream. Note that a call to this method - * might not actually write a byte to the underlying stream until a - * subsequent character is written, from which it can be determined if - * a NETASCII line separator was encountered. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @param ch The byte to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final int ch) - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - out.write(ch); - return ; - } - - writeInt(ch); - } - - - /** - * Writes a byte array to the stream. - * - * @param buffer The byte array to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final byte buffer[]) - throws IOException - { - write(buffer, 0, buffer.length); - } - - - /** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final byte buffer[], int offset, int length) - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - // FilterOutputStream method is very slow. - //super.write(buffer, offset, length); - out.write(buffer, offset, length); - return ; - } - - while (length-- > 0) { - writeInt(buffer[offset++]); - } - } - - - /** - * Closes the stream, writing all pending data. - * - * @throws IOException If an error occurs while closing the stream. - */ - @Override - public synchronized void close() - throws IOException - { - if (FromNetASCIIInputStream._noConversionRequired) - { - super.close(); - return ; - } - - if (lastWasCR) { - out.write('\r'); - } - super.close(); - } -} diff --git a/src/org/apache/commons/net/io/SocketInputStream.java b/src/org/apache/commons/net/io/SocketInputStream.java deleted file mode 100644 index 5155be4e..00000000 --- a/src/org/apache/commons/net/io/SocketInputStream.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; - -/** - * This class wraps an input stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - * - * - * @see SocketOutputStream - */ - -public class SocketInputStream extends FilterInputStream -{ - private final Socket socket; - - /** - * Creates a SocketInputStream instance wrapping an input stream and - * storing a reference to a socket that should be closed on closing - * the stream. - * - * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - */ - public SocketInputStream(final Socket socket, final InputStream stream) - { - super(stream); - this.socket = socket; - } - - /** - * Closes the stream and immediately afterward closes the referenced - * socket. - * - * @throws IOException If there is an error in closing the stream - * or socket. - */ - @Override - public void close() throws IOException - { - super.close(); - socket.close(); - } -} diff --git a/src/org/apache/commons/net/io/SocketOutputStream.java b/src/org/apache/commons/net/io/SocketOutputStream.java deleted file mode 100644 index 909ea772..00000000 --- a/src/org/apache/commons/net/io/SocketOutputStream.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.Socket; - -/** - * This class wraps an output stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - * - * - * @see SocketInputStream - */ - -public class SocketOutputStream extends FilterOutputStream -{ - private final Socket socket; - - /** - * Creates a SocketOutputStream instance wrapping an output stream and - * storing a reference to a socket that should be closed on closing - * the stream. - * - * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - */ - public SocketOutputStream(final Socket socket, final OutputStream stream) - { - super(stream); - this.socket = socket; - } - - - /** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. This method bypasses the equivalent method in - * FilterOutputStream because the FilterOutputStream implementation is - * very inefficient. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public void write(final byte buffer[], final int offset, final int length) throws IOException - { - out.write(buffer, offset, length); - } - - - /** - * Closes the stream and immediately afterward closes the referenced - * socket. - * - * @throws IOException If there is an error in closing the stream - * or socket. - */ - @Override - public void close() throws IOException - { - super.close(); - socket.close(); - } -} diff --git a/src/org/apache/commons/net/io/ToNetASCIIInputStream.java b/src/org/apache/commons/net/io/ToNetASCIIInputStream.java deleted file mode 100644 index 93986978..00000000 --- a/src/org/apache/commons/net/io/ToNetASCIIInputStream.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * This class wraps an input stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - * - * - */ - -public final class ToNetASCIIInputStream extends FilterInputStream -{ - private static final int NOTHING_SPECIAL = 0; - private static final int LAST_WAS_CR = 1; - private static final int LAST_WAS_NL = 2; - private int status; - - /** - * Creates a ToNetASCIIInputStream instance that wraps an existing - * InputStream. - * - * @param input The InputStream to wrap. - */ - public ToNetASCIIInputStream(final InputStream input) - { - super(input); - status = NOTHING_SPECIAL; - } - - - /** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. - * - * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read() throws IOException - { - final int ch; - - if (status == LAST_WAS_NL) - { - status = NOTHING_SPECIAL; - return '\n'; - } - - ch = in.read(); - - switch (ch) - { - case '\r': - status = LAST_WAS_CR; - return '\r'; - case '\n': - if (status != LAST_WAS_CR) - { - status = LAST_WAS_NL; - return '\r'; - } - //$FALL-THROUGH$ - default: - status = NOTHING_SPECIAL; - return ch; - } - // statement not reached - //return ch; - } - - - /** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - * - * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override - public int read(final byte[] buffer) throws IOException - { - return read(buffer, 0, buffer.length); - } - - - /** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * - * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override - public int read(final byte[] buffer, int offset, int length) throws IOException - { - int ch; - final int off; - - if (length < 1) { - return 0; - } - - ch = available(); - - if (length > ch) { - length = ch; - } - - // If nothing is available, block to read only one character - if (length < 1) { - length = 1; - } - - if ((ch = read()) == -1) { - return -1; - } - - off = offset; - - do - { - buffer[offset++] = (byte)ch; - } - while (--length > 0 && (ch = read()) != -1); - - return offset - off; - } - - /** Returns false. Mark is not supported. */ - @Override - public boolean markSupported() - { - return false; - } - - @Override - public int available() throws IOException - { - final int result; - - result = in.available(); - - if (status == LAST_WAS_NL) { - return result + 1; - } - - return result; - } -} diff --git a/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java b/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java deleted file mode 100644 index e99aaccf..00000000 --- a/src/org/apache/commons/net/io/ToNetASCIIOutputStream.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * This class wraps an output stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - * - * - */ - -public final class ToNetASCIIOutputStream extends FilterOutputStream -{ - private boolean lastWasCR; - - /** - * Creates a ToNetASCIIOutputStream instance that wraps an existing - * OutputStream. - * - * @param output The OutputStream to wrap. - */ - public ToNetASCIIOutputStream(final OutputStream output) - { - super(output); - lastWasCR = false; - } - - - /** - * Writes a byte to the stream. Note that a call to this method - * may result in multiple writes to the underlying input stream in order - * to convert naked newlines to NETASCII line separators. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @param ch The byte to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final int ch) - throws IOException - { - switch (ch) - { - case '\r': - lastWasCR = true; - out.write('\r'); - return ; - case '\n': - if (!lastWasCR) { - out.write('\r'); - } - //$FALL-THROUGH$ - default: - lastWasCR = false; - out.write(ch); - } - } - - - /** - * Writes a byte array to the stream. - * - * @param buffer The byte array to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final byte buffer[]) - throws IOException - { - write(buffer, 0, buffer.length); - } - - - /** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - */ - @Override - public synchronized void write(final byte buffer[], int offset, int length) - throws IOException - { - while (length-- > 0) { - write(buffer[offset++]); - } - } - -} diff --git a/src/org/apache/commons/net/io/Util.java b/src/org/apache/commons/net/io/Util.java deleted file mode 100644 index 4a593275..00000000 --- a/src/org/apache/commons/net/io/Util.java +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.io; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.net.Socket; - -/** - * The Util class cannot be instantiated and stores short static convenience - * methods that are often quite useful. - * - * - * @see CopyStreamException - * @see CopyStreamListener - * @see CopyStreamAdapter - */ - -public final class Util -{ - /** - * The default buffer size ({@value}) used by - * {@link #copyStream copyStream } and {@link #copyReader copyReader} - * and by the copyReader/copyStream methods if a zero or negative buffer size is supplied. - */ - public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; - - // Cannot be instantiated - private Util() - { } - - - /** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @param flush Whether to flush the output stream after every - * write. This is necessary for interactive sessions that rely on - * buffered streams. If you don't flush, the data will stay in - * the stream buffer. - * @return number of bytes read/written - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - */ - public static long copyStream(final InputStream source, final OutputStream dest, - final int bufferSize, final long streamSize, - final CopyStreamListener listener, - final boolean flush) - throws CopyStreamException - { - int numBytes; - long total = 0; - final byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; - - try - { - while ((numBytes = source.read(buffer)) != -1) - { - // Technically, some read(byte[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - - if (numBytes == 0) - { - final int singleByte = source.read(); - if (singleByte < 0) { - break; - } - dest.write(singleByte); - if(flush) { - dest.flush(); - } - ++total; - if (listener != null) { - listener.bytesTransferred(total, 1, streamSize); - } - continue; - } - - dest.write(buffer, 0, numBytes); - if(flush) { - dest.flush(); - } - total += numBytes; - if (listener != null) { - listener.bytesTransferred(total, numBytes, streamSize); - } - } - } - catch (final IOException e) - { - throw new CopyStreamException("IOException caught while copying.", - total, e); - } - - return total; - } - - - /** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @return number of bytes read/written - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - */ - public static long copyStream(final InputStream source, final OutputStream dest, - final int bufferSize, final long streamSize, - final CopyStreamListener listener) - throws CopyStreamException - { - return copyStream(source, dest, bufferSize, streamSize, listener, - true); - } - - - /** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size. The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @return The number of bytes read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - */ - public static long copyStream(final InputStream source, final OutputStream dest, - final int bufferSize) - throws CopyStreamException - { - return copyStream(source, dest, bufferSize, - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - - /** - * Same as copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - * @param source where to copy from - * @param dest where to copy to - * @return number of bytes copied - * @throws CopyStreamException on error - */ - public static long copyStream(final InputStream source, final OutputStream dest) - throws CopyStreamException - { - return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - - - /** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - * - * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of characters in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @return The number of characters read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - */ - public static long copyReader(final Reader source, final Writer dest, - final int bufferSize, final long streamSize, - final CopyStreamListener listener) - throws CopyStreamException - { - int numChars; - long total = 0; - final char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; - - try - { - while ((numChars = source.read(buffer)) != -1) - { - // Technically, some read(char[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - if (numChars == 0) - { - final int singleChar = source.read(); - if (singleChar < 0) { - break; - } - dest.write(singleChar); - dest.flush(); - ++total; - if (listener != null) { - listener.bytesTransferred(total, 1, streamSize); - } - continue; - } - - dest.write(buffer, 0, numChars); - dest.flush(); - total += numChars; - if (listener != null) { - listener.bytesTransferred(total, numChars, streamSize); - } - } - } - catch (final IOException e) - { - throw new CopyStreamException("IOException caught while copying.", - total, e); - } - - return total; - } - - - /** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size. The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - * - * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @return The number of characters read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - */ - public static long copyReader(final Reader source, final Writer dest, - final int bufferSize) - throws CopyStreamException - { - return copyReader(source, dest, bufferSize, - CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - - /** - * Same as copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - * @param source where to copy from - * @param dest where to copy to - * @return number of bytes copied - * @throws CopyStreamException on error - */ - public static long copyReader(final Reader source, final Writer dest) - throws CopyStreamException - { - return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - - /** - * Closes the object quietly, catching rather than throwing IOException. - * Intended for use from finally blocks. - * - * @param closeable the object to close, may be {@code null} - * @since 3.0 - */ - public static void closeQuietly(final Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (final IOException e) { - // Ignored - } - } - } - - /** - * Closes the socket quietly, catching rather than throwing IOException. - * Intended for use from finally blocks. - * - * @param socket the socket to close, may be {@code null} - * @since 3.0 - */ - public static void closeQuietly(final Socket socket) { - if (socket != null) { - try { - socket.close(); - } catch (final IOException e) { - // Ignored - } - } - } -} diff --git a/src/org/apache/commons/net/io/package-info.java b/src/org/apache/commons/net/io/package-info.java deleted file mode 100644 index 50e478bb..00000000 --- a/src/org/apache/commons/net/io/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Utility classes for IO support. - */ -package org.apache.commons.net.io; \ No newline at end of file diff --git a/src/org/apache/commons/net/package-info.java b/src/org/apache/commons/net/package-info.java deleted file mode 100644 index f9562567..00000000 --- a/src/org/apache/commons/net/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Common socket classes and protocol command utility classes - */ -package org.apache.commons.net; \ No newline at end of file diff --git a/src/org/apache/commons/net/pop3/ExtendedPOP3Client.java b/src/org/apache/commons/net/pop3/ExtendedPOP3Client.java deleted file mode 100644 index 2c380d20..00000000 --- a/src/org/apache/commons/net/pop3/ExtendedPOP3Client.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.net.util.Base64; - - -/** - * A POP3 Cilent class with protocol and authentication extensions support - * (RFC2449 and RFC2195). - * @see POP3Client - * @since 3.0 - */ -public class ExtendedPOP3Client extends POP3SClient -{ - /** - * The default ExtendedPOP3Client constructor. - * Creates a new Extended POP3 Client. - * @throws NoSuchAlgorithmException on error - */ - public ExtendedPOP3Client() throws NoSuchAlgorithmException - { - } - - /** - * Authenticate to the POP3 server by sending the AUTH command with the - * selected mechanism, using the given username and the given password. - *

- * @param method the {@link AUTH_METHOD} to use - * @param username the user name - * @param password the password - * @return True if successfully completed, false if not. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws NoSuchAlgorithmException If the CRAM hash algorithm - * cannot be instantiated by the Java runtime system. - * @throws InvalidKeyException If the CRAM hash algorithm - * failed to use the given password. - * @throws InvalidKeySpecException If the CRAM hash algorithm - * failed to use the given password. - */ - public boolean auth(final AUTH_METHOD method, - final String username, final String password) - throws IOException, NoSuchAlgorithmException, - InvalidKeyException, InvalidKeySpecException - { - if (sendCommand(POP3Command.AUTH, method.getAuthName()) - != POP3Reply.OK_INT) { - return false; - } - - switch(method) { - case PLAIN: - // the server sends an empty response ("+ "), so we don't have to read it. - return sendCommand( - new String( - Base64.encodeBase64(("\000" + username + "\000" + password).getBytes(getCharset())), - getCharset()) - ) == POP3Reply.OK; - case CRAM_MD5: - // get the CRAM challenge - final byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(2).trim()); - // get the Mac instance - final Mac hmac_md5 = Mac.getInstance("HmacMD5"); - hmac_md5.init(new SecretKeySpec(password.getBytes(getCharset()), "HmacMD5")); - // compute the result: - final byte[] hmacResult = convertToHexString(hmac_md5.doFinal(serverChallenge)).getBytes(getCharset()); - // join the byte arrays to form the reply - final byte[] usernameBytes = username.getBytes(getCharset()); - final byte[] toEncode = new byte[usernameBytes.length + 1 /* the space */ + hmacResult.length]; - System.arraycopy(usernameBytes, 0, toEncode, 0, usernameBytes.length); - toEncode[usernameBytes.length] = ' '; - System.arraycopy(hmacResult, 0, toEncode, usernameBytes.length + 1, hmacResult.length); - // send the reply and read the server code: - return sendCommand(Base64.encodeBase64StringUnChunked(toEncode)) == POP3Reply.OK; - default: - return false; - } - } - - /** - * Converts the given byte array to a String containing the hex values of the bytes. - * For example, the byte 'A' will be converted to '41', because this is the ASCII code - * (and the byte value) of the capital letter 'A'. - * @param a The byte array to convert. - * @return The resulting String of hex codes. - */ - private String convertToHexString(final byte[] a) - { - final StringBuilder result = new StringBuilder(a.length*2); - for (final byte element : a) - { - if ( (element & 0x0FF) <= 15 ) { - result.append("0"); - } - result.append(Integer.toHexString(element & 0x0FF)); - } - return result.toString(); - } - - /** - * The enumeration of currently-supported authentication methods. - */ - public enum AUTH_METHOD - { - /** The standarised (RFC4616) PLAIN method, which sends the password unencrypted (insecure). */ - PLAIN("PLAIN"), - - /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure). */ - CRAM_MD5("CRAM-MD5"); - - private final String methodName; - - AUTH_METHOD(final String methodName){ - this.methodName = methodName; - } - /** - * Gets the name of the given authentication method suitable for the server. - * @return The name of the given authentication method suitable for the server. - */ - public final String getAuthName() - { - return this.methodName; - } - } -} diff --git a/src/org/apache/commons/net/pop3/POP3.java b/src/org/apache/commons/net/pop3/POP3.java deleted file mode 100644 index 83a031e9..00000000 --- a/src/org/apache/commons/net/pop3/POP3.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.NetConstants; - -/** - * The POP3 class is not meant to be used by itself and is provided - * only so that you may easily implement your own POP3 client if - * you so desire. If you have no need to perform your own implementation, - * you should use {@link org.apache.commons.net.pop3.POP3Client}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * - * @see POP3Client - * @see org.apache.commons.net.MalformedServerReplyException - */ - -public class POP3 extends SocketClient -{ - /** The default POP3 port. Set to 110 according to RFC 1288. */ - public static final int DEFAULT_PORT = 110; - /** - * A constant representing the state where the client is not yet connected - * to a POP3 server. - */ - public static final int DISCONNECTED_STATE = -1; - /** A constant representing the POP3 authorization state. */ - public static final int AUTHORIZATION_STATE = 0; - /** A constant representing the POP3 transaction state. */ - public static final int TRANSACTION_STATE = 1; - /** A constant representing the POP3 update state. */ - public static final int UPDATE_STATE = 2; - - static final String OK = "+OK"; - // The reply indicating intermediate response to a command. - static final String OK_INT = "+ "; - static final String ERROR = "-ERR"; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1; - - private int popState; - BufferedWriter writer; - - BufferedReader reader; - int replyCode; - String lastReplyLine; - List replyLines; - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and the firing of ProtocolCommandEvents. - */ - protected ProtocolCommandSupport _commandSupport_; - - /** - * The default POP3Client constructor. Initializes the state - * to DISCONNECTED_STATE. - */ - public POP3() - { - setDefaultPort(DEFAULT_PORT); - popState = DISCONNECTED_STATE; - reader = null; - writer = null; - replyLines = new ArrayList<>(); - _commandSupport_ = new ProtocolCommandSupport(this); - } - - private void getReply() throws IOException - { - final String line; - - replyLines.clear(); - line = reader.readLine(); - - if (line == null) { - throw new EOFException("Connection closed without indication."); - } - - if (line.startsWith(OK)) { - replyCode = POP3Reply.OK; - } else if (line.startsWith(ERROR)) { - replyCode = POP3Reply.ERROR; - } else if (line.startsWith(OK_INT)) { - replyCode = POP3Reply.OK_INT; - } else { - throw new - MalformedServerReplyException( - "Received invalid POP3 protocol response from server." + line); - } - - replyLines.add(line); - lastReplyLine = line; - - fireReplyReceived(replyCode, getReplyString()); - } - - - /** - * Performs connection initialization and sets state to - * AUTHORIZATION_STATE . - */ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - reader = - new CRLFLineReader(new InputStreamReader(_input_, - DEFAULT_ENCODING)); - writer = - new BufferedWriter(new OutputStreamWriter(_output_, - DEFAULT_ENCODING)); - getReply(); - setState(AUTHORIZATION_STATE); - } - - - /** - * Set the internal POP3 state. - * @param state the new state. This must be one of the _STATE constants. - */ - public void setState(final int state) - { - popState = state; - } - - - /** - * Returns the current POP3 client state. - * - * @return The current POP3 client state. - */ - public int getState() - { - return popState; - } - - - /** - * Retrieves the additional lines of a multi-line server reply. - * @throws IOException on error - */ - public void getAdditionalReply() throws IOException - { - String line; - - line = reader.readLine(); - while (line != null) - { - replyLines.add(line); - if (line.equals(".")) { - break; - } - line = reader.readLine(); - } - } - - - /** - * Disconnects the client from the server, and sets the state to - * DISCONNECTED_STATE . The reply text information - * from the last issued command is voided to allow garbage collection - * of the memory used to store that information. - * - * @throws IOException If there is an error in disconnecting. - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - reader = null; - writer = null; - lastReplyLine = null; - replyLines.clear(); - setState(DISCONNECTED_STATE); - } - - - /** - * Sends a command an arguments to the server and returns the reply code. - * - * @param command The POP3 command to send. - * @param args The command arguments. - * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT). - * @throws IOException on error - */ - public int sendCommand(final String command, final String args) throws IOException - { - if (writer == null) { - throw new IllegalStateException("Socket is not connected"); - } - final StringBuilder __commandBuffer = new StringBuilder(); - __commandBuffer.append(command); - - if (args != null) - { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - - final String message = __commandBuffer.toString(); - writer.write(message); - writer.flush(); - - fireCommandSent(command, message); - - getReply(); - return replyCode; - } - - /** - * Sends a command with no arguments to the server and returns the - * reply code. - * - * @param command The POP3 command to send. - * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT). - * @throws IOException on error - */ - public int sendCommand(final String command) throws IOException - { - return sendCommand(command, null); - } - - /** - * Sends a command an arguments to the server and returns the reply code. - * - * @param command The POP3 command to send - * (one of the POP3Command constants). - * @param args The command arguments. - * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT). - * @throws IOException on error - */ - public int sendCommand(final int command, final String args) throws IOException - { - return sendCommand(POP3Command.commands[command], args); - } - - /** - * Sends a command with no arguments to the server and returns the - * reply code. - * - * @param command The POP3 command to send - * (one of the POP3Command constants). - * @return The server reply code (either POP3Reply.OK, POP3Reply.ERROR or POP3Reply.OK_INT). - * @throws IOException on error - */ - public int sendCommand(final int command) throws IOException - { - return sendCommand(POP3Command.commands[command], null); - } - - - /** - * Returns an array of lines received as a reply to the last command - * sent to the server. The lines have end of lines truncated. If - * the reply is a single line, but its format ndicates it should be - * a multiline reply, then you must call - * {@link #getAdditionalReply getAdditionalReply() } to - * fetch the rest of the reply, and then call getReplyStrings - * again. You only have to worry about this if you are implementing - * your own client using the {@link #sendCommand sendCommand } methods. - * - * @return The last server response. - */ - public String[] getReplyStrings() - { - return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - - /** - * Returns the reply to the last command sent to the server. - * The value is a single string containing all the reply lines including - * newlines. If the reply is a single line, but its format ndicates it - * should be a multiline reply, then you must call - * {@link #getAdditionalReply getAdditionalReply() } to - * fetch the rest of the reply, and then call getReplyString - * again. You only have to worry about this if you are implementing - * your own client using the {@link #sendCommand sendCommand } methods. - * - * @return The last server response. - */ - public String getReplyString() - { - final StringBuilder buffer = new StringBuilder(256); - - for (final String entry : replyLines) - { - buffer.append(entry); - buffer.append(SocketClient.NETASCII_EOL); - } - - return buffer.toString(); - } - - /** - * Removes a ProtocolCommandListener. - * - * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to - * the correct method {@link SocketClient#removeProtocolCommandListener} - * @param listener The ProtocolCommandListener to remove - */ - public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener){ - removeProtocolCommandListener(listener); - } - - /** - * Provide command support to super-class - */ - @Override - protected ProtocolCommandSupport getCommandSupport() { - return _commandSupport_; - } -} - diff --git a/src/org/apache/commons/net/pop3/POP3Client.java b/src/org/apache/commons/net/pop3/POP3Client.java deleted file mode 100644 index ec398ddc..00000000 --- a/src/org/apache/commons/net/pop3/POP3Client.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.IOException; -import java.io.Reader; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ListIterator; -import java.util.StringTokenizer; - -import org.apache.commons.net.io.DotTerminatedMessageReader; - -/** - * The POP3Client class implements the client side of the Internet POP3 - * Protocol defined in RFC 1939. All commands are supported, including - * the APOP command which requires MD5 encryption. See RFC 1939 for - * more details on the POP3 protocol. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * - * @see POP3MessageInfo - * @see org.apache.commons.net.io.DotTerminatedMessageReader - * @see org.apache.commons.net.MalformedServerReplyException - */ - -public class POP3Client extends POP3 -{ - - private static POP3MessageInfo parseStatus(final String line) - { - int num, size; - final StringTokenizer tokenizer; - - tokenizer = new StringTokenizer(line); - - if (!tokenizer.hasMoreElements()) { - return null; - } - - num = size = 0; - - try - { - num = Integer.parseInt(tokenizer.nextToken()); - - if (!tokenizer.hasMoreElements()) { - return null; - } - - size = Integer.parseInt(tokenizer.nextToken()); - } - catch (final NumberFormatException e) - { - return null; - } - - return new POP3MessageInfo(num, size); - } - - private static POP3MessageInfo parseUID(String line) - { - int num; - final StringTokenizer tokenizer; - - tokenizer = new StringTokenizer(line); - - if (!tokenizer.hasMoreElements()) { - return null; - } - - num = 0; - - try - { - num = Integer.parseInt(tokenizer.nextToken()); - - if (!tokenizer.hasMoreElements()) { - return null; - } - - line = tokenizer.nextToken(); - } - catch (final NumberFormatException e) - { - return null; - } - - return new POP3MessageInfo(num, line); - } - - /** - * Send a CAPA command to the POP3 server. - * @return True if the command was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * sending the CAPA command. - * @since 3.1 (was previously in ExtendedPOP3Client) - */ - public boolean capa() throws IOException - { - if (sendCommand(POP3Command.CAPA) == POP3Reply.OK) { - getAdditionalReply(); - return true; - } - return false; - - } - - /** - * Login to the POP3 server with the given username and password. You - * must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before attempting to login. A login attempt is only valid if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } - * . After logging in, the client enters the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - * - * @param username The account name being logged in to. - * @param password The plain text password of the account. - * @return True if the login attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * logging in. - */ - public boolean login(final String username, final String password) throws IOException - { - if (getState() != AUTHORIZATION_STATE) { - return false; - } - - if (sendCommand(POP3Command.USER, username) != POP3Reply.OK) { - return false; - } - - if (sendCommand(POP3Command.PASS, password) != POP3Reply.OK) { - return false; - } - - setState(TRANSACTION_STATE); - - return true; - } - - - /** - * Login to the POP3 server with the given username and authentication - * information. Use this method when connecting to a server requiring - * authentication using the APOP command. Because the timestamp - * produced in the greeting banner varies from server to server, it is - * not possible to consistently extract the information. Therefore, - * after connecting to the server, you must call - * {@link org.apache.commons.net.pop3.POP3#getReplyString getReplyString } - * and parse out the timestamp information yourself. - *

- * You must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before attempting to login. A login attempt is only valid if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#AUTHORIZATION_STATE AUTHORIZATION_STATE } - * . After logging in, the client enters the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . After connecting, you must parse out the - * server specific information to use as a timestamp, and pass that - * information to this method. The secret is a shared secret known - * to you and the server. See RFC 1939 for more details regarding - * the APOP command. - * - * @param username The account name being logged in to. - * @param timestamp The timestamp string to combine with the secret. - * @param secret The shared secret which produces the MD5 digest when - * combined with the timestamp. - * @return True if the login attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * logging in. - * @throws NoSuchAlgorithmException If the MD5 encryption algorithm - * cannot be instantiated by the Java runtime system. - */ - public boolean login(final String username, String timestamp, final String secret) - throws IOException, NoSuchAlgorithmException - { - int i; - final byte[] digest; - final StringBuilder buffer; - final StringBuilder digestBuffer; - final MessageDigest md5; - - if (getState() != AUTHORIZATION_STATE) { - return false; - } - - md5 = MessageDigest.getInstance("MD5"); - timestamp += secret; - digest = md5.digest(timestamp.getBytes(getCharset())); - digestBuffer = new StringBuilder(128); - - for (i = 0; i < digest.length; i++) { - final int digit = digest[i] & 0xff; - if (digit <= 15) { // Add leading zero if necessary (NET-351) - digestBuffer.append("0"); - } - digestBuffer.append(Integer.toHexString(digit)); - } - - buffer = new StringBuilder(256); - buffer.append(username); - buffer.append(' '); - buffer.append(digestBuffer.toString()); - - if (sendCommand(POP3Command.APOP, buffer.toString()) != POP3Reply.OK) { - return false; - } - - setState(TRANSACTION_STATE); - - return true; - } - - - /** - * Logout of the POP3 server. To fully disconnect from the server - * you must call - * {@link org.apache.commons.net.pop3.POP3#disconnect disconnect }. - * A logout attempt is valid in any state. If - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * , it enters the - * {@link org.apache.commons.net.pop3.POP3#UPDATE_STATE UPDATE_STATE } - * on a successful logout. - * - * @return True if the logout attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process - * of logging out. - */ - public boolean logout() throws IOException - { - if (getState() == TRANSACTION_STATE) { - setState(UPDATE_STATE); - } - sendCommand(POP3Command.QUIT); - return replyCode == POP3Reply.OK; - } - - - /** - * Send a NOOP command to the POP3 server. This is useful for keeping - * a connection alive since most POP3 servers will timeout after 10 - * minutes of inactivity. A noop attempt will only succeed if - * the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - * - * @return True if the noop attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * sending the NOOP command. - */ - public boolean noop() throws IOException - { - if (getState() == TRANSACTION_STATE) { - return sendCommand(POP3Command.NOOP) == POP3Reply.OK; - } - return false; - } - - - /** - * Delete a message from the POP3 server. The message is only marked - * for deletion by the server. If you decide to unmark the message, you - * must issuse a {@link #reset reset } command. Messages marked - * for deletion are only deleted by the server on - * {@link #logout logout }. - * A delete attempt can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - * - * @param messageId The message number to delete. - * @return True if the deletion attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * sending the delete command. - */ - public boolean deleteMessage(final int messageId) throws IOException - { - if (getState() == TRANSACTION_STATE) { - return sendCommand(POP3Command.DELE, Integer.toString(messageId)) - == POP3Reply.OK; - } - return false; - } - - - /** - * Reset the POP3 session. This is useful for undoing any message - * deletions that may have been performed. A reset attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . - * - * @return True if the reset attempt was successful, false if not. - * @throws IOException If a network I/O error occurs in the process of - * sending the reset command. - */ - public boolean reset() throws IOException - { - if (getState() == TRANSACTION_STATE) { - return sendCommand(POP3Command.RSET) == POP3Reply.OK; - } - return false; - } - - /** - * Get the mailbox status. A status attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of messages in the mailbox and the total - * size of the messages in bytes. Returns null if the status the - * attempt fails. - * - * @return A POP3MessageInfo instance containing the number of - * messages in the mailbox and the total size of the messages - * in bytes. Returns null if the status the attempt fails. - * @throws IOException If a network I/O error occurs in the process of - * sending the status command. - */ - public POP3MessageInfo status() throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.STAT) != POP3Reply.OK) { - return null; - } - return parseStatus(lastReplyLine.substring(3)); - } - - - /** - * List an individual message. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of the listed message and the - * size of the message in bytes. Returns null if the list - * attempt fails (e.g., if the specified message number does - * not exist). - * - * @param messageId The number of the message list. - * @return A POP3MessageInfo instance containing the number of the - * listed message and the size of the message in bytes. Returns - * null if the list attempt fails. - * @throws IOException If a network I/O error occurs in the process of - * sending the list command. - */ - public POP3MessageInfo listMessage(final int messageId) throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.LIST, Integer.toString(messageId)) - != POP3Reply.OK) { - return null; - } - return parseStatus(lastReplyLine.substring(3)); - } - - - /** - * List all messages. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns an array of POP3MessageInfo instances, - * each containing the number of a message and its size in bytes. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * - * @return An array of POP3MessageInfo instances representing all messages - * in the order they appear in the mailbox, - * each containing the number of a message and its size in bytes. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * @throws IOException If a network I/O error occurs in the process of - * sending the list command. - */ - public POP3MessageInfo[] listMessages() throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.LIST) != POP3Reply.OK) { - return null; - } - getAdditionalReply(); - - // This could be a zero length array if no messages present - final POP3MessageInfo[] messages = new POP3MessageInfo[replyLines.size() - 2]; // skip first and last lines - - final ListIterator en = replyLines.listIterator(1); // Skip first line - - // Fetch lines. - for (int line = 0; line < messages.length; line++) { - messages[line] = parseStatus(en.next()); - } - - return messages; - } - - /** - * List the unique identifier for a message. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns a POP3MessageInfo instance - * containing the number of the listed message and the - * unique identifier for that message. Returns null if the list - * attempt fails (e.g., if the specified message number does - * not exist). - * - * @param messageId The number of the message list. - * @return A POP3MessageInfo instance containing the number of the - * listed message and the unique identifier for that message. - * Returns null if the list attempt fails. - * @throws IOException If a network I/O error occurs in the process of - * sending the list unique identifier command. - */ - public POP3MessageInfo listUniqueIdentifier(final int messageId) - throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.UIDL, Integer.toString(messageId)) - != POP3Reply.OK) { - return null; - } - return parseUID(lastReplyLine.substring(3)); - } - - - /** - * List the unique identifiers for all messages. A list attempt can only - * succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - * . Returns an array of POP3MessageInfo instances, - * each containing the number of a message and its unique identifier. - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * - * @return An array of POP3MessageInfo instances representing all messages - * in the order they appear in the mailbox, - * each containing the number of a message and its unique identifier - * If there are no messages, this method returns a zero length array. - * If the list attempt fails, it returns null. - * @throws IOException If a network I/O error occurs in the process of - * sending the list unique identifier command. - */ - public POP3MessageInfo[] listUniqueIdentifiers() throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.UIDL) != POP3Reply.OK) { - return null; - } - getAdditionalReply(); - - // This could be a zero length array if no messages present - final POP3MessageInfo[] messages = new POP3MessageInfo[replyLines.size() - 2]; // skip first and last lines - - final ListIterator en = replyLines.listIterator(1); // skip first line - - // Fetch lines. - for (int line = 0; line < messages.length; line++) { - messages[line] = parseUID(en.next()); - } - - return messages; - } - - - /** - * Retrieve a message from the POP3 server. A retrieve message attempt - * can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - *

- * You must not issue any commands to the POP3 server (i.e., call any - * other methods) until you finish reading the message from the - * returned BufferedReader instance. - * The POP3 protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned BufferedReader actually reads - * directly from the POP3 connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - * - * @param messageId The number of the message to fetch. - * @return A DotTerminatedMessageReader instance - * from which the entire message can be read. - * This can safely be cast to a {@link java.io.BufferedReader BufferedReader} in order to - * use the {@link java.io.BufferedReader#readLine() BufferedReader#readLine()} method. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - * @throws IOException If a network I/O error occurs in the process of - * sending the retrieve message command. - */ - public Reader retrieveMessage(final int messageId) throws IOException - { - if (getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.RETR, Integer.toString(messageId)) != POP3Reply.OK) { - return null; - } - - return new DotTerminatedMessageReader(reader); - } - - - /** - * Retrieve only the specified top number of lines of a message from the - * POP3 server. A retrieve top lines attempt - * can only succeed if the client is in the - * {@link org.apache.commons.net.pop3.POP3#TRANSACTION_STATE TRANSACTION_STATE } - *

- * You must not issue any commands to the POP3 server (i.e., call any - * other methods) until you finish reading the message from the returned - * BufferedReader instance. - * The POP3 protocol uses the same stream for issuing commands as it does - * for returning results. Therefore the returned BufferedReader actually reads - * directly from the POP3 connection. After the end of message has been - * reached, new commands can be executed and their replies read. If - * you do not follow these requirements, your program will not work - * properly. - * - * @param messageId The number of the message to fetch. - * @param numLines The top number of lines to fetch. This must be >= 0. - * @return A DotTerminatedMessageReader instance - * from which the specified top number of lines of the message can be - * read. - * This can safely be cast to a {@link java.io.BufferedReader BufferedReader} in order to - * use the {@link java.io.BufferedReader#readLine() BufferedReader#readLine()} method. - * Returns null if the retrieval attempt fails (e.g., if the specified - * message number does not exist). - * @throws IOException If a network I/O error occurs in the process of - * sending the top command. - */ - public Reader retrieveMessageTop(final int messageId, final int numLines) - throws IOException - { - if (numLines < 0 || getState() != TRANSACTION_STATE) { - return null; - } - if (sendCommand(POP3Command.TOP, Integer.toString(messageId) + " " + - Integer.toString(numLines)) != POP3Reply.OK) { - return null; - } - - return new DotTerminatedMessageReader(reader); - } - - -} - diff --git a/src/org/apache/commons/net/pop3/POP3Command.java b/src/org/apache/commons/net/pop3/POP3Command.java deleted file mode 100644 index 3a5dfd5f..00000000 --- a/src/org/apache/commons/net/pop3/POP3Command.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/** - * POP3Command stores POP3 command code constants. - * - * - */ - -public final class POP3Command -{ - /** Send user name. */ - public static final int USER = 0; - /** Send password. */ - public static final int PASS = 1; - /** Quit session. */ - public static final int QUIT = 2; - /** Get status. */ - public static final int STAT = 3; - /** List message(s). */ - public static final int LIST = 4; - /** Retrieve message(s). */ - public static final int RETR = 5; - /** Delete message(s). */ - public static final int DELE = 6; - /** No operation. Used as a session keepalive. */ - public static final int NOOP = 7; - /** Reset session. */ - public static final int RSET = 8; - /** Authorization. */ - public static final int APOP = 9; - /** Retrieve top number lines from message. */ - public static final int TOP = 10; - /** List unique message identifier(s). */ - public static final int UIDL = 11; - /** - * The capabilities command. - * @since 3.0 - */ - public static final int CAPA = 12; - /** - * Authentication - * @since 3.0 - */ - public static final int AUTH = 13; - - private static final int NEXT = AUTH + 1; // update as necessary when adding new entries - - static final String[] commands = { - "USER", "PASS", "QUIT", "STAT", "LIST", "RETR", "DELE", "NOOP", "RSET", - "APOP", "TOP", "UIDL", "CAPA", "AUTH", - }; - - static { - if (commands.length != NEXT) { - throw new RuntimeException("Error in array definition"); - } - } - - // Cannot be instantiated. - private POP3Command() - {} - - /** - * Get the POP3 protocol string command corresponding to a command code. - * @param command the command code - * - * @return The POP3 protocol string command corresponding to a command code. - */ - public static String getCommand(final int command) - { - return commands[command]; - } -} diff --git a/src/org/apache/commons/net/pop3/POP3MessageInfo.java b/src/org/apache/commons/net/pop3/POP3MessageInfo.java deleted file mode 100644 index 1f356806..00000000 --- a/src/org/apache/commons/net/pop3/POP3MessageInfo.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/** - * POP3MessageInfo is used to return information about messages stored on - * a POP3 server. Its fields are used to mean slightly different things - * depending on the information being returned. - *

- * In response to a status command, number - * contains the number of messages in the mailbox, size - * contains the size of the mailbox in bytes, and identifier - * is null. - *

- * In response to a message listings, number - * contains the message number, size contains the - * size of the message in bytes, and identifier is null. - *

- * In response to unique identifier listings, number contains - * the message number, size is undefined, and - * identifier contains the message's unique identifier. - * - * - */ - -public final class POP3MessageInfo -{ - public int number; - public int size; - public String identifier; - - /** - * Creates a POP3MessageInfo instance with number and - * size set to 0, and identifier set to - * null. - */ - public POP3MessageInfo() - { - this(0, null, 0); - } - - /** - * Creates a POP3MessageInfo instance with number set - * to num , size set to octets , - * and identifier set to null. - * @param num the number - * @param octets the size - */ - public POP3MessageInfo(final int num, final int octets) - { - this(num, null, octets); - } - - /** - * Creates a POP3MessageInfo instance with number set - * to num , size undefined, - * and identifier set to uid. - * @param num the number - * @param uid the UID - */ - public POP3MessageInfo(final int num, final String uid) - { - this(num, uid, -1); - } - - private POP3MessageInfo(final int num, final String uid, final int size) { - this.number = num; - this.size = size; - this.identifier = uid; - } - - /** - * @since 3.6 - */ - @Override - public String toString() { - return "Number: " + number + ". Size: " + size + ". Id: " + identifier; - } -} diff --git a/src/org/apache/commons/net/pop3/POP3Reply.java b/src/org/apache/commons/net/pop3/POP3Reply.java deleted file mode 100644 index 56deb398..00000000 --- a/src/org/apache/commons/net/pop3/POP3Reply.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -/** - * POP3Reply stores POP3 reply code constants. - */ - -public final class POP3Reply -{ - /** The reply code indicating success of an operation. */ - public static final int OK = 0; - - /** The reply code indicating failure of an operation. */ - public static final int ERROR = 1; - - /** - * The reply code indicating intermediate response to a command. - * @since 3.0 - */ - public static final int OK_INT = 2; - - // Cannot be instantiated. - private POP3Reply() - {} -} diff --git a/src/org/apache/commons/net/pop3/POP3SClient.java b/src/org/apache/commons/net/pop3/POP3SClient.java deleted file mode 100644 index 1a2386f1..00000000 --- a/src/org/apache/commons/net/pop3/POP3SClient.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.pop3; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.SSLContextUtils; -import org.apache.commons.net.util.SSLSocketUtils; - -/** - * POP3 over SSL processing. Copied from FTPSClient.java and modified to suit POP3. - * If implicit mode is selected (NOT the default), SSL/TLS negotiation starts right - * after the connection has been established. In explicit mode (the default), SSL/TLS - * negotiation starts when the user calls execTLS() and the server accepts the command. - * Implicit usage: - * POP3SClient c = new POP3SClient(true); - * c.connect("127.0.0.1", 995); - * Explicit usage: - * POP3SClient c = new POP3SClient(); - * c.connect("127.0.0.1", 110); - * if (c.execTLS()) { /rest of the commands here/ } - * - * Warning: the hostname is not verified against the certificate by default, use - * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} - * (on Java 1.7+) to enable verification. - * @since 3.0 - */ -public class POP3SClient extends POP3Client -{ - // from http://www.iana.org/assignments/port-numbers - - // pop3s 995/tcp pop3 protocol over TLS/SSL (was spop3) - // pop3s 995/udp pop3 protocol over TLS/SSL (was spop3) - - private static final int DEFAULT_POP3S_PORT = 995; - - /** Default secure socket protocol name, like TLS */ - private static final String DEFAULT_PROTOCOL = "TLS"; - - /** The security mode. True - Implicit Mode / False - Explicit Mode. */ - private final boolean isImplicit; - /** The secure socket protocol to be used, like SSL/TLS. */ - private final String protocol; - /** The context object. */ - private SSLContext context; - /** The cipher suites. SSLSockets have a default set of these anyway, - so no initialization required. */ - private String[] suites; - /** The protocol versions. */ - private String[] protocols //null; - ;//{"SSLv2", "SSLv3", "TLSv1", "TLSv1.1", "SSLv2Hello"}; - - /** The FTPS {@link TrustManager} implementation, default null. */ - private TrustManager trustManager; - - /** The {@link KeyManager}, default null. */ - private KeyManager keyManager; - - /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ - private HostnameVerifier hostnameVerifier; - - /** Use Java 1.7+ HTTPS Endpoint Identification Algorithim. */ - private boolean tlsEndpointChecking; - - /** - * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * Sets security mode to explicit. - */ - public POP3SClient() - { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - */ - public POP3SClient(final boolean implicit) - { - this(DEFAULT_PROTOCOL, implicit); - } - - /** - * Constructor for POP3SClient. - * Sets security mode to explicit. - * @param proto the protocol. - */ - public POP3SClient(final String proto) - { - this(proto, false); - } - - /** - * Constructor for POP3SClient. - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - */ - public POP3SClient(final String proto, final boolean implicit) - { - this(proto, implicit, null); - } - - /** - * Constructor for POP3SClient. - * Sets the default port to {@link #DEFAULT_POP3S_PORT} - 995 - if using implicit mode - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param ctx the context to be used - */ - public POP3SClient(final String proto, final boolean implicit, final SSLContext ctx) - { - protocol = proto; - isImplicit = implicit; - context = ctx; - if (isImplicit) { - setDefaultPort(DEFAULT_POP3S_PORT); - } - } - - /** - * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param ctx A pre-configured SSL Context. - */ - public POP3SClient(final boolean implicit, final SSLContext ctx) - { - this(DEFAULT_PROTOCOL, implicit, ctx); - } - - /** - * Constructor for POP3SClient, using {@link #DEFAULT_PROTOCOL} - TLS - and isImplicit = false - * @param context A pre-configured SSL Context. - * @see #POP3SClient(boolean, SSLContext) - */ - public POP3SClient(final SSLContext context) - { - this(false, context); - } - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * @throws IOException If it is thrown by _connectAction_(). - * @see org.apache.commons.net.SocketClient#_connectAction_() - */ - @Override - protected void _connectAction_() throws IOException - { - // Implicit mode. - if (isImplicit) { - applySocketAttributes(); - performSSLNegotiation(); - } - super._connectAction_(); - // Explicit mode - don't do anything. The user calls execTLS() - } - - /** - * Performs a lazy init of the SSL context. - * @throws IOException When could not initialize the SSL context. - */ - private void initSSLContext() throws IOException - { - if (context == null) - { - context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a - * connection and carries out handshake processing. - * @throws IOException If server negotiation fails. - */ - private void performSSLNegotiation() throws IOException - { - initSSLContext(); - - final SSLSocketFactory ssf = context.getSocketFactory(); - final String host = _hostname_ != null ? _hostname_ : getRemoteAddress().getHostAddress(); - final int port = getRemotePort(); - final SSLSocket socket = - (SSLSocket) ssf.createSocket(_socket_, host, port, true); - socket.setEnableSessionCreation(true); - socket.setUseClientMode(true); - - if (tlsEndpointChecking) { - SSLSocketUtils.enableEndpointNameVerification(socket); - } - - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - if (suites != null) { - socket.setEnabledCipherSuites(suites); - } - socket.startHandshake(); - - // TODO the following setup appears to duplicate that in the super class methods - _socket_ = socket; - _input_ = socket.getInputStream(); - _output_ = socket.getOutputStream(); - reader = new CRLFLineReader(new InputStreamReader(_input_, DEFAULT_ENCODING)); - writer = new BufferedWriter(new OutputStreamWriter(_output_, DEFAULT_ENCODING)); - - if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { - throw new SSLHandshakeException("Hostname doesn't match certificate"); - } - } - - /** - * Get the {@link KeyManager} instance. - * @return The current {@link KeyManager} instance. - */ - private KeyManager getKeyManager() - { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use. - * @param newKeyManager The KeyManager implementation to set. - * @see org.apache.commons.net.util.KeyManagerUtils - */ - public void setKeyManager(final KeyManager newKeyManager) - { - keyManager = newKeyManager; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. Called before server negotiation. - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(final String[] cipherSuites) - { - suites = cipherSuites.clone(); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of cipher suite names, or null. - */ - public String[] getEnabledCipherSuites() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledCipherSuites(); - } - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(final String[] protocolVersions) - { - protocols = protocolVersions.clone(); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of protocols, or null. - */ - public String[] getEnabledProtocols() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledProtocols(); - } - return null; - } - - /** - * The TLS command execution. - * @throws SSLException If the server reply code is not positive. - * @throws IOException If an I/O error occurs while sending - * the command or performing the negotiation. - * @return TRUE if the command and negotiation succeeded. - */ - public boolean execTLS() throws SSLException, IOException - { - if (sendCommand("STLS") != POP3Reply.OK) - { - return false; - //throw new SSLException(getReplyString()); - } - performSSLNegotiation(); - return true; - } - - /** - * Get the currently configured {@link TrustManager}. - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() - { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use. - * @param newTrustManager The TrustManager implementation to set. - * @see org.apache.commons.net.util.TrustManagerUtils - */ - public void setTrustManager(final TrustManager newTrustManager) - { - trustManager = newTrustManager; - } - - /** - * Get the currently configured {@link HostnameVerifier}. - * @return A HostnameVerifier instance. - * @since 3.4 - */ - public HostnameVerifier getHostnameVerifier() - { - return hostnameVerifier; - } - - /** - * Override the default {@link HostnameVerifier} to use. - * @param newHostnameVerifier The HostnameVerifier implementation to set or null to disable. - * @since 3.4 - */ - public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) - { - hostnameVerifier = newHostnameVerifier; - } - - /** - * Return whether or not endpoint identification using the HTTPS algorithm - * on Java 1.7+ is enabled. The default behavior is for this to be disabled. - * - * @return True if enabled, false if not. - * @since 3.4 - */ - public boolean isEndpointCheckingEnabled() - { - return tlsEndpointChecking; - } - - /** - * Automatic endpoint identification checking using the HTTPS algorithm - * is supported on Java 1.7+. The default behavior is for this to be disabled. - * - * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. - * @since 3.4 - */ - public void setEndpointCheckingEnabled(final boolean enable) - { - tlsEndpointChecking = enable; - } -} - -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/pop3/package-info.java b/src/org/apache/commons/net/pop3/package-info.java deleted file mode 100644 index 45abdce5..00000000 --- a/src/org/apache/commons/net/pop3/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * POP3 and POP3S mail - */ -package org.apache.commons.net.pop3; \ No newline at end of file diff --git a/src/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java b/src/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java deleted file mode 100644 index 6aebc288..00000000 --- a/src/org/apache/commons/net/smtp/AuthenticatingSMTPClient.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.IOException; -import java.net.InetAddress; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.SSLContext; - -import org.apache.commons.net.util.Base64; - - -/** - * An SMTP Client class with authentication support (RFC4954). - * - * @see SMTPClient - * @since 3.0 - */ -public class AuthenticatingSMTPClient extends SMTPSClient -{ - /** - * The default AuthenticatingSMTPClient constructor. - * Creates a new Authenticating SMTP Client. - */ - public AuthenticatingSMTPClient() - { - } - - /** - * Overloaded constructor that takes a protocol specification - * @param protocol The protocol to use - */ - public AuthenticatingSMTPClient(final String protocol) { - super(protocol); - } - - /** - * Overloaded constructor that takes a protocol specification and the implicit argument - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @since 3.3 - */ - public AuthenticatingSMTPClient(final String proto, final boolean implicit) - { - super(proto, implicit); - } - - /** - * Overloaded constructor that takes the protocol specification, the implicit argument and encoding - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param encoding the encoding - * @since 3.3 - */ - public AuthenticatingSMTPClient(final String proto, final boolean implicit, final String encoding) - { - super(proto, implicit, encoding); - } - - /** - * Overloaded constructor that takes the implicit argument, and using {@link #DEFAULT_PROTOCOL} i.e. TLS - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param ctx A pre-configured SSL Context. - * @since 3.3 - */ - public AuthenticatingSMTPClient(final boolean implicit, final SSLContext ctx) - { - super(implicit, ctx); - } - - /** - * Overloaded constructor that takes a protocol specification and encoding - * @param protocol The protocol to use - * @param encoding The encoding to use - * @since 3.3 - */ - public AuthenticatingSMTPClient(final String protocol, final String encoding) { - super(protocol, false, encoding); - } - - /** - * A convenience method to send the ESMTP EHLO command to the server, - * receive the reply, and return the reply code. - *

- * @param hostname The hostname of the sender. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int ehlo(final String hostname) throws IOException - { - return sendCommand(SMTPCommand.EHLO, hostname); - } - - /** - * Login to the ESMTP server by sending the EHLO command with the - * given hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @param hostname The hostname with which to greet the SMTP server. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean elogin(final String hostname) throws IOException - { - return SMTPReply.isPositiveCompletion(ehlo(hostname)); - } - - - /** - * Login to the ESMTP server by sending the EHLO command with the - * client hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean elogin() throws IOException - { - final String name; - final InetAddress host; - - host = getLocalAddress(); - name = host.getHostName(); - - if (name == null) { - return false; - } - - return SMTPReply.isPositiveCompletion(ehlo(name)); - } - - /** - * Returns the integer values of the enhanced reply code of the last SMTP reply. - * @return The integer values of the enhanced reply code of the last SMTP reply. - * First digit is in the first array element. - */ - public int[] getEnhancedReplyCode() - { - final String reply = getReplyString().substring(4); - final String[] parts = reply.substring(0, reply.indexOf(' ')).split ("\\."); - final int[] res = new int[parts.length]; - for (int i = 0; i < parts.length; i++) - { - res[i] = Integer.parseInt (parts[i]); - } - return res; - } - - /** - * Authenticate to the SMTP server by sending the AUTH command with the - * selected mechanism, using the given username and the given password. - * - * @param method the method to use, one of the {@link AuthenticatingSMTPClient.AUTH_METHOD} enum values - * @param username the user name. - * If the method is XOAUTH/XOAUTH2, then this is used as the plain text oauth protocol parameter string - * which is Base64-encoded for transmission. - * @param password the password for the username. - * Ignored for XOAUTH/XOAUTH2. - * - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws NoSuchAlgorithmException If the CRAM hash algorithm - * cannot be instantiated by the Java runtime system. - * @throws InvalidKeyException If the CRAM hash algorithm - * failed to use the given password. - * @throws InvalidKeySpecException If the CRAM hash algorithm - * failed to use the given password. - */ - public boolean auth(final AuthenticatingSMTPClient.AUTH_METHOD method, - final String username, final String password) - throws IOException, NoSuchAlgorithmException, - InvalidKeyException, InvalidKeySpecException - { - if (!SMTPReply.isPositiveIntermediate(sendCommand(SMTPCommand.AUTH, - AUTH_METHOD.getAuthName(method)))) { - return false; - } - - if (method.equals(AUTH_METHOD.PLAIN)) - { - // the server sends an empty response ("334 "), so we don't have to read it. - return SMTPReply.isPositiveCompletion(sendCommand( - Base64.encodeBase64StringUnChunked(("\000" + username + "\000" + password).getBytes(getCharset())) - )); - } - else if (method.equals(AUTH_METHOD.CRAM_MD5)) - { - // get the CRAM challenge - final byte[] serverChallenge = Base64.decodeBase64(getReplyString().substring(4).trim()); - // get the Mac instance - final Mac hmac_md5 = Mac.getInstance("HmacMD5"); - hmac_md5.init(new SecretKeySpec(password.getBytes(getCharset()), "HmacMD5")); - // compute the result: - final byte[] hmacResult = convertToHexString(hmac_md5.doFinal(serverChallenge)).getBytes(getCharset()); - // join the byte arrays to form the reply - final byte[] usernameBytes = username.getBytes(getCharset()); - final byte[] toEncode = new byte[usernameBytes.length + 1 /* the space */ + hmacResult.length]; - System.arraycopy(usernameBytes, 0, toEncode, 0, usernameBytes.length); - toEncode[usernameBytes.length] = ' '; - System.arraycopy(hmacResult, 0, toEncode, usernameBytes.length + 1, hmacResult.length); - // send the reply and read the server code: - return SMTPReply.isPositiveCompletion(sendCommand( - Base64.encodeBase64StringUnChunked(toEncode))); - } - else if (method.equals(AUTH_METHOD.LOGIN)) - { - // the server sends fixed responses (base64("Username") and - // base64("Password")), so we don't have to read them. - if (!SMTPReply.isPositiveIntermediate(sendCommand( - Base64.encodeBase64StringUnChunked(username.getBytes(getCharset()))))) { - return false; - } - return SMTPReply.isPositiveCompletion(sendCommand( - Base64.encodeBase64StringUnChunked(password.getBytes(getCharset())))); - } - else if (method.equals(AUTH_METHOD.XOAUTH) || method.equals(AUTH_METHOD.XOAUTH2)) - { - return SMTPReply.isPositiveIntermediate(sendCommand( - Base64.encodeBase64StringUnChunked(username.getBytes(getCharset())) - )); - } else { - return false; // safety check - } - } - - /** - * Converts the given byte array to a String containing the hex values of the bytes. - * For example, the byte 'A' will be converted to '41', because this is the ASCII code - * (and the byte value) of the capital letter 'A'. - * @param a The byte array to convert. - * @return The resulting String of hex codes. - */ - private String convertToHexString(final byte[] a) - { - final StringBuilder result = new StringBuilder(a.length*2); - for (final byte element : a) - { - if ( (element & 0x0FF) <= 15 ) { - result.append("0"); - } - result.append(Integer.toHexString(element & 0x0FF)); - } - return result.toString(); - } - - /** - * The enumeration of currently-supported authentication methods. - */ - public enum AUTH_METHOD - { - /** The standarised (RFC4616) PLAIN method, which sends the password unencrypted (insecure). */ - PLAIN, - /** The standarised (RFC2195) CRAM-MD5 method, which doesn't send the password (secure). */ - CRAM_MD5, - /** The unstandarised Microsoft LOGIN method, which sends the password unencrypted (insecure). */ - LOGIN, - /** XOAuth method which accepts a signed and base64ed OAuth URL. */ - XOAUTH, - /** XOAuth 2 method which accepts a signed and base64ed OAuth JSON. */ - XOAUTH2; - - /** - * Gets the name of the given authentication method suitable for the server. - * @param method The authentication method to get the name for. - * @return The name of the given authentication method suitable for the server. - */ - public static final String getAuthName(final AUTH_METHOD method) - { - if (method.equals(AUTH_METHOD.PLAIN)) { - return "PLAIN"; - } else if (method.equals(AUTH_METHOD.CRAM_MD5)) { - return "CRAM-MD5"; - } else if (method.equals(AUTH_METHOD.LOGIN)) { - return "LOGIN"; - } else if (method.equals(AUTH_METHOD.XOAUTH)) { - return "XOAUTH"; - } else if (method.equals(AUTH_METHOD.XOAUTH2)) { - return "XOAUTH2"; - } else { - return null; - } - } - } -} - -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/smtp/RelayPath.java b/src/org/apache/commons/net/smtp/RelayPath.java deleted file mode 100644 index 622f1b25..00000000 --- a/src/org/apache/commons/net/smtp/RelayPath.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.util.Enumeration; -import java.util.Vector; - -/** - * A class used to represent forward and reverse relay paths. The - * SMTP MAIL command requires a reverse relay path while the SMTP RCPT - * command requires a forward relay path. See RFC 821 for more details. - * In general, you will not have to deal with relay paths. - * - * @see SMTPClient - */ - -public final class RelayPath -{ - private final Vector path; - private final String emailAddress; - - /** - * Create a relay path with the specified email address as the ultimate - * destination. - *

- * @param emailAddress The destination email address. - */ - public RelayPath(final String emailAddress) - { - this.path = new Vector<>(); - this.emailAddress = emailAddress; - } - - /** - * Add a mail relay host to the relay path. Hosts are added left to - * right. For example, the following will create the path - * < @bar.com,@foo.com:foobar@foo.com > - *

-     * path = new RelayPath("foobar@foo.com");
-     * path.addRelay("bar.com");
-     * path.addRelay("foo.com");
-     * 
- *

- * @param hostname The host to add to the relay path. - */ - public void addRelay(final String hostname) - { - path.addElement(hostname); - } - - /** - * Return the properly formatted string representation of the relay path. - *

- * @return The properly formatted string representation of the relay path. - */ - @Override - public String toString() - { - final StringBuilder buffer = new StringBuilder(); - final Enumeration hosts; - - buffer.append('<'); - - hosts = path.elements(); - - if (hosts.hasMoreElements()) - { - buffer.append('@'); - buffer.append(hosts.nextElement()); - - while (hosts.hasMoreElements()) - { - buffer.append(",@"); - buffer.append(hosts.nextElement()); - } - buffer.append(':'); - } - - buffer.append(emailAddress); - buffer.append('>'); - - return buffer.toString(); - } - -} diff --git a/src/org/apache/commons/net/smtp/SMTP.java b/src/org/apache/commons/net/smtp/SMTP.java deleted file mode 100644 index 8d20442d..00000000 --- a/src/org/apache/commons/net/smtp/SMTP.java +++ /dev/null @@ -1,775 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.ArrayList; - -import org.apache.commons.net.MalformedServerReplyException; -import org.apache.commons.net.ProtocolCommandSupport; -import org.apache.commons.net.SocketClient; -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.NetConstants; - -/** - * SMTP provides the basic the functionality necessary to implement your - * own SMTP client. To derive the full benefits of the SMTP class requires - * some knowledge of the FTP protocol defined in RFC 821. However, there - * is no reason why you should have to use the SMTP class. The - * {@link org.apache.commons.net.smtp.SMTPClient} class, - * derived from SMTP, - * implements all the functionality required of an SMTP client. The - * SMTP class is made public to provide access to various SMTP constants - * and to make it easier for adventurous programmers (or those with - * special needs) to interact with the SMTP protocol and implement their - * own clients. A set of methods with names corresponding to the SMTP - * command names are provided to facilitate this interaction. - *

- * You should keep in mind that the SMTP server may choose to prematurely - * close a connection for various reasons. The SMTP class will detect a - * premature SMTP server connection closing when it receives a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the SMTP class method encountering that reply will throw - * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * . - * SMTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * , you must disconnect the connection with - * {@link org.apache.commons.net.SocketClient#disconnect disconnect() } - * to properly clean up the system resources used by SMTP. Before - * disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode }, - * {@link #getReplyString getReplyString }, - * and {@link #getReplyStrings getReplyStrings}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * @see SMTPClient - * @see SMTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - */ - -public class SMTP extends SocketClient -{ - /** The default SMTP port (25). */ - public static final int DEFAULT_PORT = 25; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - private static final String DEFAULT_ENCODING = "ISO-8859-1"; - - /** - * The encoding to use (user-settable). - * - * @since 3.1 (changed from private to protected) - */ - protected final String encoding; - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - */ - protected ProtocolCommandSupport _commandSupport_; - - BufferedReader reader; - BufferedWriter writer; - - private int replyCode; - private final ArrayList replyLines; - private boolean newReplyString; - private String replyString; - - /** - * The default SMTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving SMTP reply information. - */ - public SMTP() - { - this(DEFAULT_ENCODING); - } - - /** - * Overloaded constructor where the user may specify a default encoding. - * @param encoding the encoing to use - * @since 2.0 - */ - public SMTP(final String encoding) { - setDefaultPort(DEFAULT_PORT); - replyLines = new ArrayList<>(); - newReplyString = false; - replyString = null; - _commandSupport_ = new ProtocolCommandSupport(this); - this.encoding = encoding; - } - - /** - * Send a command to the server. May also be used to send text data. - * - * @param command the command to send (as a plain String) - * @param args the command arguments, may be {@code null} - * @param includeSpace if {@code true}, add a space between the command and its arguments - * @return the reply code - * @throws IOException - */ - private int sendCommand(final String command, final String args, final boolean includeSpace) - throws IOException - { - final StringBuilder __commandBuffer = new StringBuilder(); - __commandBuffer.append(command); - - if (args != null) - { - if (includeSpace) { - __commandBuffer.append(' '); - } - __commandBuffer.append(args); - } - - __commandBuffer.append(SocketClient.NETASCII_EOL); - - final String message = __commandBuffer.toString(); - writer.write(message); - writer.flush(); - - fireCommandSent(command, message); - - return getReply(); - } - - /** - * - * @param command the command to send (as an int defined in {@link SMPTCommand}) - * @param args the command arguments, may be {@code null} - * @param includeSpace if {@code true}, add a space between the command and its arguments - * @return the reply code - * @throws IOException - */ - private int sendCommand(final int command, final String args, final boolean includeSpace) - throws IOException - { - return sendCommand(SMTPCommand.getCommand(command), args, includeSpace); - } - - /** Initiates control connections and gets initial reply. */ - @Override - protected void _connectAction_() throws IOException - { - super._connectAction_(); - reader = - new CRLFLineReader(new InputStreamReader(_input_, - encoding)); - writer = - new BufferedWriter(new OutputStreamWriter(_output_, - encoding)); - getReply(); - } - - - /** - * Closes the connection to the SMTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - *

- * @throws IOException If an error occurs while disconnecting. - */ - @Override - public void disconnect() throws IOException - { - super.disconnect(); - reader = null; - writer = null; - replyString = null; - replyLines.clear(); - newReplyString = false; - } - - - /** - * Sends an SMTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the SMTP command to send. - * @param args The arguments to the SMTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final String command, final String args) throws IOException - { - return sendCommand(command, args, true); - } - - - /** - * Sends an SMTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The SMTPCommand constant corresponding to the SMTP command - * to send. - * @param args The arguments to the SMTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final int command, final String args) throws IOException - { - return sendCommand(SMTPCommand.getCommand(command), args); - } - - - /** - * Sends an SMTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The text representation of the SMTP command to send. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final String command) throws IOException - { - return sendCommand(command, null); - } - - - /** - * Sends an SMTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - *

- * @param command The SMTPCommand constant corresponding to the SMTP command - * to send. - * @return The integer value of the SMTP reply code returned by the server - * in response to the command. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int sendCommand(final int command) throws IOException - { - return sendCommand(command, null); - } - - - /** - * Returns the integer value of the reply code of the last SMTP reply. - * You will usually only use this method after you connect to the - * SMTP server to check that the connection was successful since - * connect is of type void. - *

- * @return The integer value of the reply code of the last SMTP reply. - */ - public int getReplyCode() - { - return replyCode; - } - - /** - * Fetches a reply from the SMTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from either calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. Only use this - * method if you are implementing your own SMTP client or if you need to - * fetch a secondary response from the SMTP server. - *

- * @return The integer value of the reply code of the fetched SMTP reply. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while receiving the - * server reply. - */ - public int getReply() throws IOException - { - final int length; - - newReplyString = true; - replyLines.clear(); - - String line = reader.readLine(); - - if (line == null) { - throw new SMTPConnectionClosedException( - "Connection closed without indication."); - } - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - length = line.length(); - if (length < 3) { - throw new MalformedServerReplyException( - "Truncated server reply: " + line); - } - - try - { - final String code = line.substring(0, 3); - replyCode = Integer.parseInt(code); - } - catch (final NumberFormatException e) - { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + line); - } - - replyLines.add(line); - - // Get extra lines if message continues. - if (length > 3 && line.charAt(3) == '-') - { - do - { - line = reader.readLine(); - - if (line == null) { - throw new SMTPConnectionClosedException( - "Connection closed without indication."); - } - - replyLines.add(line); - - // The length() check handles problems that could arise from readLine() - // returning too soon after encountering a naked CR or some other - // anomaly. - } - while (!(line.length() >= 4 && line.charAt(3) != '-' && - Character.isDigit(line.charAt(0)))); - // This is too strong a condition because a non-conforming server - // could screw things up like ftp.funet.fi does for FTP - // line.startsWith(code))); - } - - fireReplyReceived(replyCode, getReplyString()); - - if (replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) { - throw new SMTPConnectionClosedException( - "SMTP response 421 received. Server closed connection."); - } - return replyCode; - } - - - /** - * Returns the lines of text from the last SMTP server response as an array - * of strings, one entry per line. The end of line markers of each are - * stripped from each line. - *

- * @return The lines of text from the last SMTP response as an array. - */ - public String[] getReplyStrings() - { - return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY); - } - - /** - * Returns the entire text of the last SMTP server response exactly - * as it was received, including all end of line markers in NETASCII - * format. - *

- * @return The entire text from the last SMTP response as a String. - */ - public String getReplyString() - { - final StringBuilder buffer; - - if (!newReplyString) { - return replyString; - } - - buffer = new StringBuilder(); - - for (final String line : replyLines) - { - buffer.append(line); - buffer.append(SocketClient.NETASCII_EOL); - } - - newReplyString = false; - - replyString = buffer.toString(); - return replyString; - } - - - /** - * A convenience method to send the SMTP HELO command to the server, - * receive the reply, and return the reply code. - *

- * @param hostname The hostname of the sender. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int helo(final String hostname) throws IOException - { - return sendCommand(SMTPCommand.HELO, hostname); - } - - - /** - * A convenience method to send the SMTP MAIL command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int mail(final String reversePath) throws IOException - { - return sendCommand(SMTPCommand.MAIL, reversePath, false); - } - - - /** - * A convenience method to send the SMTP RCPT command to the server, - * receive the reply, and return the reply code. - *

- * @param forwardPath The forward path. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rcpt(final String forwardPath) throws IOException - { - return sendCommand(SMTPCommand.RCPT, forwardPath, false); - } - - - /** - * A convenience method to send the SMTP DATA command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int data() throws IOException - { - return sendCommand(SMTPCommand.DATA); - } - - - /** - * A convenience method to send the SMTP SEND command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int send(final String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SEND, reversePath); - } - - - /** - * A convenience method to send the SMTP SOML command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int soml(final String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SOML, reversePath); - } - - - /** - * A convenience method to send the SMTP SAML command to the server, - * receive the reply, and return the reply code. - *

- * @param reversePath The reverese path. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int saml(final String reversePath) throws IOException - { - return sendCommand(SMTPCommand.SAML, reversePath); - } - - - /** - * A convenience method to send the SMTP RSET command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int rset() throws IOException - { - return sendCommand(SMTPCommand.RSET); - } - - - /** - * A convenience method to send the SMTP VRFY command to the server, - * receive the reply, and return the reply code. - *

- * @param user The user address to verify. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int vrfy(final String user) throws IOException - { - return sendCommand(SMTPCommand.VRFY, user); - } - - - /** - * A convenience method to send the SMTP VRFY command to the server, - * receive the reply, and return the reply code. - *

- * @param name The name to expand. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int expn(final String name) throws IOException - { - return sendCommand(SMTPCommand.EXPN, name); - } - - /** - * A convenience method to send the SMTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int help() throws IOException - { - return sendCommand(SMTPCommand.HELP); - } - - /** - * A convenience method to send the SMTP HELP command to the server, - * receive the reply, and return the reply code. - *

- * @param command The command name on which to request help. - * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int help(final String command) throws IOException - { - return sendCommand(SMTPCommand.HELP, command); - } - - /** - * A convenience method to send the SMTP NOOP command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int noop() throws IOException - { - return sendCommand(SMTPCommand.NOOP); - } - - - /** - * A convenience method to send the SMTP TURN command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int turn() throws IOException - { - return sendCommand(SMTPCommand.TURN); - } - - - /** - * A convenience method to send the SMTP QUIT command to the server, - * receive the reply, and return the reply code. - *

- * @return The reply code received from the server. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int quit() throws IOException - { - return sendCommand(SMTPCommand.QUIT); - } - - /** - * Removes a ProtocolCommandListener. - * - * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to - * the correct method {@link SocketClient#removeProtocolCommandListener} - * @param listener The ProtocolCommandListener to remove - */ - public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener){ - removeProtocolCommandListener(listener); - } - - /** - * Provide command support to super-class - */ - @Override - protected ProtocolCommandSupport getCommandSupport() { - return _commandSupport_; - } -} diff --git a/src/org/apache/commons/net/smtp/SMTPClient.java b/src/org/apache/commons/net/smtp/SMTPClient.java deleted file mode 100644 index 7f434f93..00000000 --- a/src/org/apache/commons/net/smtp/SMTPClient.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.IOException; -import java.io.Writer; -import java.net.InetAddress; - -import org.apache.commons.net.io.DotTerminatedMessageWriter; - -/** - * SMTPClient encapsulates all the functionality necessary to send files - * through an SMTP server. This class takes care of all - * low level details of interacting with an SMTP server and provides - * a convenient higher level interface. As with all classes derived - * from {@link org.apache.commons.net.SocketClient}, - * you must first connect to the server with - * {@link org.apache.commons.net.SocketClient#connect connect } - * before doing anything, and finally - * {@link org.apache.commons.net.SocketClient#disconnect disconnect } - * after you're completely finished interacting with the server. - * Then you need to check the SMTP reply code to see if the connection - * was successful. For example: - *

- *    try {
- *      int reply;
- *      client.connect("mail.foobar.com");
- *      System.out.print(client.getReplyString());
- *
- *      // After connection attempt, you should check the reply code to verify
- *      // success.
- *      reply = client.getReplyCode();
- *
- *      if(!SMTPReply.isPositiveCompletion(reply)) {
- *        client.disconnect();
- *        System.err.println("SMTP server refused connection.");
- *        System.exit(1);
- *      }
- *
- *      // Do useful stuff here.
- *      ...
- *    } catch(IOException e) {
- *      if(client.isConnected()) {
- *        try {
- *          client.disconnect();
- *        } catch(IOException f) {
- *          // do nothing
- *        }
- *      }
- *      System.err.println("Could not connect to server.");
- *      e.printStackTrace();
- *      System.exit(1);
- *    }
- * 
- *

- * Immediately after connecting is the only real time you need to check the - * reply code (because connect is of type void). The convention for all the - * SMTP command methods in SMTPClient is such that they either return a - * boolean value or some other value. - * The boolean methods return true on a successful completion reply from - * the SMTP server and false on a reply resulting in an error condition or - * failure. The methods returning a value other than boolean return a value - * containing the higher level data produced by the SMTP command, or null if a - * reply resulted in an error condition or failure. If you want to access - * the exact SMTP reply code causing a success or failure, you must call - * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after - * a success or failure. - *

- * You should keep in mind that the SMTP server may choose to prematurely - * close a connection for various reasons. The SMTPClient class will detect a - * premature SMTP server connection closing when it receives a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the method encountering that reply will throw - * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * . - * SMTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by SMTPClient. Before disconnecting, you may check - * the last reply code and text with - * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode }, - * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString }, - * and - * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link org.apache.commons.net.MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * @see SMTP - * @see SimpleSMTPHeader - * @see RelayPath - * @see SMTPConnectionClosedException - * @see org.apache.commons.net.MalformedServerReplyException - */ - -public class SMTPClient extends SMTP -{ - - /** - * Default SMTPClient constructor. Creates a new SMTPClient instance. - */ - public SMTPClient() { } - - /** - * Overloaded constructor that takes an encoding specification - * @param encoding The encoding to use - * @since 2.0 - */ - public SMTPClient(final String encoding) { - super(encoding); - } - - - /** - * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) - * does not complete the entire sequence of SMTP commands to complete a - * transaction. These types of commands require some action by the - * programmer after the reception of a positive intermediate command. - * After the programmer's code completes its actions, it must call this - * method to receive the completion reply from the server and verify the - * success of the entire transaction. - *

- * For example, - *

-     * writer = client.sendMessageData();
-     * if(writer == null) // failure
-     *   return false;
-     * header =
-     *  new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo");
-     * writer.write(header.toString());
-     * writer.write("This is just a test");
-     * writer.close();
-     * if(!client.completePendingCommand()) // failure
-     *   return false;
-     * 
- *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean completePendingCommand() throws IOException - { - return SMTPReply.isPositiveCompletion(getReply()); - } - - - /** - * Login to the SMTP server by sending the HELO command with the - * given hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @param hostname The hostname with which to greet the SMTP server. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login(final String hostname) throws IOException - { - return SMTPReply.isPositiveCompletion(helo(hostname)); - } - - - /** - * Login to the SMTP server by sending the HELO command with the - * client hostname as an argument. Before performing any mail commands, - * you must first login. - *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login() throws IOException - { - final String name; - final InetAddress host; - - host = getLocalAddress(); - name = host.getHostName(); - - if (name == null) { - return false; - } - - return SMTPReply.isPositiveCompletion(helo(name)); - } - - - /** - * Set the sender of a message using the SMTP MAIL command, specifying - * a reverse relay path. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param path The reverse relay path pointing back to the sender. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setSender(final RelayPath path) throws IOException - { - return SMTPReply.isPositiveCompletion(mail(path.toString())); - } - - - /** - * Set the sender of a message using the SMTP MAIL command, specifying - * the sender's email address. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param address The sender's email address. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setSender(final String address) throws IOException - { - return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); - } - - - /** - * Add a recipient for a message using the SMTP RCPT command, specifying - * a forward relay path. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param path The forward relay path pointing to the recipient. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean addRecipient(final RelayPath path) throws IOException - { - return SMTPReply.isPositiveCompletion(rcpt(path.toString())); - } - - - /** - * Add a recipient for a message using the SMTP RCPT command, the - * recipient's email address. The sender must be set first before any - * recipients may be specified, otherwise the mail server will reject - * your commands. - *

- * @param address The recipient's email address. - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean addRecipient(final String address) throws IOException - { - return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); - } - - - - /** - * Send the SMTP DATA command in preparation to send an email message. - * This method returns a DotTerminatedMessageWriter instance to which - * the message can be written. Null is returned if the DATA command - * fails. - *

- * You must not issue any commands to the SMTP server (i.e., call any - * (other methods) until you finish writing to the returned Writer - * instance and close it. The SMTP protocol uses the same stream for - * issuing commands as it does for returning results. Therefore the - * returned Writer actually writes directly to the SMTP connection. - * After you close the writer, you can execute new commands. If you - * do not follow these requirements your program will not work properly. - *

- * You can use the provided - * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} - * class to construct a bare minimum header. - * To construct more complicated headers you should - * refer to RFC 5322. When the Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - * The DotTerminatedMessageWriter takes care of doubling line-leading - * dots and ending the message with a single dot upon closing, so all - * you have to worry about is writing the header and the message. - *

- * Upon closing the returned Writer, you need to call - * {@link #completePendingCommand completePendingCommand() } - * to finalize the transaction and verify its success or failure from - * the server reply. - *

- * @return A DotTerminatedMessageWriter to which the message (including - * header) can be written. Returns null if the command fails. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @see #sendShortMessageData(String) - */ - public Writer sendMessageData() throws IOException - { - if (!SMTPReply.isPositiveIntermediate(data())) { - return null; - } - - return new DotTerminatedMessageWriter(writer); - } - - - /** - * A convenience method for sending short messages. This method fetches - * the Writer returned by {@link #sendMessageData sendMessageData() } - * and writes the specified String to it. After writing the message, - * this method calls {@link #completePendingCommand completePendingCommand() } - * to finalize the transaction and returns - * its success or failure. - *

- * @param message The short email message to send. - * This must include the headers and the body, but not the trailing "." - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendShortMessageData(final String message) throws IOException - { - try (final Writer writer = sendMessageData()) { - - if (writer == null) { - return false; - } - - writer.write(message); - } - - return completePendingCommand(); - } - - - /** - * A convenience method for a sending short email without having to - * explicitly set the sender and recipient(s). This method - * sets the sender and recipient using - * {@link #setSender setSender } and - * {@link #addRecipient addRecipient }, and then sends the - * message using {@link #sendShortMessageData sendShortMessageData }. - *

- * @param sender The email address of the sender. - * @param recipient The email address of the recipient. - * @param message The short email message to send. - * This must include the headers and the body, but not the trailing "." - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendSimpleMessage(final String sender, final String recipient, - final String message) - throws IOException - { - if (!setSender(sender)) { - return false; - } - - if (!addRecipient(recipient)) { - return false; - } - - return sendShortMessageData(message); - } - - - - /** - * A convenience method for a sending short email without having to - * explicitly set the sender and recipient(s). This method - * sets the sender and recipients using - * {@link #setSender(String) setSender} and - * {@link #addRecipient(String) addRecipient}, and then sends the - * message using {@link #sendShortMessageData(String) sendShortMessageData}. - *

- * Note that the method ignores failures when calling - * {@link #addRecipient(String) addRecipient} so long as - * at least one call succeeds. If no recipients can be successfully - * added then the method will fail (and does not attempt to - * send the message) - *

- * @param sender The email address of the sender. - * @param recipients An array of recipient email addresses. - * @param message The short email message to send. - * This must include the headers and the body, but not the trailing "." - * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendSimpleMessage(final String sender, final String[] recipients, - final String message) - throws IOException - { - boolean oneSuccess = false; - int count; - - if (!setSender(sender)) { - return false; - } - - for (count = 0; count < recipients.length; count++) - { - if (addRecipient(recipients[count])) { - oneSuccess = true; - } - } - - if (!oneSuccess) { - return false; - } - - return sendShortMessageData(message); - } - - - /** - * Logout of the SMTP server by sending the QUIT command. - *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean logout() throws IOException - { - return SMTPReply.isPositiveCompletion(quit()); - } - - - - /** - * Aborts the current mail transaction, resetting all server stored - * sender, recipient, and mail data, cleaing all buffers and tables. - *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean reset() throws IOException - { - return SMTPReply.isPositiveCompletion(rset()); - } - - - /** - * Verify that a username or email address is valid, i.e., that mail - * can be delivered to that mailbox on the server. - *

- * @param username The username or email address to validate. - * @return True if the username is valid, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean verify(final String username) throws IOException - { - final int result; - - result = vrfy(username); - - return result == SMTPReply.ACTION_OK || - result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD; - } - - - /** - * Fetches the system help information from the server and returns the - * full string. - *

- * @return The system help string obtained from the server. null if the - * information could not be obtained. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp() throws IOException - { - if (SMTPReply.isPositiveCompletion(help())) { - return getReplyString(); - } - return null; - } - - - /** - * Fetches the help information for a given command from the server and - * returns the full string. - *

- * @param command The command on which to ask for help. - * @return The command help string obtained from the server. null if the - * information could not be obtained. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp(final String command) throws IOException - { - if (SMTPReply.isPositiveCompletion(help(command))) { - return getReplyString(); - } - return null; - } - - - /** - * Sends a NOOP command to the SMTP server. This is useful for preventing - * server timeouts. - *

- * @return True if successfully completed, false if not. - * @throws SMTPConnectionClosedException - * If the SMTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send SMTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendNoOp() throws IOException - { - return SMTPReply.isPositiveCompletion(noop()); - } - -} diff --git a/src/org/apache/commons/net/smtp/SMTPCommand.java b/src/org/apache/commons/net/smtp/SMTPCommand.java deleted file mode 100644 index 69051dca..00000000 --- a/src/org/apache/commons/net/smtp/SMTPCommand.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -/** - * SMTPCommand stores a set of constants for SMTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 821 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 821. For those who think in terms of the actual SMTP commands, - * a set of constants such as {@link #HELO HELO } are provided - * where the constant name is the same as the SMTP command. - */ - -public final class SMTPCommand -{ - - - public static final int HELO = 0; - public static final int MAIL = 1; - public static final int RCPT = 2; - public static final int DATA = 3; - public static final int SEND = 4; - public static final int SOML = 5; - public static final int SAML = 6; - public static final int RSET = 7; - public static final int VRFY = 8; - public static final int EXPN = 9; - public static final int HELP = 10; - public static final int NOOP = 11; - public static final int TURN = 12; - public static final int QUIT = 13; - - /** - * The authorization command - * @since 3.0 - */ - public static final int AUTH = 14 ; - - /** - * The extended hello command - * @since 3.0 - */ - public static final int EHLO = 15 ; - - private static final int NEXT = EHLO + 1; // update as necessary when adding new entries - - public static final int HELLO = HELO; - public static final int LOGIN = HELO; - public static final int MAIL_FROM = MAIL; - public static final int RECIPIENT = RCPT; - public static final int SEND_MESSAGE_DATA = DATA; - public static final int SEND_FROM = SEND; - public static final int SEND_OR_MAIL_FROM = SOML; - public static final int SEND_AND_MAIL_FROM = SAML; - public static final int RESET = RSET; - public static final int VERIFY = VRFY; - public static final int EXPAND = EXPN; - // public static final int HELP = HELP; - // public static final int NOOP = NOOP; - // public static final int TURN = TURN; - // public static final int QUIT = QUIT; - public static final int LOGOUT = QUIT; - - // Cannot be instantiated - private SMTPCommand() - {} - - private static final String[] commands = { - "HELO", "MAIL FROM:", "RCPT TO:", "DATA", "SEND FROM:", "SOML FROM:", - "SAML FROM:", "RSET", "VRFY", "EXPN", "HELP", "NOOP", "TURN", "QUIT", - "AUTH", "EHLO" - }; - - - static { - if (commands.length != NEXT) { - throw new RuntimeException("Error in array definition"); - } - } - - /** - * Retrieve the SMTP protocol command string corresponding to a specified - * command code. - *

- * @param command The command code. - * @return The SMTP protcol command string corresponding to a specified - * command code. - */ - public static String getCommand(final int command) - { - return commands[command]; - } - -} diff --git a/src/org/apache/commons/net/smtp/SMTPConnectionClosedException.java b/src/org/apache/commons/net/smtp/SMTPConnectionClosedException.java deleted file mode 100644 index e3bf40ce..00000000 --- a/src/org/apache/commons/net/smtp/SMTPConnectionClosedException.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.IOException; - -/** - * SMTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an SMTP connection resulting from a - * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } - * response (SMTP reply code 421) to a - * failed SMTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * SMTPConnectionClosedException. - * - * - * @see SMTP - * @see SMTPClient - */ - -public final class SMTPConnectionClosedException extends IOException -{ - - private static final long serialVersionUID = 626520434326660627L; - - /** Constructs a SMTPConnectionClosedException with no message */ - public SMTPConnectionClosedException() - { - } - - /** - * Constructs a SMTPConnectionClosedException with a specified message. - * - * @param message The message explaining the reason for the exception. - */ - public SMTPConnectionClosedException(final String message) - { - super(message); - } - -} diff --git a/src/org/apache/commons/net/smtp/SMTPReply.java b/src/org/apache/commons/net/smtp/SMTPReply.java deleted file mode 100644 index 8906f5b4..00000000 --- a/src/org/apache/commons/net/smtp/SMTPReply.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -/** - * SMTPReply stores a set of constants for SMTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 821 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 821. - */ - -public final class SMTPReply -{ - - public static final int SYSTEM_STATUS = 211; - public static final int HELP_MESSAGE = 214; - public static final int SERVICE_READY = 220; - public static final int SERVICE_CLOSING_TRANSMISSION_CHANNEL = 221; - public static final int ACTION_OK = 250; - public static final int USER_NOT_LOCAL_WILL_FORWARD = 251; - public static final int START_MAIL_INPUT = 354; - public static final int SERVICE_NOT_AVAILABLE = 421; - public static final int ACTION_NOT_TAKEN = 450; - public static final int ACTION_ABORTED = 451; - public static final int INSUFFICIENT_STORAGE = 452; - public static final int UNRECOGNIZED_COMMAND = 500; - public static final int SYNTAX_ERROR_IN_ARGUMENTS = 501; - public static final int COMMAND_NOT_IMPLEMENTED = 502; - public static final int BAD_COMMAND_SEQUENCE = 503; - public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = 504; - public static final int MAILBOX_UNAVAILABLE = 550; - public static final int USER_NOT_LOCAL = 551; - public static final int STORAGE_ALLOCATION_EXCEEDED = 552; - public static final int MAILBOX_NAME_NOT_ALLOWED = 553; - public static final int TRANSACTION_FAILED = 554; - - // Cannot be instantiated - private SMTPReply() - {} - - /** - * Determine if a reply code is a positive preliminary response. All - * codes beginning with a 1 are positive preliminary responses. - * Postitive preliminary responses are used to indicate tentative success. - * No further commands can be issued to the SMTP server after a positive - * preliminary response until a follow up response is received from the - * server. - *

- * Note: No SMTP commands defined in RFC 822 provide this - * type of reply. - *

- * @param reply The reply code to test. - * @return True if a reply code is a positive preliminary response, false - * if not. - */ - public static boolean isPositivePreliminary(final int reply) - { - return reply >= 100 && reply < 200; - } - - /** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The SMTP server will send a positive completion response on the final - * successful completion of a command. - *

- * @param reply The reply code to test. - * @return True if a reply code is a positive completion response, false - * if not. - */ - public static boolean isPositiveCompletion(final int reply) - { - return reply >= 200 && reply < 300; - } - - /** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The SMTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part sequence of - * commands. For example, after a successful DATA command, a positive - * intermediate response will be sent to indicate that the server is - * ready to receive the message data. - *

- * @param reply The reply code to test. - * @return True if a reply code is a positive intermediate response, false - * if not. - */ - public static boolean isPositiveIntermediate(final int reply) - { - return reply >= 300 && reply < 400; - } - - /** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The SMTP server will send a negative transient response on the - * failure of a command that can be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - */ - public static boolean isNegativeTransient(final int reply) - { - return reply >= 400 && reply < 500; - } - - /** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The SMTP server will send a negative permanent response on the - * failure of a command that cannot be reattempted with success. - *

- * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - */ - public static boolean isNegativePermanent(final int reply) - { - return reply >= 500 && reply < 600; - } - -} diff --git a/src/org/apache/commons/net/smtp/SMTPSClient.java b/src/org/apache/commons/net/smtp/SMTPSClient.java deleted file mode 100644 index 9f333bf4..00000000 --- a/src/org/apache/commons/net/smtp/SMTPSClient.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.commons.net.io.CRLFLineReader; -import org.apache.commons.net.util.SSLContextUtils; -import org.apache.commons.net.util.SSLSocketUtils; - -/** - * SMTP over SSL processing. Copied from FTPSClient.java and modified to suit SMTP. - * If implicit mode is selected (NOT the default), SSL/TLS negotiation starts right - * after the connection has been established. In explicit mode (the default), SSL/TLS - * negotiation starts when the user calls execTLS() and the server accepts the command. - * Implicit usage: - *

- *               SMTPSClient c = new SMTPSClient(true);
- *               c.connect("127.0.0.1", 465);
- * 
- * Explicit usage: - *
- *               SMTPSClient c = new SMTPSClient();
- *               c.connect("127.0.0.1", 25);
- *               if (c.execTLS()) {
- *                 // Rest of the commands here
- *               }
- * 
- * Warning: the hostname is not verified against the certificate by default, use - * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} - * (on Java 1.7+) to enable verification. - * @since 3.0 - */ -public class SMTPSClient extends SMTPClient -{ - /** Default secure socket protocol name, like TLS */ - private static final String DEFAULT_PROTOCOL = "TLS"; - - /** The security mode. True - Implicit Mode / False - Explicit Mode. */ - - private final boolean isImplicit; - /** The secure socket protocol to be used, like SSL/TLS. */ - - private final String protocol; - /** The context object. */ - - private SSLContext context; - /** The cipher suites. SSLSockets have a default set of these anyway, - so no initialization required. */ - - private String[] suites; - /** The protocol versions. */ - - private String[] protocols; - - /** The {@link TrustManager} implementation, default null (i.e. use system managers). */ - private TrustManager trustManager; - - /** The {@link KeyManager}, default null (i.e. use system managers). */ - private KeyManager keyManager; // seems not to be required - - /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ - private HostnameVerifier hostnameVerifier; - - /** Use Java 1.7+ HTTPS Endpoint Identification Algorithim. */ - private boolean tlsEndpointChecking; - - /** - * Constructor for SMTPSClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * Sets security mode to explicit (isImplicit = false). - */ - public SMTPSClient() - { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for SMTPSClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - */ - public SMTPSClient(final boolean implicit) - { - this(DEFAULT_PROTOCOL, implicit); - } - - /** - * Constructor for SMTPSClient, using explicit security mode. - * @param proto the protocol. - */ - public SMTPSClient(final String proto) - { - this(proto, false); - } - - /** - * Constructor for SMTPSClient. - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - */ - public SMTPSClient(final String proto, final boolean implicit) - { - protocol = proto; - isImplicit = implicit; - } - - /** - * Constructor for SMTPSClient. - * @param proto the protocol. - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param encoding the encoding - * @since 3.3 - */ - public SMTPSClient(final String proto, final boolean implicit, final String encoding) - { - super(encoding); - protocol = proto; - isImplicit = implicit; - } - - /** - * Constructor for SMTPSClient, using {@link #DEFAULT_PROTOCOL} i.e. TLS - * @param implicit The security mode, {@code true} for implicit, {@code false} for explicit - * @param ctx A pre-configured SSL Context. - */ - public SMTPSClient(final boolean implicit, final SSLContext ctx) - { - isImplicit = implicit; - context = ctx; - protocol = DEFAULT_PROTOCOL; - } - - /** - * Constructor for SMTPSClient. - * @param context A pre-configured SSL Context. - * @see #SMTPSClient(boolean, SSLContext) - */ - public SMTPSClient(final SSLContext context) - { - this(false, context); - } - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * @throws IOException If it is thrown by _connectAction_(). - * @see org.apache.commons.net.SocketClient#_connectAction_() - */ - @Override - protected void _connectAction_() throws IOException - { - // Implicit mode. - if (isImplicit) { - applySocketAttributes(); - performSSLNegotiation(); - } - super._connectAction_(); - // Explicit mode - don't do anything. The user calls execTLS() - } - - /** - * Performs a lazy init of the SSL context. - * @throws IOException When could not initialize the SSL context. - */ - private void initSSLContext() throws IOException - { - if (context == null) - { - context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a - * connection and carries out handshake processing. - * @throws IOException If server negotiation fails. - */ - private void performSSLNegotiation() throws IOException - { - initSSLContext(); - - final SSLSocketFactory ssf = context.getSocketFactory(); - final String host = _hostname_ != null ? _hostname_ : getRemoteAddress().getHostAddress(); - final int port = getRemotePort(); - final SSLSocket socket = - (SSLSocket) ssf.createSocket(_socket_, host, port, true); - socket.setEnableSessionCreation(true); - socket.setUseClientMode(true); - - if (tlsEndpointChecking) { - SSLSocketUtils.enableEndpointNameVerification(socket); - } - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - if (suites != null) { - socket.setEnabledCipherSuites(suites); - } - socket.startHandshake(); - - // TODO the following setup appears to duplicate that in the super class methods - _socket_ = socket; - _input_ = socket.getInputStream(); - _output_ = socket.getOutputStream(); - reader = new CRLFLineReader( - new InputStreamReader(_input_, encoding)); - writer = new BufferedWriter( - new OutputStreamWriter(_output_, encoding)); - - if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { - throw new SSLHandshakeException("Hostname doesn't match certificate"); - } - } - - /** - * Get the {@link KeyManager} instance. - * @return The current {@link KeyManager} instance. - */ - public KeyManager getKeyManager() - { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use. - * @param newKeyManager The KeyManager implementation to set. - * @see org.apache.commons.net.util.KeyManagerUtils - */ - public void setKeyManager(final KeyManager newKeyManager) - { - keyManager = newKeyManager; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. Called before server negotiation. - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(final String[] cipherSuites) - { - suites = cipherSuites.clone(); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of cipher suite names, or null. - */ - public String[] getEnabledCipherSuites() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledCipherSuites(); - } - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(final String[] protocolVersions) - { - protocols = protocolVersions.clone(); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When the underlying {@link java.net.Socket Socket} is not an {@link SSLSocket} instance, returns null. - * @return An array of protocols, or null. - */ - public String[] getEnabledProtocols() - { - if (_socket_ instanceof SSLSocket) - { - return ((SSLSocket)_socket_).getEnabledProtocols(); - } - return null; - } - - /** - * The TLS command execution. - * @throws IOException If an I/O error occurs while sending - * the command or performing the negotiation. - * @return TRUE if the command and negotiation succeeded. - */ - public boolean execTLS() throws IOException - { - if (!SMTPReply.isPositiveCompletion(sendCommand("STARTTLS"))) - { - return false; - //throw new SSLException(getReplyString()); - } - performSSLNegotiation(); - return true; - } - - /** - * Get the currently configured {@link TrustManager}. - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() - { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use. - * @param newTrustManager The TrustManager implementation to set. - * @see org.apache.commons.net.util.TrustManagerUtils - */ - public void setTrustManager(final TrustManager newTrustManager) - { - trustManager = newTrustManager; - } - - /** - * Get the currently configured {@link HostnameVerifier}. - * @return A HostnameVerifier instance. - * @since 3.4 - */ - public HostnameVerifier getHostnameVerifier() - { - return hostnameVerifier; - } - - /** - * Override the default {@link HostnameVerifier} to use. - * @param newHostnameVerifier The HostnameVerifier implementation to set or null to disable. - * @since 3.4 - */ - public void setHostnameVerifier(final HostnameVerifier newHostnameVerifier) - { - hostnameVerifier = newHostnameVerifier; - } - - /** - * Return whether or not endpoint identification using the HTTPS algorithm - * on Java 1.7+ is enabled. The default behavior is for this to be disabled. - * - * @return True if enabled, false if not. - * @since 3.4 - */ - public boolean isEndpointCheckingEnabled() - { - return tlsEndpointChecking; - } - - /** - * Automatic endpoint identification checking using the HTTPS algorithm - * is supported on Java 1.7+. The default behavior is for this to be disabled. - * - * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. - * @since 3.4 - */ - public void setEndpointCheckingEnabled(final boolean enable) - { - tlsEndpointChecking = enable; - } -} - -/* kate: indent-width 4; replace-tabs on; */ diff --git a/src/org/apache/commons/net/smtp/SimpleSMTPHeader.java b/src/org/apache/commons/net/smtp/SimpleSMTPHeader.java deleted file mode 100644 index f3513c24..00000000 --- a/src/org/apache/commons/net/smtp/SimpleSMTPHeader.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.smtp; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * This class is used to construct a bare minimum - * acceptable header for an email message. To construct more - * complicated headers you should refer to RFC 5322. When the - * Java Mail API is finalized, you will be - * able to use it to compose fully compliant Internet text messages. - *

- * The main purpose of the class is to faciliatate the mail sending - * process, by relieving the programmer from having to explicitly format - * a simple message header. For example: - *

- * writer = client.sendMessageData();
- * if(writer == null) // failure
- *   return false;
- * header =
- *    new SimpleSMTPHeader("foobar@foo.com", "foo@bar.com" "Just testing");
- * header.addCC("bar@foo.com");
- * header.addHeaderField("Organization", "Foobar, Inc.");
- * writer.write(header.toString());
- * writer.write("This is just a test");
- * writer.close();
- * if(!client.completePendingCommand()) // failure
- *   return false;
- * 
- * - * @see SMTPClient - */ - -public class SimpleSMTPHeader -{ - private final String subject; - private final String from; - private final String to; - private final StringBuffer headerFields; - private boolean hasHeaderDate; - private StringBuffer cc; - - /** - * Creates a new SimpleSMTPHeader instance initialized with the given - * from, to, and subject header field values. - *

- * @param from The value of the From: header field. This - * should be the sender's email address. - * Must not be null. - * @param to The value of the To: header field. This - * should be the recipient's email address. - * May be null - * @param subject The value of the Subject: header field. - * This should be the subject of the message. - * May be null - */ - public SimpleSMTPHeader(final String from, final String to, final String subject) - { - if (from == null) { - throw new IllegalArgumentException("From cannot be null"); - } - this.to = to; - this.from = from; - this.subject = subject; - this.headerFields = new StringBuffer(); - this.cc = null; - } - - /** - * Adds an arbitrary header field with the given value to the article - * header. These headers will be written before the From, To, Subject, and - * Cc fields when the SimpleSMTPHeader is convertered to a string. - * An example use would be: - *

-     * header.addHeaderField("Organization", "Foobar, Inc.");
-     * 
- *

- * @param headerField The header field to add, not including the colon. - * @param value The value of the added header field. - */ - public void addHeaderField(final String headerField, final String value) - { - if (!hasHeaderDate && "Date".equals(headerField)) { - hasHeaderDate = true; - } - headerFields.append(headerField); - headerFields.append(": "); - headerFields.append(value); - headerFields.append('\n'); - } - - - /** - * Add an email address to the CC (carbon copy or courtesy copy) list. - *

- * @param address The email address to add to the CC list. - */ - public void addCC(final String address) - { - if (cc == null) { - cc = new StringBuffer(); - } else { - cc.append(", "); - } - - cc.append(address); - } - - - /** - * Converts the SimpleSMTPHeader to a properly formatted header in - * the form of a String, including the blank line used to separate - * the header from the article body. The header fields CC and Subject - * are only included when they are non-null. - *

- * @return The message header in the form of a String. - */ - @Override - public String toString() - { - final StringBuilder header = new StringBuilder(); - - final String pattern = "EEE, dd MMM yyyy HH:mm:ss Z"; // Fri, 21 Nov 1997 09:55:06 -0600 - final SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.ENGLISH); - - if (!hasHeaderDate) { - addHeaderField("Date", format.format(new Date())); - } - if (headerFields.length() > 0) { - header.append(headerFields.toString()); - } - - header.append("From: ").append(from).append("\n"); - - if (to != null) { - header.append("To: ").append(to).append("\n"); - } - - if (cc != null) - { - header.append("Cc: ").append(cc.toString()).append("\n"); - } - - if (subject != null) - { - header.append("Subject: ").append(subject).append("\n"); - } - - header.append('\n'); // end of headers; body follows - - return header.toString(); - } -} - - - diff --git a/src/org/apache/commons/net/smtp/package-info.java b/src/org/apache/commons/net/smtp/package-info.java deleted file mode 100644 index 59af64a8..00000000 --- a/src/org/apache/commons/net/smtp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * SMTP and SMTPS mail - */ -package org.apache.commons.net.smtp; \ No newline at end of file diff --git a/src/org/apache/commons/net/util/Base64.java b/src/org/apache/commons/net/util/Base64.java deleted file mode 100644 index 96e02046..00000000 --- a/src/org/apache/commons/net/util/Base64.java +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.util; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; - - -/** - * Provides Base64 encoding and decoding as defined by RFC 2045. - * - *

- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose - * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and Borenstein. - *

- *

- * The class can be parameterized in the following manner with various constructors: - *

    - *
  • URL-safe mode: Default off.
  • - *
  • Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of - * 4 in the encoded data. - *
  • Line separator: Default is CRLF ("\r\n")
  • - *
- *

- * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode - * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). - *

- * - * @see RFC 2045 - * @since 2.2 - */ -public class Base64 { - private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; - - private static final int DEFAULT_BUFFER_SIZE = 8192; - - /** - * Chunk size per RFC 2045 section 6.8. - * - *

- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any - * equal signs. - *

- * - * @see RFC 2045 section 6.8 - */ - static final int CHUNK_SIZE = 76; - - /** - * Chunk separator per RFC 2045 section 2.1. - * - * @see RFC 2045 section 2.1 - */ - private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; - - /** - * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" - * equivalents as specified in Table 1 of RFC 2045. - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] STANDARD_ENCODE_TABLE = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / - * changed to - and _ to make the encoded Base64 results more URL-SAFE. - * This table is only used when the Base64's mode is set to URL-SAFE. - */ - private static final byte[] URL_SAFE_ENCODE_TABLE = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' - }; - - /** - * Byte used to pad output. - */ - private static final byte PAD = '='; - - /** - * This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in - * Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64 - * alphabet but fall within the bounds of the array are translated to -1. - * - * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both - * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit). - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] DECODE_TABLE = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - }; - - /** Mask used to extract 6 bits, used when encoding */ - private static final int MASK_6BITS = 0x3f; - - /** Mask used to extract 8 bits, used in decoding base64 bytes */ - private static final int MASK_8BITS = 0xff; - - // The static final fields above are used for the original static byte[] methods on Base64. - // The private member fields below are used with the new streaming approach, which requires - // some state be preserved between calls of encode() and decode(). - - /** - * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able - * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch - * between the two modes. - */ - private final byte[] encodeTable; - - /** - * Line length for encoding. Not used when decoding. A value of zero or less implies no chunking of the base64 - * encoded data. - */ - private final int lineLength; - - /** - * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. - */ - private final byte[] lineSeparator; - - /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. - * decodeSize = 3 + lineSeparator.length; - */ - private final int decodeSize; - - /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing. - * encodeSize = 4 + lineSeparator.length; - */ - private final int encodeSize; - - /** - * Buffer for streaming. - */ - private byte[] buffer; - - /** - * Position where next character should be written in the buffer. - */ - private int pos; - - /** - * Position where next character should be read from the buffer. - */ - private int readPos; - - /** - * Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to - * make sure each encoded line never goes beyond lineLength (if lineLength > 0). - */ - private int currentLinePos; - - /** - * Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when decoding. This variable - * helps track that. - */ - private int modulus; - - /** - * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64 object becomes useless, - * and must be thrown away. - */ - private boolean eof; - - /** - * Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store and extract the - * base64 encoding or decoding from this variable. - */ - private int x; - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. - *

- * - *

- * When decoding all variants are supported. - *

- */ - public Base64() { - this(false); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. - *

- * When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE. - *

- * - *

- * When decoding all variants are supported. - *

- * - * @param urlSafe - * if true, URL-safe encoding is used. In most cases this should be set to - * false. - * @since 1.4 - */ - public Base64(final boolean urlSafe) { - this(CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength - * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. - * @since 1.4 - */ - public Base64(final int lineLength) { - this(lineLength, CHUNK_SEPARATOR); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length and line separator are given in the constructor, and the encoding table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength - * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. - * @param lineSeparator - * Each line of encoded data will end with this sequence of bytes. - * @throws IllegalArgumentException - * Thrown when the provided lineSeparator included some base64 characters. - * @since 1.4 - */ - public Base64(final int lineLength, final byte[] lineSeparator) { - this(lineLength, lineSeparator, false); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length and line separator are given in the constructor, and the encoding table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength - * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored when decoding. - * @param lineSeparator - * Each line of encoded data will end with this sequence of bytes. - * @param urlSafe - * Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode - * operations. Decoding seamlessly handles both modes. - * @throws IllegalArgumentException - * The provided lineSeparator included some base64 characters. That's not going to work! - * @since 1.4 - */ - public Base64(int lineLength, byte[] lineSeparator, final boolean urlSafe) { - if (lineSeparator == null) { - lineLength = 0; // disable chunk-separating - lineSeparator = NetConstants.EMPTY_BTYE_ARRAY; // this just gets ignored - } - this.lineLength = lineLength > 0 ? (lineLength / 4) * 4 : 0; - this.lineSeparator = new byte[lineSeparator.length]; - System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); - if (lineLength > 0) { - this.encodeSize = 4 + lineSeparator.length; - } else { - this.encodeSize = 4; - } - this.decodeSize = this.encodeSize - 1; - if (containsBase64Byte(lineSeparator)) { - final String sep = newStringUtf8(lineSeparator); - throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]"); - } - this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; - } - - /** - * Returns our current encode mode. True if we're URL-SAFE, false otherwise. - * - * @return true if we're in URL-SAFE mode, false otherwise. - * @since 1.4 - */ - public boolean isUrlSafe() { - return this.encodeTable == URL_SAFE_ENCODE_TABLE; - } - - /** - * Returns true if this Base64 object has buffered data for reading. - * - * @return true if there is Base64 object still available for reading. - */ - boolean hasData() { - return this.buffer != null; - } - - /** - * Returns the amount of buffered data available for reading. - * - * @return The amount of buffered data available for reading. - */ - int avail() { - return buffer != null ? pos - readPos : 0; - } - - /** Doubles our buffer. */ - private void resizeBuffer() { - if (buffer == null) { - buffer = new byte[DEFAULT_BUFFER_SIZE]; - pos = 0; - readPos = 0; - } else { - final byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR]; - System.arraycopy(buffer, 0, b, 0, buffer.length); - buffer = b; - } - } - - /** - * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail - * bytes. Returns how many bytes were actually extracted. - * - * @param b - * byte[] array to extract the buffered data into. - * @param bPos - * position in byte[] array to start extraction at. - * @param bAvail - * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available). - * @return The number of bytes successfully extracted into the provided byte[] array. - */ - int readResults(final byte[] b, final int bPos, final int bAvail) { - if (buffer != null) { - final int len = Math.min(avail(), bAvail); - if (buffer != b) { - System.arraycopy(buffer, readPos, b, bPos, len); - readPos += len; - if (readPos >= pos) { - buffer = null; - } - } else { - // Re-using the original consumer's output array is only - // allowed for one round. - buffer = null; - } - return len; - } - return eof ? -1 : 0; - } - - /** - * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the consumer's output - * array for one round (if the consumer calls this method first) instead of starting our own buffer. - * - * @param out - * byte[] array to buffer directly to. - * @param outPos - * Position to start buffering into. - * @param outAvail - * Amount of bytes available for direct buffering. - */ - void setInitialBuffer(final byte[] out, final int outPos, final int outAvail) { - // We can re-use consumer's original output array under - // special circumstances, saving on some System.arraycopy(). - if (out != null && out.length == outAvail) { - buffer = out; - pos = outPos; - readPos = outPos; - } - } - - /** - *

- * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with - * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last - * remaining bytes (if not multiple of 3). - *

- *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- * - * @param in - * byte[] array of binary data to base64 encode. - * @param inPos - * Position to start reading data from. - * @param inAvail - * Amount of bytes available from input for encoding. - */ - void encode(final byte[] in, int inPos, final int inAvail) { - if (eof) { - return; - } - // inAvail < 0 is how we're informed of EOF in the underlying data we're - // encoding. - if (inAvail < 0) { - eof = true; - if (buffer == null || buffer.length - pos < encodeSize) { - resizeBuffer(); - } - switch (modulus) { - case 1 : - buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS]; - // URL-SAFE skips the padding to further reduce size. - if (encodeTable == STANDARD_ENCODE_TABLE) { - buffer[pos++] = PAD; - buffer[pos++] = PAD; - } - break; - - case 2 : - buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS]; - // URL-SAFE skips the padding to further reduce size. - if (encodeTable == STANDARD_ENCODE_TABLE) { - buffer[pos++] = PAD; - } - break; - default: - break; // other values ignored - } - if (lineLength > 0 && pos > 0) { - System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length); - pos += lineSeparator.length; - } - } else { - for (int i = 0; i < inAvail; i++) { - if (buffer == null || buffer.length - pos < encodeSize) { - resizeBuffer(); - } - modulus = (++modulus) % 3; - int b = in[inPos++]; - if (b < 0) { - b += 256; - } - x = (x << 8) + b; - if (0 == modulus) { - buffer[pos++] = encodeTable[(x >> 18) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 12) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 6) & MASK_6BITS]; - buffer[pos++] = encodeTable[x & MASK_6BITS]; - currentLinePos += 4; - if (lineLength > 0 && lineLength <= currentLinePos) { - System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length); - pos += lineSeparator.length; - currentLinePos = 0; - } - } - } - } - } - - /** - *

- * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once - * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1" - * call is not necessary when decoding, but it doesn't hurt, either. - *

- *

- * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are - * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in, - * garbage-out philosophy: it will not check the provided data for validity. - *

- *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- * - * @param in - * byte[] array of ascii data to base64 decode. - * @param inPos - * Position to start reading data from. - * @param inAvail - * Amount of bytes available from input for encoding. - */ - void decode(final byte[] in, int inPos, final int inAvail) { - if (eof) { - return; - } - if (inAvail < 0) { - eof = true; - } - for (int i = 0; i < inAvail; i++) { - if (buffer == null || buffer.length - pos < decodeSize) { - resizeBuffer(); - } - final byte b = in[inPos++]; - if (b == PAD) { - // We're done. - eof = true; - break; - } - if (b >= 0 && b < DECODE_TABLE.length) { - final int result = DECODE_TABLE[b]; - if (result >= 0) { - modulus = (++modulus) % 4; - x = (x << 6) + result; - if (modulus == 0) { - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS); - buffer[pos++] = (byte) (x & MASK_8BITS); - } - } - } - } - - // Two forms of EOF as far as base64 decoder is concerned: actual - // EOF (-1) and first time '=' character is encountered in stream. - // This approach makes the '=' padding characters completely optional. - if (eof && modulus != 0) { - x = x << 6; - switch (modulus) { - case 2 : - x = x << 6; - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - break; - case 3 : - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS); - break; - default: - break; // other values ignored - } - } - } - - /** - * Returns whether or not the octet is in the base 64 alphabet. - * - * @param octet - * The value to test - * @return true if the value is defined in the the base 64 alphabet, false otherwise. - * @since 1.4 - */ - public static boolean isBase64(final byte octet) { - return octet == PAD || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); - } - - /** - * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the - * method treats whitespace as valid. - * - * @param arrayOctet - * byte array to test - * @return true if all bytes are valid characters in the Base64 alphabet or if the byte array is empty; - * false, otherwise - */ - public static boolean isArrayByteBase64(final byte[] arrayOctet) { - for (final byte element : arrayOctet) { - if (!isBase64(element) && !isWhiteSpace(element)) { - return false; - } - } - return true; - } - - /** - * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. - * - * @param arrayOctet - * byte array to test - * @return true if any byte is a valid character in the Base64 alphabet; false herwise - */ - private static boolean containsBase64Byte(final byte[] arrayOctet) { - for (final byte element : arrayOctet) - { - if (isBase64(element)) { - return true; - } - } - return false; - } - - /** - * Encodes binary data using the base64 algorithm but does not chunk the output. - * - * @param binaryData - * binary data to encode - * @return byte[] containing Base64 characters in their UTF-8 representation. - */ - public static byte[] encodeBase64(final byte[] binaryData) { - return encodeBase64(binaryData, false); - } - - /** - * Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF. - *

- * For a non-chunking version, see {@link #encodeBase64StringUnChunked(byte[])}. - * - * @param binaryData - * binary data to encode - * @return String containing Base64 characters. - * @since 1.4 - */ - public static String encodeBase64String(final byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, true)); - } - - /** - * Encodes binary data using the base64 algorithm, without using chunking. - *

- * For a chunking version, see {@link #encodeBase64String(byte[])}. - * - * @param binaryData - * binary data to encode - * @return String containing Base64 characters. - * @since 3.2 - */ - public static String encodeBase64StringUnChunked(final byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, false)); - } - - /** - * Encodes binary data using the base64 algorithm. - * - * @param binaryData - * binary data to encode - * @param useChunking whether to split the output into chunks - * @return String containing Base64 characters. - * @since 3.2 - */ - public static String encodeBase64String(final byte[] binaryData, final boolean useChunking) { - return newStringUtf8(encodeBase64(binaryData, useChunking)); - } - - /** - * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The - * url-safe variation emits - and _ instead of + and / characters. - * - * @param binaryData - * binary data to encode - * @return byte[] containing Base64 characters in their UTF-8 representation. - * @since 1.4 - */ - public static byte[] encodeBase64URLSafe(final byte[] binaryData) { - return encodeBase64(binaryData, false, true); - } - - /** - * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The - * url-safe variation emits - and _ instead of + and / characters. - * - * @param binaryData - * binary data to encode - * @return String containing Base64 characters - * @since 1.4 - */ - public static String encodeBase64URLSafeString(final byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, false, true)); - } - - /** - * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks - * - * @param binaryData - * binary data to encode - * @return Base64 characters chunked in 76 character blocks - */ - public static byte[] encodeBase64Chunked(final byte[] binaryData) { - return encodeBase64(binaryData, true); - } - - /** - * Decodes a String containing containing characters in the Base64 alphabet. - * - * @param pArray - * A String containing Base64 character data - * @return a byte array containing binary data - * @since 1.4 - */ - public byte[] decode(final String pArray) { - return decode(getBytesUtf8(pArray)); - } - - private byte[] getBytesUtf8(final String pArray) { - return pArray.getBytes(StandardCharsets.UTF_8); - } - - /** - * Decodes a byte[] containing containing characters in the Base64 alphabet. - * - * @param pArray - * A byte array containing Base64 character data - * @return a byte array containing binary data - */ - public byte[] decode(final byte[] pArray) { - reset(); - if (pArray == null || pArray.length == 0) { - return pArray; - } - final long len = (pArray.length * 3) / 4; - final byte[] buf = new byte[(int) len]; - setInitialBuffer(buf, 0, buf.length); - decode(pArray, 0, pArray.length); - decode(pArray, 0, -1); // Notify decoder of EOF. - - // Would be nice to just return buf (like we sometimes do in the encode - // logic), but we have no idea what the line-length was (could even be - // variable). So we cannot determine ahead of time exactly how big an - // array is necessary. Hence the need to construct a 2nd byte array to - // hold the final result: - - final byte[] result = new byte[pos]; - readResults(result, 0, result.length); - return result; - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. - * - * @param binaryData - * Array containing binary data to encode. - * @param isChunked - * if true this encoder will chunk the base64 output into 76 character blocks - * @return Base64-encoded data. - * @throws IllegalArgumentException - * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} - */ - public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) { - return encodeBase64(binaryData, isChunked, false); - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. - * - * @param binaryData - * Array containing binary data to encode. - * @param isChunked - * if true this encoder will chunk the base64 output into 76 character blocks - * @param urlSafe - * if true this encoder will emit - and _ instead of the usual + and / characters. - * @return Base64-encoded data. - * @throws IllegalArgumentException - * Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE} - * @since 1.4 - */ - public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) { - return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks. - * - * @param binaryData - * Array containing binary data to encode. - * @param isChunked - * if true this encoder will chunk the base64 output into 76 character blocks - * @param urlSafe - * if true this encoder will emit - and _ instead of the usual + and / characters. - * @param maxResultSize - * The maximum result size to accept. - * @return Base64-encoded data. - * @throws IllegalArgumentException - * Thrown when the input array needs an output array bigger than maxResultSize - * @since 1.4 - */ - public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe, - final int maxResultSize) { - if (binaryData == null || binaryData.length == 0) { - return binaryData; - } - - final long len = getEncodeLength(binaryData, isChunked ? CHUNK_SIZE : 0, - isChunked ? CHUNK_SEPARATOR : NetConstants.EMPTY_BTYE_ARRAY); - if (len > maxResultSize) { - throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + len - + ") than the specified maxium size of " + maxResultSize); - } - - final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); - return b64.encode(binaryData); - } - - /** - * Decodes a Base64 String into octets. - * - * @param base64String - * String containing Base64 data - * @return Array containing decoded data. - * @since 1.4 - */ - public static byte[] decodeBase64(final String base64String) { - return new Base64().decode(base64String); - } - - /** - * Decodes Base64 data into octets. - * - * @param base64Data - * Byte array containing Base64 data - * @return Array containing decoded data. - */ - public static byte[] decodeBase64(final byte[] base64Data) { - return new Base64().decode(base64Data); - } - - /** - * Checks if a byte value is whitespace or not. - * - * @param byteToCheck - * the byte to check - * @return true if byte is whitespace, false otherwise - */ - private static boolean isWhiteSpace(final byte byteToCheck) { - switch (byteToCheck) { - case ' ' : - case '\n' : - case '\r' : - case '\t' : - return true; - default : - return false; - } - } - - /** - * Encodes a byte[] containing binary data, into a String containing characters in the Base64 alphabet. - * - * @param pArray - * a byte array containing binary data - * @return A String containing only Base64 character data - * @since 1.4 - */ - public String encodeToString(final byte[] pArray) { - return newStringUtf8(encode(pArray)); - } - - private static String newStringUtf8(final byte[] encode) { - return new String(encode, StandardCharsets.UTF_8); - } - - /** - * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 alphabet. - * - * @param pArray - * a byte array containing binary data - * @return A byte array containing only Base64 character data - */ - public byte[] encode(final byte[] pArray) { - reset(); - if (pArray == null || pArray.length == 0) { - return pArray; - } - final long len = getEncodeLength(pArray, lineLength, lineSeparator); - byte[] buf = new byte[(int) len]; - setInitialBuffer(buf, 0, buf.length); - encode(pArray, 0, pArray.length); - encode(pArray, 0, -1); // Notify encoder of EOF. - // Encoder might have resized, even though it was unnecessary. - if (buffer != buf) { - readResults(buf, 0, buf.length); - } - // In URL-SAFE mode we skip the padding characters, so sometimes our - // final length is a bit smaller. - if (isUrlSafe() && pos < buf.length) { - final byte[] smallerBuf = new byte[pos]; - System.arraycopy(buf, 0, smallerBuf, 0, pos); - buf = smallerBuf; - } - return buf; - } - - /** - * Pre-calculates the amount of space needed to base64-encode the supplied array. - * - * @param pArray byte[] array which will later be encoded - * @param chunkSize line-length of the output (<= 0 means no chunking) between each - * chunkSeparator (e.g. CRLF). - * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF). - * - * @return amount of space needed to encoded the supplied array. Returns - * a long since a max-len array will require Integer.MAX_VALUE + 33%. - */ - private static long getEncodeLength(final byte[] pArray, int chunkSize, final byte[] chunkSeparator) { - // base64 always encodes to multiples of 4. - chunkSize = (chunkSize / 4) * 4; - - long len = (pArray.length * 4) / 3; - final long mod = len % 4; - if (mod != 0) { - len += 4 - mod; - } - if (chunkSize > 0) { - final boolean lenChunksPerfectly = len % chunkSize == 0; - len += (len / chunkSize) * chunkSeparator.length; - if (!lenChunksPerfectly) { - len += chunkSeparator.length; - } - } - return len; - } - - // Implementation of integer encoding used for crypto - /** - * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature - * - * @param pArray - * a byte array containing base64 character data - * @return A BigInteger - * @since 1.4 - */ - public static BigInteger decodeInteger(final byte[] pArray) { - return new BigInteger(1, decodeBase64(pArray)); - } - - /** - * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature - * - * @param bigInt - * a BigInteger - * @return A byte array containing base64 character data - * @throws NullPointerException - * if null is passed in - * @since 1.4 - */ - public static byte[] encodeInteger(final BigInteger bigInt) { - if (bigInt == null) { - throw new NullPointerException("encodeInteger called with null parameter"); - } - return encodeBase64(toIntegerBytes(bigInt), false); - } - - /** - * Returns a byte-array representation of a BigInteger without sign bit. - * - * @param bigInt - * BigInteger to be converted - * @return a byte array representation of the BigInteger parameter - */ - static byte[] toIntegerBytes(final BigInteger bigInt) { - int bitlen = bigInt.bitLength(); - // round bitlen - bitlen = ((bitlen + 7) >> 3) << 3; - final byte[] bigBytes = bigInt.toByteArray(); - - if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { - return bigBytes; - } - // set up params for copying everything but sign bit - int startSrc = 0; - int len = bigBytes.length; - - // if bigInt is exactly byte-aligned, just skip signbit in copy - if ((bigInt.bitLength() % 8) == 0) { - startSrc = 1; - len--; - } - final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec - final byte[] resizedBytes = new byte[bitlen / 8]; - System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); - return resizedBytes; - } - - /** - * Resets this Base64 object to its initial newly constructed state. - */ - private void reset() { - buffer = null; - pos = 0; - readPos = 0; - currentLinePos = 0; - modulus = 0; - eof = false; - } - - // Getters for use in testing - - int getLineLength() { - return lineLength; - } - - byte[] getLineSeparator() { - return lineSeparator.clone(); - } -} diff --git a/src/org/apache/commons/net/util/Charsets.java b/src/org/apache/commons/net/util/Charsets.java deleted file mode 100644 index 1b6f8393..00000000 --- a/src/org/apache/commons/net/util/Charsets.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.util; - -import java.nio.charset.Charset; - -/** - * Helps dealing with Charsets. - * - * @since 3.3 - */ -public class Charsets { - - /** - * Returns a charset object for the given charset name. - * - * @param charsetName - * The name of the requested charset; may be a canonical name, an alias, or null. If null, return the - * default charset. - * @return A charset object for the named charset - */ - public static Charset toCharset(final String charsetName) { - return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName); - } - - /** - * Returns a charset object for the given charset name. - * - * @param charsetName - * The name of the requested charset; may be a canonical name, an alias, or null. - * If null, return the default charset. - * @param defaultCharsetName the charset name to use if the requested charset is null - * - * @return A charset object for the named charset - */ - public static Charset toCharset(final String charsetName, final String defaultCharsetName) { - return charsetName == null ? Charset.forName(defaultCharsetName) : Charset.forName(charsetName); - } -} diff --git a/src/org/apache/commons/net/util/KeyManagerUtils.java b/src/org/apache/commons/net/util/KeyManagerUtils.java deleted file mode 100644 index 6e93df19..00000000 --- a/src/org/apache/commons/net/util/KeyManagerUtils.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.Socket; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Enumeration; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.X509ExtendedKeyManager; - -import org.apache.commons.net.io.Util; - -/** - * General KeyManager utilities - *

- * How to use with a client certificate: - *

- * KeyManager km = KeyManagerUtils.createClientKeyManager("JKS",
- *     "/path/to/privatekeystore.jks","storepassword",
- *     "privatekeyalias", "keypassword");
- * FTPSClient cl = new FTPSClient();
- * cl.setKeyManager(km);
- * cl.connect(...);
- * 
- * If using the default store type and the key password is the same as the - * store password, these parameters can be omitted.
- * If the desired key is the first or only key in the keystore, the keyAlias parameter - * can be omitted, in which case the code becomes: - *
- * KeyManager km = KeyManagerUtils.createClientKeyManager(
- *     "/path/to/privatekeystore.jks","storepassword");
- * FTPSClient cl = new FTPSClient();
- * cl.setKeyManager(km);
- * cl.connect(...);
- * 
- * - * @since 3.0 - */ -public final class KeyManagerUtils { - - private static final String DEFAULT_STORE_TYPE = KeyStore.getDefaultType(); - - private KeyManagerUtils(){ - // Not instantiable - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * - * @param ks the keystore to use - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key entry alias is used - * @param keyPass the password of the key to use - * @return the customised KeyManager - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(final KeyStore ks, final String keyAlias, final String keyPass) - throws GeneralSecurityException - { - final ClientKeyStore cks = new ClientKeyStore(ks, keyAlias != null ? keyAlias : findAlias(ks), keyPass); - return new X509KeyManager(cks); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * - * @param storeType the type of the keyStore, e.g. "JKS" - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key entry alias is used - * @param keyPass the password of the key to use - * @return the customised KeyManager - * @throws GeneralSecurityException if there is a problem creating the keystore - * @throws IOException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager( - final String storeType, final File storePath, final String storePass, final String keyAlias, final String keyPass) - throws IOException, GeneralSecurityException - { - final KeyStore ks = loadStore(storeType, storePath, storePass); - return createClientKeyManager(ks, keyAlias, keyPass); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * Uses the default store type and assumes the key password is the same as the store password - * - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key entry alias is used - * @return the customised KeyManager - * @throws IOException if there is a problem creating the keystore - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(final File storePath, final String storePass, final String keyAlias) - throws IOException, GeneralSecurityException - { - return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, keyAlias, storePass); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * Uses the default store type and assumes the key password is the same as the store password. - * The key alias is found by searching the keystore for the first private key entry - * - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @return the customised KeyManager - * @throws IOException if there is a problem creating the keystore - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(final File storePath, final String storePass) - throws IOException, GeneralSecurityException - { - return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, null, storePass); - } - - private static KeyStore loadStore(final String storeType, final File storePath, final String storePass) - throws KeyStoreException, IOException, GeneralSecurityException { - final KeyStore ks = KeyStore.getInstance(storeType); - FileInputStream stream = null; - try { - stream = new FileInputStream(storePath); - ks.load(stream, storePass.toCharArray()); - } finally { - Util.closeQuietly(stream); - } - return ks; - } - - private static String findAlias(final KeyStore ks) throws KeyStoreException { - final Enumeration e = ks.aliases(); - while(e.hasMoreElements()) { - final String entry = e.nextElement(); - if (ks.isKeyEntry(entry)) { - return entry; - } - } - throw new KeyStoreException("Cannot find a private key entry"); - } - - private static class ClientKeyStore { - - private final X509Certificate[] certChain; - private final PrivateKey key; - private final String keyAlias; - - ClientKeyStore(final KeyStore ks, final String keyAlias, final String keyPass) throws GeneralSecurityException - { - this.keyAlias = keyAlias; - this.key = (PrivateKey) ks.getKey(this.keyAlias, keyPass.toCharArray()); - final Certificate[] certs = ks.getCertificateChain(this.keyAlias); - final X509Certificate[] X509certs = new X509Certificate[certs.length]; - for (int i=0; i < certs.length; i++) { - X509certs[i] = (X509Certificate) certs[i]; - } - this.certChain = X509certs; - } - - final X509Certificate[] getCertificateChain() { - return this.certChain; - } - - final PrivateKey getPrivateKey() { - return this.key; - } - - final String getAlias() { - return this.keyAlias; - } - } - - private static class X509KeyManager extends X509ExtendedKeyManager { - - private final ClientKeyStore keyStore; - - X509KeyManager(final ClientKeyStore keyStore) { - this.keyStore = keyStore; - } - - // Call sequence: 1 - @Override - public String chooseClientAlias(final String[] keyType, final Principal[] issuers, - final Socket socket) { - return keyStore.getAlias(); - } - - // Call sequence: 2 - @Override - public X509Certificate[] getCertificateChain(final String alias) { - return keyStore.getCertificateChain(); - } - - @Override - public String[] getClientAliases(final String keyType, final Principal[] issuers) { - return new String[]{ keyStore.getAlias()}; - } - - // Call sequence: 3 - @Override - public PrivateKey getPrivateKey(final String alias) { - return keyStore.getPrivateKey(); - } - - @Override - public String[] getServerAliases(final String keyType, final Principal[] issuers) { - return null; - } - - @Override - public String chooseServerAlias(final String keyType, final Principal[] issuers, final Socket socket) { - return null; - } - - } - -} diff --git a/src/org/apache/commons/net/util/ListenerList.java b/src/org/apache/commons/net/util/ListenerList.java deleted file mode 100644 index a5012659..00000000 --- a/src/org/apache/commons/net/util/ListenerList.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.util; - -import java.io.Serializable; -import java.util.EventListener; -import java.util.Iterator; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - */ - -public class ListenerList implements Serializable, Iterable -{ - private static final long serialVersionUID = -1934227607974228213L; - - private final CopyOnWriteArrayList listeners; - - public ListenerList() - { - listeners = new CopyOnWriteArrayList<>(); - } - - public void addListener(final EventListener listener) - { - listeners.add(listener); - } - - public void removeListener(final EventListener listener) - { - listeners.remove(listener); - } - - public int getListenerCount() - { - return listeners.size(); - } - - /** - * Return an {@link Iterator} for the {@link EventListener} instances. - * - * @return an {@link Iterator} for the {@link EventListener} instances - * @since 2.0 - * TODO Check that this is a good defensive strategy - */ - @Override - public Iterator iterator() { - return listeners.iterator(); - } - -} diff --git a/src/org/apache/commons/net/util/NetConstants.java b/src/org/apache/commons/net/util/NetConstants.java deleted file mode 100644 index 9c48871f..00000000 --- a/src/org/apache/commons/net/util/NetConstants.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.net.util; - -import java.security.cert.X509Certificate; - -/** - * Constants provided as public only for our own implementation, you can consider this private for now. - * - * @since 3.8.0 - */ -public class NetConstants { - - /** - * An empty immutable {@code String} array. - */ - public static final String[] EMPTY_STRING_ARRAY = new String[0]; - - /** - * An empty immutable {@code byte} array. - */ - public static final byte[] EMPTY_BTYE_ARRAY = new byte[0]; - - /** - * An empty immutable {link X509Certificate} array. - */ - public static final X509Certificate[] EMPTY_X509_CERTIFICATE_ARRAY = new X509Certificate[0]; - - /** - * Prevents instantiation. - */ - private NetConstants() { - } -} diff --git a/src/org/apache/commons/net/util/SSLContextUtils.java b/src/org/apache/commons/net/util/SSLContextUtils.java deleted file mode 100644 index df2d7aab..00000000 --- a/src/org/apache/commons/net/util/SSLContextUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.util; - -import java.io.IOException; -import java.security.GeneralSecurityException; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -/** - * General utilities for SSLContext. - * @since 3.0 - */ -public class SSLContextUtils { - - private SSLContextUtils() { - // Not instantiable - } - - /** - * Create and initialize an SSLContext. - * @param protocol the protocol used to instatiate the context - * @param keyManager the key manager, may be {@code null} - * @param trustManager the trust manager, may be {@code null} - * @return the initialized context. - * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs - */ - public static SSLContext createSSLContext(final String protocol, final KeyManager keyManager, final TrustManager trustManager) - throws IOException { - return createSSLContext(protocol, - keyManager == null ? null : new KeyManager[] { keyManager }, - trustManager == null ? null : new TrustManager[] { trustManager }); - } - - /** - * Create and initialize an SSLContext. - * @param protocol the protocol used to instatiate the context - * @param keyManagers the array of key managers, may be {@code null} but array entries must not be {@code null} - * @param trustManagers the array of trust managers, may be {@code null} but array entries must not be {@code null} - * @return the initialized context. - * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs - */ - public static SSLContext createSSLContext(final String protocol, final KeyManager[] keyManagers, - final TrustManager[] trustManagers) throws IOException { - final SSLContext ctx; - try { - ctx = SSLContext.getInstance(protocol); - ctx.init(keyManagers, trustManagers, /* SecureRandom */ null); - } catch (final GeneralSecurityException e) { - final IOException ioe = new IOException("Could not initialize SSL context"); - ioe.initCause(e); - throw ioe; - } - return ctx; - } -} diff --git a/src/org/apache/commons/net/util/SSLSocketUtils.java b/src/org/apache/commons/net/util/SSLSocketUtils.java deleted file mode 100644 index dd05993a..00000000 --- a/src/org/apache/commons/net/util/SSLSocketUtils.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.apache.commons.net.util; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.net.ssl.SSLSocket; - -/** - * General utilities for SSLSocket. - * - * @since 3.4 - */ -public class SSLSocketUtils { - private SSLSocketUtils() { - // Not instantiable - } - - /** - * Enable the HTTPS endpoint identification algorithm on an SSLSocket. - * - * @param socket the SSL socket - * @return {@code true} on success (this is only supported on Java 1.7+) - */ - public static boolean enableEndpointNameVerification(final SSLSocket socket) { - try { - final Class cls = Class.forName("javax.net.ssl.SSLParameters"); - final Method setEndpointIdentificationAlgorithm = cls - .getDeclaredMethod("setEndpointIdentificationAlgorithm", String.class); - final Method getSSLParameters = SSLSocket.class.getDeclaredMethod("getSSLParameters"); - final Method setSSLParameters = SSLSocket.class.getDeclaredMethod("setSSLParameters", cls); - if (setEndpointIdentificationAlgorithm != null && getSSLParameters != null && setSSLParameters != null) { - final Object sslParams = getSSLParameters.invoke(socket); - if (sslParams != null) { - setEndpointIdentificationAlgorithm.invoke(sslParams, "HTTPS"); - setSSLParameters.invoke(socket, sslParams); - return true; - } - } - } catch (final SecurityException | ClassNotFoundException | NoSuchMethodException | IllegalArgumentException | - IllegalAccessException | InvocationTargetException e) { // Ignored - } - return false; - } -} diff --git a/src/org/apache/commons/net/util/SubnetUtils.java b/src/org/apache/commons/net/util/SubnetUtils.java deleted file mode 100644 index 740dfa6a..00000000 --- a/src/org/apache/commons/net/util/SubnetUtils.java +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.commons.net.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A class that performs some subnet calculations given a network address and a subnet mask. - * @see "http://www.faqs.org/rfcs/rfc1519.html" - * @since 2.0 - */ -public class SubnetUtils { - - private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; - private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,2})"; // 0 -> 32 - private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); - private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); - private static final int NBITS = 32; - - private static final String PARSE_FAIL = "Could not parse [%s]"; - - private final int netmask; - private final int address; - private final int network; - private final int broadcast; - - /** Whether the broadcast/network address are included in host count */ - private boolean inclusiveHostCount; - - - /** - * Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" - * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" - * @throws IllegalArgumentException if the parameter is invalid, - * i.e. does not match n.n.n.n/m where n=1-3 decimal digits, m = 1-2 decimal digits in range 0-32 - */ - public SubnetUtils(final String cidrNotation) { - final Matcher matcher = cidrPattern.matcher(cidrNotation); - - if (matcher.matches()) { - this.address = matchAddress(matcher); - - /* Create a binary netmask from the number of bits specification /x */ - - final int trailingZeroes = NBITS - rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS); - /* - * An IPv4 netmask consists of 32 bits, a contiguous sequence - * of the specified number of ones followed by all zeros. - * So, it can be obtained by shifting an unsigned integer (32 bits) to the left by - * the number of trailing zeros which is (32 - the # bits specification). - * Note that there is no unsigned left shift operator, so we have to use - * a long to ensure that the left-most bit is shifted out correctly. - */ - this.netmask = (int) (0x0FFFFFFFFL << trailingZeroes ); - - /* Calculate base network address */ - this.network = address & netmask; - - /* Calculate broadcast address */ - this.broadcast = network | ~netmask; - } else { - throw new IllegalArgumentException(String.format(PARSE_FAIL, cidrNotation)); - } - } - - /** - * Constructor that takes a dotted decimal address and a dotted decimal mask. - * @param address An IP address, e.g. "192.168.0.1" - * @param mask A dotted decimal netmask e.g. "255.255.0.0" - * @throws IllegalArgumentException if the address or mask is invalid, - * i.e. does not match n.n.n.n where n=1-3 decimal digits and the mask is not all zeros - */ - public SubnetUtils(final String address, final String mask) { - this.address = toInteger(address); - this.netmask = toInteger(mask); - - if ((this.netmask & -this.netmask) - 1 != ~this.netmask) { - throw new IllegalArgumentException(String.format(PARSE_FAIL, mask)); - } - - /* Calculate base network address */ - this.network = this.address & this.netmask; - - /* Calculate broadcast address */ - this.broadcast = this.network | ~this.netmask; - } - - - /** - * Returns true if the return value of {@link SubnetInfo#getAddressCount()} - * includes the network and broadcast addresses. - * @since 2.2 - * @return true if the host count includes the network and broadcast addresses - */ - public boolean isInclusiveHostCount() { - return inclusiveHostCount; - } - - /** - * Set to true if you want the return value of {@link SubnetInfo#getAddressCount()} - * to include the network and broadcast addresses. - * This also applies to {@link SubnetInfo#isInRange(int)} - * @param inclusiveHostCount true if network and broadcast addresses are to be included - * @since 2.2 - */ - public void setInclusiveHostCount(final boolean inclusiveHostCount) { - this.inclusiveHostCount = inclusiveHostCount; - } - - - - /** - * Convenience container for subnet summary information. - * - */ - public final class SubnetInfo { - /* Mask to convert unsigned int to a long (i.e. keep 32 bits) */ - private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; - - private SubnetInfo() {} - - // long versions of the values (as unsigned int) which are more suitable for range checking - private long networkLong() { return network & UNSIGNED_INT_MASK; } - private long broadcastLong(){ return broadcast & UNSIGNED_INT_MASK; } - - private int low() { - return isInclusiveHostCount() ? network : - broadcastLong() - networkLong() > 1 ? network + 1 : 0; - } - - private int high() { - return isInclusiveHostCount() ? broadcast : - broadcastLong() - networkLong() > 1 ? broadcast -1 : 0; - } - - /** - * Returns true if the parameter address is in the - * range of usable endpoint addresses for this subnet. This excludes the - * network and broadcast addresses. Use {@link SubnetUtils#setInclusiveHostCount(boolean)} - * to change this. - * @param address A dot-delimited IPv4 address, e.g. "192.168.0.1" - * @return True if in range, false otherwise - */ - public boolean isInRange(final String address) { - return isInRange(toInteger(address)); - } - - /** - * Returns true if the parameter address is in the - * range of usable endpoint addresses for this subnet. This excludes the - * network and broadcast addresses by default. Use {@link SubnetUtils#setInclusiveHostCount(boolean)} - * to change this. - * @param address the address to check - * @return true if it is in range - * @since 3.4 (made public) - */ - public boolean isInRange(final int address) { - if (address == 0) { // cannot ever be in range; rejecting now avoids problems with CIDR/31,32 - return false; - } - final long addLong = address & UNSIGNED_INT_MASK; - final long lowLong = low() & UNSIGNED_INT_MASK; - final long highLong = high() & UNSIGNED_INT_MASK; - return addLong >= lowLong && addLong <= highLong; - } - - public String getBroadcastAddress() { - return format(toArray(broadcast)); - } - - public String getNetworkAddress() { - return format(toArray(network)); - } - - public String getNetmask() { - return format(toArray(netmask)); - } - - public String getAddress() { - return format(toArray(address)); - } - - public String getNextAddress() { - return format(toArray(address + 1)); - } - - public String getPreviousAddress() { - return format(toArray(address - 1)); - } - - /** - * Return the low address as a dotted IP address. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address - */ - public String getLowAddress() { - return format(toArray(low())); - } - - /** - * Return the high address as a dotted IP address. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address - */ - public String getHighAddress() { - return format(toArray(high())); - } - - /** - * Get the count of available addresses. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * @return the count of addresses, may be zero. - * @throws RuntimeException if the correct count is greater than {@code Integer.MAX_VALUE} - * @deprecated (3.4) use {@link #getAddressCountLong()} instead - */ - @Deprecated - public int getAddressCount() { - final long countLong = getAddressCountLong(); - if (countLong > Integer.MAX_VALUE) { - throw new RuntimeException("Count is larger than an integer: " + countLong); - } - // N.B. cannot be negative - return (int)countLong; - } - - /** - * Get the count of available addresses. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * @return the count of addresses, may be zero. - * @since 3.4 - */ - public long getAddressCountLong() { - final long b = broadcastLong(); - final long n = networkLong(); - final long count = b - n + (isInclusiveHostCount() ? 1 : -1); - return count < 0 ? 0 : count; - } - - public int asInteger(final String address) { - return toInteger(address); - } - - public String getCidrSignature() { - return format(toArray(address)) + "/" + pop(netmask); - } - - public String[] getAllAddresses() { - final int ct = getAddressCount(); - final String[] addresses = new String[ct]; - if (ct == 0) { - return addresses; - } - for (int add = low(), j=0; add <= high(); ++add, ++j) { - addresses[j] = format(toArray(add)); - } - return addresses; - } - - /* - * Convert a packed integer address into a 4-element array - */ - private int[] toArray(final int val) { - final int ret[] = new int[4]; - for (int j = 3; j >= 0; --j) { - ret[j] |= val >>> 8*(3-j) & 0xff; - } - return ret; - } - - /* - * Convert a 4-element array into dotted decimal format - */ - private String format(final int[] octets) { - final StringBuilder str = new StringBuilder(); - for (int i =0; i < octets.length; ++i){ - str.append(octets[i]); - if (i != octets.length - 1) { - str.append("."); - } - } - return str.toString(); - } - - /** - * {@inheritDoc} - * @since 2.2 - */ - @Override - public String toString() { - final StringBuilder buf = new StringBuilder(); - buf.append("CIDR Signature:\t[").append(getCidrSignature()).append("]") - .append(" Netmask: [").append(getNetmask()).append("]\n") - .append("Network:\t[").append(getNetworkAddress()).append("]\n") - .append("Broadcast:\t[").append(getBroadcastAddress()).append("]\n") - .append("First Address:\t[").append(getLowAddress()).append("]\n") - .append("Last Address:\t[").append(getHighAddress()).append("]\n") - .append("# Addresses:\t[").append(getAddressCount()).append("]\n"); - return buf.toString(); - } - } - - /** - * Return a {@link SubnetInfo} instance that contains subnet-specific statistics - * @return new instance - */ - public final SubnetInfo getInfo() { return new SubnetInfo(); } - - /* - * Convert a dotted decimal format address to a packed integer format - */ - private static int toInteger(final String address) { - final Matcher matcher = addressPattern.matcher(address); - if (matcher.matches()) { - return matchAddress(matcher); - } - throw new IllegalArgumentException(String.format(PARSE_FAIL, address)); - } - - /* - * Convenience method to extract the components of a dotted decimal address and - * pack into an integer using a regex match - */ - private static int matchAddress(final Matcher matcher) { - int addr = 0; - for (int i = 1; i <= 4; ++i) { - final int n = rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255); - addr |= (n & 0xff) << 8*(4-i); - } - return addr; - } - - /* - * Convenience function to check integer boundaries. - * Checks if a value x is in the range [begin,end]. - * Returns x if it is in range, throws an exception otherwise. - */ - private static int rangeCheck(final int value, final int begin, final int end) { - if (value >= begin && value <= end) { // (begin,end] - return value; - } - - throw new IllegalArgumentException("Value [" + value + "] not in range ["+begin+","+end+"]"); - } - - /* - * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy - * see Hacker's Delight section 5.1 - */ - int pop(int x) { - x = x - (x >>> 1 & 0x55555555); - x = (x & 0x33333333) + (x >>> 2 & 0x33333333); - x = x + (x >>> 4) & 0x0F0F0F0F; - x = x + (x >>> 8); - x = x + (x >>> 16); - return x & 0x0000003F; - } - - public SubnetUtils getNext() { - return new SubnetUtils(getInfo().getNextAddress(), getInfo().getNetmask()); - } - - public SubnetUtils getPrevious() { - return new SubnetUtils(getInfo().getPreviousAddress(), getInfo().getNetmask()); - } - -} diff --git a/src/org/apache/commons/net/util/TrustManagerUtils.java b/src/org/apache/commons/net/util/TrustManagerUtils.java deleted file mode 100644 index 1bddc0be..00000000 --- a/src/org/apache/commons/net/util/TrustManagerUtils.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.commons.net.util; - -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -/** - * TrustManager utilities for generating TrustManagers. - * - * @since 3.0 - */ -public final class TrustManagerUtils -{ - private static class TrustManager implements X509TrustManager { - - private final boolean checkServerValidity; - - TrustManager(final boolean checkServerValidity) { - this.checkServerValidity = checkServerValidity; - } - - /** - * Never generates a CertificateException. - */ - @Override - public void checkClientTrusted(final X509Certificate[] certificates, final String authType) - { - } - - @Override - public void checkServerTrusted(final X509Certificate[] certificates, final String authType) - throws CertificateException - { - if (checkServerValidity) { - for (final X509Certificate certificate : certificates) - { - certificate.checkValidity(); - } - } - } - - /** - * @return an empty array of certificates - */ - @Override - public X509Certificate[] getAcceptedIssuers() - { - return NetConstants.EMPTY_X509_CERTIFICATE_ARRAY; - } - } - - private static final X509TrustManager ACCEPT_ALL=new TrustManager(false); - - private static final X509TrustManager CHECK_SERVER_VALIDITY=new TrustManager(true); - - /** - * Generate a TrustManager that performs no checks. - * - * @return the TrustManager - */ - public static X509TrustManager getAcceptAllTrustManager(){ - return ACCEPT_ALL; - } - - /** - * Generate a TrustManager that checks server certificates for validity, - * but otherwise performs no checks. - * - * @return the validating TrustManager - */ - public static X509TrustManager getValidateServerCertificateTrustManager(){ - return CHECK_SERVER_VALIDITY; - } - - /** - * Return the default TrustManager provided by the JVM. - *

- * This should be the same as the default used by - * {@link javax.net.ssl.SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom) - * SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} - * when the TrustManager parameter is set to {@code null} - * @param keyStore the KeyStore to use, may be {@code null} - * @return the default TrustManager - * @throws GeneralSecurityException if an error occurs - */ - public static X509TrustManager getDefaultTrustManager(final KeyStore keyStore) throws GeneralSecurityException { - final String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - final TrustManagerFactory instance = TrustManagerFactory.getInstance(defaultAlgorithm); - instance.init(keyStore); - return (X509TrustManager) instance.getTrustManagers()[0]; - } - -} diff --git a/src/org/apache/commons/net/util/package-info.java b/src/org/apache/commons/net/util/package-info.java deleted file mode 100644 index a7c573e2..00000000 --- a/src/org/apache/commons/net/util/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Utility classes - */ -package org.apache.commons.net.util; \ No newline at end of file diff --git a/src/plugin.yml b/src/plugin.yml deleted file mode 100644 index b6f918d4..00000000 --- a/src/plugin.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: ServerBackup -author: Seblii -version: 2.7.1 -api-version: 1.18 - -main: de.sebli.serverbackup.ServerBackup - -commands: - backup: - aliases: [serverbackup] - permission: backup.admin - -permissions: - backup.admin: - description: Permission for all backup commands \ No newline at end of file