📄 fileexpirationservice.java
字号:
/*
* Copyright (c) 2001 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Sun Microsystems, Inc. for Project JXTA."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA",
* nor may "JXTA" appear in their name, without prior written
* permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of Project JXTA. For more
* information on Project JXTA, please see
* <http://www.jxta.org/>.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*
* $Id: FileExpirationService.java,v 1.22 2002/05/16 05:55:46 bondolo Exp $
*/
package net.jxta.impl.cm;
import java.io.*;
import java.util.*;
import java.lang.IllegalArgumentException;
import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import net.jxta.impl.util.TimeUtils;
class FileExpirationService {
static final Category LOG = Category.getInstance(FileExpirationService.class.getName());
static final String SCHED_DB_FILENAME = "scheduler.db";
static final String TEMP_SCHED_DB_FILENAME = ".tmp.scheduler.db";
static final int SCHEDULE = 1;
static final int CANCEL = 2;
static final long COMPRESS_INTERVAL = 30 * TimeUtils.AMINUTE;
static final int MOD_THRESHOLD = 128;
File dir;
File db;
File tmpDb;
DataOutputStream out;
FileDescriptor outFD;
Hashtable hash;
int mods;
SchedulerService ss;
SchedulerService.PendingAction pendingCompressAction;
ExpirationListener listener;
/**
* Interface called when the time finally comes for the file to be deleted.
* The expiration service does not actually delete the files, because they
* may be republished during the call of the 'expire' handler.
**/
interface ExpirationListener {
/**
* The file which has expired and needs to be deleted. In some rare
* cases the file provided may no longer exist (It's not the expiration
* service's fault) these notifications are provided so that the
* listener can take recovery action.
*
* @param file the file which has expired.
* @return true if the expiration service should delete the file
* otherwise false.
*
**/
public boolean expired(File file);
}
/**
* inner class for performing periodic compression of the expiration log
* file.
**/
class CleanupAction implements SchedulerService.Action {
public void perform(SchedulerService ss) {
try{
synchronized( FileExpirationService.this ) {
if (db.exists())
compress(true);
else {
if (LOG.isEnabledFor(Priority.WARN))
LOG.warn("Expiry log not present!" );
}
}
} catch (IOException e) {
if (LOG.isEnabledFor(Priority.DEBUG))
LOG.debug("Compression of log stream failed.", e);
}
// still re-schedule, because the administrator may
// see the log messages and do something that will
// make the compress action succeed later. or something.
pendingCompressAction =
ss.scheduleAction(this, COMPRESS_INTERVAL);
}
}
/**
* Testing action for advancing the clock so that things magically expire
* more quickly than they would normally.
**/
static class TimewarpAction implements SchedulerService.Action {
private long warpby;
private long warpinterval;
public TimewarpAction( long warpinterval, long warpby ) {
this.warpinterval = warpinterval;
this.warpby = warpby;
}
public void perform(SchedulerService ss) {
ss.scheduleAction(this, warpinterval + warpby );
synchronized (ss) {
TimeUtils.timeWarp( warpby );
ss.notifyAll();
}
}
}
/**
* inner class which is called by the Scheduler service when an entry
* expires.
**/
class ExpireAction implements SchedulerService.Action {
Entry entry;
ExpireAction(Entry entry) {
this.entry = entry;
}
public void perform(SchedulerService ss) throws IOException {
// Do not synchronize for the listener, it never changes after
// construction.
// But do synchronize for hash.remove. Other methods rely
// on the hashtable not changing while they're synchronized.
try {
boolean needsDelete = true;
if (listener != null)
needsDelete = listener.expired(entry.file);
if( needsDelete )
entry.file.delete();
} catch ( Throwable t ) {
if (LOG.isEnabledFor(Priority.DEBUG))
LOG.debug( "Throwable caught while dispatching expiration listener.", t );
} finally {
// remove this entry from the hash, its going away.
synchronized(FileExpirationService.this) {
hash.remove(entry.file.getCanonicalPath());
}
// mark this entry as dead.
synchronized( entry ) {
entry.file = null; // dead entry.
entry.expiryAction = null;
}
}
}
}
/**
* static inner class for entries in the expiration hash table.
**/
static class Entry {
/**
* The file
**/
File file;
/**
* The absolute time in milliseconds at which this document will expire.
**/
long expiresAt;
/**
* the duration of validity in milliseconds within a cache other than
* its original publication location.
**/
long cacheLifetime;
/**
* The action to be performed when it expires.
**/
SchedulerService.PendingAction expiryAction;
/**
* @param expiresAt time after which the document is removed from
* the local cahce. Expressed in absolute milliseconds.
* @param cacheLifetime time after which the document is removed from
* remote caches. Expressed in relative milliseconds.
*/
Entry( File file, long expiresAt, long cacheLifetime ) {
this.file = file;
this.expiresAt = expiresAt;
this.cacheLifetime = cacheLifetime;
}
}
/**
* @param ss The scheduler used to be used.
* @param dir The directory containing the files being managed.
* @param listener who will be told when files expires.
*/
FileExpirationService( SchedulerService ss,
File dir,
ExpirationListener listener) throws IOException {
this.ss = ss;
this.dir = dir;
this.listener = listener;
hash = new Hashtable();
if ( !dir.exists() )
if( !dir.mkdirs() ) {
throw new IOException( "Could not create target directory" );
}
else if( !dir.isDirectory() ) {
throw new IllegalArgumentException( "dir exists and is not a directory" );
}
db = new File( dir, SCHED_DB_FILENAME );
mods = 0;
tmpDb = new File( dir, TEMP_SCHED_DB_FILENAME );
if ( tmpDb.exists() )
tmpDb.delete();
if ( tmpDb.exists() ) {
if (LOG.isEnabledFor(Priority.WARN))
LOG.warn("Could not delete temp file. This will be a problem..." );
}
// if there is an existing db, we populate the hash table from it.
try {
if (db.exists()) {
compress( true );
} else {
openlog( db, false );
}
} catch ( IOException problems ) {
if (LOG.isEnabledFor(Priority.ERROR))
LOG.error("Could not open existing db or make a new one.", problems );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -