1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.config;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.nio.file.FileVisitResult;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.nio.file.SimpleFileVisitor;
28 import java.nio.file.attribute.BasicFileAttributes;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 import javax.xml.transform.TransformerException;
32 import javax.xml.transform.stream.StreamResult;
33 import javax.xml.transform.stream.StreamSource;
34
35 import org.apache.logging.log4j.core.config.ConfigurationException;
36 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
37 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
38 import org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder;
39 import org.apache.logging.log4j.core.tools.BasicCommandLineArguments;
40 import org.apache.logging.log4j.core.tools.picocli.CommandLine;
41 import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command;
42 import org.apache.logging.log4j.core.tools.picocli.CommandLine.Option;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public final class Log4j1ConfigurationConverter {
61
62 @Command(name = "Log4j1ConfigurationConverter")
63 public static class CommandLineArguments extends BasicCommandLineArguments implements Runnable {
64
65 @Option(names = { "--failfast", "-f" }, description = "Fails on the first failure in recurse mode.")
66 private boolean failFast;
67
68 @Option(names = { "--in", "-i" }, description = "Specifies the input file.")
69 private Path pathIn;
70
71 @Option(names = { "--out", "-o" }, description = "Specifies the output file.")
72 private Path pathOut;
73
74 @Option(names = { "--recurse", "-r" }, description = "Recurses into this folder looking for the input file")
75 private Path recurseIntoPath;
76
77 @Option(names = { "--verbose", "-v" }, description = "Be verbose.")
78 private boolean verbose;
79
80 public Path getPathIn() {
81 return pathIn;
82 }
83
84 public Path getPathOut() {
85 return pathOut;
86 }
87
88 public Path getRecurseIntoPath() {
89 return recurseIntoPath;
90 }
91
92 public boolean isFailFast() {
93 return failFast;
94 }
95
96 public boolean isVerbose() {
97 return verbose;
98 }
99
100 public void setFailFast(final boolean failFast) {
101 this.failFast = failFast;
102 }
103
104 public void setPathIn(final Path pathIn) {
105 this.pathIn = pathIn;
106 }
107
108 public void setPathOut(final Path pathOut) {
109 this.pathOut = pathOut;
110 }
111
112 public void setRecurseIntoPath(final Path recurseIntoPath) {
113 this.recurseIntoPath = recurseIntoPath;
114 }
115
116 public void setVerbose(final boolean verbose) {
117 this.verbose = verbose;
118 }
119
120 @Override
121 public void run() {
122 if (isHelp()) {
123 CommandLine.usage(this, System.err);
124 return;
125 }
126 new Log4j1ConfigurationConverter(this).run();
127 }
128
129 @Override
130 public String toString() {
131 return "CommandLineArguments [recurseIntoPath=" + recurseIntoPath + ", verbose=" + verbose + ", pathIn="
132 + pathIn + ", pathOut=" + pathOut + "]";
133 }
134 }
135
136 private static final String FILE_EXT_XML = ".xml";
137
138 public static void main(final String[] args) {
139 CommandLine.run(new CommandLineArguments(), System.err, args);
140 }
141
142 public static Log4j1ConfigurationConverter run(final CommandLineArguments cla) {
143 final Log4j1ConfigurationConverter log4j1ConfigurationConverter = new Log4j1ConfigurationConverter(cla);
144 log4j1ConfigurationConverter.run();
145 return log4j1ConfigurationConverter;
146 }
147
148 private final CommandLineArguments cla;
149
150 private Log4j1ConfigurationConverter(final CommandLineArguments cla) {
151 this.cla = cla;
152 }
153
154 protected void convert(final InputStream input, final OutputStream output) throws IOException {
155 final ConfigurationBuilder<BuiltConfiguration> builder = new Log4j1ConfigurationParser()
156 .buildConfigurationBuilder(input);
157 builder.writeXmlConfiguration(output);
158 }
159
160 InputStream getInputStream() throws IOException {
161 final Path pathIn = cla.getPathIn();
162 return pathIn == null ? System.in : new InputStreamWrapper(Files.newInputStream(pathIn), pathIn.toString());
163 }
164
165 OutputStream getOutputStream() throws IOException {
166 final Path pathOut = cla.getPathOut();
167 return pathOut == null ? System.out : Files.newOutputStream(pathOut);
168 }
169
170 private void run() {
171 if (cla.getRecurseIntoPath() != null) {
172 final AtomicInteger countOKs = new AtomicInteger();
173 final AtomicInteger countFails = new AtomicInteger();
174 try {
175 Files.walkFileTree(cla.getRecurseIntoPath(), new SimpleFileVisitor<Path>() {
176 @Override
177 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
178 throws IOException {
179 if (cla.getPathIn() == null || file.getFileName().equals(cla.getPathIn())) {
180 verbose("Reading %s", file);
181 String newFile = file.getFileName().toString();
182 final int lastIndex = newFile.lastIndexOf(".");
183 newFile = lastIndex < 0 ? newFile + FILE_EXT_XML
184 : newFile.substring(0, lastIndex) + FILE_EXT_XML;
185 final Path resolvedPath = file.resolveSibling(newFile);
186 try (final InputStream input = new InputStreamWrapper(Files.newInputStream(file), file.toString());
187 final OutputStream output = Files.newOutputStream(resolvedPath)) {
188 try {
189 final ByteArrayOutputStream tmpOutput = new ByteArrayOutputStream();
190 convert(input, tmpOutput);
191 tmpOutput.close();
192 DefaultConfigurationBuilder.formatXml(
193 new StreamSource(new ByteArrayInputStream(tmpOutput.toByteArray())),
194 new StreamResult(output));
195 countOKs.incrementAndGet();
196 } catch (ConfigurationException | IOException e) {
197 countFails.incrementAndGet();
198 if (cla.isFailFast()) {
199 throw e;
200 }
201 e.printStackTrace();
202 } catch (TransformerException e) {
203 countFails.incrementAndGet();
204 if (cla.isFailFast()) {
205 throw new IOException(e);
206 }
207 e.printStackTrace();
208 }
209 verbose("Wrote %s", resolvedPath);
210 }
211 }
212 return FileVisitResult.CONTINUE;
213 }
214 });
215 } catch (final IOException e) {
216 throw new ConfigurationException(e);
217 } finally {
218 verbose("OK = %,d, Failures = %,d, Total = %,d", countOKs.get(), countFails.get(),
219 countOKs.get() + countFails.get());
220 }
221 } else {
222 verbose("Reading %s", cla.getPathIn());
223 try (final InputStream input = getInputStream(); final OutputStream output = getOutputStream()) {
224 convert(input, output);
225 } catch (final IOException e) {
226 throw new ConfigurationException(e);
227 }
228 verbose("Wrote %s", cla.getPathOut());
229 }
230 }
231
232 private void verbose(final String template, final Object... args) {
233 if (cla.isVerbose()) {
234 System.err.println(String.format(template, args));
235 }
236 }
237
238 }