/*
* Copyright (C) 2006-2008 Alfresco Software Limited.
*
* 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 program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.jlan.smb.server.notify;
import java.util.Date;
import org.alfresco.jlan.server.filesys.DiskDeviceContext;
import org.alfresco.jlan.server.filesys.NetworkFile;
import org.alfresco.jlan.server.filesys.NotifyChange;
import org.alfresco.jlan.smb.server.SMBSrvSession;
/**
* Notify Change Request Details Class
*
* @author gkspencer
*/
public class NotifyRequest {
// Constants
public final static long DefaultRequestTimeout = 10000L; // 10 seconds
// Notify change filter
private int m_filter;
// Flag to indicate if sub-directories of the directory being watched will also trigger notifications
private boolean m_watchTree;
// Session that posted the notify change request
private SMBSrvSession m_sess;
// Directory being watched
private NetworkFile m_watchDir;
// Root relative path, normalised to uppercase
private String m_watchPath;
// Unique client request id.
//
// If the multiplex id equals -1 the request has completed and we are waiting for the request to be reset with a
// new multiplex id.
private int m_mid;
private int m_tid;
private int m_pid;
private int m_uid;
// Notifications to buffer whilst waiting for request to be reset
private int m_maxQueueLen;
// Disk device context that the request is associated with
private DiskDeviceContext m_diskCtx;
// Buffered event list
private NotifyChangeEventList m_bufferedEvents;
// Notify request completed flag
private boolean m_completed;
private long m_expiresAt;
// Flag to indicate that many file changes have occurred and a notify enum status should be returned
// to the client
private boolean m_notifyEnum;
/**
* Class constructor
*
* @param filter int
* @param watchTree boolean
* @param sess SMBSrvSession
* @param dir NetworkFile
* @param mid int
* @param tid int
* @param pid int
* @param uid int
* @param qlen int
*/
public NotifyRequest(int filter, boolean watchTree, SMBSrvSession sess, NetworkFile dir, int mid, int tid, int pid, int uid, int qlen) {
m_filter = filter;
m_watchTree = watchTree;
m_sess = sess;
m_watchDir = dir;
m_mid = mid;
m_tid = tid;
m_pid = pid;
m_uid = uid;
m_maxQueueLen = qlen;
// Set the normalised watch path
m_watchPath = m_watchDir.getFullName().toUpperCase();
if ( m_watchPath.length() == 0)
m_watchPath = "\\";
else if ( m_watchPath.indexOf('/') != -1)
m_watchPath = m_watchPath.replace( '/', '\\');
}
/**
* Get the notify change filter
*
* @return int
*/
public final int getFilter() {
return m_filter;
}
/**
* Determine if the request has completed
*
* @return boolean
*/
public final boolean isCompleted() {
return m_completed;
}
/**
* Determine if the request has expired
*
* @param curTime long
* @return boolean
*/
public final boolean hasExpired(long curTime) {
if ( isCompleted() == false)
return false;
else if ( m_expiresAt < curTime)
return true;
return false;
}
/**
* Determine if the filter has file name change notification, triggered if a file is created, renamed or deleted
*
* @return boolean
*/
public final boolean hasFileNameChange() {
return hasFilter(NotifyChange.FileName);
}
/**
* Determine if the filter has directory name change notification, triggered if a directory is created or deleted.
*
* @return boolean
*/
public final boolean hasDirectoryNameChange() {
return hasFilter(NotifyChange.DirectoryName);
}
/**
* Determine if the filter has attribute change notification
*
* @return boolean
*/
public final boolean hasAttributeChange() {
return hasFilter(NotifyChange.Attributes);
}
/**
* Determine if the filter has file size change notification
*
* @return boolean
*/
public final boolean hasFileSizeChange() {
return hasFilter(NotifyChange.Size);
}
/**
* Determine if the filter has last write time change notification
*
* @return boolean
*/
public final boolean hasFileWriteTimeChange() {
return hasFilter(NotifyChange.LastWrite);
}
/**
* Determine if the filter has last access time change notification
*
* @return boolean
*/
public final boolean hasFileAccessTimeChange() {
return hasFilter(NotifyChange.LastAccess);
}
/**
* Determine if the filter has creation time change notification
*
* @return boolean
*/
public final boolean hasFileCreateTimeChange() {
return hasFilter(NotifyChange.Creation);
}
/**
* Determine if the filter has the security descriptor change notification
*
* @return boolean
*/
public final boolean hasSecurityDescriptorChange() {
return hasFilter(NotifyChange.Security);
}
/**
* Check if the change filter has the specified flag enabled
*
* @param flag
* @return boolean
*/
public final boolean hasFilter(int flag) {
return ( m_filter & flag) != 0 ? true : false;
}
/**
* Check if the notify enum flag is set
*
* @return boolean
*/
public final boolean hasNotifyEnum() {
return m_notifyEnum;
}
/**
* Determine if sub-directories of the directory being watched should also trigger notifications
*
* @return boolean
*/
public final boolean hasWatchTree() {
return m_watchTree;
}
/**
* Get the session that posted the notify request
*
* @return SMBSrvSession
*/
public final SMBSrvSession getSession() {
return m_sess;
}
/**
* Get the directory being watched
*
* @return NetworkFile
*/
public final NetworkFile getDirectory() {
return m_watchDir;
}
/**
* Get the normalised watch path
*
* @return String
*/
public final String getWatchPath() {
return m_watchPath;
}
/**
* Get the multiplex-id of the request
*
* @return int
*/
public final int getMultiplexId() {
return m_mid;
}
/**
* Get the tree id of the request
*
* @return int
*/
public final int getTreeId() {
return m_tid;
}
/**
* Get the process id of the request
*
* @return int
*/
public final int getProcessId() {
return m_pid;
}
/**
* Get the user id of the request
*
* @return int
*/
public final int getUserId() {
return m_uid;
}
/**
* Return the expiry time that a completed request must be reset by before being removed from
* the queue.
*
* @return long
*/
public final long getExpiryTime() {
return m_expiresAt;
}
/**
* Get the associated disk context
*
* @return DiskDeviceContext
*/
public final DiskDeviceContext getDiskContext() {
return m_diskCtx;
}
/**
* Return the maximum number of notifications to buffer whilst waiting for the request to be reset
*
* @return int
*/
public final int getMaximumQueueLength() {
return m_maxQueueLen;
}
/**
* Determine if there are buffered events
*
* @return boolean
*/
public final boolean hasBufferedEvents() {
if ( m_bufferedEvents != null && m_bufferedEvents.numberOfEvents() > 0)
return true;
return false;
}
/**
* Return the buffered notification event list
*
* @return NotifyChangeEventList
*/
public final NotifyChangeEventList getBufferedEventList() {
return m_bufferedEvents;
}
/**
* Add a buffered notification event, to be sent when the notify request is reset by the client
*
* @param evt NotifyChangeEvent
*/
public final void addEvent(NotifyChangeEvent evt) {
// Check if the notify enum flag is set, if so then do not buffer any events
if ( hasNotifyEnum())
return;
// Check if the buffered event list has been allocated
if ( m_bufferedEvents == null)
m_bufferedEvents = new NotifyChangeEventList();
// Add the event if the list has not reached the maximum buffered event count
if ( m_bufferedEvents.numberOfEvents() < getMaximumQueueLength()) {
// Buffer the event until the client resets the notify filter
m_bufferedEvents.addEvent(evt);
}
else {
// Remove all buffered events and set the notify enum flag to indicate that there
// have been many file changes
removeAllEvents();
setNotifyEnum(true);
}
}
/**
* Remove all buffered events from the request
*/
public final void removeAllEvents() {
if ( m_bufferedEvents != null) {
m_bufferedEvents.removeAllEvents();
m_bufferedEvents = null;
}
}
/**
* Clear the buffered event list, do not destroy the list
*/
public final void clearBufferedEvents() {
m_bufferedEvents = null;
}
/**
* Set/clear the notify enum flag that indicates if there have been many file changes
*
* @param ena boolean
*/
public final void setNotifyEnum(boolean ena) {
m_notifyEnum = ena;
}
/**
* Set the associated disk device context
*
* @param ctx DiskDeviceContext
*/
protected final void setDiskContext(DiskDeviceContext ctx) {
m_diskCtx = ctx;
}
/**
* Set the multiplex id for the notification
*
* @param mid int
*/
public final void setMultiplexId(int mid) {
m_mid = mid;
}
/**
* Set the request completed flag
*
* @param comp boolean
*/
public final void setCompleted(boolean comp) {
m_completed = comp;
if ( comp)
m_expiresAt = System.currentTimeMillis() + DefaultRequestTimeout;
}
/**
* Set the request completed flag and set an expiry time when the request expires
*
* @param comp boolean
* @param expires long
*/
public final void setCompleted(boolean comp, long expires) {
m_completed = comp;
m_expiresAt = expires;
}
/**
* Return the notify request as a string
*
* @return String
*/
public String toString() {
StringBuffer str = new StringBuffer();
str.append("[");
str.append(getSession().getUniqueId());
str.append(":");
if ( getWatchPath().length() == 0)
str.append("Root");
else
str.append(getWatchPath());
str.append(":");
if ( hasFileNameChange())
str.append("File,");
if ( hasDirectoryNameChange())
str.append("Dir,");
if ( hasAttributeChange())
str.append("Attr,");
if ( hasFileSizeChange())
str.append("Size,");
if ( hasFileWriteTimeChange())
str.append("Write,");
if ( hasFileAccessTimeChange())
str.append("Access,");
if ( hasFileCreateTimeChange())
str.append("Create,");
if ( hasSecurityDescriptorChange())
str.append("Security,");
if ( hasWatchTree())
str.append("Tree");
else
str.append("NoTree");
str.append(" MID=");
str.append(getMultiplexId());
str.append(" PID=");
str.append(getProcessId());
str.append(" TID=");
str.append(getTreeId());
str.append(" UID=");
str.append(getUserId());
if ( isCompleted()) {
str.append(",Completed,TMO=");
str.append(new Date(getExpiryTime()).toString());
}
str.append(",Queue=");
str.append(getMaximumQueueLength());
if ( hasBufferedEvents()) {
str.append("/");
str.append(getBufferedEventList().numberOfEvents());
}
if ( hasNotifyEnum())
str.append(",ENUM");
str.append("]");
return str.toString();
}
}