mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
CIFS desktop actions framework.
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3514 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -64,12 +64,15 @@ import org.alfresco.filesys.server.core.ShareType;
|
|||||||
import org.alfresco.filesys.server.core.SharedDevice;
|
import org.alfresco.filesys.server.core.SharedDevice;
|
||||||
import org.alfresco.filesys.server.core.SharedDeviceList;
|
import org.alfresco.filesys.server.core.SharedDeviceList;
|
||||||
import org.alfresco.filesys.server.filesys.DefaultShareMapper;
|
import org.alfresco.filesys.server.filesys.DefaultShareMapper;
|
||||||
import org.alfresco.filesys.server.filesys.DiskDeviceContext;
|
|
||||||
import org.alfresco.filesys.server.filesys.DiskInterface;
|
import org.alfresco.filesys.server.filesys.DiskInterface;
|
||||||
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
|
import org.alfresco.filesys.server.filesys.DiskSharedDevice;
|
||||||
import org.alfresco.filesys.server.filesys.HomeShareMapper;
|
import org.alfresco.filesys.server.filesys.HomeShareMapper;
|
||||||
import org.alfresco.filesys.smb.ServerType;
|
import org.alfresco.filesys.smb.ServerType;
|
||||||
import org.alfresco.filesys.smb.TcpipSMB;
|
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.util.IPAddress;
|
import org.alfresco.filesys.util.IPAddress;
|
||||||
import org.alfresco.filesys.util.X64;
|
import org.alfresco.filesys.util.X64;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
@@ -1582,7 +1585,7 @@ public class ServerConfiguration implements ApplicationListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the top level filesystems confgiruation element
|
// Get the top level filesystems configuration element
|
||||||
|
|
||||||
ConfigElement filesystems = config.getConfigElement("filesystems");
|
ConfigElement filesystems = config.getConfigElement("filesystems");
|
||||||
|
|
||||||
@@ -1633,8 +1636,9 @@ public class ServerConfiguration implements ApplicationListener
|
|||||||
{
|
{
|
||||||
// Create a new filesystem driver instance and create a context for
|
// Create a new filesystem driver instance and create a context for
|
||||||
// the new filesystem
|
// the new filesystem
|
||||||
|
|
||||||
DiskInterface filesysDriver = this.diskInterface;
|
DiskInterface filesysDriver = this.diskInterface;
|
||||||
DiskDeviceContext filesysContext = (DiskDeviceContext) filesysDriver.createContext(elem);
|
ContentContext filesysContext = (ContentContext) filesysDriver.createContext(elem);
|
||||||
|
|
||||||
// Check if an access control list has been specified
|
// Check if an access control list has been specified
|
||||||
|
|
||||||
@@ -1664,6 +1668,18 @@ public class ServerConfiguration implements ApplicationListener
|
|||||||
|
|
||||||
DiskSharedDevice filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext);
|
DiskSharedDevice filesys = new DiskSharedDevice(filesysName, filesysDriver, filesysContext);
|
||||||
|
|
||||||
|
// Attach desktop actions to the filesystem
|
||||||
|
|
||||||
|
ConfigElement deskActionsElem = elem.getChild("desktopActions");
|
||||||
|
if ( deskActionsElem != null)
|
||||||
|
{
|
||||||
|
// Get the desktop actions list
|
||||||
|
|
||||||
|
DesktopActionTable desktopActions = processDesktopActions(deskActionsElem, filesys);
|
||||||
|
if ( desktopActions != null)
|
||||||
|
filesysContext.setDesktopActions( desktopActions, filesysDriver);
|
||||||
|
}
|
||||||
|
|
||||||
// Add any access controls to the share
|
// Add any access controls to the share
|
||||||
|
|
||||||
filesys.setAccessControlList(acls);
|
filesys.setAccessControlList(acls);
|
||||||
@@ -1899,6 +1915,99 @@ public class ServerConfiguration implements ApplicationListener
|
|||||||
return acls;
|
return acls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a desktop actions sub-section and return the desktop action table
|
||||||
|
*
|
||||||
|
* @param deskActionElem ConfigElement
|
||||||
|
* @param fileSys DiskSharedDevice
|
||||||
|
*/
|
||||||
|
private final DesktopActionTable processDesktopActions(ConfigElement deskActionElem, DiskSharedDevice fileSys)
|
||||||
|
{
|
||||||
|
// Get the desktop action configuration elements
|
||||||
|
|
||||||
|
DesktopActionTable desktopActions = null;
|
||||||
|
List<ConfigElement> actionElems = deskActionElem.getChildren();
|
||||||
|
|
||||||
|
if ( actionElems != null)
|
||||||
|
{
|
||||||
|
// Check for the global configuration section
|
||||||
|
|
||||||
|
ConfigElement globalConfig = deskActionElem.getChild("global");
|
||||||
|
|
||||||
|
// Allocate the actions table
|
||||||
|
|
||||||
|
desktopActions = new DesktopActionTable();
|
||||||
|
|
||||||
|
// Process the desktop actions list
|
||||||
|
|
||||||
|
for ( ConfigElement actionElem : actionElems)
|
||||||
|
{
|
||||||
|
if ( actionElem.getName().equals("action"))
|
||||||
|
{
|
||||||
|
// Get the desktop action class name or bean id
|
||||||
|
|
||||||
|
ConfigElement className = actionElem.getChild("class");
|
||||||
|
if ( className != null)
|
||||||
|
{
|
||||||
|
// Load the desktop action class, create a new instance
|
||||||
|
|
||||||
|
Object actionObj = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create a new desktop action instance
|
||||||
|
|
||||||
|
actionObj = Class.forName(className.getValue()).newInstance();
|
||||||
|
|
||||||
|
// Make sure the object is a desktop action
|
||||||
|
|
||||||
|
if ( actionObj instanceof DesktopAction)
|
||||||
|
{
|
||||||
|
// Initialize the desktop action
|
||||||
|
|
||||||
|
DesktopAction deskAction = (DesktopAction) actionObj;
|
||||||
|
deskAction.initializeAction(globalConfig, actionElem, fileSys);
|
||||||
|
|
||||||
|
// Add the action to the list of desktop actions
|
||||||
|
|
||||||
|
desktopActions.addAction(deskAction);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug("Added desktop action " + deskAction.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new AlfrescoRuntimeException("Desktop action does not extend DesktopAction class, " + className.getValue());
|
||||||
|
}
|
||||||
|
catch ( ClassNotFoundException ex)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Desktop action class not found, " + className.getValue());
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException ex)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Failed to create desktop action instance, " + className.getValue(), ex);
|
||||||
|
}
|
||||||
|
catch ( InstantiationException ex)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Failed to create desktop action instance, " + className.getValue(), ex);
|
||||||
|
}
|
||||||
|
catch (DesktopActionException ex)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Failed to initialize desktop action", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( actionElem.getName().equals("global") == false)
|
||||||
|
throw new AlfrescoRuntimeException("Invalid configuration element in desktopActions section, " + actionElem.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the desktop actions list
|
||||||
|
|
||||||
|
return desktopActions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the platforms attribute returning the set of platform ids
|
* Parse the platforms attribute returning the set of platform ids
|
||||||
*
|
*
|
||||||
|
@@ -1,589 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2005-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.smb.repo;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
import org.alfresco.filesys.server.SrvSession;
|
|
||||||
import org.alfresco.filesys.server.filesys.DiskDeviceContext;
|
|
||||||
import org.alfresco.filesys.server.filesys.FileName;
|
|
||||||
import org.alfresco.filesys.server.filesys.IOControlNotImplementedException;
|
|
||||||
import org.alfresco.filesys.server.filesys.NetworkFile;
|
|
||||||
import org.alfresco.filesys.server.filesys.NotifyChange;
|
|
||||||
import org.alfresco.filesys.server.filesys.TreeConnection;
|
|
||||||
import org.alfresco.filesys.smb.NTIOCtl;
|
|
||||||
import org.alfresco.filesys.smb.SMBException;
|
|
||||||
import org.alfresco.filesys.smb.SMBStatus;
|
|
||||||
import org.alfresco.filesys.smb.server.repo.CifsHelper;
|
|
||||||
import org.alfresco.filesys.smb.server.repo.ContentDiskDriver;
|
|
||||||
import org.alfresco.filesys.smb.server.repo.IOControlHandler;
|
|
||||||
import org.alfresco.filesys.util.DataBuffer;
|
|
||||||
import org.alfresco.model.ContentModel;
|
|
||||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
|
||||||
import org.alfresco.service.cmr.lock.LockType;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content Disk Driver I/O Control Handler Class
|
|
||||||
*
|
|
||||||
* <p>Provides the custom I/O control code handling used by the CIFS client interface application.
|
|
||||||
*
|
|
||||||
* @author gkspencer
|
|
||||||
*/
|
|
||||||
public class ContentIOControlHandler implements IOControlHandler
|
|
||||||
{
|
|
||||||
// Logging
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ContentIOControlHandler.class);
|
|
||||||
|
|
||||||
// Services and helpers
|
|
||||||
|
|
||||||
private CifsHelper cifsHelper;
|
|
||||||
private TransactionService transactionService;
|
|
||||||
private NodeService nodeService;
|
|
||||||
private CheckOutCheckInService checkInOutService;
|
|
||||||
|
|
||||||
private ContentDiskDriver contentDriver;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
public ContentIOControlHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initalize the I/O control handler
|
|
||||||
*
|
|
||||||
* @param contentDriver ContentDiskDriver
|
|
||||||
* @param cifsHelper CifsHelper
|
|
||||||
* @param transService TransactionService
|
|
||||||
* @param nodeService NodeService
|
|
||||||
* @param cociService CheckOutCheckInService
|
|
||||||
*/
|
|
||||||
public void initialize( ContentDiskDriver contentDriver, CifsHelper cifsHelper,
|
|
||||||
TransactionService transService, NodeService nodeService, CheckOutCheckInService cociService)
|
|
||||||
{
|
|
||||||
this.contentDriver = contentDriver;
|
|
||||||
this.cifsHelper = cifsHelper;
|
|
||||||
this.transactionService = transService;
|
|
||||||
this.nodeService = nodeService;
|
|
||||||
this.checkInOutService = cociService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a filesystem I/O control request
|
|
||||||
*
|
|
||||||
* @param sess Server session
|
|
||||||
* @param tree Tree connection.
|
|
||||||
* @param ctrlCode I/O control code
|
|
||||||
* @param fid File id
|
|
||||||
* @param dataBuf I/O control specific input data
|
|
||||||
* @param isFSCtrl true if this is a filesystem control, or false for a device control
|
|
||||||
* @param filter if bit0 is set indicates that the control applies to the share root handle
|
|
||||||
* @return DataBuffer
|
|
||||||
* @exception IOControlNotImplementedException
|
|
||||||
* @exception SMBException
|
|
||||||
*/
|
|
||||||
public DataBuffer processIOControl(SrvSession sess, TreeConnection tree, int ctrlCode, int fid, DataBuffer dataBuf,
|
|
||||||
boolean isFSCtrl, int filter)
|
|
||||||
throws IOControlNotImplementedException, SMBException
|
|
||||||
{
|
|
||||||
// Validate the file id
|
|
||||||
|
|
||||||
NetworkFile netFile = tree.findFile(fid);
|
|
||||||
if ( netFile == null || netFile.isDirectory() == false)
|
|
||||||
throw new SMBException(SMBStatus.NTErr, SMBStatus.NTInvalidParameter);
|
|
||||||
|
|
||||||
// Split the control code
|
|
||||||
|
|
||||||
int devType = NTIOCtl.getDeviceType(ctrlCode);
|
|
||||||
int ioFunc = NTIOCtl.getFunctionCode(ctrlCode);
|
|
||||||
|
|
||||||
if ( devType != NTIOCtl.DeviceFileSystem || dataBuf == null)
|
|
||||||
throw new IOControlNotImplementedException();
|
|
||||||
|
|
||||||
// Check if the request has a valid signature for an Alfresco CIFS server I/O control
|
|
||||||
|
|
||||||
if ( dataBuf.getLength() < IOControl.Signature.length())
|
|
||||||
throw new IOControlNotImplementedException("Bad request length");
|
|
||||||
|
|
||||||
String sig = dataBuf.getString(IOControl.Signature.length(), false);
|
|
||||||
|
|
||||||
if ( sig == null || sig.compareTo(IOControl.Signature) != 0)
|
|
||||||
throw new IOControlNotImplementedException("Bad request signature");
|
|
||||||
|
|
||||||
// Get the node for the parent folder, make sure it is a folder
|
|
||||||
|
|
||||||
NodeRef folderNode = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
folderNode = contentDriver.getNodeForPath(tree, netFile.getFullName());
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( folderNode) == false)
|
|
||||||
folderNode = null;
|
|
||||||
}
|
|
||||||
catch ( FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
folderNode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the folder node is not valid return an error
|
|
||||||
|
|
||||||
if ( folderNode == null)
|
|
||||||
throw new SMBException(SMBStatus.NTErr, SMBStatus.NTAccessDenied);
|
|
||||||
|
|
||||||
// Debug
|
|
||||||
|
|
||||||
if ( logger.isInfoEnabled()) {
|
|
||||||
logger.info("IO control func=0x" + Integer.toHexString(ioFunc) + ", fid=" + fid + ", buffer=" + dataBuf);
|
|
||||||
logger.info(" Folder nodeRef=" + folderNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the I/O control code is one of our custom codes
|
|
||||||
|
|
||||||
DataBuffer retBuffer = null;
|
|
||||||
|
|
||||||
switch ( ioFunc)
|
|
||||||
{
|
|
||||||
// Probe to check if this is an Alfresco CIFS server
|
|
||||||
|
|
||||||
case IOControl.CmdProbe:
|
|
||||||
|
|
||||||
// Return a buffer with the signature
|
|
||||||
|
|
||||||
retBuffer = new DataBuffer(IOControl.Signature.length());
|
|
||||||
retBuffer.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
|
||||||
retBuffer.putInt(IOControl.StsSuccess);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Get file information for a file within the current folder
|
|
||||||
|
|
||||||
case IOControl.CmdFileStatus:
|
|
||||||
|
|
||||||
// Process the file status request
|
|
||||||
|
|
||||||
retBuffer = procIOFileStatus( sess, tree, dataBuf, folderNode);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Check-in file request
|
|
||||||
|
|
||||||
case IOControl.CmdCheckIn:
|
|
||||||
|
|
||||||
// Process the check-in request
|
|
||||||
|
|
||||||
retBuffer = procIOCheckIn( sess, tree, dataBuf, folderNode, netFile);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Check-out file request
|
|
||||||
|
|
||||||
case IOControl.CmdCheckOut:
|
|
||||||
|
|
||||||
// Process the check-out request
|
|
||||||
|
|
||||||
retBuffer = procIOCheckOut( sess, tree, dataBuf, folderNode, netFile);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Unknown I/O control code
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IOControlNotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the reply buffer, may be null
|
|
||||||
|
|
||||||
return retBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process the file status I/O request
|
|
||||||
*
|
|
||||||
* @param sess Server session
|
|
||||||
* @param tree Tree connection
|
|
||||||
* @param reqBuf Request buffer
|
|
||||||
* @param folderNode NodeRef of parent folder
|
|
||||||
* @return DataBuffer
|
|
||||||
*/
|
|
||||||
private final DataBuffer procIOFileStatus( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode)
|
|
||||||
{
|
|
||||||
// Start a transaction
|
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, true);
|
|
||||||
|
|
||||||
// Get the file name from the request
|
|
||||||
|
|
||||||
String fName = reqBuf.getString( true);
|
|
||||||
logger.info(" File status, fname=" + fName);
|
|
||||||
|
|
||||||
// Create a response buffer
|
|
||||||
|
|
||||||
DataBuffer respBuf = new DataBuffer(256);
|
|
||||||
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
|
||||||
|
|
||||||
// Get the node for the file/folder
|
|
||||||
|
|
||||||
NodeRef childNode = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the file/folder was found
|
|
||||||
|
|
||||||
if ( childNode == null)
|
|
||||||
{
|
|
||||||
// Return an error response
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
|
||||||
{
|
|
||||||
// Only return the status and node type for folders
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsSuccess);
|
|
||||||
respBuf.putInt(IOControl.TypeFolder);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Indicate that this is a file node
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsSuccess);
|
|
||||||
respBuf.putInt(IOControl.TypeFile);
|
|
||||||
|
|
||||||
// Check if this file is a working copy
|
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
|
|
||||||
{
|
|
||||||
// Indicate that this is a working copy
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.True);
|
|
||||||
|
|
||||||
// Get the owner username and file it was copied from
|
|
||||||
|
|
||||||
String owner = (String) nodeService.getProperty( childNode, ContentModel.PROP_WORKING_COPY_OWNER);
|
|
||||||
String copiedFrom = null;
|
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_COPIEDFROM))
|
|
||||||
{
|
|
||||||
// Get the path of the file the working copy was generated from
|
|
||||||
|
|
||||||
NodeRef fromNode = (NodeRef) nodeService.getProperty( childNode, ContentModel.PROP_COPY_REFERENCE);
|
|
||||||
if ( fromNode != null)
|
|
||||||
copiedFrom = (String) nodeService.getProperty( fromNode, ContentModel.PROP_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pack the owner and copied from values
|
|
||||||
|
|
||||||
respBuf.putString(owner != null ? owner : "", true, true);
|
|
||||||
respBuf.putString(copiedFrom != null ? copiedFrom : "", true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not a working copy
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.False);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the lock status of the file
|
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_LOCKABLE))
|
|
||||||
{
|
|
||||||
// Get the lock type and owner
|
|
||||||
|
|
||||||
String lockTypeStr = (String) nodeService.getProperty( childNode, ContentModel.PROP_LOCK_TYPE);
|
|
||||||
String lockOwner = null;
|
|
||||||
|
|
||||||
if ( lockTypeStr != null)
|
|
||||||
lockOwner = (String) nodeService.getProperty( childNode, ContentModel.PROP_LOCK_OWNER);
|
|
||||||
|
|
||||||
// Pack the lock type, and owner if there is a lock on the file
|
|
||||||
|
|
||||||
if ( lockTypeStr == null)
|
|
||||||
respBuf.putInt(IOControl.LockNone);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LockType lockType = LockType.valueOf( lockTypeStr);
|
|
||||||
|
|
||||||
respBuf.putInt(lockType == LockType.READ_ONLY_LOCK ? IOControl.LockRead : IOControl.LockWrite);
|
|
||||||
respBuf.putString(lockOwner != null ? lockOwner : "", true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// File is not lockable
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.LockNone);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the content data details for the file
|
|
||||||
|
|
||||||
ContentData contentData = (ContentData) nodeService.getProperty( childNode, ContentModel.PROP_CONTENT);
|
|
||||||
|
|
||||||
if ( contentData != null)
|
|
||||||
{
|
|
||||||
// Get the content mime-type
|
|
||||||
|
|
||||||
String mimeType = contentData.getMimetype();
|
|
||||||
|
|
||||||
// Pack the content length and mime-type
|
|
||||||
|
|
||||||
respBuf.putInt( IOControl.True);
|
|
||||||
respBuf.putLong( contentData.getSize());
|
|
||||||
respBuf.putString( mimeType != null ? mimeType : "", true, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// File does not have any content
|
|
||||||
|
|
||||||
respBuf.putInt( IOControl.False);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the response
|
|
||||||
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process the check in I/O request
|
|
||||||
*
|
|
||||||
* @param sess Server session
|
|
||||||
* @param tree Tree connection
|
|
||||||
* @param reqBuf Request buffer
|
|
||||||
* @param folderNode NodeRef of parent folder
|
|
||||||
* @param netFile NetworkFile for the folder
|
|
||||||
* @return DataBuffer
|
|
||||||
*/
|
|
||||||
private final DataBuffer procIOCheckIn( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
|
||||||
NetworkFile netFile)
|
|
||||||
{
|
|
||||||
// Start a transaction
|
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, false);
|
|
||||||
|
|
||||||
// Get the file name from the request
|
|
||||||
|
|
||||||
String fName = reqBuf.getString( true);
|
|
||||||
boolean keepCheckedOut = reqBuf.getInt() == IOControl.True ? true : false;
|
|
||||||
|
|
||||||
logger.info(" CheckIn, fname=" + fName + ", keepCheckedOut=" + keepCheckedOut);
|
|
||||||
|
|
||||||
// Create a response buffer
|
|
||||||
|
|
||||||
DataBuffer respBuf = new DataBuffer(256);
|
|
||||||
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
|
||||||
|
|
||||||
// Get the node for the file/folder
|
|
||||||
|
|
||||||
NodeRef childNode = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the file/folder was found
|
|
||||||
|
|
||||||
if ( childNode == null)
|
|
||||||
{
|
|
||||||
// Return an error response
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
|
||||||
{
|
|
||||||
// Return an error status, attempt to check in a folder
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsBadParameter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check if this file is a working copy
|
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Check in the file
|
|
||||||
|
|
||||||
checkInOutService.checkin( childNode, null, null, keepCheckedOut);
|
|
||||||
|
|
||||||
// Check in was successful
|
|
||||||
|
|
||||||
respBuf.putInt( IOControl.StsSuccess);
|
|
||||||
|
|
||||||
// Check if there are any file/directory change notify requests active
|
|
||||||
|
|
||||||
DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
|
|
||||||
if (diskCtx.hasChangeHandler()) {
|
|
||||||
|
|
||||||
// Build the relative path to the checked in file
|
|
||||||
|
|
||||||
String fileName = FileName.buildPath( netFile.getFullName(), null, fName, FileName.DOS_SEPERATOR);
|
|
||||||
|
|
||||||
// Queue a file deleted change notification
|
|
||||||
|
|
||||||
diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Return an error status and message
|
|
||||||
|
|
||||||
respBuf.setPosition( IOControl.Signature.length());
|
|
||||||
respBuf.putInt(IOControl.StsError);
|
|
||||||
respBuf.putString( ex.getMessage(), true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Not a working copy
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsNotWorkingCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the response
|
|
||||||
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process the check out I/O request
|
|
||||||
*
|
|
||||||
* @param sess Server session
|
|
||||||
* @param tree Tree connection
|
|
||||||
* @param reqBuf Request buffer
|
|
||||||
* @param folderNode NodeRef of parent folder
|
|
||||||
* @param netFile NetworkFile for the folder
|
|
||||||
* @return DataBuffer
|
|
||||||
*/
|
|
||||||
private final DataBuffer procIOCheckOut( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
|
||||||
NetworkFile netFile)
|
|
||||||
{
|
|
||||||
// Start a transaction
|
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, false);
|
|
||||||
|
|
||||||
// Get the file name from the request
|
|
||||||
|
|
||||||
String fName = reqBuf.getString( true);
|
|
||||||
|
|
||||||
logger.info(" CheckOut, fname=" + fName);
|
|
||||||
|
|
||||||
// Create a response buffer
|
|
||||||
|
|
||||||
DataBuffer respBuf = new DataBuffer(256);
|
|
||||||
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
|
||||||
|
|
||||||
// Get the node for the file/folder
|
|
||||||
|
|
||||||
NodeRef childNode = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the file/folder was found
|
|
||||||
|
|
||||||
if ( childNode == null)
|
|
||||||
{
|
|
||||||
// Return an error response
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
|
||||||
{
|
|
||||||
// Return an error status, attempt to check in a folder
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsBadParameter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Check out the file
|
|
||||||
|
|
||||||
NodeRef workingCopyNode = checkInOutService.checkout( childNode);
|
|
||||||
|
|
||||||
// Get the working copy file name
|
|
||||||
|
|
||||||
String workingCopyName = (String) nodeService.getProperty( workingCopyNode, ContentModel.PROP_NAME);
|
|
||||||
|
|
||||||
// Check out was successful, pack the working copy name
|
|
||||||
|
|
||||||
respBuf.putInt( IOControl.StsSuccess);
|
|
||||||
respBuf.putString( workingCopyName, true, true);
|
|
||||||
|
|
||||||
// Check if there are any file/directory change notify requests active
|
|
||||||
|
|
||||||
DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
|
|
||||||
if (diskCtx.hasChangeHandler()) {
|
|
||||||
|
|
||||||
// Build the relative path to the checked in file
|
|
||||||
|
|
||||||
String fileName = FileName.buildPath( netFile.getFullName(), null, workingCopyName, FileName.DOS_SEPERATOR);
|
|
||||||
|
|
||||||
// Queue a file added change notification
|
|
||||||
|
|
||||||
diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Return an error status and message
|
|
||||||
|
|
||||||
respBuf.setPosition( IOControl.Signature.length());
|
|
||||||
respBuf.putInt(IOControl.StsError);
|
|
||||||
respBuf.putString( ex.getMessage(), true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the response
|
|
||||||
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2005-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.smb.repo;
|
|
||||||
|
|
||||||
import org.alfresco.filesys.smb.NTIOCtl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content Disk Driver I/O Control Codes Class
|
|
||||||
*
|
|
||||||
* <p>contains I/O control codes and status codes used by the content disk driver I/O control
|
|
||||||
* implementation.
|
|
||||||
*
|
|
||||||
* @author gkspencer
|
|
||||||
*/
|
|
||||||
public class IOControl
|
|
||||||
{
|
|
||||||
// Custom I/O control codes
|
|
||||||
|
|
||||||
public static final int CmdProbe = NTIOCtl.FsCtlCustom;
|
|
||||||
public static final int CmdFileStatus = NTIOCtl.FsCtlCustom + 1;
|
|
||||||
public static final int CmdCheckOut = NTIOCtl.FsCtlCustom + 2;
|
|
||||||
public static final int CmdCheckIn = NTIOCtl.FsCtlCustom + 3;
|
|
||||||
|
|
||||||
// I/O control request/response signature
|
|
||||||
|
|
||||||
public static final String Signature = "ALFRESCO";
|
|
||||||
|
|
||||||
// I/O control status codes
|
|
||||||
|
|
||||||
public static final int StsSuccess = 0;
|
|
||||||
|
|
||||||
public static final int StsError = 1;
|
|
||||||
public static final int StsFileNotFound = 2;
|
|
||||||
public static final int StsAccessDenied = 3;
|
|
||||||
public static final int StsBadParameter = 4;
|
|
||||||
public static final int StsNotWorkingCopy = 5;
|
|
||||||
|
|
||||||
// Boolean field values
|
|
||||||
|
|
||||||
public static final int True = 1;
|
|
||||||
public static final int False = 0;
|
|
||||||
|
|
||||||
// File status field values
|
|
||||||
//
|
|
||||||
// Node type
|
|
||||||
|
|
||||||
public static final int TypeFile = 0;
|
|
||||||
public static final int TypeFolder = 1;
|
|
||||||
|
|
||||||
// Lock status
|
|
||||||
|
|
||||||
public static final int LockNone = 0;
|
|
||||||
public static final int LockRead = 1;
|
|
||||||
public static final int LockWrite = 2;
|
|
||||||
}
|
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005 Alfresco, Inc.
|
* Copyright (C) 2005-2006 Alfresco, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Mozilla Public License version 1.1
|
* Licensed under the Mozilla Public License version 1.1
|
||||||
* with a permitted attribution clause. You may obtain a
|
* with a permitted attribution clause. You may obtain a
|
||||||
@@ -16,8 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.filesys.smb.server.repo;
|
package org.alfresco.filesys.smb.server.repo;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import org.alfresco.filesys.server.filesys.*;
|
import org.alfresco.filesys.server.filesys.*;
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
|
import org.alfresco.filesys.smb.server.repo.pseudo.ContentPseudoFileImpl;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
|
||||||
import org.alfresco.service.cmr.repository.*;
|
import org.alfresco.service.cmr.repository.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,15 +45,23 @@ public class ContentContext extends DiskDeviceContext
|
|||||||
|
|
||||||
private FileStateTable m_stateTable;
|
private FileStateTable m_stateTable;
|
||||||
|
|
||||||
// Drag and drop pseudo file
|
|
||||||
|
|
||||||
private PseudoFile m_dragAndDropApp;
|
|
||||||
|
|
||||||
// URL pseudo file web path prefix (server/port/webapp) and link file name
|
// URL pseudo file web path prefix (server/port/webapp) and link file name
|
||||||
|
|
||||||
private String m_urlPathPrefix;
|
private String m_urlPathPrefix;
|
||||||
private String m_urlFileName;
|
private String m_urlFileName;
|
||||||
|
|
||||||
|
// Pseudo file interface
|
||||||
|
|
||||||
|
private PseudoFileInterface m_pseudoFileInterface;
|
||||||
|
|
||||||
|
// Desktop actions
|
||||||
|
|
||||||
|
private DesktopActionTable m_desktopActions;
|
||||||
|
|
||||||
|
// I/O control handler
|
||||||
|
|
||||||
|
private IOControlHandler m_ioHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*
|
*
|
||||||
@@ -146,25 +157,108 @@ public class ContentContext extends DiskDeviceContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the drag and drop pseudo file has been configured
|
* Determine if the pseudo file interface is enabled
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public final boolean hasDragAndDropApp()
|
public final boolean hasPseudoFileInterface()
|
||||||
{
|
{
|
||||||
return m_dragAndDropApp != null ? true : false;
|
return m_pseudoFileInterface != null ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the drag and drop pseudo file
|
* Return the pseudo file interface
|
||||||
*
|
*
|
||||||
* @return PseudoFile
|
* @return PseudoFileInterface
|
||||||
*/
|
*/
|
||||||
public final PseudoFile getDragAndDropApp()
|
public final PseudoFileInterface getPseudoFileInterface()
|
||||||
{
|
{
|
||||||
return m_dragAndDropApp;
|
return m_pseudoFileInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the pseudo file interface for this filesystem
|
||||||
|
*/
|
||||||
|
public final void enabledPseudoFileInterface()
|
||||||
|
{
|
||||||
|
if ( m_pseudoFileInterface == null)
|
||||||
|
m_pseudoFileInterface = new ContentPseudoFileImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there are desktop actins configured
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasDesktopActions()
|
||||||
|
{
|
||||||
|
return m_desktopActions != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the desktop actions table
|
||||||
|
*
|
||||||
|
* @return DesktopActionTable
|
||||||
|
*/
|
||||||
|
public final DesktopActionTable getDesktopActions()
|
||||||
|
{
|
||||||
|
return m_desktopActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the count of desktop actions
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int numberOfDesktopActions()
|
||||||
|
{
|
||||||
|
return m_desktopActions != null ? m_desktopActions.numberOfActions() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a desktop action
|
||||||
|
*
|
||||||
|
* @param action DesktopAction
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean addDesktopAction(DesktopAction action)
|
||||||
|
{
|
||||||
|
// Check if the desktop actions table has been created
|
||||||
|
|
||||||
|
if ( m_desktopActions == null)
|
||||||
|
{
|
||||||
|
m_desktopActions = new DesktopActionTable();
|
||||||
|
|
||||||
|
// Enable pseudo files
|
||||||
|
|
||||||
|
enabledPseudoFileInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the action
|
||||||
|
|
||||||
|
return m_desktopActions.addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if custom I/O control handling is enabled for this filesystem
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasIOHandler()
|
||||||
|
{
|
||||||
|
return m_ioHandler != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the custom I/O control handler
|
||||||
|
*
|
||||||
|
* @return IOControlHandler
|
||||||
|
*/
|
||||||
|
public final IOControlHandler getIOHandler()
|
||||||
|
{
|
||||||
|
return m_ioHandler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the URL pseudo file is enabled
|
* Determine if the URL pseudo file is enabled
|
||||||
*
|
*
|
||||||
@@ -197,16 +291,6 @@ public class ContentContext extends DiskDeviceContext
|
|||||||
return m_urlFileName;
|
return m_urlFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the drag and drop application details
|
|
||||||
*
|
|
||||||
* @param dragDropApp PseudoFile
|
|
||||||
*/
|
|
||||||
public final void setDragAndDropApp(PseudoFile dragDropApp)
|
|
||||||
{
|
|
||||||
m_dragAndDropApp = dragDropApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the URL path prefix
|
* Set the URL path prefix
|
||||||
*
|
*
|
||||||
@@ -215,6 +299,9 @@ public class ContentContext extends DiskDeviceContext
|
|||||||
public final void setURLPrefix(String urlPrefix)
|
public final void setURLPrefix(String urlPrefix)
|
||||||
{
|
{
|
||||||
m_urlPathPrefix = urlPrefix;
|
m_urlPathPrefix = urlPrefix;
|
||||||
|
|
||||||
|
if ( urlPrefix != null)
|
||||||
|
enabledPseudoFileInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,8 +312,43 @@ public class ContentContext extends DiskDeviceContext
|
|||||||
public final void setURLFileName(String urlFileName)
|
public final void setURLFileName(String urlFileName)
|
||||||
{
|
{
|
||||||
m_urlFileName = urlFileName;
|
m_urlFileName = urlFileName;
|
||||||
|
|
||||||
|
if ( urlFileName != null)
|
||||||
|
enabledPseudoFileInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the desktop actions
|
||||||
|
*
|
||||||
|
* @param desktopActions DesktopActionTable
|
||||||
|
* @param filesysDriver DiskInterface
|
||||||
|
*/
|
||||||
|
public final void setDesktopActions(DesktopActionTable desktopActions, DiskInterface filesysDriver)
|
||||||
|
{
|
||||||
|
// Enumerate the desktop actions and add to this filesystem
|
||||||
|
|
||||||
|
Enumeration<String> names = desktopActions.enumerateActionNames();
|
||||||
|
|
||||||
|
while ( names.hasMoreElements())
|
||||||
|
{
|
||||||
|
addDesktopAction( desktopActions.getAction(names.nextElement()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are desktop actions then create the custom I/O control handler
|
||||||
|
|
||||||
|
if ( numberOfDesktopActions() > 0)
|
||||||
|
{
|
||||||
|
// Access the filesystem driver
|
||||||
|
|
||||||
|
ContentDiskDriver contentDriver = (ContentDiskDriver) filesysDriver;
|
||||||
|
|
||||||
|
// Create the custom I/O control handler
|
||||||
|
|
||||||
|
m_ioHandler = new ContentIOControlHandler();
|
||||||
|
m_ioHandler.initialize(contentDriver, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the filesystem context
|
* Close the filesystem context
|
||||||
*/
|
*/
|
||||||
|
@@ -16,12 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.filesys.smb.server.repo;
|
package org.alfresco.filesys.smb.server.repo;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
@@ -52,8 +48,6 @@ import org.alfresco.filesys.smb.SMBStatus;
|
|||||||
import org.alfresco.filesys.smb.SharingMode;
|
import org.alfresco.filesys.smb.SharingMode;
|
||||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||||
import org.alfresco.filesys.smb.server.repo.FileState.FileStateStatus;
|
import org.alfresco.filesys.smb.server.repo.FileState.FileStateStatus;
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.ContentPseudoFileImpl;
|
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.LocalPseudoFile;
|
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.MemoryNetworkFile;
|
import org.alfresco.filesys.smb.server.repo.pseudo.MemoryNetworkFile;
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
|
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile;
|
||||||
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
|
import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFileInterface;
|
||||||
@@ -105,18 +99,10 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
private SearchService searchService;
|
private SearchService searchService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private PermissionService permissionService;
|
private PermissionService permissionService;
|
||||||
private CheckOutCheckInService checkInOutService;
|
private CheckOutCheckInService checkOutInService;
|
||||||
|
|
||||||
private AuthenticationComponent authComponent;
|
private AuthenticationComponent authComponent;
|
||||||
|
|
||||||
// I/O control handler
|
|
||||||
|
|
||||||
private IOControlHandler m_ioHandler;
|
|
||||||
|
|
||||||
// Pseudo files interface
|
|
||||||
|
|
||||||
private PseudoFileInterface m_pseudoFiles;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*
|
*
|
||||||
@@ -127,6 +113,75 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
this.cifsHelper = cifsHelper;
|
this.cifsHelper = cifsHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the CIFS helper
|
||||||
|
*
|
||||||
|
* @return CifsHelper
|
||||||
|
*/
|
||||||
|
public final CifsHelper getCifsHelper()
|
||||||
|
{
|
||||||
|
return this.cifsHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the transaction service
|
||||||
|
*
|
||||||
|
* @return TransactionService
|
||||||
|
*/
|
||||||
|
public final TransactionService getTransactionService()
|
||||||
|
{
|
||||||
|
return this.transactionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node service
|
||||||
|
*
|
||||||
|
* @return NodeService
|
||||||
|
*/
|
||||||
|
public final NodeService getNodeService()
|
||||||
|
{
|
||||||
|
return this.nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the content service
|
||||||
|
*
|
||||||
|
* @return ContentService
|
||||||
|
*/
|
||||||
|
public final ContentService getContentService()
|
||||||
|
{
|
||||||
|
return this.contentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the namespace service
|
||||||
|
*
|
||||||
|
* @return NamespaceService
|
||||||
|
*/
|
||||||
|
public final NamespaceService getNamespaceService()
|
||||||
|
{
|
||||||
|
return this.namespaceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the search service
|
||||||
|
*
|
||||||
|
* @return SearchService
|
||||||
|
*/
|
||||||
|
public final SearchService getSearchService(){
|
||||||
|
return this.searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the check in/out service
|
||||||
|
*
|
||||||
|
* @return CheckOutInService
|
||||||
|
*/
|
||||||
|
public final CheckOutCheckInService getCheckInOutService()
|
||||||
|
{
|
||||||
|
return this.checkOutInService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param contentService the content service
|
* @param contentService the content service
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +213,6 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
{
|
{
|
||||||
this.searchService = searchService;
|
this.searchService = searchService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param transactionService the transaction service
|
* @param transactionService the transaction service
|
||||||
@@ -181,11 +235,11 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
/**
|
/**
|
||||||
* Set the check in/out service
|
* Set the check in/out service
|
||||||
*
|
*
|
||||||
* @param checkInOutService CheckOutCheckInService
|
* @param checkInService CheckOutInService
|
||||||
*/
|
*/
|
||||||
public void setCheckInOutService(CheckOutCheckInService checkInOutService)
|
public void setCheckInOutService(CheckOutCheckInService checkInService)
|
||||||
{
|
{
|
||||||
this.checkInOutService = checkInOutService;
|
this.checkOutInService = checkInService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -337,67 +391,6 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the client side drag and drop appliction has been enabled
|
|
||||||
|
|
||||||
ConfigElement dragDropElem = cfg.getChild( "dragAndDrop");
|
|
||||||
if ( dragDropElem != null)
|
|
||||||
{
|
|
||||||
// Get the pseudo file name and path to the actual file on the local filesystem
|
|
||||||
|
|
||||||
ConfigElement pseudoName = dragDropElem.getChild( "filename");
|
|
||||||
ConfigElement appPath = dragDropElem.getChild( "path");
|
|
||||||
|
|
||||||
if ( pseudoName != null && appPath != null)
|
|
||||||
{
|
|
||||||
// Check that the application exists on the local filesystem
|
|
||||||
|
|
||||||
URL appURL = this.getClass().getClassLoader().getResource(appPath.getValue());
|
|
||||||
if ( appURL == null)
|
|
||||||
throw new DeviceContextException("Failed to find drag and drop application, " + appPath.getValue());
|
|
||||||
|
|
||||||
// Decode the URL path, it might contain escaped characters
|
|
||||||
|
|
||||||
String appURLPath = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
appURLPath = URLDecoder.decode( appURL.getFile(), "UTF-8");
|
|
||||||
}
|
|
||||||
catch ( UnsupportedEncodingException ex)
|
|
||||||
{
|
|
||||||
throw new DeviceContextException("Failed to decode drag/drop path, " + ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the drag/drop file exists
|
|
||||||
|
|
||||||
File appFile = new File(appURLPath);
|
|
||||||
if ( appFile.exists() == false)
|
|
||||||
throw new DeviceContextException("Drag and drop application not found, " + appPath.getValue());
|
|
||||||
|
|
||||||
// Create the pseudo file for the drag and drop application
|
|
||||||
|
|
||||||
PseudoFile dragDropPseudo = new LocalPseudoFile( pseudoName.getValue(), appFile.getAbsolutePath());
|
|
||||||
context.setDragAndDropApp( dragDropPseudo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the custom I/O handler
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_ioHandler = new ContentIOControlHandler();
|
|
||||||
m_ioHandler.initialize( this, cifsHelper, transactionService, nodeService, checkInOutService);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Log the error
|
|
||||||
|
|
||||||
logger.error("Failed to initialize I/O control handler", ex);
|
|
||||||
|
|
||||||
// Rethrow the exception
|
|
||||||
|
|
||||||
throw new DeviceContextException("Failed to initialize I/O control handler");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if URL link files are enabled
|
// Check if URL link files are enabled
|
||||||
|
|
||||||
ConfigElement urlFileElem = cfg.getChild( "urlFile");
|
ConfigElement urlFileElem = cfg.getChild( "urlFile");
|
||||||
@@ -428,15 +421,6 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable pseudo file support if the drag and drop app and/or URL link files are enabled
|
|
||||||
|
|
||||||
if ( context.hasDragAndDropApp() || context.hasURLFile())
|
|
||||||
{
|
|
||||||
// Create the pseudo file handler
|
|
||||||
|
|
||||||
m_pseudoFiles = new ContentPseudoFileImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if locked files should be marked as offline
|
// Check if locked files should be marked as offline
|
||||||
|
|
||||||
ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
|
ConfigElement offlineFiles = cfg.getChild( "offlineFiles");
|
||||||
@@ -459,21 +443,23 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
/**
|
/**
|
||||||
* Check if pseudo file support is enabled
|
* Check if pseudo file support is enabled
|
||||||
*
|
*
|
||||||
|
* @param context ContentContext
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public final boolean hasPseudoFileInterface()
|
public final boolean hasPseudoFileInterface(ContentContext context)
|
||||||
{
|
{
|
||||||
return m_pseudoFiles != null ? true : false;
|
return context.hasPseudoFileInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the pseudo file support implementation
|
* Return the pseudo file support implementation
|
||||||
*
|
*
|
||||||
|
* @param context ContentContext
|
||||||
* @return PseudoFileInterface
|
* @return PseudoFileInterface
|
||||||
*/
|
*/
|
||||||
public final PseudoFileInterface getPseudoFileInterface()
|
public final PseudoFileInterface getPseudoFileInterface(ContentContext context)
|
||||||
{
|
{
|
||||||
return m_pseudoFiles;
|
return context.getPseudoFileInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -523,11 +509,11 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
|
|
||||||
FileInfo finfo = null;
|
FileInfo finfo = null;
|
||||||
|
|
||||||
if ( hasPseudoFileInterface())
|
if ( hasPseudoFileInterface(ctx))
|
||||||
{
|
{
|
||||||
// Get the pseudo file
|
// Get the pseudo file
|
||||||
|
|
||||||
PseudoFile pfile = getPseudoFileInterface().getPseudoFile( session, tree, path);
|
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( session, tree, path);
|
||||||
if ( pfile != null)
|
if ( pfile != null)
|
||||||
{
|
{
|
||||||
// DEBUG
|
// DEBUG
|
||||||
@@ -707,8 +693,8 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
|
|
||||||
// Add pseudo files to the folder being searched
|
// Add pseudo files to the folder being searched
|
||||||
|
|
||||||
if ( hasPseudoFileInterface())
|
if ( hasPseudoFileInterface(ctx))
|
||||||
getPseudoFileInterface().addPseudoFilesToFolder( sess, tree, paths[0]);
|
getPseudoFileInterface(ctx).addPseudoFilesToFolder( sess, tree, paths[0]);
|
||||||
|
|
||||||
// Set the search node and file spec
|
// Set the search node and file spec
|
||||||
|
|
||||||
@@ -908,11 +894,11 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
|
|
||||||
// Check if pseudo files are enabled
|
// Check if pseudo files are enabled
|
||||||
|
|
||||||
if ( hasPseudoFileInterface())
|
if ( hasPseudoFileInterface(ctx))
|
||||||
{
|
{
|
||||||
// Check if the path is to a pseudo file
|
// Check if the path is to a pseudo file
|
||||||
|
|
||||||
PseudoFile pfile = getPseudoFileInterface().getPseudoFile( sess, tree, params.getPath());
|
PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath());
|
||||||
if ( pfile != null)
|
if ( pfile != null)
|
||||||
{
|
{
|
||||||
// Create a network file to access the pseudo file data
|
// Create a network file to access the pseudo file data
|
||||||
@@ -1425,11 +1411,11 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
{
|
{
|
||||||
// Delete the pseudo file
|
// Delete the pseudo file
|
||||||
|
|
||||||
if ( hasPseudoFileInterface())
|
if ( hasPseudoFileInterface(ctx))
|
||||||
{
|
{
|
||||||
// Delete the pseudo file
|
// Delete the pseudo file
|
||||||
|
|
||||||
getPseudoFileInterface().deletePseudoFile( sess, tree, file.getFullName());
|
getPseudoFileInterface(ctx).deletePseudoFile( sess, tree, file.getFullName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1698,10 +1684,14 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Get the device context
|
||||||
|
|
||||||
|
ContentContext ctx = (ContentContext) tree.getContext();
|
||||||
|
|
||||||
// Check if pseudo files are enabled
|
// Check if pseudo files are enabled
|
||||||
|
|
||||||
if ( hasPseudoFileInterface() &&
|
if ( hasPseudoFileInterface(ctx) &&
|
||||||
getPseudoFileInterface().isPseudoFile( sess, tree, name))
|
getPseudoFileInterface(ctx).isPseudoFile( sess, tree, name))
|
||||||
{
|
{
|
||||||
// Allow the file information to be changed
|
// Allow the file information to be changed
|
||||||
|
|
||||||
@@ -1997,8 +1987,9 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface
|
|||||||
|
|
||||||
// Check if the I/O control handler is enabled
|
// Check if the I/O control handler is enabled
|
||||||
|
|
||||||
if ( m_ioHandler != null)
|
ContentContext ctx = (ContentContext) tree.getContext();
|
||||||
return m_ioHandler.processIOControl( sess, tree, ctrlCode, fid, dataBuf, isFSCtrl, filter);
|
if ( ctx.hasIOHandler())
|
||||||
|
return ctx.getIOHandler().processIOControl( sess, tree, ctrlCode, fid, dataBuf, isFSCtrl, filter);
|
||||||
else
|
else
|
||||||
throw new IOControlNotImplementedException();
|
throw new IOControlNotImplementedException();
|
||||||
}
|
}
|
||||||
|
@@ -19,11 +19,8 @@ package org.alfresco.filesys.smb.server.repo;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
import org.alfresco.filesys.server.SrvSession;
|
import org.alfresco.filesys.server.SrvSession;
|
||||||
import org.alfresco.filesys.server.filesys.DiskDeviceContext;
|
|
||||||
import org.alfresco.filesys.server.filesys.FileName;
|
|
||||||
import org.alfresco.filesys.server.filesys.IOControlNotImplementedException;
|
import org.alfresco.filesys.server.filesys.IOControlNotImplementedException;
|
||||||
import org.alfresco.filesys.server.filesys.NetworkFile;
|
import org.alfresco.filesys.server.filesys.NetworkFile;
|
||||||
import org.alfresco.filesys.server.filesys.NotifyChange;
|
|
||||||
import org.alfresco.filesys.server.filesys.TreeConnection;
|
import org.alfresco.filesys.server.filesys.TreeConnection;
|
||||||
import org.alfresco.filesys.smb.NTIOCtl;
|
import org.alfresco.filesys.smb.NTIOCtl;
|
||||||
import org.alfresco.filesys.smb.SMBException;
|
import org.alfresco.filesys.smb.SMBException;
|
||||||
@@ -33,7 +30,6 @@ import org.alfresco.filesys.smb.server.repo.ContentDiskDriver;
|
|||||||
import org.alfresco.filesys.smb.server.repo.IOControlHandler;
|
import org.alfresco.filesys.smb.server.repo.IOControlHandler;
|
||||||
import org.alfresco.filesys.util.DataBuffer;
|
import org.alfresco.filesys.util.DataBuffer;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
|
||||||
import org.alfresco.service.cmr.lock.LockType;
|
import org.alfresco.service.cmr.lock.LockType;
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
@@ -55,14 +51,10 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ContentIOControlHandler.class);
|
private static final Log logger = LogFactory.getLog(ContentIOControlHandler.class);
|
||||||
|
|
||||||
// Services and helpers
|
// Filesystem driver and context
|
||||||
|
|
||||||
private CifsHelper cifsHelper;
|
|
||||||
private TransactionService transactionService;
|
|
||||||
private NodeService nodeService;
|
|
||||||
private CheckOutCheckInService checkInOutService;
|
|
||||||
|
|
||||||
private ContentDiskDriver contentDriver;
|
private ContentDiskDriver contentDriver;
|
||||||
|
private ContentContext contentContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor
|
* Default constructor
|
||||||
@@ -75,21 +67,64 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
* Initalize the I/O control handler
|
* Initalize the I/O control handler
|
||||||
*
|
*
|
||||||
* @param contentDriver ContentDiskDriver
|
* @param contentDriver ContentDiskDriver
|
||||||
* @param cifsHelper CifsHelper
|
* @param contentContext ContentContext
|
||||||
* @param transService TransactionService
|
|
||||||
* @param nodeService NodeService
|
|
||||||
* @param cociService CheckOutCheckInService
|
|
||||||
*/
|
*/
|
||||||
public void initialize( ContentDiskDriver contentDriver, CifsHelper cifsHelper,
|
public void initialize( ContentDiskDriver contentDriver, ContentContext contentContext)
|
||||||
TransactionService transService, NodeService nodeService, CheckOutCheckInService cociService)
|
|
||||||
{
|
{
|
||||||
this.contentDriver = contentDriver;
|
this.contentDriver = contentDriver;
|
||||||
this.cifsHelper = cifsHelper;
|
this.contentContext = contentContext;
|
||||||
this.transactionService = transService;
|
|
||||||
this.nodeService = nodeService;
|
|
||||||
this.checkInOutService = cociService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the CIFS helper
|
||||||
|
*
|
||||||
|
* @return CifsHelper
|
||||||
|
*/
|
||||||
|
public final CifsHelper getCifsHelper()
|
||||||
|
{
|
||||||
|
return contentDriver.getCifsHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the transaction service
|
||||||
|
*
|
||||||
|
* @return TransactionService
|
||||||
|
*/
|
||||||
|
public final TransactionService getTransactionService()
|
||||||
|
{
|
||||||
|
return contentDriver.getTransactionService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node service
|
||||||
|
*
|
||||||
|
* @return NodeService
|
||||||
|
*/
|
||||||
|
public final NodeService getNodeService()
|
||||||
|
{
|
||||||
|
return contentDriver.getNodeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the filesystem driver
|
||||||
|
*
|
||||||
|
* @return ContentDiskDriver
|
||||||
|
*/
|
||||||
|
public final ContentDiskDriver getContentDriver()
|
||||||
|
{
|
||||||
|
return contentDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the filesystem context
|
||||||
|
*
|
||||||
|
* @return ContentContext
|
||||||
|
*/
|
||||||
|
public final ContentContext getContentContext()
|
||||||
|
{
|
||||||
|
return contentContext;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a filesystem I/O control request
|
* Process a filesystem I/O control request
|
||||||
*
|
*
|
||||||
@@ -140,7 +175,7 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
{
|
{
|
||||||
folderNode = contentDriver.getNodeForPath(tree, netFile.getFullName());
|
folderNode = contentDriver.getNodeForPath(tree, netFile.getFullName());
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( folderNode) == false)
|
if ( getCifsHelper().isDirectory( folderNode) == false)
|
||||||
folderNode = null;
|
folderNode = null;
|
||||||
}
|
}
|
||||||
catch ( FileNotFoundException ex)
|
catch ( FileNotFoundException ex)
|
||||||
@@ -155,9 +190,9 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
if ( logger.isInfoEnabled()) {
|
if ( logger.isDebugEnabled()) {
|
||||||
logger.info("IO control func=0x" + Integer.toHexString(ioFunc) + ", fid=" + fid + ", buffer=" + dataBuf);
|
logger.debug("IO control func=0x" + Integer.toHexString(ioFunc) + ", fid=" + fid + ", buffer=" + dataBuf);
|
||||||
logger.info(" Folder nodeRef=" + folderNode);
|
logger.debug(" Folder nodeRef=" + folderNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the I/O control code is one of our custom codes
|
// Check if the I/O control code is one of our custom codes
|
||||||
@@ -166,48 +201,49 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
switch ( ioFunc)
|
switch ( ioFunc)
|
||||||
{
|
{
|
||||||
// Probe to check if this is an Alfresco CIFS server
|
// Probe to check if this is an Alfresco CIFS server
|
||||||
|
|
||||||
case IOControl.CmdProbe:
|
case IOControl.CmdProbe:
|
||||||
|
|
||||||
// Return a buffer with the signature
|
// Return a buffer with the signature and protocol version
|
||||||
|
|
||||||
retBuffer = new DataBuffer(IOControl.Signature.length());
|
retBuffer = new DataBuffer(IOControl.Signature.length());
|
||||||
retBuffer.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
retBuffer.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
||||||
retBuffer.putInt(IOControl.StsSuccess);
|
retBuffer.putInt(DesktopAction.StsSuccess);
|
||||||
break;
|
retBuffer.putInt(IOControl.Version);
|
||||||
|
break;
|
||||||
// Get file information for a file within the current folder
|
|
||||||
|
// Get file information for a file within the current folder
|
||||||
case IOControl.CmdFileStatus:
|
|
||||||
|
case IOControl.CmdFileStatus:
|
||||||
// Process the file status request
|
|
||||||
|
// Process the file status request
|
||||||
retBuffer = procIOFileStatus( sess, tree, dataBuf, folderNode);
|
|
||||||
break;
|
retBuffer = procIOFileStatus( sess, tree, dataBuf, folderNode);
|
||||||
|
break;
|
||||||
// Check-in file request
|
|
||||||
|
// Get action information for the specified executable path
|
||||||
case IOControl.CmdCheckIn:
|
|
||||||
|
case IOControl.CmdGetActionInfo:
|
||||||
// Process the check-in request
|
|
||||||
|
// Process the get action information request
|
||||||
retBuffer = procIOCheckIn( sess, tree, dataBuf, folderNode, netFile);
|
|
||||||
break;
|
retBuffer = procGetActionInfo(sess, tree, dataBuf, folderNode, netFile);
|
||||||
|
break;
|
||||||
// Check-out file request
|
|
||||||
|
// Run the named action
|
||||||
case IOControl.CmdCheckOut:
|
|
||||||
|
case IOControl.CmdRunAction:
|
||||||
// Process the check-out request
|
|
||||||
|
// Process the run action request
|
||||||
retBuffer = procIOCheckOut( sess, tree, dataBuf, folderNode, netFile);
|
|
||||||
break;
|
retBuffer = procRunAction(sess, tree, dataBuf, folderNode, netFile);
|
||||||
|
break;
|
||||||
// Unknown I/O control code
|
|
||||||
|
// Unknown I/O control code
|
||||||
default:
|
|
||||||
throw new IOControlNotImplementedException();
|
default:
|
||||||
|
throw new IOControlNotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the reply buffer, may be null
|
// Return the reply buffer, may be null
|
||||||
@@ -228,12 +264,14 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
{
|
{
|
||||||
// Start a transaction
|
// Start a transaction
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, true);
|
sess.beginTransaction( getTransactionService(), true);
|
||||||
|
|
||||||
// Get the file name from the request
|
// Get the file name from the request
|
||||||
|
|
||||||
String fName = reqBuf.getString( true);
|
String fName = reqBuf.getString( true);
|
||||||
logger.info(" File status, fname=" + fName);
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug(" File status, fname=" + fName);
|
||||||
|
|
||||||
// Create a response buffer
|
// Create a response buffer
|
||||||
|
|
||||||
@@ -246,7 +284,7 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
childNode = getCifsHelper().getNodeRef( folderNode, fName);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException ex)
|
catch (FileNotFoundException ex)
|
||||||
{
|
{
|
||||||
@@ -258,29 +296,29 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
{
|
{
|
||||||
// Return an error response
|
// Return an error response
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
respBuf.putInt(DesktopAction.StsFileNotFound);
|
||||||
return respBuf;
|
return respBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
// Check if this is a file or folder node
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
if ( getCifsHelper().isDirectory( childNode))
|
||||||
{
|
{
|
||||||
// Only return the status and node type for folders
|
// Only return the status and node type for folders
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsSuccess);
|
respBuf.putInt(DesktopAction.StsSuccess);
|
||||||
respBuf.putInt(IOControl.TypeFolder);
|
respBuf.putInt(IOControl.TypeFolder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Indicate that this is a file node
|
// Indicate that this is a file node
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsSuccess);
|
respBuf.putInt(DesktopAction.StsSuccess);
|
||||||
respBuf.putInt(IOControl.TypeFile);
|
respBuf.putInt(IOControl.TypeFile);
|
||||||
|
|
||||||
// Check if this file is a working copy
|
// Check if this file is a working copy
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
|
if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
|
||||||
{
|
{
|
||||||
// Indicate that this is a working copy
|
// Indicate that this is a working copy
|
||||||
|
|
||||||
@@ -288,16 +326,16 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
// Get the owner username and file it was copied from
|
// Get the owner username and file it was copied from
|
||||||
|
|
||||||
String owner = (String) nodeService.getProperty( childNode, ContentModel.PROP_WORKING_COPY_OWNER);
|
String owner = (String) getNodeService().getProperty( childNode, ContentModel.PROP_WORKING_COPY_OWNER);
|
||||||
String copiedFrom = null;
|
String copiedFrom = null;
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_COPIEDFROM))
|
if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_COPIEDFROM))
|
||||||
{
|
{
|
||||||
// Get the path of the file the working copy was generated from
|
// Get the path of the file the working copy was generated from
|
||||||
|
|
||||||
NodeRef fromNode = (NodeRef) nodeService.getProperty( childNode, ContentModel.PROP_COPY_REFERENCE);
|
NodeRef fromNode = (NodeRef) getNodeService().getProperty( childNode, ContentModel.PROP_COPY_REFERENCE);
|
||||||
if ( fromNode != null)
|
if ( fromNode != null)
|
||||||
copiedFrom = (String) nodeService.getProperty( fromNode, ContentModel.PROP_NAME);
|
copiedFrom = (String) getNodeService().getProperty( fromNode, ContentModel.PROP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack the owner and copied from values
|
// Pack the owner and copied from values
|
||||||
@@ -314,15 +352,15 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
// Check the lock status of the file
|
// Check the lock status of the file
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_LOCKABLE))
|
if ( getNodeService().hasAspect( childNode, ContentModel.ASPECT_LOCKABLE))
|
||||||
{
|
{
|
||||||
// Get the lock type and owner
|
// Get the lock type and owner
|
||||||
|
|
||||||
String lockTypeStr = (String) nodeService.getProperty( childNode, ContentModel.PROP_LOCK_TYPE);
|
String lockTypeStr = (String) getNodeService().getProperty( childNode, ContentModel.PROP_LOCK_TYPE);
|
||||||
String lockOwner = null;
|
String lockOwner = null;
|
||||||
|
|
||||||
if ( lockTypeStr != null)
|
if ( lockTypeStr != null)
|
||||||
lockOwner = (String) nodeService.getProperty( childNode, ContentModel.PROP_LOCK_OWNER);
|
lockOwner = (String) getNodeService().getProperty( childNode, ContentModel.PROP_LOCK_OWNER);
|
||||||
|
|
||||||
// Pack the lock type, and owner if there is a lock on the file
|
// Pack the lock type, and owner if there is a lock on the file
|
||||||
|
|
||||||
@@ -345,7 +383,7 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
// Get the content data details for the file
|
// Get the content data details for the file
|
||||||
|
|
||||||
ContentData contentData = (ContentData) nodeService.getProperty( childNode, ContentModel.PROP_CONTENT);
|
ContentData contentData = (ContentData) getNodeService().getProperty( childNode, ContentModel.PROP_CONTENT);
|
||||||
|
|
||||||
if ( contentData != null)
|
if ( contentData != null)
|
||||||
{
|
{
|
||||||
@@ -371,9 +409,9 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
|
|
||||||
return respBuf;
|
return respBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the check in I/O request
|
* Process the get action information request
|
||||||
*
|
*
|
||||||
* @param sess Server session
|
* @param sess Server session
|
||||||
* @param tree Tree connection
|
* @param tree Tree connection
|
||||||
@@ -382,208 +420,208 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
* @param netFile NetworkFile for the folder
|
* @param netFile NetworkFile for the folder
|
||||||
* @return DataBuffer
|
* @return DataBuffer
|
||||||
*/
|
*/
|
||||||
private final DataBuffer procIOCheckIn( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
private final DataBuffer procGetActionInfo( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
||||||
NetworkFile netFile)
|
NetworkFile netFile)
|
||||||
{
|
{
|
||||||
// Start a transaction
|
// Get the executable file name from the request
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, false);
|
String exeName = reqBuf.getString( true);
|
||||||
|
|
||||||
// Get the file name from the request
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug(" Get action info, exe=" + exeName);
|
||||||
String fName = reqBuf.getString( true);
|
|
||||||
boolean keepCheckedOut = reqBuf.getInt() == IOControl.True ? true : false;
|
|
||||||
|
|
||||||
logger.info(" CheckIn, fname=" + fName + ", keepCheckedOut=" + keepCheckedOut);
|
|
||||||
|
|
||||||
// Create a response buffer
|
// Create a response buffer
|
||||||
|
|
||||||
DataBuffer respBuf = new DataBuffer(256);
|
DataBuffer respBuf = new DataBuffer(256);
|
||||||
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
||||||
|
|
||||||
// Get the node for the file/folder
|
// Get the desktop actions list
|
||||||
|
|
||||||
NodeRef childNode = null;
|
DesktopActionTable deskActions = contentContext.getDesktopActions();
|
||||||
|
if ( deskActions == null)
|
||||||
try
|
|
||||||
{
|
{
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
respBuf.putInt(DesktopAction.StsNoSuchAction);
|
||||||
|
return respBuf;
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
|
// Convert the executable name to an action name
|
||||||
|
|
||||||
|
DesktopAction deskAction = deskActions.getActionViaPseudoName(exeName);
|
||||||
|
if ( deskAction == null)
|
||||||
{
|
{
|
||||||
|
respBuf.putInt(DesktopAction.StsNoSuchAction);
|
||||||
|
return respBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the desktop action details
|
||||||
|
|
||||||
|
respBuf.putInt(DesktopAction.StsSuccess);
|
||||||
|
respBuf.putString(deskAction.getName(), true);
|
||||||
|
respBuf.putInt(deskAction.getAttributes());
|
||||||
|
respBuf.putInt(deskAction.getPreProcessActions());
|
||||||
|
|
||||||
|
String confirmStr = deskAction.getConfirmationString();
|
||||||
|
respBuf.putString(confirmStr != null ? confirmStr : "", true);
|
||||||
|
|
||||||
|
// Return the response
|
||||||
|
|
||||||
|
return respBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the run action request
|
||||||
|
*
|
||||||
|
* @param sess Server session
|
||||||
|
* @param tree Tree connection
|
||||||
|
* @param reqBuf Request buffer
|
||||||
|
* @param folderNode NodeRef of parent folder
|
||||||
|
* @param netFile NetworkFile for the folder
|
||||||
|
* @return DataBuffer
|
||||||
|
*/
|
||||||
|
private final DataBuffer procRunAction( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
||||||
|
NetworkFile netFile)
|
||||||
|
{
|
||||||
|
// Get the name of the action to run
|
||||||
|
|
||||||
|
String actionName = reqBuf.getString(true);
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug(" Run action, name=" + actionName);
|
||||||
|
|
||||||
|
// Create a response buffer
|
||||||
|
|
||||||
|
DataBuffer respBuf = new DataBuffer(256);
|
||||||
|
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
||||||
|
|
||||||
|
// Find the action handler
|
||||||
|
|
||||||
|
DesktopActionTable deskActions = contentContext.getDesktopActions();
|
||||||
|
DesktopAction action = null;
|
||||||
|
|
||||||
|
if ( deskActions != null)
|
||||||
|
action = deskActions.getAction(actionName);
|
||||||
|
|
||||||
|
if ( action == null)
|
||||||
|
{
|
||||||
|
respBuf.putInt(DesktopAction.StsNoSuchAction);
|
||||||
|
respBuf.putString("", true);
|
||||||
|
return respBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the file/folder was found
|
// Start a transaction
|
||||||
|
|
||||||
if ( childNode == null)
|
sess.beginTransaction( getTransactionService(), true);
|
||||||
{
|
|
||||||
// Return an error response
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
// Get the list of targets for the action
|
||||||
|
|
||||||
|
int targetCnt = reqBuf.getInt();
|
||||||
|
DesktopParams deskParams = new DesktopParams(sess, folderNode, netFile);
|
||||||
|
|
||||||
|
while ( reqBuf.getAvailableLength() > 4 && targetCnt > 0)
|
||||||
{
|
{
|
||||||
// Return an error status, attempt to check in a folder
|
// Get the desktop target details
|
||||||
|
|
||||||
|
int typ = reqBuf.getInt();
|
||||||
|
String path = reqBuf.getString(true);
|
||||||
|
|
||||||
|
DesktopTarget target = new DesktopTarget(typ, path);
|
||||||
|
deskParams.addTarget(target);
|
||||||
|
|
||||||
|
// Find the node for the target path
|
||||||
|
|
||||||
|
NodeRef childNode = null;
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsBadParameter);
|
try
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check if this file is a working copy
|
|
||||||
|
|
||||||
if ( nodeService.hasAspect( childNode, ContentModel.ASPECT_WORKING_COPY))
|
|
||||||
{
|
{
|
||||||
try
|
// Check if the target path is relative to the folder we are working in or the root of the filesystem
|
||||||
{
|
|
||||||
// Check in the file
|
if ( path.startsWith("\\"))
|
||||||
|
{
|
||||||
checkInOutService.checkin( childNode, null, null, keepCheckedOut);
|
// Path is relative to the root of the filesystem
|
||||||
|
|
||||||
|
childNode = getCifsHelper().getNodeRef(contentContext.getRootNode(), path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Path is relative to the folder we are working in
|
||||||
|
|
||||||
|
childNode = getCifsHelper().getNodeRef( folderNode, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Check in was successful
|
// If the node is not valid then return an error status
|
||||||
|
|
||||||
respBuf.putInt( IOControl.StsSuccess);
|
if (childNode != null)
|
||||||
|
{
|
||||||
// Check if there are any file/directory change notify requests active
|
// Set the node ref for the target
|
||||||
|
|
||||||
DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
|
target.setNode(childNode);
|
||||||
if (diskCtx.hasChangeHandler()) {
|
|
||||||
|
|
||||||
// Build the relative path to the checked in file
|
|
||||||
|
|
||||||
String fileName = FileName.buildPath( netFile.getFullName(), null, fName, FileName.DOS_SEPERATOR);
|
|
||||||
|
|
||||||
// Queue a file deleted change notification
|
|
||||||
|
|
||||||
diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Return an error status and message
|
|
||||||
|
|
||||||
respBuf.setPosition( IOControl.Signature.length());
|
|
||||||
respBuf.putInt(IOControl.StsError);
|
|
||||||
respBuf.putString( ex.getMessage(), true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not a working copy
|
// Build an error response
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsNotWorkingCopy);
|
respBuf.putInt(DesktopAction.StsFileNotFound);
|
||||||
|
respBuf.putString("Cannot find noderef for path " + path, true);
|
||||||
|
|
||||||
|
return respBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the target count
|
||||||
|
|
||||||
|
targetCnt--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the response
|
// DEBUG
|
||||||
|
|
||||||
return respBuf;
|
if (logger.isDebugEnabled())
|
||||||
}
|
{
|
||||||
|
logger.debug(" Desktop params: " + deskParams.numberOfTargetNodes());
|
||||||
/**
|
for ( int i = 0; i < deskParams.numberOfTargetNodes(); i++) {
|
||||||
* Process the check out I/O request
|
DesktopTarget target = deskParams.getTarget(i);
|
||||||
*
|
logger.debug(" " + target);
|
||||||
* @param sess Server session
|
}
|
||||||
* @param tree Tree connection
|
}
|
||||||
* @param reqBuf Request buffer
|
|
||||||
* @param folderNode NodeRef of parent folder
|
|
||||||
* @param netFile NetworkFile for the folder
|
|
||||||
* @return DataBuffer
|
|
||||||
*/
|
|
||||||
private final DataBuffer procIOCheckOut( SrvSession sess, TreeConnection tree, DataBuffer reqBuf, NodeRef folderNode,
|
|
||||||
NetworkFile netFile)
|
|
||||||
{
|
|
||||||
// Start a transaction
|
|
||||||
|
|
||||||
sess.beginTransaction( transactionService, false);
|
// Run the desktop action
|
||||||
|
|
||||||
// Get the file name from the request
|
DesktopResponse deskResponse = null;
|
||||||
|
|
||||||
String fName = reqBuf.getString( true);
|
|
||||||
|
|
||||||
logger.info(" CheckOut, fname=" + fName);
|
|
||||||
|
|
||||||
// Create a response buffer
|
|
||||||
|
|
||||||
DataBuffer respBuf = new DataBuffer(256);
|
|
||||||
respBuf.putFixedString(IOControl.Signature, IOControl.Signature.length());
|
|
||||||
|
|
||||||
// Get the node for the file/folder
|
|
||||||
|
|
||||||
NodeRef childNode = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
childNode = cifsHelper.getNodeRef( folderNode, fName);
|
// Run the desktop action
|
||||||
|
|
||||||
|
deskResponse = action.runAction(deskParams);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
// Create an error response
|
||||||
|
|
||||||
|
deskResponse = new DesktopResponse(DesktopAction.StsError, ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the file/folder was found
|
|
||||||
|
|
||||||
if ( childNode == null)
|
// Pack the action response
|
||||||
{
|
|
||||||
// Return an error response
|
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsFileNotFound);
|
|
||||||
return respBuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is a file or folder node
|
|
||||||
|
|
||||||
if ( cifsHelper.isDirectory( childNode))
|
if ( deskResponse != null)
|
||||||
{
|
{
|
||||||
// Return an error status, attempt to check in a folder
|
// Pack the status
|
||||||
|
|
||||||
respBuf.putInt(IOControl.StsBadParameter);
|
respBuf.putInt(deskResponse.getStatus());
|
||||||
|
respBuf.putString(deskResponse.hasStatusMessage() ? deskResponse.getStatusMessage() : "", true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
// Pack an error response
|
||||||
{
|
|
||||||
// Check out the file
|
respBuf.putInt(DesktopAction.StsError);
|
||||||
|
respBuf.putString("Action did not return response", true);
|
||||||
NodeRef workingCopyNode = checkInOutService.checkout( childNode);
|
|
||||||
|
|
||||||
// Get the working copy file name
|
|
||||||
|
|
||||||
String workingCopyName = (String) nodeService.getProperty( workingCopyNode, ContentModel.PROP_NAME);
|
|
||||||
|
|
||||||
// Check out was successful, pack the working copy name
|
|
||||||
|
|
||||||
respBuf.putInt( IOControl.StsSuccess);
|
|
||||||
respBuf.putString( workingCopyName, true, true);
|
|
||||||
|
|
||||||
// Check if there are any file/directory change notify requests active
|
|
||||||
|
|
||||||
DiskDeviceContext diskCtx = (DiskDeviceContext) tree.getContext();
|
|
||||||
if (diskCtx.hasChangeHandler()) {
|
|
||||||
|
|
||||||
// Build the relative path to the checked in file
|
|
||||||
|
|
||||||
String fileName = FileName.buildPath( netFile.getFullName(), null, workingCopyName, FileName.DOS_SEPERATOR);
|
|
||||||
|
|
||||||
// Queue a file added change notification
|
|
||||||
|
|
||||||
diskCtx.getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Return an error status and message
|
|
||||||
|
|
||||||
respBuf.setPosition( IOControl.Signature.length());
|
|
||||||
respBuf.putInt(IOControl.StsError);
|
|
||||||
respBuf.putString( ex.getMessage(), true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the response
|
// Return the response
|
||||||
|
|
||||||
return respBuf;
|
return respBuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.smb.server.repo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop Action Exception Class
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class DesktopActionException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1006648817889605047L;
|
||||||
|
|
||||||
|
// Status code
|
||||||
|
|
||||||
|
private int m_stsCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param sts int
|
||||||
|
* @param msg String
|
||||||
|
*/
|
||||||
|
public DesktopActionException(int sts, String msg)
|
||||||
|
{
|
||||||
|
super(msg);
|
||||||
|
m_stsCode = sts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param s String
|
||||||
|
*/
|
||||||
|
public DesktopActionException(String s)
|
||||||
|
{
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param s String
|
||||||
|
* @param ex Exception
|
||||||
|
*/
|
||||||
|
public DesktopActionException(String s, Throwable ex)
|
||||||
|
{
|
||||||
|
super(s, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getStatusCode()
|
||||||
|
{
|
||||||
|
return m_stsCode;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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.smb.server.repo;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop Action Table Class
|
||||||
|
*
|
||||||
|
* <p>Contains a list of desktop actions indexed by action name.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class DesktopActionTable {
|
||||||
|
|
||||||
|
// Table of actions, indexed by action name and pseudo file name
|
||||||
|
|
||||||
|
private Hashtable<String, DesktopAction> m_actions;
|
||||||
|
private Hashtable<String, DesktopAction> m_actionsPseudo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*/
|
||||||
|
public DesktopActionTable()
|
||||||
|
{
|
||||||
|
m_actions = new Hashtable<String, DesktopAction>();
|
||||||
|
m_actionsPseudo = new Hashtable<String, DesktopAction>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a named action
|
||||||
|
*
|
||||||
|
* @param name String
|
||||||
|
* @return DesktopAction
|
||||||
|
*/
|
||||||
|
public final DesktopAction getAction(String name)
|
||||||
|
{
|
||||||
|
return m_actions.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an action via the pseudo file name
|
||||||
|
*
|
||||||
|
* @param pseudoName String
|
||||||
|
* @return DesktopAction
|
||||||
|
*/
|
||||||
|
public final DesktopAction getActionViaPseudoName(String pseudoName)
|
||||||
|
{
|
||||||
|
return m_actionsPseudo.get(pseudoName.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the count of actions
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int numberOfActions()
|
||||||
|
{
|
||||||
|
return m_actions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an action
|
||||||
|
*
|
||||||
|
* @param action DesktopAction
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean addAction(DesktopAction action)
|
||||||
|
{
|
||||||
|
if ( m_actions.get( action.getName()) == null)
|
||||||
|
{
|
||||||
|
m_actions.put(action.getName(), action);
|
||||||
|
m_actionsPseudo.put(action.getPseudoFile().getFileName().toUpperCase(), action);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerate the action names
|
||||||
|
*
|
||||||
|
* @return Enumeration<String>
|
||||||
|
*/
|
||||||
|
public final Enumeration<String> enumerateActionNames()
|
||||||
|
{
|
||||||
|
return m_actions.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an action
|
||||||
|
*
|
||||||
|
* @param name String
|
||||||
|
* @return DesktopAction
|
||||||
|
*/
|
||||||
|
public final DesktopAction removeAction(String name)
|
||||||
|
{
|
||||||
|
DesktopAction action = m_actions.remove(name);
|
||||||
|
if ( action != null)
|
||||||
|
m_actionsPseudo.remove(action.getPseudoFile().getFileName().toUpperCase());
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.server.SrvSession;
|
||||||
|
import org.alfresco.filesys.server.filesys.NetworkFile;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop Parameters Class
|
||||||
|
*
|
||||||
|
* <p>Contains the parameters for a desktop action request from the client side application.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class DesktopParams {
|
||||||
|
|
||||||
|
// File server session
|
||||||
|
|
||||||
|
private SrvSession m_session;
|
||||||
|
|
||||||
|
// Folder node that the actions are working in
|
||||||
|
|
||||||
|
private NodeRef m_folderNode;
|
||||||
|
|
||||||
|
// Network file for the folder node
|
||||||
|
|
||||||
|
private NetworkFile m_folderFile;
|
||||||
|
|
||||||
|
// List of file/folder/node targets for the action
|
||||||
|
|
||||||
|
private List<DesktopTarget> m_targets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*/
|
||||||
|
public DesktopParams()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param sess SrvSession
|
||||||
|
* @param folderNode NodeRef
|
||||||
|
* @param folderFile NetworkFile
|
||||||
|
*/
|
||||||
|
public DesktopParams(SrvSession sess, NodeRef folderNode, NetworkFile folderFile)
|
||||||
|
{
|
||||||
|
m_session = sess;
|
||||||
|
m_folderNode = folderNode;
|
||||||
|
m_folderFile = folderFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the count of target nodes for the action
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int numberOfTargetNodes()
|
||||||
|
{
|
||||||
|
return m_targets != null ? m_targets.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the file server session
|
||||||
|
*
|
||||||
|
* @return SrvSession
|
||||||
|
*/
|
||||||
|
public final SrvSession getSession()
|
||||||
|
{
|
||||||
|
return m_session;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the working directory node
|
||||||
|
*
|
||||||
|
* @return NodeRef
|
||||||
|
*/
|
||||||
|
public final NodeRef getFolderNode()
|
||||||
|
{
|
||||||
|
return m_folderNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the folder network file
|
||||||
|
*
|
||||||
|
* @return NetworkFile
|
||||||
|
*/
|
||||||
|
public final NetworkFile getFolder()
|
||||||
|
{
|
||||||
|
return m_folderFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the folder network file
|
||||||
|
*
|
||||||
|
* @param netFile NetworkFile
|
||||||
|
*/
|
||||||
|
public final void setFolder(NetworkFile netFile)
|
||||||
|
{
|
||||||
|
m_folderFile = netFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the required target
|
||||||
|
*
|
||||||
|
* @param idx int
|
||||||
|
* @return DesktopTarget
|
||||||
|
*/
|
||||||
|
public final DesktopTarget getTarget(int idx)
|
||||||
|
{
|
||||||
|
DesktopTarget deskTarget = null;
|
||||||
|
|
||||||
|
if ( m_targets != null && idx >= 0 && idx < m_targets.size())
|
||||||
|
deskTarget = m_targets.get(idx);
|
||||||
|
|
||||||
|
return deskTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a target node for the action
|
||||||
|
*
|
||||||
|
* @param target DesktopTarget
|
||||||
|
*/
|
||||||
|
public final void addTarget(DesktopTarget target)
|
||||||
|
{
|
||||||
|
if ( m_targets == null)
|
||||||
|
m_targets = new ArrayList<DesktopTarget>();
|
||||||
|
m_targets.add(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the desktop parameters as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
str.append("[");
|
||||||
|
str.append("Targets=");
|
||||||
|
str.append(numberOfTargetNodes());
|
||||||
|
str.append("]");
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop Response Class
|
||||||
|
*
|
||||||
|
* <p>Holds the status code, optional status message and optional values returned by a desktop action.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class DesktopResponse {
|
||||||
|
|
||||||
|
// Desktop action status and optional status message
|
||||||
|
|
||||||
|
private int m_status;
|
||||||
|
private String m_statusMsg;
|
||||||
|
|
||||||
|
// Optional return values
|
||||||
|
|
||||||
|
private List<Object> m_responseValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param sts int
|
||||||
|
*/
|
||||||
|
public DesktopResponse(int sts)
|
||||||
|
{
|
||||||
|
m_status = sts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param sts int
|
||||||
|
* @param msg String
|
||||||
|
*/
|
||||||
|
public DesktopResponse(int sts, String msg)
|
||||||
|
{
|
||||||
|
m_status = sts;
|
||||||
|
m_statusMsg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status code
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getStatus()
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there is an optional status message
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasStatusMessage()
|
||||||
|
{
|
||||||
|
return m_statusMsg != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status message
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getStatusMessage()
|
||||||
|
{
|
||||||
|
return m_statusMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there are optional response values
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasResponseValues()
|
||||||
|
{
|
||||||
|
return m_responseValues != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the count of response values
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int numberOfResponseValues()
|
||||||
|
{
|
||||||
|
return m_responseValues != null ? m_responseValues.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response value list
|
||||||
|
*
|
||||||
|
* @return List<Object>
|
||||||
|
*/
|
||||||
|
public final List<Object> getResponseValues()
|
||||||
|
{
|
||||||
|
return m_responseValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a response value
|
||||||
|
*
|
||||||
|
* @param respObj Object
|
||||||
|
*/
|
||||||
|
public final void addResponseValue(Object respObj)
|
||||||
|
{
|
||||||
|
if ( m_responseValues == null)
|
||||||
|
m_responseValues = new ArrayList<Object>();
|
||||||
|
|
||||||
|
m_responseValues.add(respObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the status code and message
|
||||||
|
*
|
||||||
|
* @param sts int
|
||||||
|
* @param msg String
|
||||||
|
*/
|
||||||
|
public final void setStatus(int sts, String msg)
|
||||||
|
{
|
||||||
|
m_status = sts;
|
||||||
|
m_statusMsg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the desktop response as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
str.append("[");
|
||||||
|
str.append(getStatus());
|
||||||
|
str.append(":");
|
||||||
|
if ( hasStatusMessage())
|
||||||
|
str.append(getStatusMessage());
|
||||||
|
else
|
||||||
|
str.append("<NoMsg>");
|
||||||
|
str.append(":Values=");
|
||||||
|
str.append(numberOfResponseValues());
|
||||||
|
str.append("]");
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop Target Class
|
||||||
|
*
|
||||||
|
* <p>Contains the details of a target file/folder/node for a desktop action.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class DesktopTarget {
|
||||||
|
|
||||||
|
// Desktop target types
|
||||||
|
|
||||||
|
public static final int TargetFile = 0;
|
||||||
|
public static final int TargetFolder = 1;
|
||||||
|
public static final int TargetCopiedFile = 2;
|
||||||
|
public static final int TargetCopiedFolder = 3;
|
||||||
|
public static final int TargetNodeRef = 4;
|
||||||
|
|
||||||
|
// Target type
|
||||||
|
|
||||||
|
private int m_type;
|
||||||
|
|
||||||
|
// Target path/id
|
||||||
|
|
||||||
|
private String m_target;
|
||||||
|
|
||||||
|
// Associated noderef
|
||||||
|
|
||||||
|
private NodeRef m_noderef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class constructor
|
||||||
|
*
|
||||||
|
* @param typ int
|
||||||
|
* @param path String
|
||||||
|
*/
|
||||||
|
public DesktopTarget(int typ, String path)
|
||||||
|
{
|
||||||
|
m_type = typ;
|
||||||
|
m_target = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the target type
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int isType()
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the target path/id
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getTarget()
|
||||||
|
{
|
||||||
|
return m_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the associated node is valid
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasNodeRef()
|
||||||
|
{
|
||||||
|
return m_noderef != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the associated node
|
||||||
|
*
|
||||||
|
* @return NodeRef
|
||||||
|
*/
|
||||||
|
public final NodeRef getNode()
|
||||||
|
{
|
||||||
|
return m_noderef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the target type as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getTypeAsString()
|
||||||
|
{
|
||||||
|
String str = null;
|
||||||
|
|
||||||
|
switch( isType())
|
||||||
|
{
|
||||||
|
case TargetFile:
|
||||||
|
str = "File";
|
||||||
|
break;
|
||||||
|
case TargetFolder:
|
||||||
|
str = "Folder";
|
||||||
|
break;
|
||||||
|
case TargetCopiedFile:
|
||||||
|
str = "File Copy";
|
||||||
|
break;
|
||||||
|
case TargetCopiedFolder:
|
||||||
|
str = "Folder Copy";
|
||||||
|
break;
|
||||||
|
case TargetNodeRef:
|
||||||
|
str = "NodeRef";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the associated node
|
||||||
|
*
|
||||||
|
* @param node NodeRef
|
||||||
|
*/
|
||||||
|
public final void setNode(NodeRef node)
|
||||||
|
{
|
||||||
|
m_noderef = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the desktop target as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
str.append("[");
|
||||||
|
str.append(getTypeAsString());
|
||||||
|
str.append(":");
|
||||||
|
str.append(getTarget());
|
||||||
|
|
||||||
|
if ( hasNodeRef())
|
||||||
|
{
|
||||||
|
str.append(":");
|
||||||
|
str.append(getNode());
|
||||||
|
}
|
||||||
|
str.append("]");
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -21,7 +21,7 @@ import org.alfresco.filesys.smb.NTIOCtl;
|
|||||||
/**
|
/**
|
||||||
* Content Disk Driver I/O Control Codes Class
|
* Content Disk Driver I/O Control Codes Class
|
||||||
*
|
*
|
||||||
* <p>contains I/O control codes and status codes used by the content disk driver I/O control
|
* <p>Contains I/O control codes and status codes used by the content disk driver I/O control
|
||||||
* implementation.
|
* implementation.
|
||||||
*
|
*
|
||||||
* @author gkspencer
|
* @author gkspencer
|
||||||
@@ -30,24 +30,20 @@ public class IOControl
|
|||||||
{
|
{
|
||||||
// Custom I/O control codes
|
// Custom I/O control codes
|
||||||
|
|
||||||
public static final int CmdProbe = NTIOCtl.FsCtlCustom;
|
public static final int CmdProbe = NTIOCtl.FsCtlCustom;
|
||||||
public static final int CmdFileStatus = NTIOCtl.FsCtlCustom + 1;
|
public static final int CmdFileStatus = NTIOCtl.FsCtlCustom + 1;
|
||||||
public static final int CmdCheckOut = NTIOCtl.FsCtlCustom + 2;
|
// Version 1 CmdCheckOut = NTIOCtl.FsCtlCustom + 2
|
||||||
public static final int CmdCheckIn = NTIOCtl.FsCtlCustom + 3;
|
// Version 1 CmdCheckIn = NTIOCtl.FsCtlCustom + 3
|
||||||
|
public static final int CmdGetActionInfo = NTIOCtl.FsCtlCustom + 4;
|
||||||
|
public static final int CmdRunAction = NTIOCtl.FsCtlCustom + 5;
|
||||||
|
|
||||||
// I/O control request/response signature
|
// I/O control request/response signature
|
||||||
|
|
||||||
public static final String Signature = "ALFRESCO";
|
public static final String Signature = "ALFRESCO";
|
||||||
|
|
||||||
// I/O control status codes
|
// I/O control interface version id
|
||||||
|
|
||||||
public static final int StsSuccess = 0;
|
public static final int Version = 2;
|
||||||
|
|
||||||
public static final int StsError = 1;
|
|
||||||
public static final int StsFileNotFound = 2;
|
|
||||||
public static final int StsAccessDenied = 3;
|
|
||||||
public static final int StsBadParameter = 4;
|
|
||||||
public static final int StsNotWorkingCopy = 5;
|
|
||||||
|
|
||||||
// Boolean field values
|
// Boolean field values
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@
|
|||||||
package org.alfresco.filesys.smb.server.repo;
|
package org.alfresco.filesys.smb.server.repo;
|
||||||
|
|
||||||
import org.alfresco.filesys.server.filesys.IOCtlInterface;
|
import org.alfresco.filesys.server.filesys.IOCtlInterface;
|
||||||
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
|
||||||
@@ -34,11 +33,7 @@ public interface IOControlHandler extends IOCtlInterface
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param contentDriver ContentDiskDriver
|
* @param contentDriver ContentDiskDriver
|
||||||
* @param cifsHelper CifsHelper
|
* @param contentContext ContentContext
|
||||||
* @param transService TransactionService
|
|
||||||
* @param nodeService NodeService
|
|
||||||
* @param cociService CheckOutCheckInService
|
|
||||||
*/
|
*/
|
||||||
public void initialize( ContentDiskDriver contentDriver, CifsHelper cifsHelper,
|
public void initialize( ContentDiskDriver contentDriver, ContentContext contentContext);
|
||||||
TransactionService transService, NodeService nodeService, CheckOutCheckInService cociService);
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo.desk;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.server.filesys.FileName;
|
||||||
|
import org.alfresco.filesys.server.filesys.NotifyChange;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopParams;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopResponse;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopTarget;
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check In/Out Desktop Action Class
|
||||||
|
*
|
||||||
|
* <p>Provides check in/out functionality via CIFS using the desktop action interface.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class CheckInOutDesktopAction extends DesktopAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*/
|
||||||
|
public CheckInOutDesktopAction()
|
||||||
|
{
|
||||||
|
super( DesktopAction.AttrAnyFiles, DesktopAction.PreConfirmAction + DesktopAction.PreCopyToTarget + DesktopAction.PreLocalToWorkingCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfirmationString() {
|
||||||
|
return "Run check in/out action";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the desktop action
|
||||||
|
*
|
||||||
|
* @param params DesktopParams
|
||||||
|
* @return DesktopResponse
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DesktopResponse runAction(DesktopParams params) {
|
||||||
|
|
||||||
|
// check if there are any files/folders to process
|
||||||
|
|
||||||
|
if ( params.numberOfTargetNodes() == 0)
|
||||||
|
return new DesktopResponse(StsSuccess);
|
||||||
|
|
||||||
|
// Start a transaction
|
||||||
|
|
||||||
|
params.getSession().beginTransaction(getTransactionService(), false);
|
||||||
|
|
||||||
|
// Process the list of target nodes
|
||||||
|
|
||||||
|
DesktopResponse response = new DesktopResponse(StsSuccess);
|
||||||
|
|
||||||
|
for ( int idx = 0; idx < params.numberOfTargetNodes(); idx++)
|
||||||
|
{
|
||||||
|
// Get the current target node
|
||||||
|
|
||||||
|
DesktopTarget target = params.getTarget(idx);
|
||||||
|
|
||||||
|
// Check if the node is a working copy
|
||||||
|
|
||||||
|
if ( getNodeService().hasAspect( target.getNode(), ContentModel.ASPECT_WORKING_COPY))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check in the file
|
||||||
|
|
||||||
|
getCheckInOutService().checkin( target.getNode(), null, null, false);
|
||||||
|
|
||||||
|
// Check if there are any file/directory change notify requests active
|
||||||
|
|
||||||
|
if ( getContext().hasChangeHandler()) {
|
||||||
|
|
||||||
|
// Build the relative path to the checked in file
|
||||||
|
|
||||||
|
String fileName = null;
|
||||||
|
|
||||||
|
if ( target.getTarget().startsWith(FileName.DOS_SEPERATOR_STR))
|
||||||
|
{
|
||||||
|
// Path is already relative to filesystem root
|
||||||
|
|
||||||
|
fileName = target.getTarget();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Build a root relative path for the file
|
||||||
|
|
||||||
|
fileName = FileName.buildPath( params.getFolder().getFullName(), null, target.getTarget(), FileName.DOS_SEPERATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue a file deleted change notification
|
||||||
|
|
||||||
|
getContext().getChangeHandler().notifyFileChanged(NotifyChange.ActionRemoved, fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Return an error status and message
|
||||||
|
|
||||||
|
response.setStatus(StsError, "Checkin failed for " + target.getTarget() + ", " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check out the file
|
||||||
|
|
||||||
|
NodeRef workingCopyNode = getCheckInOutService().checkout( target.getNode());
|
||||||
|
|
||||||
|
// Get the working copy file name
|
||||||
|
|
||||||
|
String workingCopyName = (String) getNodeService().getProperty( workingCopyNode, ContentModel.PROP_NAME);
|
||||||
|
|
||||||
|
// Check out was successful, pack the working copy name
|
||||||
|
|
||||||
|
response.setStatus(StsSuccess, "Checked out working copy " + workingCopyName);
|
||||||
|
|
||||||
|
// Check if there are any file/directory change notify requests active
|
||||||
|
|
||||||
|
if ( getContext().hasChangeHandler()) {
|
||||||
|
|
||||||
|
// Build the relative path to the checked in file
|
||||||
|
|
||||||
|
String fileName = FileName.buildPath( params.getFolder().getFullName(), null, workingCopyName, FileName.DOS_SEPERATOR);
|
||||||
|
|
||||||
|
// Queue a file added change notification
|
||||||
|
|
||||||
|
getContext().getChangeHandler().notifyFileChanged(NotifyChange.ActionAdded, fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Return an error status and message
|
||||||
|
|
||||||
|
response.setStatus(StsError, "Failed to checkout " + target.getTarget() + ", " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a success status for now
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo.desk;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopParams;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command Line Desktop Action Class
|
||||||
|
*
|
||||||
|
* <p>Simple desktop action that returns a test command line.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class CmdLineDesktopAction extends DesktopAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*/
|
||||||
|
public CmdLineDesktopAction()
|
||||||
|
{
|
||||||
|
super( 0, DesktopAction.PreConfirmAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfirmationString() {
|
||||||
|
return "Run commandline action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DesktopResponse runAction(DesktopParams params) {
|
||||||
|
|
||||||
|
// Return a URL in the status message
|
||||||
|
|
||||||
|
return new DesktopResponse(StsCommandLine, "C:\\Windows\\notepad.exe");
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo.desk;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopParams;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echo Desktop Action Class
|
||||||
|
*
|
||||||
|
* <p>Simple desktop action that echoes back the received string.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class EchoDesktopAction extends DesktopAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*/
|
||||||
|
public EchoDesktopAction()
|
||||||
|
{
|
||||||
|
super( 0, DesktopAction.PreConfirmAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfirmationString() {
|
||||||
|
return "Run echo action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DesktopResponse runAction(DesktopParams params) {
|
||||||
|
|
||||||
|
// Return a text message
|
||||||
|
|
||||||
|
return new DesktopResponse(StsSuccess, "Test message from echo action at " + new Date());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-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.smb.server.repo.desk;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopParams;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL Desktop Action Class
|
||||||
|
*
|
||||||
|
* <p>Simple desktop action that returns a test URL.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class URLDesktopAction extends DesktopAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*/
|
||||||
|
public URLDesktopAction()
|
||||||
|
{
|
||||||
|
super( 0, DesktopAction.PreConfirmAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfirmationString() {
|
||||||
|
return "Run URL action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DesktopResponse runAction(DesktopParams params) {
|
||||||
|
|
||||||
|
// Return a URL in the status message
|
||||||
|
|
||||||
|
return new DesktopResponse(StsLaunchURL, "http://www.alfresco.com");
|
||||||
|
}
|
||||||
|
}
|
@@ -16,11 +16,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.filesys.smb.server.repo.pseudo;
|
package org.alfresco.filesys.smb.server.repo.pseudo;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import org.alfresco.filesys.server.SrvSession;
|
import org.alfresco.filesys.server.SrvSession;
|
||||||
import org.alfresco.filesys.server.filesys.FileName;
|
import org.alfresco.filesys.server.filesys.FileName;
|
||||||
import org.alfresco.filesys.server.filesys.TreeConnection;
|
import org.alfresco.filesys.server.filesys.TreeConnection;
|
||||||
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
import org.alfresco.filesys.smb.server.SMBSrvSession;
|
||||||
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopAction;
|
||||||
|
import org.alfresco.filesys.smb.server.repo.DesktopActionTable;
|
||||||
import org.alfresco.filesys.smb.server.repo.FileState;
|
import org.alfresco.filesys.smb.server.repo.FileState;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -126,27 +130,40 @@ public class ContentPseudoFileImpl implements PseudoFileInterface
|
|||||||
|
|
||||||
boolean isCIFS = sess instanceof SMBSrvSession;
|
boolean isCIFS = sess instanceof SMBSrvSession;
|
||||||
|
|
||||||
// Add the drag and drop pseudo file, if enabled
|
// Add the desktop action pseudo files
|
||||||
|
|
||||||
if ( isCIFS && ctx.hasDragAndDropApp())
|
if ( isCIFS && ctx.numberOfDesktopActions() > 0)
|
||||||
{
|
{
|
||||||
// If the file state is null create a file state for the path
|
// If the file state is null create a file state for the path
|
||||||
|
|
||||||
if ( fstate == null)
|
if ( fstate == null)
|
||||||
ctx.getStateTable().findFileState( path, true, true);
|
ctx.getStateTable().findFileState( path, true, true);
|
||||||
|
|
||||||
// Enable the drag and drop pseudo file
|
// Add the desktop action pseudo files
|
||||||
|
|
||||||
fstate.addPseudoFile( ctx.getDragAndDropApp());
|
DesktopActionTable actions = ctx.getDesktopActions();
|
||||||
|
Enumeration<String> actionNames = actions.enumerateActionNames();
|
||||||
|
|
||||||
|
while(actionNames.hasMoreElements())
|
||||||
|
{
|
||||||
|
// Get the current desktop action
|
||||||
|
|
||||||
|
String name = actionNames.nextElement();
|
||||||
|
DesktopAction action = actions.getAction(name);
|
||||||
|
|
||||||
|
// Add the pseudo file for the desktop action
|
||||||
|
|
||||||
|
if ( action.hasPseudoFile())
|
||||||
|
{
|
||||||
|
fstate.addPseudoFile( action.getPseudoFile());
|
||||||
|
pseudoCnt++;
|
||||||
|
|
||||||
// Update the count of pseudo files added
|
// DEBUG
|
||||||
|
|
||||||
pseudoCnt++;
|
if ( logger.isInfoEnabled())
|
||||||
|
logger.info("Added desktop action " + action.getName() + " for " + path);
|
||||||
// DEBUG
|
}
|
||||||
|
}
|
||||||
if ( logger.isInfoEnabled())
|
|
||||||
logger.info("Added drag/drop pseudo file for " + path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the URL link pseudo file, if enabled
|
// Add the URL link pseudo file, if enabled
|
||||||
|
Reference in New Issue
Block a user