mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Checkpoint of file state refactoring.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4417 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -836,7 +836,7 @@ public abstract class CifsAuthenticator
|
||||
// Create the disk driver and context
|
||||
|
||||
DiskInterface diskDrv = m_config.getDiskInterface();
|
||||
DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
|
||||
DiskDeviceContext diskCtx = new ContentContext(client.getUserName(), "", "", client.getHomeFolder());
|
||||
|
||||
// Default the filesystem to look like an 80Gb sized disk with 90% free space
|
||||
|
||||
|
@@ -69,13 +69,13 @@ import org.alfresco.filesys.server.core.SharedDeviceList;
|
||||
import org.alfresco.filesys.server.filesys.DefaultShareMapper;
|
||||
import org.alfresco.filesys.server.filesys.DiskInterface;
|
||||
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
|
||||
import org.alfresco.filesys.server.filesys.HomeShareMapper;
|
||||
import org.alfresco.filesys.smb.ServerType;
|
||||
import org.alfresco.filesys.smb.TcpipSMB;
|
||||
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
||||
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||
import org.alfresco.filesys.smb.server.repo.DesktopActionException;
|
||||
import org.alfresco.filesys.smb.server.repo.DesktopActionTable;
|
||||
import org.alfresco.filesys.smb.server.repo.HomeShareMapper;
|
||||
import org.alfresco.filesys.util.IPAddress;
|
||||
import org.alfresco.filesys.util.StringList;
|
||||
import org.alfresco.filesys.util.X64;
|
||||
@@ -1692,11 +1692,16 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
||||
// the new filesystem
|
||||
|
||||
DiskInterface filesysDriver = this.avmDiskInterface;
|
||||
AVMContext filesysContext = (AVMContext) filesysDriver.createContext(elem);
|
||||
AVMContext filesysContext = (AVMContext) filesysDriver.createContext( filesysDriver, filesysName, elem);
|
||||
filesysContext.setFilesystemName(filesysName);
|
||||
|
||||
// Create the shared filesystem
|
||||
|
||||
filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext);
|
||||
|
||||
// Start the filesystem
|
||||
|
||||
filesysContext.startFilesystem(filesys);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1704,7 +1709,7 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
||||
// the new filesystem
|
||||
|
||||
DiskInterface filesysDriver = this.diskInterface;
|
||||
ContentContext filesysContext = (ContentContext) filesysDriver.createContext(elem);
|
||||
ContentContext filesysContext = (ContentContext) filesysDriver.createContext( filesysDriver, filesysName, elem);
|
||||
|
||||
// Check if an access control list has been specified
|
||||
|
||||
@@ -1804,7 +1809,7 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
||||
{
|
||||
// Create the new share for the store
|
||||
|
||||
AVMContext avmContext = new AVMContext( storeName + ":/", AVMContext.VERSION_HEAD);
|
||||
AVMContext avmContext = new AVMContext( storeName, storeName + ":/", AVMContext.VERSION_HEAD);
|
||||
|
||||
// Create the shared filesystem
|
||||
|
||||
|
@@ -29,14 +29,17 @@ public class DeviceContext
|
||||
|
||||
private String m_devName;
|
||||
|
||||
// Filesystem name
|
||||
|
||||
private String m_filesysName;
|
||||
|
||||
// Flag to indicate if the device is available. Unavailable devices will not be listed by the
|
||||
// various
|
||||
// protocol servers.
|
||||
// various protocol servers.
|
||||
|
||||
private boolean m_available = true;
|
||||
|
||||
/**
|
||||
* DeviceContext constructor.
|
||||
* Default constructor
|
||||
*/
|
||||
public DeviceContext()
|
||||
{
|
||||
@@ -44,23 +47,37 @@ public class DeviceContext
|
||||
}
|
||||
|
||||
/**
|
||||
* DeviceContext constructor.
|
||||
* Class constructor
|
||||
*
|
||||
* @param filesysName String
|
||||
* @param devName String
|
||||
*/
|
||||
public DeviceContext(String devName)
|
||||
public DeviceContext(String filesysName, String devName)
|
||||
{
|
||||
m_devName = devName;
|
||||
m_filesysName = filesysName;
|
||||
m_devName = devName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the device name.
|
||||
*
|
||||
* @return java.lang.String
|
||||
* @return String
|
||||
*/
|
||||
public final String getDeviceName()
|
||||
{
|
||||
return m_devName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filesystem name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getFilesystemName()
|
||||
{
|
||||
return m_filesysName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the filesystem is available
|
||||
*
|
||||
@@ -84,13 +101,23 @@ public class DeviceContext
|
||||
/**
|
||||
* Set the device name.
|
||||
*
|
||||
* @param name java.lang.String
|
||||
* @param name String
|
||||
*/
|
||||
public final void setDeviceName(String name)
|
||||
{
|
||||
m_devName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filesystem name
|
||||
*
|
||||
* @param filesysName String
|
||||
*/
|
||||
public final void setFilesystemName( String filesysName)
|
||||
{
|
||||
m_filesysName = filesysName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the device context, free any resources allocated by the context
|
||||
*/
|
||||
@@ -108,6 +135,8 @@ public class DeviceContext
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("[");
|
||||
str.append(getFilesystemName());
|
||||
str.append(",");
|
||||
str.append(getDeviceName());
|
||||
str.append("]");
|
||||
|
||||
|
@@ -32,11 +32,14 @@ public interface DeviceInterface
|
||||
* of the shared device. The same DeviceInterface implementation may be used for multiple
|
||||
* shares.
|
||||
*
|
||||
* @param devIface DeviceInterface
|
||||
* @param name String
|
||||
* @param args ConfigElement
|
||||
* @return DeviceContext
|
||||
* @exception DeviceContextException
|
||||
*/
|
||||
public DeviceContext createContext(ConfigElement args) throws DeviceContextException;
|
||||
public DeviceContext createContext(DeviceInterface devIface, String name, ConfigElement args)
|
||||
throws DeviceContextException;
|
||||
|
||||
/**
|
||||
* Connection opened to this disk device
|
||||
|
@@ -383,7 +383,7 @@ public class SharedDevice implements Comparable
|
||||
*/
|
||||
public DeviceContext createContext(String[] args)
|
||||
{
|
||||
return new DeviceContext(args[0]);
|
||||
return new DeviceContext("", args[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -59,11 +59,12 @@ public class DiskDeviceContext extends DeviceContext
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param filesysName String
|
||||
* @param devName String
|
||||
*/
|
||||
public DiskDeviceContext(String devName)
|
||||
public DiskDeviceContext(String filesysName, String devName)
|
||||
{
|
||||
super(devName);
|
||||
super(filesysName, devName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
|
||||
package org.alfresco.filesys.server.filesys;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.alfresco.config.ConfigElement;
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.auth.ClientInfo;
|
||||
import org.alfresco.filesys.server.auth.InvalidUserException;
|
||||
import org.alfresco.filesys.server.config.InvalidConfigurationException;
|
||||
import org.alfresco.filesys.server.config.ServerConfiguration;
|
||||
import org.alfresco.filesys.server.core.ShareMapper;
|
||||
import org.alfresco.filesys.server.core.ShareType;
|
||||
import org.alfresco.filesys.server.core.SharedDevice;
|
||||
import org.alfresco.filesys.server.core.SharedDeviceList;
|
||||
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Home Share Mapper Class
|
||||
*
|
||||
* <p>Maps disk share lookup requests to the list of shares defined in the server
|
||||
* configuration and provides a dynamic home share mapped to the users home node.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class HomeShareMapper implements ShareMapper
|
||||
{
|
||||
// Logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol");
|
||||
|
||||
// Home folder share name
|
||||
|
||||
public static final String HOME_FOLDER_SHARE = "HOME";
|
||||
|
||||
// Server configuration
|
||||
|
||||
private ServerConfiguration m_config;
|
||||
|
||||
// Home folder share name
|
||||
|
||||
private String m_homeShareName = HOME_FOLDER_SHARE;
|
||||
|
||||
// Debug enable flag
|
||||
|
||||
private boolean m_debug;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public HomeShareMapper()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the share mapper
|
||||
*
|
||||
* @param config ServerConfiguration
|
||||
* @param params ConfigElement
|
||||
* @exception InvalidConfigurationException
|
||||
*/
|
||||
public void initializeMapper(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
|
||||
{
|
||||
// Save the server configuration
|
||||
|
||||
m_config = config;
|
||||
|
||||
// Check if the home share name has been specified
|
||||
|
||||
String homeName = params.getAttribute("name");
|
||||
if ( homeName != null && homeName.length() > 0)
|
||||
m_homeShareName = homeName;
|
||||
|
||||
// Check if debug is enabled
|
||||
|
||||
if (params != null && params.getChild("debug") != null)
|
||||
m_debug = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if debug output is enabled
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasDebug()
|
||||
{
|
||||
return m_debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the home folder share name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getHomeFolderName()
|
||||
{
|
||||
return m_homeShareName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of available shares.
|
||||
*
|
||||
* @param host String
|
||||
* @param sess SrvSession
|
||||
* @param allShares boolean
|
||||
* @return SharedDeviceList
|
||||
*/
|
||||
public SharedDeviceList getShareList(String host, SrvSession sess, boolean allShares)
|
||||
{
|
||||
// Check if the user has a home folder, and the session does not currently have any
|
||||
// dynamic shares defined
|
||||
|
||||
if ( sess != null && sess.hasClientInformation() && sess.hasDynamicShares() == false)
|
||||
{
|
||||
ClientInfo client = sess.getClientInformation();
|
||||
if ( client.hasHomeFolder())
|
||||
{
|
||||
// Create the home folder share
|
||||
|
||||
DiskSharedDevice homeShare = createHomeDiskShare(client);
|
||||
sess.addDynamicShare(homeShare);
|
||||
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Added " + getHomeFolderName() + " share to list of shares for " + client.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of the global share list and add the per session dynamic shares
|
||||
|
||||
SharedDeviceList shrList = new SharedDeviceList(m_config.getShares());
|
||||
|
||||
if ( sess != null && sess.hasDynamicShares()) {
|
||||
|
||||
// Add the per session dynamic shares
|
||||
|
||||
shrList.addShares(sess.getDynamicShareList());
|
||||
}
|
||||
|
||||
// Remove unavailable shares from the list and return the list
|
||||
|
||||
if ( allShares == false)
|
||||
shrList.removeUnavailableShares();
|
||||
return shrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a share using the name and type for the specified client.
|
||||
*
|
||||
* @param host String
|
||||
* @param name String
|
||||
* @param typ int
|
||||
* @param sess SrvSession
|
||||
* @param create boolean
|
||||
* @return SharedDevice
|
||||
* @exception InvalidUserException
|
||||
*/
|
||||
public SharedDevice findShare(String tohost, String name, int typ, SrvSession sess, boolean create)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
// Check for the special HOME disk share
|
||||
|
||||
SharedDevice share = null;
|
||||
|
||||
if (( typ == ShareType.DISK || typ == ShareType.UNKNOWN) && name.equalsIgnoreCase(getHomeFolderName()) &&
|
||||
sess.getClientInformation() != null) {
|
||||
|
||||
// Get the client details
|
||||
|
||||
ClientInfo client = sess.getClientInformation();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("Map share " + name + ", type=" + ShareType.TypeAsString(typ) + ", client=" + client);
|
||||
|
||||
// Check if the user has a home folder node
|
||||
|
||||
if ( client != null && client.hasHomeFolder()) {
|
||||
|
||||
// Check if the share has already been created for the session
|
||||
|
||||
if ( sess.hasDynamicShares()) {
|
||||
|
||||
// Check if the required share exists in the sessions dynamic share list
|
||||
|
||||
share = sess.getDynamicShareList().findShare(name, typ, false);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug(" Reusing existing dynamic share for " + name);
|
||||
}
|
||||
|
||||
// Check if we found a share, if not then create a new dynamic share for the home directory
|
||||
|
||||
if ( share == null && create == true) {
|
||||
|
||||
// Create the home share mapped to the users home folder
|
||||
|
||||
DiskSharedDevice diskShare = createHomeDiskShare(client);
|
||||
|
||||
// Add the new share to the sessions dynamic share list
|
||||
|
||||
sess.addDynamicShare(diskShare);
|
||||
share = diskShare;
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug(" Mapped share " + name + " to " + client.getHomeFolder());
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new InvalidUserException("No home directory");
|
||||
}
|
||||
else {
|
||||
|
||||
// Find the required share by name/type. Use a case sensitive search first, if that fails use a case
|
||||
// insensitive search.
|
||||
|
||||
share = m_config.getShares().findShare(name, typ, false);
|
||||
|
||||
if ( share == null) {
|
||||
|
||||
// Try a case insensitive search for the required share
|
||||
|
||||
share = m_config.getShares().findShare(name, typ, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the share is available
|
||||
|
||||
if ( share != null && share.getContext() != null && share.getContext().isAvailable() == false)
|
||||
share = null;
|
||||
|
||||
// Return the shared device, or null if no matching device was found
|
||||
|
||||
return share;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete temporary shares for the specified session
|
||||
*
|
||||
* @param sess SrvSession
|
||||
*/
|
||||
public void deleteShares(SrvSession sess)
|
||||
{
|
||||
|
||||
// Check if the session has any dynamic shares
|
||||
|
||||
if ( sess.hasDynamicShares() == false)
|
||||
return;
|
||||
|
||||
// Delete the dynamic shares
|
||||
|
||||
SharedDeviceList shares = sess.getDynamicShareList();
|
||||
Enumeration<SharedDevice> enm = shares.enumerateShares();
|
||||
|
||||
while ( enm.hasMoreElements()) {
|
||||
|
||||
// Get the current share from the list
|
||||
|
||||
SharedDevice shr = (SharedDevice) enm.nextElement();
|
||||
|
||||
// Close the shared device
|
||||
|
||||
shr.getContext().CloseContext();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Deleted dynamic share " + shr);
|
||||
}
|
||||
|
||||
// Clear the dynamic share list
|
||||
|
||||
shares.removeAllShares();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the share mapper, release any resources.
|
||||
*/
|
||||
public void closeMapper()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a disk share for the home folder
|
||||
*
|
||||
* @param client ClientInfo
|
||||
* @return DiskSharedDevice
|
||||
*/
|
||||
private final DiskSharedDevice createHomeDiskShare(ClientInfo client)
|
||||
{
|
||||
// Create the disk driver and context
|
||||
|
||||
DiskInterface diskDrv = m_config.getDiskInterface();
|
||||
DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
|
||||
|
||||
// Default the filesystem to look like an 80Gb sized disk with 90% free space
|
||||
|
||||
diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
|
||||
|
||||
// Create a temporary shared device for the users home directory
|
||||
|
||||
return new DiskSharedDevice(getHomeFolderName(), diskDrv, diskCtx, SharedDevice.Temporary);
|
||||
}
|
||||
}
|
632
source/java/org/alfresco/filesys/server/state/FileState.java
Normal file
632
source/java/org/alfresco/filesys/server/state/FileState.java
Normal file
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.state;
|
||||
|
||||
import org.alfresco.filesys.locking.FileLock;
|
||||
import org.alfresco.filesys.locking.FileLockList;
|
||||
import org.alfresco.filesys.locking.LockConflictException;
|
||||
import org.alfresco.filesys.locking.NotLockedException;
|
||||
import org.alfresco.filesys.server.filesys.FileOpenParams;
|
||||
import org.alfresco.filesys.server.filesys.FileStatus;
|
||||
import org.alfresco.filesys.smb.SharingMode;
|
||||
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
|
||||
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileList;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* File State Class
|
||||
*
|
||||
* <p>Keeps track of file state across all sessions on the server, to keep track of file sharing modes,
|
||||
* file locks and also for synchronizing access to files/folders.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class FileState
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(FileState.class);
|
||||
|
||||
// File state constants
|
||||
|
||||
public final static long NoTimeout = -1L;
|
||||
public final static long DefTimeout = 2 * 60000L; // 2 minutes
|
||||
public final static long RenameTimeout = 1 * 60000L; // 1 minute
|
||||
|
||||
// File status
|
||||
|
||||
public enum FileStateStatus { NotExist, FileExists, FolderExists, Renamed };
|
||||
|
||||
// File name/path
|
||||
|
||||
private String m_path;
|
||||
|
||||
// File state timeout, -1 indicates no timeout
|
||||
|
||||
private long m_tmo;
|
||||
|
||||
// File status, indicates if the file/folder exists and if it is a file or folder.
|
||||
|
||||
private FileStateStatus m_fileStatus = FileStateStatus.NotExist;
|
||||
|
||||
// Open file count
|
||||
|
||||
private int m_openCount;
|
||||
|
||||
// Sharing mode
|
||||
|
||||
private int m_sharedAccess = SharingMode.READWRITE;
|
||||
|
||||
// File lock list, allocated once there are active locks on this file
|
||||
|
||||
private FileLockList m_lockList;
|
||||
|
||||
// Node for this file
|
||||
|
||||
private NodeRef m_nodeRef;
|
||||
|
||||
// Link to the new file state when a file is renamed
|
||||
|
||||
private FileState m_newNameState;
|
||||
|
||||
// Pseudo file list
|
||||
|
||||
private PseudoFileList m_pseudoFiles;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param fname String
|
||||
* @param isdir boolean
|
||||
*/
|
||||
public FileState(String fname, boolean isdir)
|
||||
{
|
||||
|
||||
// Normalize the file path
|
||||
|
||||
setPath(fname);
|
||||
setExpiryTime(System.currentTimeMillis() + DefTimeout);
|
||||
|
||||
// Set the file/folder status
|
||||
|
||||
setFileStatus( isdir ? FileStateStatus.FolderExists : FileStateStatus.FileExists);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file name/path
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getPath()
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file status
|
||||
*
|
||||
* @return FileStateStatus
|
||||
*/
|
||||
public final FileStateStatus getFileStatus()
|
||||
{
|
||||
return m_fileStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the file/folder exists
|
||||
*
|
||||
* @return boolen
|
||||
*/
|
||||
public final boolean exists()
|
||||
{
|
||||
if ( m_fileStatus == FileStateStatus.FileExists ||
|
||||
m_fileStatus == FileStateStatus.FolderExists)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the directory state
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean isDirectory()
|
||||
{
|
||||
return m_fileStatus == FileStateStatus.FolderExists ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the associated node has been set
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasNodeRef()
|
||||
{
|
||||
return m_nodeRef != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated node
|
||||
*
|
||||
* @return NodeRef
|
||||
*/
|
||||
public final NodeRef getNodeRef()
|
||||
{
|
||||
return m_nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file open count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getOpenCount()
|
||||
{
|
||||
return m_openCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the shared access mode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getSharedAccess()
|
||||
{
|
||||
return m_sharedAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are active locks on this file
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasActiveLocks()
|
||||
{
|
||||
if (m_lockList != null && m_lockList.numberOfLocks() > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this file state does not expire
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasNoTimeout()
|
||||
{
|
||||
return m_tmo == NoTimeout ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file can be opened depending on any current file opens and the sharing mode of
|
||||
* the first file open
|
||||
*
|
||||
* @param params FileOpenParams
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean allowsOpen(FileOpenParams params)
|
||||
{
|
||||
|
||||
// If the file is not currently open then allow the file open
|
||||
|
||||
if (getOpenCount() == 0)
|
||||
return true;
|
||||
|
||||
// Check the shared access mode
|
||||
|
||||
if (getSharedAccess() == SharingMode.READWRITE && params.getSharedAccess() == SharingMode.READWRITE)
|
||||
return true;
|
||||
else if ((getSharedAccess() & SharingMode.READ) != 0 && params.isReadOnlyAccess())
|
||||
return true;
|
||||
else if ((getSharedAccess() & SharingMode.WRITE) != 0 && params.isWriteOnlyAccess())
|
||||
return true;
|
||||
|
||||
// Sharing violation, do not allow the file open
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the file open count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final synchronized int incrementOpenCount()
|
||||
{
|
||||
return m_openCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the file open count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final synchronized int decrementOpenCount()
|
||||
{
|
||||
|
||||
// Debug
|
||||
|
||||
if (m_openCount <= 0)
|
||||
logger.debug("@@@@@ File close name=" + getPath() + ", count=" + m_openCount + " <<ERROR>>");
|
||||
else
|
||||
m_openCount--;
|
||||
|
||||
return m_openCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file state has expired
|
||||
*
|
||||
* @param curTime long
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasExpired(long curTime)
|
||||
{
|
||||
if (m_tmo == NoTimeout)
|
||||
return false;
|
||||
if (curTime > m_tmo)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of seconds left before the file state expires
|
||||
*
|
||||
* @param curTime long
|
||||
* @return long
|
||||
*/
|
||||
public final long getSecondsToExpire(long curTime)
|
||||
{
|
||||
if (m_tmo == NoTimeout)
|
||||
return -1;
|
||||
return (m_tmo - curTime) / 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the file state has an associated rename state
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasRenameState()
|
||||
{
|
||||
return m_newNameState != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated rename state
|
||||
*
|
||||
* @return FileState
|
||||
*/
|
||||
public final FileState getRenameState()
|
||||
{
|
||||
return m_newNameState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a folder has pseudo files associated with it
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasPseudoFiles()
|
||||
{
|
||||
if ( m_pseudoFiles != null)
|
||||
return m_pseudoFiles.numberOfFiles() > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pseudo file list
|
||||
*
|
||||
* @return PseudoFileList
|
||||
*/
|
||||
public final PseudoFileList getPseudoFileList()
|
||||
{
|
||||
return m_pseudoFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pseudo file to this folder
|
||||
*
|
||||
* @param pfile PseudoFile
|
||||
*/
|
||||
public final void addPseudoFile(PseudoFile pfile)
|
||||
{
|
||||
if ( m_pseudoFiles == null)
|
||||
m_pseudoFiles = new PseudoFileList();
|
||||
m_pseudoFiles.addFile( pfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file status
|
||||
*
|
||||
* @param status FileStateStatus
|
||||
*/
|
||||
public final void setFileStatus(FileStateStatus status)
|
||||
{
|
||||
m_fileStatus = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file status
|
||||
*
|
||||
* @param fsts int
|
||||
*/
|
||||
public final void setFileStatus(int fsts)
|
||||
{
|
||||
if ( fsts == FileStatus.FileExists)
|
||||
m_fileStatus = FileStateStatus.FileExists;
|
||||
else if ( fsts == FileStatus.DirectoryExists)
|
||||
m_fileStatus = FileStateStatus.FolderExists;
|
||||
else if ( fsts == FileStatus.NotExist)
|
||||
m_fileStatus = FileStateStatus.NotExist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file state expiry time
|
||||
*
|
||||
* @param expire long
|
||||
*/
|
||||
public final void setExpiryTime(long expire)
|
||||
{
|
||||
m_tmo = expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node ref for the file/folder
|
||||
*
|
||||
* @param nodeRef NodeRef
|
||||
*/
|
||||
public final void setNodeRef(NodeRef nodeRef)
|
||||
{
|
||||
m_nodeRef = nodeRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the associated file state when a file is renamed, this is the link to the new file state
|
||||
*
|
||||
* @param fstate FileState
|
||||
*/
|
||||
public final void setRenameState(FileState fstate)
|
||||
{
|
||||
m_newNameState = fstate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the shared access mode, from the first file open
|
||||
*
|
||||
* @param mode int
|
||||
*/
|
||||
public final void setSharedAccess(int mode)
|
||||
{
|
||||
if (getOpenCount() == 0)
|
||||
m_sharedAccess = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file path
|
||||
*
|
||||
* @param path String
|
||||
*/
|
||||
public final void setPath(String path)
|
||||
{
|
||||
|
||||
// Split the path into directories and file name, only uppercase the directories to
|
||||
// normalize the path.
|
||||
|
||||
m_path = normalizePath(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of active locks on this file
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfLocks()
|
||||
{
|
||||
if (m_lockList != null)
|
||||
return m_lockList.numberOfLocks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a lock to this file
|
||||
*
|
||||
* @param lock FileLock
|
||||
* @exception LockConflictException
|
||||
*/
|
||||
public final void addLock(FileLock lock) throws LockConflictException
|
||||
{
|
||||
|
||||
// Check if the lock list has been allocated
|
||||
|
||||
if (m_lockList == null)
|
||||
{
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
|
||||
// Allocate the lock list, check if the lock list has been allocated elsewhere
|
||||
// as we may have been waiting for the lock
|
||||
|
||||
if (m_lockList == null)
|
||||
m_lockList = new FileLockList();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the lock to the list, check if there are any lock conflicts
|
||||
|
||||
synchronized (m_lockList)
|
||||
{
|
||||
|
||||
// Check if the new lock overlaps with any existing locks
|
||||
|
||||
if (m_lockList.allowsLock(lock))
|
||||
{
|
||||
|
||||
// Add the new lock to the list
|
||||
|
||||
m_lockList.addLock(lock);
|
||||
}
|
||||
else
|
||||
throw new LockConflictException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a lock on this file
|
||||
*
|
||||
* @param lock FileLock
|
||||
* @exception NotLockedException
|
||||
*/
|
||||
public final void removeLock(FileLock lock) throws NotLockedException
|
||||
{
|
||||
|
||||
// Check if the lock list has been allocated
|
||||
|
||||
if (m_lockList == null)
|
||||
throw new NotLockedException();
|
||||
|
||||
// Remove the lock from the active list
|
||||
|
||||
synchronized (m_lockList)
|
||||
{
|
||||
|
||||
// Remove the lock, check if we found the matching lock
|
||||
|
||||
if (m_lockList.removeLock(lock) == null)
|
||||
throw new NotLockedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file is readable for the specified section of the file and process id
|
||||
*
|
||||
* @param offset long
|
||||
* @param len long
|
||||
* @param pid int
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean canReadFile(long offset, long len, int pid)
|
||||
{
|
||||
|
||||
// Check if the lock list is valid
|
||||
|
||||
if (m_lockList == null)
|
||||
return true;
|
||||
|
||||
// Check if the file section is readable by the specified process
|
||||
|
||||
boolean readOK = false;
|
||||
|
||||
synchronized (m_lockList)
|
||||
{
|
||||
|
||||
// Check if the file section is readable
|
||||
|
||||
readOK = m_lockList.canReadFile(offset, len, pid);
|
||||
}
|
||||
|
||||
// Return the read status
|
||||
|
||||
return readOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file is writeable for the specified section of the file and process id
|
||||
*
|
||||
* @param offset long
|
||||
* @param len long
|
||||
* @param pid int
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean canWriteFile(long offset, long len, int pid)
|
||||
{
|
||||
|
||||
// Check if the lock list is valid
|
||||
|
||||
if (m_lockList == null)
|
||||
return true;
|
||||
|
||||
// Check if the file section is writeable by the specified process
|
||||
|
||||
boolean writeOK = false;
|
||||
|
||||
synchronized (m_lockList)
|
||||
{
|
||||
|
||||
// Check if the file section is writeable
|
||||
|
||||
writeOK = m_lockList.canWriteFile(offset, len, pid);
|
||||
}
|
||||
|
||||
// Return the write status
|
||||
|
||||
return writeOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the path to uppercase the directory names and keep the case of the file name.
|
||||
*
|
||||
* @param path String
|
||||
* @return String
|
||||
*/
|
||||
public final static String normalizePath(String path)
|
||||
{
|
||||
return path.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file state as a string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("[");
|
||||
str.append(getPath());
|
||||
str.append(",");
|
||||
str.append(getFileStatus());
|
||||
str.append(":Opn=");
|
||||
str.append(getOpenCount());
|
||||
|
||||
str.append(",Expire=");
|
||||
str.append(getSecondsToExpire(System.currentTimeMillis()));
|
||||
|
||||
str.append(",Locks=");
|
||||
str.append(numberOfLocks());
|
||||
|
||||
str.append(",Ref=");
|
||||
if ( hasNodeRef())
|
||||
str.append(getNodeRef().getId());
|
||||
else
|
||||
str.append("Null");
|
||||
|
||||
if ( isDirectory())
|
||||
{
|
||||
str.append(",Pseudo=");
|
||||
if ( hasPseudoFiles())
|
||||
str.append(getPseudoFileList().numberOfFiles());
|
||||
else
|
||||
str.append(0);
|
||||
}
|
||||
str.append("]");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
|
||||
package org.alfresco.filesys.server.state;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* File State Reaper Class
|
||||
*
|
||||
* <p>FileStateTable objects register with the file state reaper to periodically check for expired file states.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class FileStateReaper implements Runnable {
|
||||
|
||||
// Logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog(FileStateReaper.class);
|
||||
|
||||
// Default expire check thread interval
|
||||
|
||||
private static final long DEFAULT_EXPIRECHECK = 15000;
|
||||
|
||||
// Wakeup interval for the expire file state checker thread
|
||||
|
||||
private long m_expireInterval = DEFAULT_EXPIRECHECK;
|
||||
|
||||
// File state checker thread
|
||||
|
||||
private Thread m_thread;
|
||||
|
||||
// Shutdown request flag
|
||||
|
||||
private boolean m_shutdown;
|
||||
|
||||
// List of file state tables to be scanned for expired file states
|
||||
|
||||
private Hashtable<String, FileStateTable> m_stateTables;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public FileStateReaper()
|
||||
{
|
||||
// Create the reaper thread
|
||||
|
||||
m_thread = new Thread(this);
|
||||
m_thread.setDaemon(true);
|
||||
m_thread.setName("FileStateReaper");
|
||||
m_thread.start();
|
||||
|
||||
// Create the file state table list
|
||||
|
||||
m_stateTables = new Hashtable<String, FileStateTable>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the expired file state checker interval, in milliseconds
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getCheckInterval()
|
||||
{
|
||||
return m_expireInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expired file state checker interval, in milliseconds
|
||||
*
|
||||
* @param chkIntval long
|
||||
*/
|
||||
public final void setCheckInterval(long chkIntval)
|
||||
{
|
||||
m_expireInterval = chkIntval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file state table to the reaper list
|
||||
*
|
||||
* @param filesysName String
|
||||
* @param stateTable FileStateTable
|
||||
*/
|
||||
public final void addStateTable( String filesysName, FileStateTable stateTable)
|
||||
{
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug( "Added file state table for " + filesysName);
|
||||
|
||||
m_stateTables.put( filesysName, stateTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a state table from the reaper list
|
||||
*
|
||||
* @param filesysName String
|
||||
*/
|
||||
public final void removeStateTable( String filesysName)
|
||||
{
|
||||
m_stateTables.remove( filesysName);
|
||||
|
||||
// DEBUG
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug( "Removed file state table for " + filesysName);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Expired file state checker thread
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
// Loop forever
|
||||
|
||||
m_shutdown = false;
|
||||
|
||||
while ( m_shutdown == false)
|
||||
{
|
||||
|
||||
// Sleep for the required interval
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(getCheckInterval());
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Check for shutdown
|
||||
|
||||
if ( m_shutdown == true)
|
||||
{
|
||||
// Debug
|
||||
|
||||
if ( logger.isDebugEnabled())
|
||||
logger.debug("FileStateReaper thread closing");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there are any state tables registered
|
||||
|
||||
if ( m_stateTables != null && m_stateTables.size() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Loop through the registered file state tables and remove expired file states
|
||||
|
||||
Enumeration<String> filesysNames = m_stateTables.keys();
|
||||
|
||||
while ( filesysNames.hasMoreElements())
|
||||
{
|
||||
// Get the current filesystem name and associated state table
|
||||
|
||||
String filesysName = filesysNames.nextElement();
|
||||
FileStateTable stateTable = m_stateTables.get( filesysName);
|
||||
|
||||
// Check for expired file states
|
||||
|
||||
int cnt = stateTable.removeExpiredFileStates();
|
||||
|
||||
// Debug
|
||||
|
||||
if (logger.isDebugEnabled() && cnt > 0)
|
||||
logger.debug("Expired " + cnt + " file states for " + filesysName + ", cache=" + stateTable.numberOfStates());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log errors if not shutting down
|
||||
|
||||
if ( m_shutdown == false)
|
||||
logger.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the file state checker thread to shutdown
|
||||
*/
|
||||
public final void shutdownRequest() {
|
||||
m_shutdown = true;
|
||||
|
||||
if ( m_thread != null)
|
||||
{
|
||||
try {
|
||||
m_thread.interrupt();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.state;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.logging.*;
|
||||
|
||||
/**
|
||||
* File State Table Class
|
||||
*
|
||||
* <p>Contains an indexed list of the currently open files/folders.
|
||||
*
|
||||
* @author gkspencer
|
||||
*/
|
||||
public class FileStateTable
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(FileStateTable.class);
|
||||
|
||||
// Initial allocation size for the state cache
|
||||
|
||||
private static final int INITIAL_SIZE = 100;
|
||||
|
||||
// File state table, keyed by file path
|
||||
|
||||
private Hashtable<String, FileState> m_stateTable;
|
||||
|
||||
// File state expiry time in seconds
|
||||
|
||||
private long m_cacheTimer = 2 * 60000L; // 2 minutes default
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public FileStateTable()
|
||||
{
|
||||
m_stateTable = new Hashtable<String, FileState>(INITIAL_SIZE);
|
||||
|
||||
// Start the expired file state checker thread
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file state cache timer, in milliseconds
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getCacheTimer()
|
||||
{
|
||||
return m_cacheTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of states in the cache
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfStates()
|
||||
{
|
||||
return m_stateTable.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default file state cache timer, in milliseconds
|
||||
*
|
||||
* @param tmo long
|
||||
*/
|
||||
public final void setCacheTimer(long tmo)
|
||||
{
|
||||
m_cacheTimer = tmo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new file state
|
||||
*
|
||||
* @param fstate FileState
|
||||
*/
|
||||
public final synchronized void addFileState(FileState fstate)
|
||||
{
|
||||
|
||||
// Check if the file state already exists in the cache
|
||||
|
||||
if (logger.isDebugEnabled() && m_stateTable.get(fstate.getPath()) != null)
|
||||
logger.debug("***** addFileState() state=" + fstate.toString() + " - ALREADY IN CACHE *****");
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled() && fstate == null)
|
||||
{
|
||||
logger.debug("addFileState() NULL FileState");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the file state timeout and add to the cache
|
||||
|
||||
fstate.setExpiryTime(System.currentTimeMillis() + getCacheTimer());
|
||||
m_stateTable.put(fstate.getPath(), fstate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the file state for the specified path
|
||||
*
|
||||
* @param path String
|
||||
* @return FileState
|
||||
*/
|
||||
public final synchronized FileState findFileState(String path)
|
||||
{
|
||||
return m_stateTable.get(FileState.normalizePath(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the file state for the specified path, and optionally create a new file state if not
|
||||
* found
|
||||
*
|
||||
* @param path String
|
||||
* @param isdir boolean
|
||||
* @param create boolean
|
||||
* @return FileState
|
||||
*/
|
||||
public final synchronized FileState findFileState(String path, boolean isdir, boolean create)
|
||||
{
|
||||
|
||||
// Find the required file state, if it exists
|
||||
|
||||
FileState state = m_stateTable.get(FileState.normalizePath(path));
|
||||
|
||||
// Check if we should create a new file state
|
||||
|
||||
if (state == null && create == true)
|
||||
{
|
||||
|
||||
// Create a new file state
|
||||
|
||||
state = new FileState(path, isdir);
|
||||
|
||||
// Set the file state timeout and add to the cache
|
||||
|
||||
state.setExpiryTime(System.currentTimeMillis() + getCacheTimer());
|
||||
m_stateTable.put(state.getPath(), state);
|
||||
}
|
||||
|
||||
// Return the file state
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the name that a file state is cached under, and the associated file state
|
||||
*
|
||||
* @param oldName String
|
||||
* @param newName String
|
||||
* @return FileState
|
||||
*/
|
||||
public final synchronized FileState updateFileState(String oldName, String newName)
|
||||
{
|
||||
|
||||
// Find the current file state
|
||||
|
||||
FileState state = m_stateTable.remove(FileState.normalizePath(oldName));
|
||||
|
||||
// Rename the file state and add it back into the cache using the new name
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
state.setPath(newName);
|
||||
addFileState(state);
|
||||
}
|
||||
|
||||
// Return the updated file state
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate the file state cache
|
||||
*
|
||||
* @return Enumeration
|
||||
*/
|
||||
public final Enumeration enumerate()
|
||||
{
|
||||
return m_stateTable.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the file state for the specified path
|
||||
*
|
||||
* @param path String
|
||||
* @return FileState
|
||||
*/
|
||||
public final synchronized FileState removeFileState(String path)
|
||||
{
|
||||
|
||||
// Remove the file state from the cache
|
||||
|
||||
FileState state = m_stateTable.remove(FileState.normalizePath(path));
|
||||
|
||||
// Return the removed file state
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a file state, remove the existing entry, update the path and add the state back into
|
||||
* the cache using the new path.
|
||||
*
|
||||
* @param newPath String
|
||||
* @param state FileState
|
||||
*/
|
||||
public final synchronized void renameFileState(String newPath, FileState state)
|
||||
{
|
||||
|
||||
// Remove the existing file state from the cache, using the original name
|
||||
|
||||
m_stateTable.remove(state.getPath());
|
||||
|
||||
// Update the file state path and add it back to the cache using the new name
|
||||
|
||||
state.setPath(FileState.normalizePath(newPath));
|
||||
m_stateTable.put(state.getPath(), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all file states from the cache
|
||||
*/
|
||||
public final synchronized void removeAllFileStates()
|
||||
{
|
||||
|
||||
// Check if there are any items in the cache
|
||||
|
||||
if (m_stateTable == null || m_stateTable.size() == 0)
|
||||
return;
|
||||
|
||||
// Enumerate the file state cache and remove expired file state objects
|
||||
|
||||
Enumeration enm = m_stateTable.keys();
|
||||
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
|
||||
// Get the file state
|
||||
|
||||
FileState state = m_stateTable.get(enm.nextElement());
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("++ Closed: " + state.getPath());
|
||||
}
|
||||
|
||||
// Remove all the file states
|
||||
|
||||
m_stateTable.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove expired file states from the cache
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int removeExpiredFileStates()
|
||||
{
|
||||
|
||||
// Check if there are any items in the cache
|
||||
|
||||
if (m_stateTable == null || m_stateTable.size() == 0)
|
||||
return 0;
|
||||
|
||||
// Enumerate the file state cache and remove expired file state objects
|
||||
|
||||
Enumeration enm = m_stateTable.keys();
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
int expiredCnt = 0;
|
||||
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
|
||||
// Get the file state
|
||||
|
||||
FileState state = m_stateTable.get(enm.nextElement());
|
||||
|
||||
if (state != null && state.hasNoTimeout() == false)
|
||||
{
|
||||
|
||||
synchronized (state)
|
||||
{
|
||||
|
||||
// Check if the file state has expired and there are no open references to the
|
||||
// file
|
||||
|
||||
if (state.hasExpired(curTime) && state.getOpenCount() == 0)
|
||||
{
|
||||
|
||||
// Remove the expired file state
|
||||
|
||||
m_stateTable.remove(state.getPath());
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Expired file state: " + state);
|
||||
|
||||
// Update the expired count
|
||||
|
||||
expiredCnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the count of expired file states that were removed
|
||||
|
||||
return expiredCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the state cache entries to the specified stream
|
||||
*/
|
||||
public final void Dump()
|
||||
{
|
||||
|
||||
// Dump the file state cache entries to the specified stream
|
||||
|
||||
if (m_stateTable.size() > 0)
|
||||
logger.debug("FileStateCache Entries:");
|
||||
|
||||
Enumeration enm = m_stateTable.keys();
|
||||
long curTime = System.currentTimeMillis();
|
||||
|
||||
while (enm.hasMoreElements())
|
||||
{
|
||||
String fname = (String) enm.nextElement();
|
||||
FileState state = m_stateTable.get(fname);
|
||||
|
||||
logger.debug(" " + fname + "(" + state.getSecondsToExpire(curTime) + ") : " + state);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user