001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 018package org.apache.logging.log4j.core.appender.rolling.action; 019 020import java.io.IOException; 021import java.nio.file.FileVisitOption; 022import java.nio.file.FileVisitor; 023import java.nio.file.Files; 024import java.nio.file.Path; 025import java.nio.file.Paths; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.EnumSet; 029import java.util.List; 030import java.util.Set; 031import java.util.concurrent.TimeUnit; 032 033import org.apache.logging.log4j.core.lookup.StrSubstitutor; 034 035/** 036 * Abstract action for processing files that are accepted by the specified PathFilters. 037 */ 038public abstract class AbstractPathAction extends AbstractAction { 039 040 private final String basePathString; 041 private final Set<FileVisitOption> options; 042 private final int maxDepth; 043 private final List<PathCondition> pathConditions; 044 private final StrSubstitutor subst; 045 046 /** 047 * Creates a new AbstractPathAction that starts scanning for files to process from the specified base path. 048 * 049 * @param basePath base path from where to start scanning for files to process. 050 * @param followSymbolicLinks whether to follow symbolic links. Default is false. 051 * @param maxDepth The maxDepth parameter is the maximum number of levels of directories to visit. A value of 0 052 * means that only the starting file is visited, unless denied by the security manager. A value of 053 * MAX_VALUE may be used to indicate that all levels should be visited. 054 * @param pathFilters an array of path filters (if more than one, they all need to accept a path before it is 055 * processed). 056 */ 057 protected AbstractPathAction(final String basePath, final boolean followSymbolicLinks, final int maxDepth, 058 final PathCondition[] pathFilters, final StrSubstitutor subst) { 059 this.basePathString = basePath; 060 this.options = followSymbolicLinks ? EnumSet.of(FileVisitOption.FOLLOW_LINKS) 061 : Collections.<FileVisitOption> emptySet(); 062 this.maxDepth = maxDepth; 063 this.pathConditions = Arrays.asList(Arrays.copyOf(pathFilters, pathFilters.length)); 064 this.subst = subst; 065 } 066 067 @Override 068 public boolean execute() throws IOException { 069 return execute(createFileVisitor(getBasePath(), pathConditions)); 070 } 071 072 public boolean execute(final FileVisitor<Path> visitor) throws IOException { 073 final long start = System.nanoTime(); 074 LOGGER.debug("Starting {}", this); 075 076 Files.walkFileTree(getBasePath(), options, maxDepth, visitor); 077 078 final double duration = System.nanoTime() - start; 079 LOGGER.debug("{} complete in {} seconds", getClass().getSimpleName(), duration / TimeUnit.SECONDS.toNanos(1)); 080 081 // TODO return (visitor.success || ignoreProcessingFailure) 082 return true; // do not abort rollover even if processing failed 083 } 084 085 /** 086 * Creates a new {@code FileVisitor<Path>} to pass to the {@link Files#walkFileTree(Path, Set, int, FileVisitor)} 087 * method when the {@link #execute()} method is invoked. 088 * <p> 089 * The visitor is responsible for processing the files it encounters that are accepted by all filters. 090 * 091 * @param visitorBaseDir base dir from where to start scanning for files to process 092 * @param conditions filters that determine if a file should be processed 093 * @return a new {@code FileVisitor<Path>} 094 */ 095 protected abstract FileVisitor<Path> createFileVisitor(final Path visitorBaseDir, 096 final List<PathCondition> conditions); 097 098 /** 099 * Returns the base path from where to start scanning for files to delete. Lookups are resolved, so if the 100 * configuration was <code><Delete basePath="${sys:user.home}/abc" /></code> then this method returns a path 101 * to the "abc" file or directory in the user's home directory. 102 * 103 * @return the base path (all lookups resolved) 104 */ 105 public Path getBasePath() { 106 return Paths.get(subst.replace(getBasePathString())); 107 } 108 109 /** 110 * Returns the base path as it was specified in the configuration. Lookups are not resolved. 111 * 112 * @return the base path as it was specified in the configuration 113 */ 114 public String getBasePathString() { 115 return basePathString; 116 } 117 118 public StrSubstitutor getStrSubstitutor() { 119 return subst; 120 } 121 122 /** 123 * Returns whether to follow symbolic links or not. 124 * 125 * @return the options 126 */ 127 public Set<FileVisitOption> getOptions() { 128 return Collections.unmodifiableSet(options); 129 } 130 131 /** 132 * Returns whether to follow symbolic links or not. 133 * 134 * @return whether to follow symbolic links or not 135 */ 136 public boolean isFollowSymbolicLinks() { 137 return options.contains(FileVisitOption.FOLLOW_LINKS); 138 } 139 140 /** 141 * Returns the maximum number of directory levels to visit. 142 * 143 * @return the maxDepth 144 */ 145 public int getMaxDepth() { 146 return maxDepth; 147 } 148 149 /** 150 * Returns the list of PathCondition objects. 151 * 152 * @return the pathFilters 153 */ 154 public List<PathCondition> getPathConditions() { 155 return Collections.unmodifiableList(pathConditions); 156 } 157 158 @Override 159 public String toString() { 160 return getClass().getSimpleName() + "[basePath=" + getBasePath() + ", options=" + options + ", maxDepth=" 161 + maxDepth + ", conditions=" + pathConditions + "]"; 162 } 163}