/*
GNU GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
package org.lobobrowser.store;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarFile;
import org.lobobrowser.security.LocalSecurityPolicy;
// TODO: This doesn't seem to be used anymore. Remove?
class TempFileManager {
private static TempFileManager instance;
private static final String GENERAL_PREFIX = "gngr-";
private static final long ONE_DAY = 24L * 60 * 60 * 1000;
private static final long ONE_MONTH = 30L * ONE_DAY;
private static final long THIRTY_YEARS = 30L * 365 * ONE_DAY;
private static final String FILE_PREFIX = GENERAL_PREFIX + ((System.currentTimeMillis() - THIRTY_YEARS) / 1000) + "-";
private final File TEMP_DIRECTORY;
private final ReferenceQueue<JarFile> REFERENCE_QUEUE = new ReferenceQueue<>();
private final Map<String, LocalWeakReference> wrByPath = new HashMap<>();
private int counter = 0;
public static TempFileManager getInstance() {
// Do it this way to allow other statics to initialize.
if (instance == null) {
synchronized (TempFileManager.class) {
if (instance == null) {
instance = new TempFileManager();
}
}
}
return instance;
}
private TempFileManager() {
Runtime.getRuntime().addShutdownHook(new ShutdownThread());
final File tempDirectory = new File(LocalSecurityPolicy.STORE_DIRECTORY, "tmp");
TEMP_DIRECTORY = tempDirectory;
if (!tempDirectory.exists()) {
tempDirectory.mkdirs();
}
final File[] files = tempDirectory.listFiles();
if (files != null) {
// Cleanup files theoretically left by previously running instance.
for (final File file : files) {
final String name = file.getName();
if (name.startsWith(GENERAL_PREFIX) && !name.startsWith(FILE_PREFIX)) {
// We can't really assume only one instance of the application
// is running. Need to be a little lenient about deleting these.
if (file.lastModified() < (System.currentTimeMillis() - ONE_MONTH)) {
file.delete();
}
}
}
}
}
private void shutdownCleanup() {
final File[] files = TEMP_DIRECTORY.listFiles();
if (files != null) {
for (final File file : files) {
try {
final String name = file.getName();
if (name.startsWith(FILE_PREFIX)) {
final String canonical = file.getCanonicalPath();
synchronized (this) {
// Need to close these JAR files, otherwise
// deletion does not happen in Windows.
final LocalWeakReference wr = this.wrByPath.get(canonical);
final JarFile jarFile = wr.get();
if (jarFile != null) {
jarFile.close();
}
}
file.delete();
}
} catch (final java.io.IOException ioe) {
// ignore
}
}
}
}
public JarFile createJarFile(final byte[] bytes) throws java.io.IOException {
// Dequeue and clean up first
for (;;) {
final Reference<? extends JarFile> ref = REFERENCE_QUEUE.poll();
if (ref == null) {
break;
}
final String canonical = ((LocalWeakReference) ref).canonicalPath;
new File(canonical).delete();
synchronized (this) {
this.wrByPath.remove(canonical);
}
}
final File file = this.newTempFile();
try (
final OutputStream out = new FileOutputStream(file)) {
out.write(bytes);
}
final JarFile jarFile = new JarFile(file);
final String canonical = file.getCanonicalPath();
final LocalWeakReference wr = new LocalWeakReference(jarFile, REFERENCE_QUEUE, canonical);
synchronized (this) {
// This serves simply to retain the weak reference.
this.wrByPath.put(canonical, wr);
}
return jarFile;
}
public File newTempFile() throws IOException {
synchronized (this) {
final int newCounter = this.counter++;
final File file = new File(this.TEMP_DIRECTORY, FILE_PREFIX + newCounter);
return file;
}
}
private static class LocalWeakReference extends WeakReference<JarFile> {
public final String canonicalPath;
public LocalWeakReference(final JarFile referent, final ReferenceQueue<? super JarFile> q, final String canonicalPath) {
super(referent, q);
this.canonicalPath = canonicalPath;
}
}
private class ShutdownThread extends Thread {
@Override
public void run() {
shutdownCleanup();
}
}
}