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