Skip to content

Commit 4b7065b

Browse files
ppkarwaszvy
andauthored
Simplify file manager registry factory pattern (#3968)
* Simplify file manager registry factory pattern The current factory pattern used with the `AbstractManager` registry is unnecessarily complex. It relies on: * **Stateless factory classes** to create managers of each type, * **Separate `FactoryData` parameter objects** to pass construction data #### What this PR does This PR simplifies the registry factory mechanism by: * Replacing the factory classes with **inline lambda factories** * Allowing **stateful factory lambdas**, removing boilerplate `FactoryData` classes in most cases * Keeping factory logic **localized and easier to follow** within the registry call site This is a **pure refactoring**, it does not change behavior. It improves code readability and maintainability by reducing indirection and eliminating unnecessary types. #### Notes `FactoryData` parameter objects are still used where necessary: * **`RollingFileManager`** and **`RollingRandomAccessFileManager`** still require parameter objects since they update state on each retrieval, not just during initialization. * Other managers still pass `Configuration` through `ConfigurationFactoryData` to access `getLoggerContext()`, which remains useful. * fix: add reference to PR number * Apply suggestions from code review Co-authored-by: Volkan Yazıcı <volkan@yazi.ci> --------- Co-authored-by: Volkan Yazıcı <volkan@yazi.ci>
1 parent 296d1d7 commit 4b7065b

File tree

7 files changed

+242
-614
lines changed

7 files changed

+242
-614
lines changed

log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) {
133133
* @param <M> The Type of the Manager to be created.
134134
* @param <T> The type of the Factory data.
135135
* @return A Manager with the specified name and type.
136+
* @throws IllegalStateException if the factory is unable to create the manager
136137
*/
137138
// @SuppressWarnings("resource"): this is a factory method, the resource is allocated and released elsewhere.
138139
@SuppressWarnings("resource")

log4j-core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java

Lines changed: 37 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@
5050
*/
5151
public class FileManager extends OutputStreamManager {
5252

53-
private static final FileManagerFactory FACTORY = new FileManagerFactory();
54-
5553
private final boolean isAppend;
5654
private final boolean createOnDemand;
5755
private final boolean isLocking;
@@ -194,7 +192,7 @@ protected FileManager(
194192
* @param locking true if the file should be locked while writing, false otherwise.
195193
* @param bufferedIo true if the contents should be buffered as they are written.
196194
* @param createOnDemand true if you want to lazy-create the file (a.k.a. on-demand.)
197-
* @param advertiseUri the URI to use when advertising the file
195+
* @param advertiseURI the URI to use when advertising the file
198196
* @param layout The layout
199197
* @param bufferSize buffer size for buffered IO
200198
* @param filePermissions File permissions
@@ -209,34 +207,52 @@ public static FileManager getFileManager(
209207
boolean locking,
210208
final boolean bufferedIo,
211209
final boolean createOnDemand,
212-
final String advertiseUri,
210+
final String advertiseURI,
213211
final Layout<? extends Serializable> layout,
214212
final int bufferSize,
215213
final String filePermissions,
216214
final String fileOwner,
217215
final String fileGroup,
218216
final Configuration configuration) {
219-
220-
if (locking && bufferedIo) {
221-
locking = false;
222-
}
217+
// Disable locking if buffered IO is enabled
218+
boolean actualLocking = !bufferedIo && locking;
219+
int actualBufferSize = bufferedIo ? bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE;
223220
return narrow(
224221
FileManager.class,
225222
getManager(
226223
fileName,
227-
new FactoryData(
228-
append,
229-
locking,
230-
bufferedIo,
231-
bufferSize,
232-
createOnDemand,
233-
advertiseUri,
234-
layout,
235-
filePermissions,
236-
fileOwner,
237-
fileGroup,
238-
configuration),
239-
FACTORY));
224+
(name, data) -> {
225+
Objects.requireNonNull(name, "filename is missing");
226+
final File file = new File(name);
227+
try {
228+
FileUtils.makeParentDirs(file);
229+
final boolean writeHeader = !append || !file.exists();
230+
final ByteBuffer byteBuffer = ByteBuffer.allocate(actualBufferSize);
231+
final FileOutputStream fos = createOnDemand ? null : new FileOutputStream(file, append);
232+
final FileManager fm = new FileManager(
233+
data.getLoggerContext(),
234+
name,
235+
fos,
236+
append,
237+
actualLocking,
238+
createOnDemand,
239+
advertiseURI,
240+
layout,
241+
filePermissions,
242+
fileOwner,
243+
fileGroup,
244+
writeHeader,
245+
byteBuffer);
246+
if (fos != null && fm.attributeViewEnabled) {
247+
fm.defineAttributeView(file.toPath());
248+
}
249+
return fm;
250+
} catch (final IOException ex) {
251+
LOGGER.error("FileManager ({}): {}", name, ex);
252+
}
253+
return null;
254+
},
255+
new ConfigurationFactoryData(configuration)));
240256
}
241257

242258
@Override
@@ -426,108 +442,4 @@ public Map<String, String> getContentFormat() {
426442
result.put("fileURI", advertiseURI);
427443
return result;
428444
}
429-
430-
/**
431-
* Factory Data.
432-
*/
433-
private static class FactoryData extends ConfigurationFactoryData {
434-
private final boolean append;
435-
private final boolean locking;
436-
private final boolean bufferedIo;
437-
private final int bufferSize;
438-
private final boolean createOnDemand;
439-
private final String advertiseURI;
440-
private final Layout<? extends Serializable> layout;
441-
private final String filePermissions;
442-
private final String fileOwner;
443-
private final String fileGroup;
444-
445-
/**
446-
* Constructor.
447-
* @param append Append status.
448-
* @param locking Locking status.
449-
* @param bufferedIo Buffering flag.
450-
* @param bufferSize Buffer size.
451-
* @param createOnDemand if you want to lazy-create the file (a.k.a. on-demand.)
452-
* @param advertiseURI the URI to use when advertising the file
453-
* @param layout The layout
454-
* @param filePermissions File permissions
455-
* @param fileOwner File owner
456-
* @param fileGroup File group
457-
* @param configuration the configuration
458-
*/
459-
public FactoryData(
460-
final boolean append,
461-
final boolean locking,
462-
final boolean bufferedIo,
463-
final int bufferSize,
464-
final boolean createOnDemand,
465-
final String advertiseURI,
466-
final Layout<? extends Serializable> layout,
467-
final String filePermissions,
468-
final String fileOwner,
469-
final String fileGroup,
470-
final Configuration configuration) {
471-
super(configuration);
472-
this.append = append;
473-
this.locking = locking;
474-
this.bufferedIo = bufferedIo;
475-
this.bufferSize = bufferSize;
476-
this.createOnDemand = createOnDemand;
477-
this.advertiseURI = advertiseURI;
478-
this.layout = layout;
479-
this.filePermissions = filePermissions;
480-
this.fileOwner = fileOwner;
481-
this.fileGroup = fileGroup;
482-
}
483-
}
484-
485-
/**
486-
* Factory to create a FileManager.
487-
*/
488-
private static class FileManagerFactory implements ManagerFactory<FileManager, FactoryData> {
489-
490-
/**
491-
* Creates a FileManager.
492-
* @param name The name of the File.
493-
* @param data The FactoryData
494-
* @return The FileManager for the File.
495-
*/
496-
@Override
497-
@SuppressFBWarnings(
498-
value = "PATH_TRAVERSAL_IN",
499-
justification = "The destination file should be specified in the configuration file.")
500-
public FileManager createManager(final String name, final FactoryData data) {
501-
Objects.requireNonNull(name, "filename is missing");
502-
final File file = new File(name);
503-
try {
504-
FileUtils.makeParentDirs(file);
505-
final boolean writeHeader = !data.append || !file.exists();
506-
final int actualSize = data.bufferedIo ? data.bufferSize : Constants.ENCODER_BYTE_BUFFER_SIZE;
507-
final ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[actualSize]);
508-
final FileOutputStream fos = data.createOnDemand ? null : new FileOutputStream(file, data.append);
509-
final FileManager fm = new FileManager(
510-
data.getLoggerContext(),
511-
name,
512-
fos,
513-
data.append,
514-
data.locking,
515-
data.createOnDemand,
516-
data.advertiseURI,
517-
data.layout,
518-
data.filePermissions,
519-
data.fileOwner,
520-
data.fileGroup,
521-
writeHeader,
522-
byteBuffer);
523-
if (fos != null && fm.attributeViewEnabled) {
524-
fm.defineAttributeView(file.toPath());
525-
}
526-
return fm;
527-
} catch (final IOException ex) {
528-
LOGGER.error("FileManager (" + name + ") " + ex, ex);
529-
}
530-
return null;
531-
}
532-
}
533445
}

log4j-core/src/main/java/org/apache/logging/log4j/core/appender/MemoryMappedFileManager.java

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
package org.apache.logging.log4j.core.appender;
1818

19-
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2019
import java.io.File;
2120
import java.io.IOException;
2221
import java.io.OutputStream;
@@ -58,7 +57,6 @@ public class MemoryMappedFileManager extends OutputStreamManager {
5857
static final int DEFAULT_REGION_LENGTH = 32 * 1024 * 1024;
5958

6059
private static final int MAX_REMAP_COUNT = 10;
61-
private static final MemoryMappedFileManagerFactory FACTORY = new MemoryMappedFileManagerFactory();
6260
private static final double NANOS_PER_MILLISEC = 1000.0 * 1000.0;
6361

6462
private final boolean immediateFlush;
@@ -111,8 +109,37 @@ public static MemoryMappedFileManager getFileManager(
111109
MemoryMappedFileManager.class,
112110
getManager(
113111
fileName,
114-
new FactoryData(append, immediateFlush, regionLength, advertiseURI, layout),
115-
FACTORY));
112+
(name, ignored) -> {
113+
final File file = new File(name);
114+
if (!append) {
115+
file.delete();
116+
}
117+
118+
final boolean writeHeader = !append || !file.exists();
119+
final OutputStream os = NullOutputStream.getInstance();
120+
RandomAccessFile raf = null;
121+
try {
122+
FileUtils.makeParentDirs(file);
123+
raf = new RandomAccessFile(name, "rw");
124+
final long position = (append) ? raf.length() : 0;
125+
raf.setLength(position + regionLength);
126+
return new MemoryMappedFileManager(
127+
raf,
128+
name,
129+
os,
130+
immediateFlush,
131+
position,
132+
regionLength,
133+
advertiseURI,
134+
layout,
135+
writeHeader);
136+
} catch (final Exception ex) {
137+
LOGGER.error("MemoryMappedFileManager (" + name + ") " + ex, ex);
138+
Closer.closeSilently(raf);
139+
}
140+
return null;
141+
},
142+
(Void) null));
116143
}
117144

118145
/**
@@ -341,54 +368,4 @@ public FactoryData(
341368
this.layout = layout;
342369
}
343370
}
344-
345-
/**
346-
* Factory to create a MemoryMappedFileManager.
347-
*/
348-
private static class MemoryMappedFileManagerFactory
349-
implements ManagerFactory<MemoryMappedFileManager, FactoryData> {
350-
351-
/**
352-
* Create a MemoryMappedFileManager.
353-
*
354-
* @param name The name of the File.
355-
* @param data The FactoryData
356-
* @return The MemoryMappedFileManager for the File.
357-
*/
358-
@SuppressWarnings("resource")
359-
@Override
360-
@SuppressFBWarnings(
361-
value = "PATH_TRAVERSAL_IN",
362-
justification = "The destination file should be specified in the configuration file.")
363-
public MemoryMappedFileManager createManager(final String name, final FactoryData data) {
364-
final File file = new File(name);
365-
if (!data.append) {
366-
file.delete();
367-
}
368-
369-
final boolean writeHeader = !data.append || !file.exists();
370-
final OutputStream os = NullOutputStream.getInstance();
371-
RandomAccessFile raf = null;
372-
try {
373-
FileUtils.makeParentDirs(file);
374-
raf = new RandomAccessFile(name, "rw");
375-
final long position = (data.append) ? raf.length() : 0;
376-
raf.setLength(position + data.regionLength);
377-
return new MemoryMappedFileManager(
378-
raf,
379-
name,
380-
os,
381-
data.immediateFlush,
382-
position,
383-
data.regionLength,
384-
data.advertiseURI,
385-
data.layout,
386-
writeHeader);
387-
} catch (final Exception ex) {
388-
LOGGER.error("MemoryMappedFileManager (" + name + ") " + ex, ex);
389-
Closer.closeSilently(raf);
390-
}
391-
return null;
392-
}
393-
}
394371
}

0 commit comments

Comments
 (0)