1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.appender.rolling.action;
19
20 import java.io.IOException;
21 import java.nio.file.FileVisitor;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.util.List;
25 import java.util.Objects;
26
27 import org.apache.logging.log4j.core.config.Configuration;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
31 import org.apache.logging.log4j.core.config.plugins.PluginElement;
32 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
34
35
36
37
38 @Plugin(name = "Delete", category = "Core", printObject = true)
39 public class DeleteAction extends AbstractPathAction {
40
41 private final PathSorter pathSorter;
42 private final boolean testMode;
43 private final ScriptCondition scriptCondition;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 DeleteAction(final String basePath, final boolean followSymbolicLinks, final int maxDepth, final boolean testMode,
62 final PathSorter sorter, final PathCondition[] pathConditions, final ScriptCondition scriptCondition,
63 final StrSubstitutor subst) {
64 super(basePath, followSymbolicLinks, maxDepth, pathConditions, subst);
65 this.testMode = testMode;
66 this.pathSorter = Objects.requireNonNull(sorter, "sorter");
67 this.scriptCondition = scriptCondition;
68 if (scriptCondition == null && (pathConditions == null || pathConditions.length == 0)) {
69 LOGGER.error("Missing Delete conditions: unconditional Delete not supported");
70 throw new IllegalArgumentException("Unconditional Delete not supported");
71 }
72 }
73
74
75
76
77
78
79 @Override
80 public boolean execute() throws IOException {
81 if (scriptCondition != null) {
82 return executeScript();
83 } else {
84 return super.execute();
85 }
86 }
87
88 private boolean executeScript() throws IOException {
89 final List<PathWithAttributes> selectedForDeletion = callScript();
90 if (selectedForDeletion == null) {
91 LOGGER.trace("Script returned null list (no files to delete)");
92 return true;
93 }
94 deleteSelectedFiles(selectedForDeletion);
95 return true;
96 }
97
98 private List<PathWithAttributes> callScript() throws IOException {
99 final List<PathWithAttributes> sortedPaths = getSortedPaths();
100 trace("Sorted paths:", sortedPaths);
101 final List<PathWithAttributes> result = scriptCondition.selectFilesToDelete(getBasePath(), sortedPaths);
102 return result;
103 }
104
105 private void deleteSelectedFiles(final List<PathWithAttributes> selectedForDeletion) throws IOException {
106 trace("Paths the script selected for deletion:", selectedForDeletion);
107 for (final PathWithAttributes pathWithAttributes : selectedForDeletion) {
108 final Path path = pathWithAttributes == null ? null : pathWithAttributes.getPath();
109 if (isTestMode()) {
110 LOGGER.info("Deleting {} (TEST MODE: file not actually deleted)", path);
111 } else {
112 delete(path);
113 }
114 }
115 }
116
117
118
119
120
121
122
123 protected void delete(final Path path) throws IOException {
124 LOGGER.trace("Deleting {}", path);
125 Files.deleteIfExists(path);
126 }
127
128
129
130
131
132
133 @Override
134 public boolean execute(final FileVisitor<Path> visitor) throws IOException {
135 final List<PathWithAttributes> sortedPaths = getSortedPaths();
136 trace("Sorted paths:", sortedPaths);
137
138 for (PathWithAttributes element : sortedPaths) {
139 try {
140 visitor.visitFile(element.getPath(), element.getAttributes());
141 } catch (final IOException ioex) {
142 LOGGER.error("Error in post-rollover Delete when visiting {}", element.getPath(), ioex);
143 visitor.visitFileFailed(element.getPath(), ioex);
144 }
145 }
146
147 return true;
148 }
149
150 private void trace(final String label, final List<PathWithAttributes> sortedPaths) {
151 LOGGER.trace(label);
152 for (final PathWithAttributes pathWithAttributes : sortedPaths) {
153 LOGGER.trace(pathWithAttributes);
154 }
155 }
156
157
158
159
160
161
162
163 List<PathWithAttributes> getSortedPaths() throws IOException {
164 final SortingVisitor sort = new SortingVisitor(pathSorter);
165 super.execute(sort);
166 final List<PathWithAttributes> sortedPaths = sort.getSortedPaths();
167 return sortedPaths;
168 }
169
170
171
172
173
174
175 public boolean isTestMode() {
176 return testMode;
177 }
178
179 @Override
180 protected FileVisitor<Path> createFileVisitor(final Path visitorBaseDir, final List<PathCondition> conditions) {
181 return new DeletingVisitor(visitorBaseDir, conditions, testMode);
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 @PluginFactory
203 public static DeleteAction createDeleteAction(
204
205 @PluginAttribute("basePath") final String basePath,
206 @PluginAttribute(value = "followLinks", defaultBoolean = false) final boolean followLinks,
207 @PluginAttribute(value = "maxDepth", defaultInt = 1) final int maxDepth,
208 @PluginAttribute(value = "testMode", defaultBoolean = false) final boolean testMode,
209 @PluginElement("PathSorter") final PathSorter sorterParameter,
210 @PluginElement("PathConditions") final PathCondition[] pathConditions,
211 @PluginElement("ScriptCondition") final ScriptCondition scriptCondition,
212 @PluginConfiguration final Configuration config) {
213
214 final PathSorter sorter = sorterParameter == null ? new PathSortByModificationTime(true) : sorterParameter;
215 return new DeleteAction(basePath, followLinks, maxDepth, testMode, sorter, pathConditions, scriptCondition,
216 config.getStrSubstitutor());
217 }
218 }