Skip to content

Package: WeakDataFile$CleanupRunnable

WeakDataFile$CleanupRunnable

nameinstructionbranchcomplexitylinemethod
run()
M: 38 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Distribution License v. 1.0, which is available at
6: * http://www.eclipse.org/org/documents/edl-v10.php.
7: *
8: * SPDX-License-Identifier: BSD-3-Clause
9: */
10:
11: package org.jvnet.mimepull;
12:
13: import java.nio.file.Files;
14: import java.nio.file.Path;
15: import java.nio.file.StandardCopyOption;
16: import java.util.concurrent.TimeUnit;
17:
18: import java.io.File;
19: import java.io.IOException;
20: import java.io.RandomAccessFile;
21: import java.lang.ref.ReferenceQueue;
22: import java.lang.ref.WeakReference;
23: import java.util.Queue;
24: import java.util.concurrent.ConcurrentLinkedQueue;
25: import java.util.concurrent.ScheduledExecutorService;
26: import java.util.logging.Level;
27: import java.util.logging.Logger;
28:
29: /**
30: * Removing files based on this
31: * <a href="https://www.oracle.com/technical-resources/articles/javase/finalization.html">article</a>
32: *
33: * @author Jitendra Kotamraju
34: */
35: final class WeakDataFile extends WeakReference<DataFile> {
36:
37: private static final Logger LOGGER = Logger.getLogger(WeakDataFile.class.getName());
38: private static int TIMEOUT = 10; //milliseconds
39: //private static final int MAX_ITERATIONS = 2;
40: private static ReferenceQueue<DataFile> refQueue = new ReferenceQueue<>();
41: private static Queue<WeakDataFile> refList = new ConcurrentLinkedQueue<>();
42: private File file;
43: private final RandomAccessFile raf;
44: private static boolean hasCleanUpExecutor = false;
45: static {
46: int delay = 10;
47: try {
48: delay = Integer.getInteger("org.jvnet.mimepull.delay", 10);
49: } catch (SecurityException se) {
50: if (LOGGER.isLoggable(Level.CONFIG)) {
51: LOGGER.log(Level.CONFIG, "Cannot read ''{0}'' property, using defaults.",
52: new Object[] {"org.jvnet.mimepull.delay"});
53: }
54: }
55: CleanUpExecutorFactory executorFactory = CleanUpExecutorFactory.newInstance();
56: if (executorFactory!=null) {
57: if (LOGGER.isLoggable(Level.FINE)) {
58: LOGGER.log(Level.FINE, "Initializing clean up executor for MIMEPULL: {0}", executorFactory.getClass().getName());
59: }
60: ScheduledExecutorService scheduler = executorFactory.getScheduledExecutorService();
61: scheduler.scheduleWithFixedDelay(new CleanupRunnable(), delay, delay, TimeUnit.SECONDS);
62: hasCleanUpExecutor = true;
63: }
64: }
65:
66: WeakDataFile(DataFile df, File file) {
67: super(df, refQueue);
68: refList.add(this);
69: this.file = file;
70: try {
71: raf = new RandomAccessFile(file, "rw");
72: } catch(IOException ioe) {
73: throw new MIMEParsingException(ioe);
74: }
75: if (!hasCleanUpExecutor) {
76: drainRefQueueBounded();
77: }
78: }
79:
80: synchronized void read(long pointer, byte[] buf, int offset, int length ) {
81: try {
82: raf.seek(pointer);
83: raf.readFully(buf, offset, length);
84: } catch(IOException ioe) {
85: throw new MIMEParsingException(ioe);
86: }
87: }
88:
89: synchronized long writeTo(long pointer, byte[] data, int offset, int length) {
90: try {
91: raf.seek(pointer);
92: raf.write(data, offset, length);
93: return raf.getFilePointer(); // Update pointer for next write
94: } catch(IOException ioe) {
95: throw new MIMEParsingException(ioe);
96: }
97: }
98:
99: void close() {
100: if (LOGGER.isLoggable(Level.FINE)) {
101: LOGGER.log(Level.FINE, "Deleting file = {0}", file.getName());
102: }
103: refList.remove(this);
104: try {
105: raf.close();
106: boolean deleted = file.delete();
107: if (!deleted) {
108: if (LOGGER.isLoggable(Level.INFO)) {
109: LOGGER.log(Level.INFO, "File {0} was not deleted", file.getAbsolutePath());
110: }
111: }
112: } catch(IOException ioe) {
113: throw new MIMEParsingException(ioe);
114: }
115: }
116:
117: void renameTo(File f) {
118: if (LOGGER.isLoggable(Level.FINE)) {
119: LOGGER.log(Level.FINE, "Moving file={0} to={1}", new Object[]{file, f});
120: }
121: refList.remove(this);
122: try {
123: raf.close();
124: Path target = Files.move(file.toPath(), f.toPath(), StandardCopyOption.REPLACE_EXISTING);
125: boolean renamed = f.toPath().equals(target);
126: if (!renamed) {
127: if (LOGGER.isLoggable(Level.INFO)) {
128: throw new MIMEParsingException("File " + file.getAbsolutePath() +
129: " was not moved to " + f.getAbsolutePath());
130: }
131: }
132: file = target.toFile();
133: } catch(IOException ioe) {
134: throw new MIMEParsingException(ioe);
135: }
136:
137: }
138:
139: static void drainRefQueueBounded() {
140: WeakDataFile weak;
141: while (( weak = (WeakDataFile) refQueue.poll()) != null ) {
142: if (LOGGER.isLoggable(Level.FINE)) {
143: LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file);
144: }
145: weak.close();
146: }
147: }
148:
149: private static class CleanupRunnable implements Runnable {
150:
151: @Override
152: public void run() {
153: try {
154:• if (LOGGER.isLoggable(Level.FINE)) {
155: LOGGER.log(Level.FINE, "Running cleanup task");
156: }
157: WeakDataFile weak = (WeakDataFile) refQueue.remove(TIMEOUT);
158:• while (weak != null) {
159:• if (LOGGER.isLoggable(Level.FINE)) {
160: LOGGER.log(Level.FINE, "Cleaning file = {0} from reference queue.", weak.file);
161: }
162: weak.close();
163: weak = (WeakDataFile) refQueue.remove(TIMEOUT);
164: }
165: } catch (InterruptedException e) {
166: }
167: }
168: }
169: }