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 return scriptCondition != null ? executeScript() : super.execute();
82 }
83
84 private boolean executeScript() throws IOException {
85 final List<PathWithAttributes> selectedForDeletion = callScript();
86 if (selectedForDeletion == null) {
87 LOGGER.trace("Script returned null list (no files to delete)");
88 return true;
89 }
90 deleteSelectedFiles(selectedForDeletion);
91 return true;
92 }
93
94 private List<PathWithAttributes> callScript() throws IOException {
95 final List<PathWithAttributes> sortedPaths = getSortedPaths();
96 trace("Sorted paths:", sortedPaths);
97 final List<PathWithAttributes> result = scriptCondition.selectFilesToDelete(getBasePath(), sortedPaths);
98 return result;
99 }
100
101 private void deleteSelectedFiles(final List<PathWithAttributes> selectedForDeletion) throws IOException {
102 trace("Paths the script selected for deletion:", selectedForDeletion);
103 for (final PathWithAttributes pathWithAttributes : selectedForDeletion) {
104 final Path path = pathWithAttributes == null ? null : pathWithAttributes.getPath();
105 if (isTestMode()) {
106 LOGGER.info("Deleting {} (TEST MODE: file not actually deleted)", path);
107 } else {
108 delete(path);
109 }
110 }
111 }
112
113
114
115
116
117
118
119 protected void delete(final Path path) throws IOException {
120 LOGGER.trace("Deleting {}", path);
121 Files.deleteIfExists(path);
122 }
123
124
125
126
127
128
129 @Override
130 public boolean execute(final FileVisitor<Path> visitor) throws IOException {
131 final List<PathWithAttributes> sortedPaths = getSortedPaths();
132 trace("Sorted paths:", sortedPaths);
133
134 for (final PathWithAttributes element : sortedPaths) {
135 try {
136 visitor.visitFile(element.getPath(), element.getAttributes());
137 } catch (final IOException ioex) {
138 LOGGER.error("Error in post-rollover Delete when visiting {}", element.getPath(), ioex);
139 visitor.visitFileFailed(element.getPath(), ioex);
140 }
141 }
142
143 return true;
144 }
145
146 private void trace(final String label, final List<PathWithAttributes> sortedPaths) {
147 LOGGER.trace(label);
148 for (final PathWithAttributes pathWithAttributes : sortedPaths) {
149 LOGGER.trace(pathWithAttributes);
150 }
151 }
152
153
154
155
156
157
158
159 List<PathWithAttributes> getSortedPaths() throws IOException {
160 final SortingVisitor sort = new SortingVisitor(pathSorter);
161 super.execute(sort);
162 final List<PathWithAttributes> sortedPaths = sort.getSortedPaths();
163 return sortedPaths;
164 }
165
166
167
168
169
170
171 public boolean isTestMode() {
172 return testMode;
173 }
174
175 @Override
176 protected FileVisitor<Path> createFileVisitor(final Path visitorBaseDir, final List<PathCondition> conditions) {
177 return new DeletingVisitor(visitorBaseDir, conditions, testMode);
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198 @PluginFactory
199 public static DeleteAction createDeleteAction(
200
201 @PluginAttribute("basePath") final String basePath,
202 @PluginAttribute(value = "followLinks", defaultBoolean = false) final boolean followLinks,
203 @PluginAttribute(value = "maxDepth", defaultInt = 1) final int maxDepth,
204 @PluginAttribute(value = "testMode", defaultBoolean = false) final boolean testMode,
205 @PluginElement("PathSorter") final PathSorter sorterParameter,
206 @PluginElement("PathConditions") final PathCondition[] pathConditions,
207 @PluginElement("ScriptCondition") final ScriptCondition scriptCondition,
208 @PluginConfiguration final Configuration config) {
209
210 final PathSorter sorter = sorterParameter == null ? new PathSortByModificationTime(true) : sorterParameter;
211 return new DeleteAction(basePath, followLinks, maxDepth, testMode, sorter, pathConditions, scriptCondition,
212 config.getStrSubstitutor());
213 }
214 }