mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-16 17:55:15 +00:00
Added support for link nodes in the repo filesystem driver.
Includes a patch to update existing link node file extensions from .lnk to .url, as CIFS requires .url files to generate the file:// links. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4947 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
parent
01fb4eac8a
commit
60ba6773c5
@ -123,3 +123,8 @@ patch.wcmFolders.webprojects.result.exists=The Web Projects folder already exist
|
|||||||
patch.wcmFolders.webprojects.result.created=The Web Projects folder was successfully created: {0}
|
patch.wcmFolders.webprojects.result.created=The Web Projects folder was successfully created: {0}
|
||||||
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
|
patch.wcmFolders.webforms.result.exists=The Web Forms folder already exists: {0}
|
||||||
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
|
patch.wcmFolders.webforms.result.created=The Web Forms folder was successfully created: {0}
|
||||||
|
|
||||||
|
patch.linkNodeExtension.description=Fixes link node file extensions to have a .url extension.
|
||||||
|
patch.linkNodeExtension.result=Fixed {0} link node file extensions. See file {1} for details.
|
||||||
|
patch.linkNodeExtension.err.unable_to_fix=Auto-fixing of link node file extensions failed. See file {0} for details.
|
||||||
|
patch.linkNodeExtension.rewritten=Name ''{0}'' rewritten to ''{1}''
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
<property name="permissionService"><ref bean="permissionService"/></property>
|
<property name="permissionService"><ref bean="permissionService"/></property>
|
||||||
<property name="authenticationComponent"><ref bean="authenticationComponent"/></property>
|
<property name="authenticationComponent"><ref bean="authenticationComponent"/></property>
|
||||||
<property name="authenticationService"><ref bean="authenticationService"/></property>
|
<property name="authenticationService"><ref bean="authenticationService"/></property>
|
||||||
|
<property name="fileFolderService"><ref bean="FileFolderService" /></property>
|
||||||
<property name="serviceRegistry"><ref bean="ServiceRegistry"/></property>
|
<property name="serviceRegistry"><ref bean="ServiceRegistry"/></property>
|
||||||
<property name="stateReaper"><ref bean="fileStateReaper"/></property>
|
<property name="stateReaper"><ref bean="fileStateReaper"/></property>
|
||||||
</bean>
|
</bean>
|
||||||
|
@ -586,4 +586,19 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="patch.LinkNodeFileExtension" class="org.alfresco.repo.admin.patch.impl.LinkNodeFileExtensionPatch" parent="basePatch" >
|
||||||
|
<property name="id"><value>patch.LinkNodeFileExtension</value></property>
|
||||||
|
<property name="description"><value>patch.invalidNameEnding.description</value></property>
|
||||||
|
<property name="fixesFromSchema"><value>0</value></property>
|
||||||
|
<property name="fixesToSchema"><value>33</value></property>
|
||||||
|
<property name="targetSchema"><value>34</value></property>
|
||||||
|
<!-- helper beans -->
|
||||||
|
<property name="sessionFactory">
|
||||||
|
<ref bean="sessionFactory" />
|
||||||
|
</property>
|
||||||
|
<property name="nodeDaoService">
|
||||||
|
<ref bean="nodeDaoService" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@ -19,4 +19,4 @@ version.build=@build-number@
|
|||||||
|
|
||||||
# Schema number
|
# Schema number
|
||||||
|
|
||||||
version.schema=33
|
version.schema=34
|
||||||
|
@ -334,6 +334,16 @@ public abstract class AlfrescoContext extends DiskDeviceContext
|
|||||||
*/
|
*/
|
||||||
protected abstract IOControlHandler createIOHandler( DiskInterface filesysDriver);
|
protected abstract IOControlHandler createIOHandler( DiskInterface filesysDriver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the I/O control handler
|
||||||
|
*
|
||||||
|
* @param ioctlHandler IOControlHandler
|
||||||
|
*/
|
||||||
|
protected void setIOHandler( IOControlHandler ioctlHandler)
|
||||||
|
{
|
||||||
|
m_ioHandler = ioctlHandler;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the filesystem context
|
* Close the filesystem context
|
||||||
*/
|
*/
|
||||||
|
@ -29,7 +29,6 @@ import java.util.StringTokenizer;
|
|||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.filesys.server.filesys.FileAttribute;
|
import org.alfresco.filesys.server.filesys.FileAttribute;
|
||||||
import org.alfresco.filesys.server.filesys.FileExistsException;
|
import org.alfresco.filesys.server.filesys.FileExistsException;
|
||||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
|
||||||
import org.alfresco.filesys.server.filesys.FileName;
|
import org.alfresco.filesys.server.filesys.FileName;
|
||||||
import org.alfresco.filesys.util.WildCard;
|
import org.alfresco.filesys.util.WildCard;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
@ -175,14 +174,12 @@ public class CifsHelper
|
|||||||
* @return Returns the existing node reference
|
* @return Returns the existing node reference
|
||||||
* @throws FileNotFoundException
|
* @throws FileNotFoundException
|
||||||
*/
|
*/
|
||||||
public FileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
|
public ContentFileInfo getFileInformation(NodeRef pathRootNodeRef, String path) throws FileNotFoundException
|
||||||
{
|
{
|
||||||
// get the node being referenced
|
// get the node being referenced
|
||||||
NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
|
NodeRef nodeRef = getNodeRef(pathRootNodeRef, path);
|
||||||
|
|
||||||
FileInfo fileInfo = getFileInformation(nodeRef);
|
return getFileInformation(nodeRef);
|
||||||
|
|
||||||
return fileInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,13 +193,14 @@ public class CifsHelper
|
|||||||
* @return Returns the file information pertinent to the node
|
* @return Returns the file information pertinent to the node
|
||||||
* @throws FileNotFoundException if the path refers to a non-existent file
|
* @throws FileNotFoundException if the path refers to a non-existent file
|
||||||
*/
|
*/
|
||||||
public FileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
|
public ContentFileInfo getFileInformation(NodeRef nodeRef) throws FileNotFoundException
|
||||||
{
|
{
|
||||||
// get the file info
|
// get the file info
|
||||||
org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
|
org.alfresco.service.cmr.model.FileInfo fileFolderInfo = fileFolderService.getFileInfo(nodeRef);
|
||||||
|
|
||||||
// retrieve required properties and create file info
|
// retrieve required properties and create file info
|
||||||
FileInfo fileInfo = new FileInfo();
|
ContentFileInfo fileInfo = new ContentFileInfo();
|
||||||
|
fileInfo.setNodeRef(nodeRef);
|
||||||
|
|
||||||
// unset all attribute flags
|
// unset all attribute flags
|
||||||
int fileAttributes = 0;
|
int fileAttributes = 0;
|
||||||
@ -251,6 +249,11 @@ public class CifsHelper
|
|||||||
|
|
||||||
fileInfo.setFileAttributes( attr);
|
fileInfo.setFileAttributes( attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it is a link node
|
||||||
|
|
||||||
|
if ( fileFolderInfo.isLink())
|
||||||
|
fileInfo.setLinkNodeRef( fileFolderInfo.getLinkNodeRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
// created
|
// created
|
||||||
|
@ -55,6 +55,10 @@ public class ContentContext extends AlfrescoContext
|
|||||||
m_rootPath = rootPath;
|
m_rootPath = rootPath;
|
||||||
|
|
||||||
m_rootNodeRef = rootNodeRef;
|
m_rootNodeRef = rootNodeRef;
|
||||||
|
|
||||||
|
// Create the I/O control handler
|
||||||
|
|
||||||
|
setIOHandler( createIOHandler( null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,6 @@ import javax.transaction.UserTransaction;
|
|||||||
import org.alfresco.config.ConfigElement;
|
import org.alfresco.config.ConfigElement;
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
|
import org.alfresco.filesys.alfresco.AlfrescoDiskDriver;
|
||||||
import org.alfresco.filesys.avm.AVMNetworkFile;
|
|
||||||
import org.alfresco.filesys.server.SrvSession;
|
import org.alfresco.filesys.server.SrvSession;
|
||||||
import org.alfresco.filesys.server.core.DeviceContext;
|
import org.alfresco.filesys.server.core.DeviceContext;
|
||||||
import org.alfresco.filesys.server.core.DeviceContextException;
|
import org.alfresco.filesys.server.core.DeviceContextException;
|
||||||
@ -56,6 +55,7 @@ import org.alfresco.filesys.util.WildCard;
|
|||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.service.cmr.lock.NodeLockedException;
|
import org.alfresco.service.cmr.lock.NodeLockedException;
|
||||||
|
import org.alfresco.service.cmr.model.FileFolderService;
|
||||||
import org.alfresco.service.cmr.repository.ContentService;
|
import org.alfresco.service.cmr.repository.ContentService;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
@ -101,6 +101,7 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
private SearchService searchService;
|
private SearchService searchService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private PermissionService permissionService;
|
private PermissionService permissionService;
|
||||||
|
private FileFolderService fileFolderService;
|
||||||
|
|
||||||
private AuthenticationComponent authComponent;
|
private AuthenticationComponent authComponent;
|
||||||
private AuthenticationService authService;
|
private AuthenticationService authService;
|
||||||
@ -254,6 +255,16 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file folder server
|
||||||
|
*
|
||||||
|
* @param fileService FileFolderService
|
||||||
|
*/
|
||||||
|
public void setFileFolderService(FileFolderService fileService)
|
||||||
|
{
|
||||||
|
fileFolderService = fileService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse and validate the parameter string and create a device context object for this instance
|
* Parse and validate the parameter string and create a device context object for this instance
|
||||||
* of the shared device. The same DeviceInterface implementation may be used for multiple
|
* of the shared device. The same DeviceInterface implementation may be used for multiple
|
||||||
@ -466,6 +477,11 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
|
|
||||||
context.enableStateTable( true, getStateReaper());
|
context.enableStateTable( true, getStateReaper());
|
||||||
|
|
||||||
|
// Initialize the I/O control handler
|
||||||
|
|
||||||
|
if ( context.hasIOHandler())
|
||||||
|
context.getIOHandler().initialize( this, context);
|
||||||
|
|
||||||
// Return the context for this shared filesystem
|
// Return the context for this shared filesystem
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
@ -1200,9 +1216,53 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the node is a link node
|
||||||
|
|
||||||
|
NodeRef linkRef = (NodeRef) nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION);
|
||||||
|
NetworkFile netFile = null;
|
||||||
|
|
||||||
|
if ( linkRef == null)
|
||||||
|
{
|
||||||
// Create the network file
|
// Create the network file
|
||||||
|
|
||||||
NetworkFile netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
|
netFile = ContentNetworkFile.createFile(transactionService, nodeService, contentService, cifsHelper, nodeRef, params);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert the target node to a path, convert to URL format
|
||||||
|
|
||||||
|
String path = getPathForNode( tree, linkRef);
|
||||||
|
path = path.replace( FileName.DOS_SEPERATOR, '/');
|
||||||
|
|
||||||
|
// Build the URL file data
|
||||||
|
|
||||||
|
StringBuilder urlStr = new StringBuilder();
|
||||||
|
|
||||||
|
urlStr.append("[InternetShortcut]\r\n");
|
||||||
|
urlStr.append("URL=file://");
|
||||||
|
urlStr.append( sess.getServer().getServerName());
|
||||||
|
urlStr.append("/");
|
||||||
|
urlStr.append( tree.getSharedDevice().getName());
|
||||||
|
urlStr.append( path);
|
||||||
|
urlStr.append("\r\n");
|
||||||
|
|
||||||
|
// Create the in memory pseudo file for the URL link
|
||||||
|
|
||||||
|
byte[] urlData = urlStr.toString().getBytes();
|
||||||
|
|
||||||
|
// Get the file information for the link node
|
||||||
|
|
||||||
|
FileInfo fInfo = cifsHelper.getFileInformation( nodeRef);
|
||||||
|
|
||||||
|
// Set the file size to the actual data length
|
||||||
|
|
||||||
|
fInfo.setFileSize( urlData.length);
|
||||||
|
|
||||||
|
// Create the network file using the in-memory file data
|
||||||
|
|
||||||
|
netFile = new LinkMemoryNetworkFile( fInfo.getFileName(), urlData, fInfo, nodeRef);
|
||||||
|
netFile.setFullName( params.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
// Generate a file id for the file
|
// Generate a file id for the file
|
||||||
|
|
||||||
@ -1619,12 +1679,12 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
|
|
||||||
if (file.hasDeleteOnClose())
|
if (file.hasDeleteOnClose())
|
||||||
{
|
{
|
||||||
// Check if the file is a content file
|
// Check if the file is a noderef based file
|
||||||
|
|
||||||
if ( file instanceof ContentNetworkFile)
|
if ( file instanceof NodeRefNetworkFile)
|
||||||
{
|
{
|
||||||
ContentNetworkFile contentNetFile = (ContentNetworkFile) file;
|
NodeRefNetworkFile nodeNetFile = (NodeRefNetworkFile) file;
|
||||||
NodeRef nodeRef = contentNetFile.getNodeRef();
|
NodeRef nodeRef = nodeNetFile.getNodeRef();
|
||||||
|
|
||||||
// We don't know how long the network file has had the reference, so check for existence
|
// We don't know how long the network file has had the reference, so check for existence
|
||||||
|
|
||||||
@ -1776,14 +1836,22 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
ContentContext ctx = (ContentContext) tree.getContext();
|
ContentContext ctx = (ContentContext) tree.getContext();
|
||||||
|
|
||||||
// Get the file/folder to move
|
// Get the file/folder to move
|
||||||
|
|
||||||
NodeRef nodeToMoveRef = getNodeForPath(tree, oldName);
|
NodeRef nodeToMoveRef = getNodeForPath(tree, oldName);
|
||||||
|
|
||||||
|
// Check if the node is a link node
|
||||||
|
|
||||||
|
if ( nodeToMoveRef != null && nodeService.getProperty(nodeToMoveRef, ContentModel.PROP_LINK_DESTINATION) != null)
|
||||||
|
throw new AccessDeniedException("Cannot rename link nodes");
|
||||||
|
|
||||||
// Get the new target folder - it must be a folder
|
// Get the new target folder - it must be a folder
|
||||||
|
|
||||||
String[] splitPaths = FileName.splitPath(newName);
|
String[] splitPaths = FileName.splitPath(newName);
|
||||||
NodeRef targetFolderRef = getNodeForPath(tree, splitPaths[0]);
|
NodeRef targetFolderRef = getNodeForPath(tree, splitPaths[0]);
|
||||||
String name = splitPaths[1]; // the new file or folder name
|
String name = splitPaths[1];
|
||||||
|
|
||||||
// Update the state table
|
// Update the state table
|
||||||
|
|
||||||
boolean relinked = false;
|
boolean relinked = false;
|
||||||
if ( ctx.hasStateTable())
|
if ( ctx.hasStateTable())
|
||||||
{
|
{
|
||||||
@ -2195,6 +2263,44 @@ public class ContentDiskDriver extends AlfrescoDiskDriver implements DiskInterfa
|
|||||||
return cifsHelper.getNodeRef(ctx.getRootNode(), path);
|
return cifsHelper.getNodeRef(ctx.getRootNode(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a node into a share relative path
|
||||||
|
*
|
||||||
|
* @param tree TreeConnection
|
||||||
|
* @param nodeRef NodeRef
|
||||||
|
* @return String
|
||||||
|
* @exception FileNotFoundException
|
||||||
|
*/
|
||||||
|
public String getPathForNode( TreeConnection tree, NodeRef nodeRef)
|
||||||
|
throws FileNotFoundException
|
||||||
|
{
|
||||||
|
// Convert the target node to a path
|
||||||
|
|
||||||
|
ContentContext ctx = (ContentContext) tree.getContext();
|
||||||
|
List<org.alfresco.service.cmr.model.FileInfo> linkPaths = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
linkPaths = fileFolderService.getNamePath( ctx.getRootNode(), nodeRef);
|
||||||
|
}
|
||||||
|
catch ( org.alfresco.service.cmr.model.FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the share relative path to the node
|
||||||
|
|
||||||
|
StringBuilder pathStr = new StringBuilder();
|
||||||
|
|
||||||
|
for ( org.alfresco.service.cmr.model.FileInfo fInfo : linkPaths) {
|
||||||
|
pathStr.append( FileName.DOS_SEPERATOR);
|
||||||
|
pathStr.append( fInfo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the share relative path
|
||||||
|
|
||||||
|
return pathStr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file state for the specified path
|
* Get the file state for the specified path
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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.filesys.server.filesys.FileInfo;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content Disk Driver File Info Class
|
||||||
|
*
|
||||||
|
* <p>Adds fields for the file/folder NodeRef, and linked NodeRef for a link node.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class ContentFileInfo extends FileInfo {
|
||||||
|
|
||||||
|
// Version id
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2518699645372408663L;
|
||||||
|
|
||||||
|
// File/folder node
|
||||||
|
|
||||||
|
private NodeRef m_nodeRef;
|
||||||
|
|
||||||
|
// Linked node
|
||||||
|
|
||||||
|
private NodeRef m_linkRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the file/folder node
|
||||||
|
*
|
||||||
|
* @return NodeRef
|
||||||
|
*/
|
||||||
|
public final NodeRef getNodeRef()
|
||||||
|
{
|
||||||
|
return m_nodeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this is a link node
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean isLinkNode()
|
||||||
|
{
|
||||||
|
return m_linkRef != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the link node, or null if this is not a link
|
||||||
|
*
|
||||||
|
* @return NodeRef
|
||||||
|
*/
|
||||||
|
public final NodeRef getLinkNodeRef()
|
||||||
|
{
|
||||||
|
return m_linkRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the node for this file/folder
|
||||||
|
*
|
||||||
|
* @param node NodeRef
|
||||||
|
*/
|
||||||
|
public final void setNodeRef(NodeRef node)
|
||||||
|
{
|
||||||
|
m_nodeRef = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the link node
|
||||||
|
*
|
||||||
|
* @param link NodeRef
|
||||||
|
*/
|
||||||
|
public final void setLinkNodeRef(NodeRef link)
|
||||||
|
{
|
||||||
|
m_linkRef = link;
|
||||||
|
}
|
||||||
|
}
|
@ -175,6 +175,20 @@ public class ContentIOControlHandler implements IOControlHandler
|
|||||||
int devType = NTIOCtl.getDeviceType(ctrlCode);
|
int devType = NTIOCtl.getDeviceType(ctrlCode);
|
||||||
int ioFunc = NTIOCtl.getFunctionCode(ctrlCode);
|
int ioFunc = NTIOCtl.getFunctionCode(ctrlCode);
|
||||||
|
|
||||||
|
// Check for I/O controls that require a success status
|
||||||
|
|
||||||
|
if ( devType == NTIOCtl.DeviceFileSystem)
|
||||||
|
{
|
||||||
|
// I/O control requests that require a success status
|
||||||
|
//
|
||||||
|
// Create or get object id
|
||||||
|
|
||||||
|
if ( ioFunc == NTIOCtl.FsCtlCreateOrGetObjectId)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the I/O control looks like a custom I/O control request
|
||||||
|
|
||||||
if ( devType != NTIOCtl.DeviceFileSystem || dataBuf == null)
|
if ( devType != NTIOCtl.DeviceFileSystem || dataBuf == null)
|
||||||
throw new IOControlNotImplementedException();
|
throw new IOControlNotImplementedException();
|
||||||
|
|
||||||
|
@ -50,14 +50,13 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
*
|
*
|
||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
*/
|
*/
|
||||||
public class ContentNetworkFile extends NetworkFile
|
public class ContentNetworkFile extends NodeRefNetworkFile
|
||||||
{
|
{
|
||||||
private static final Log logger = LogFactory.getLog(ContentNetworkFile.class);
|
private static final Log logger = LogFactory.getLog(ContentNetworkFile.class);
|
||||||
|
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
private NodeService nodeService;
|
private NodeService nodeService;
|
||||||
private ContentService contentService;
|
private ContentService contentService;
|
||||||
private NodeRef nodeRef;
|
|
||||||
|
|
||||||
// File channel to file content
|
// File channel to file content
|
||||||
|
|
||||||
@ -175,12 +174,11 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
NodeRef nodeRef,
|
NodeRef nodeRef,
|
||||||
String name)
|
String name)
|
||||||
{
|
{
|
||||||
super(name);
|
super(name, nodeRef);
|
||||||
setFullName(name);
|
setFullName(name);
|
||||||
this.transactionService = transactionService;
|
this.transactionService = transactionService;
|
||||||
this.nodeService = nodeService;
|
this.nodeService = nodeService;
|
||||||
this.contentService = contentService;
|
this.contentService = contentService;
|
||||||
this.nodeRef = nodeRef;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,7 +191,7 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
str.append( "[");
|
str.append( "[");
|
||||||
str.append( nodeRef.getId());
|
str.append( getNodeRef().getId());
|
||||||
str.append( ",channel=");
|
str.append( ",channel=");
|
||||||
str.append( channel);
|
str.append( channel);
|
||||||
if ( channel != null)
|
if ( channel != null)
|
||||||
@ -205,14 +203,6 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
return str.toString();
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Returns the node reference representing this file
|
|
||||||
*/
|
|
||||||
public NodeRef getNodeRef()
|
|
||||||
{
|
|
||||||
return nodeRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns true if the channel should be writable
|
* @return Returns true if the channel should be writable
|
||||||
*
|
*
|
||||||
@ -304,7 +294,7 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
{
|
{
|
||||||
// Get a writeable channel to the content
|
// Get a writeable channel to the content
|
||||||
|
|
||||||
content = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, false);
|
content = contentService.getWriter( getNodeRef(), ContentModel.PROP_CONTENT, false);
|
||||||
|
|
||||||
// Indicate that we have a writable channel to the file
|
// Indicate that we have a writable channel to the file
|
||||||
|
|
||||||
@ -318,14 +308,14 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
{
|
{
|
||||||
// Get a read-only channel to the content
|
// Get a read-only channel to the content
|
||||||
|
|
||||||
content = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
content = contentService.getReader( getNodeRef(), ContentModel.PROP_CONTENT);
|
||||||
|
|
||||||
// Ensure that the content we are going to read is valid
|
// Ensure that the content we are going to read is valid
|
||||||
|
|
||||||
content = FileContentReader.getSafeContentReader(
|
content = FileContentReader.getSafeContentReader(
|
||||||
(ContentReader) content,
|
(ContentReader) content,
|
||||||
I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT),
|
I18NUtil.getMessage(FileContentReader.MSG_MISSING_CONTENT),
|
||||||
nodeRef, content);
|
getNodeRef(), content);
|
||||||
|
|
||||||
// Indicate that we only have a read-only channel to the data
|
// Indicate that we only have a read-only channel to the data
|
||||||
|
|
||||||
@ -372,7 +362,7 @@ public class ContentNetworkFile extends NetworkFile
|
|||||||
// Update node properties
|
// Update node properties
|
||||||
|
|
||||||
ContentData contentData = content.getContentData();
|
ContentData contentData = content.getContentData();
|
||||||
nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, contentData);
|
nodeService.setProperty( getNodeRef(), ContentModel.PROP_CONTENT, contentData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ package org.alfresco.filesys.smb.server.repo;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.server.filesys.FileAttribute;
|
||||||
import org.alfresco.filesys.server.filesys.FileInfo;
|
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||||
import org.alfresco.filesys.server.filesys.FileName;
|
import org.alfresco.filesys.server.filesys.FileName;
|
||||||
import org.alfresco.filesys.server.filesys.SearchContext;
|
import org.alfresco.filesys.server.filesys.SearchContext;
|
||||||
@ -37,8 +38,18 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
*/
|
*/
|
||||||
public class ContentSearchContext extends SearchContext
|
public class ContentSearchContext extends SearchContext
|
||||||
{
|
{
|
||||||
|
// Debug logging
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ContentSearchContext.class);
|
private static final Log logger = LogFactory.getLog(ContentSearchContext.class);
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
//
|
||||||
|
// Link file size, actual size will be set if/when the link is opened
|
||||||
|
|
||||||
|
public final static int LinkFileSize = 512;
|
||||||
|
|
||||||
|
// List of nodes returned from the folder search
|
||||||
|
|
||||||
private CifsHelper cifsHelper;
|
private CifsHelper cifsHelper;
|
||||||
private List<NodeRef> results;
|
private List<NodeRef> results;
|
||||||
private int index = -1;
|
private int index = -1;
|
||||||
@ -193,7 +204,7 @@ public class ContentSearchContext extends SearchContext
|
|||||||
{
|
{
|
||||||
// Get the file information and copy across to the callers file info
|
// Get the file information and copy across to the callers file info
|
||||||
|
|
||||||
FileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "");
|
ContentFileInfo nextInfo = cifsHelper.getFileInformation(nextNodeRef, "");
|
||||||
info.copyFrom(nextInfo);
|
info.copyFrom(nextInfo);
|
||||||
|
|
||||||
// Generate a file id for the current file
|
// Generate a file id for the current file
|
||||||
@ -203,6 +214,20 @@ public class ContentSearchContext extends SearchContext
|
|||||||
|
|
||||||
info.setFileId( pathStr.toString().hashCode());
|
info.setFileId( pathStr.toString().hashCode());
|
||||||
|
|
||||||
|
// Check if this is a link node
|
||||||
|
|
||||||
|
if ( nextInfo.isLinkNode())
|
||||||
|
{
|
||||||
|
// Set a dummy file size for the link data that will be generated if/when the file is opened
|
||||||
|
|
||||||
|
info.setFileSize( LinkFileSize);
|
||||||
|
|
||||||
|
// Make the link read-only
|
||||||
|
|
||||||
|
if ( info.isReadOnly() == false)
|
||||||
|
info.setFileAttributes( info.getFileAttributes() + FileAttribute.ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
// Indicate that the file information is valid
|
// Indicate that the file information is valid
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.IOException;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.server.filesys.FileInfo;
|
||||||
|
import org.alfresco.filesys.smb.SeekType;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link Node In Memory Network File Class
|
||||||
|
*
|
||||||
|
* <p>In memory network file implementation that uses a memory buffer for the file data.
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class LinkMemoryNetworkFile extends NodeRefNetworkFile
|
||||||
|
{
|
||||||
|
// Current file position
|
||||||
|
|
||||||
|
private long m_filePos;
|
||||||
|
|
||||||
|
// File data
|
||||||
|
|
||||||
|
private byte[] m_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param name String
|
||||||
|
* @param localPath String
|
||||||
|
* @param finfo FileInfo
|
||||||
|
* @param nodeRef NodeRef
|
||||||
|
*/
|
||||||
|
public LinkMemoryNetworkFile(String name, byte[] data, FileInfo finfo, NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
super( name, nodeRef);
|
||||||
|
|
||||||
|
// Set the file data
|
||||||
|
|
||||||
|
m_data = data;
|
||||||
|
if ( m_data == null)
|
||||||
|
m_data = new byte[0];
|
||||||
|
|
||||||
|
// Set the file size
|
||||||
|
|
||||||
|
setFileSize( m_data.length);
|
||||||
|
|
||||||
|
// Set the creation and modification date/times
|
||||||
|
|
||||||
|
setModifyDate( finfo.getModifyDateTime());
|
||||||
|
setCreationDate( finfo.getCreationDateTime());
|
||||||
|
|
||||||
|
// Set the file id and relative path
|
||||||
|
|
||||||
|
if ( finfo.getPath() != null)
|
||||||
|
{
|
||||||
|
setFileId( finfo.getPath().hashCode());
|
||||||
|
setFullName( finfo.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the network file.
|
||||||
|
*/
|
||||||
|
public void closeFile() throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current file position.
|
||||||
|
*
|
||||||
|
* @return long
|
||||||
|
*/
|
||||||
|
public long currentPosition()
|
||||||
|
{
|
||||||
|
return m_filePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush the file.
|
||||||
|
*
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public void flushFile() throws IOException
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the end of file has been reached.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isEndOfFile() throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Check if we reached end of file
|
||||||
|
|
||||||
|
if ( m_filePos == m_data.length)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the file.
|
||||||
|
*
|
||||||
|
* @param createFlag boolean
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public void openFile(boolean createFlag) throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Indicate that the file is open
|
||||||
|
|
||||||
|
setClosed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from the file.
|
||||||
|
*
|
||||||
|
* @param buf byte[]
|
||||||
|
* @param len int
|
||||||
|
* @param pos int
|
||||||
|
* @param fileOff long
|
||||||
|
* @return Length of data read.
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public int readFile(byte[] buf, int len, int pos, long fileOff) throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Check if the read is within the file data range
|
||||||
|
|
||||||
|
long fileLen = (long) m_data.length;
|
||||||
|
|
||||||
|
if ( fileOff >= fileLen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Calculate the actual read length
|
||||||
|
|
||||||
|
if (( fileOff + len) > fileLen)
|
||||||
|
len = (int) ( fileLen - fileOff);
|
||||||
|
|
||||||
|
// Copy the data to the user buffer
|
||||||
|
|
||||||
|
System.arraycopy( m_data, (int) fileOff, buf, pos, len);
|
||||||
|
|
||||||
|
// Update the current file position
|
||||||
|
|
||||||
|
m_filePos = fileOff + len;
|
||||||
|
|
||||||
|
// Return the actual length of data read
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seek to the specified file position.
|
||||||
|
*
|
||||||
|
* @param pos long
|
||||||
|
* @param typ int
|
||||||
|
* @return long
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public long seekFile(long pos, int typ) throws IOException
|
||||||
|
{
|
||||||
|
// Seek to the required file position
|
||||||
|
|
||||||
|
switch (typ)
|
||||||
|
{
|
||||||
|
// From start of file
|
||||||
|
|
||||||
|
case SeekType.StartOfFile:
|
||||||
|
if (currentPosition() != pos)
|
||||||
|
m_filePos = pos;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// From current position
|
||||||
|
|
||||||
|
case SeekType.CurrentPos:
|
||||||
|
m_filePos += pos;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// From end of file
|
||||||
|
|
||||||
|
case SeekType.EndOfFile:
|
||||||
|
m_filePos += pos;
|
||||||
|
if ( m_filePos < 0)
|
||||||
|
m_filePos = 0L;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the new file position
|
||||||
|
|
||||||
|
return currentPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncate the file
|
||||||
|
*
|
||||||
|
* @param siz long
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public void truncateFile(long siz) throws IOException
|
||||||
|
{
|
||||||
|
// Allow the truncate, do not alter the pseduo file data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a block of data to the file.
|
||||||
|
*
|
||||||
|
* @param buf byte[]
|
||||||
|
* @param len int
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public void writeFile(byte[] buf, int len, int pos) throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Allow the write, just do not do anything
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a block of data to the file.
|
||||||
|
*
|
||||||
|
* @param buf byte[]
|
||||||
|
* @param len int
|
||||||
|
* @param pos int
|
||||||
|
* @param offset long
|
||||||
|
* @exception IOException
|
||||||
|
*/
|
||||||
|
public void writeFile(byte[] buf, int len, int pos, long offset) throws java.io.IOException
|
||||||
|
{
|
||||||
|
// Allow the write, just do not do anything
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.filesys.server.filesys.NetworkFile;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NodeRef Based Network File Class
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public abstract class NodeRefNetworkFile extends NetworkFile {
|
||||||
|
|
||||||
|
// Associated node ref
|
||||||
|
|
||||||
|
protected NodeRef m_nodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a network file object with the specified file/directory name.
|
||||||
|
*
|
||||||
|
* @param name File name string.
|
||||||
|
*/
|
||||||
|
public NodeRefNetworkFile(String name)
|
||||||
|
{
|
||||||
|
super( name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a network file object with the specified file/directory name.
|
||||||
|
*
|
||||||
|
* @param name File name string.
|
||||||
|
* @param node NodeRef
|
||||||
|
*/
|
||||||
|
public NodeRefNetworkFile(String name, NodeRef node)
|
||||||
|
{
|
||||||
|
super( name);
|
||||||
|
|
||||||
|
m_nodeRef = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node ref
|
||||||
|
*
|
||||||
|
* @return NodeRef
|
||||||
|
*/
|
||||||
|
public NodeRef getNodeRef()
|
||||||
|
{
|
||||||
|
return m_nodeRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the node ref
|
||||||
|
*
|
||||||
|
* @param nodeRef NodeRef
|
||||||
|
*/
|
||||||
|
public void setNodeRef( NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
m_nodeRef = nodeRef;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 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.repo.admin.patch.impl;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.i18n.I18NUtil;
|
||||||
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.admin.patch.AbstractPatch;
|
||||||
|
import org.alfresco.repo.domain.hibernate.NodeImpl;
|
||||||
|
import org.alfresco.repo.node.db.NodeDaoService;
|
||||||
|
import org.alfresco.service.cmr.admin.PatchException;
|
||||||
|
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||||
|
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that all names do not end with ' ' or '.'
|
||||||
|
*
|
||||||
|
* @author David Caruana
|
||||||
|
*/
|
||||||
|
public class LinkNodeFileExtensionPatch extends AbstractPatch
|
||||||
|
{
|
||||||
|
private static final String MSG_SUCCESS = "patch.linkNodeExtension.result";
|
||||||
|
private static final String MSG_REWRITTEN = "patch.linkNodeExtension.rewritten";
|
||||||
|
private static final String ERR_UNABLE_TO_FIX = "patch.linkNodeExtension.err.unable_to_fix";
|
||||||
|
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
private NodeDaoService nodeDaoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public LinkNodeFileExtensionPatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the session factory
|
||||||
|
*
|
||||||
|
* @param sessionFactory SessionFactory
|
||||||
|
*/
|
||||||
|
public void setSessionFactory(SessionFactory sessionFactory)
|
||||||
|
{
|
||||||
|
this.sessionFactory = sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param nodeDaoService The service that generates the CRC values
|
||||||
|
*/
|
||||||
|
public void setNodeDaoService(NodeDaoService nodeDaoService)
|
||||||
|
{
|
||||||
|
this.nodeDaoService = nodeDaoService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkProperties()
|
||||||
|
{
|
||||||
|
super.checkProperties();
|
||||||
|
checkPropertyNotNull(sessionFactory, "sessionFactory");
|
||||||
|
checkPropertyNotNull(nodeDaoService, "nodeDaoService");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String applyInternal() throws Exception
|
||||||
|
{
|
||||||
|
// Initialise the helper
|
||||||
|
|
||||||
|
HibernateHelper helper = new HibernateHelper();
|
||||||
|
helper.setSessionFactory(sessionFactory);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Fix the link node file names
|
||||||
|
|
||||||
|
return helper.fixNames();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
helper.closeWriter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HibernateHelper extends HibernateDaoSupport
|
||||||
|
{
|
||||||
|
private File logFile;
|
||||||
|
private FileChannel channel;
|
||||||
|
|
||||||
|
private HibernateHelper() throws IOException
|
||||||
|
{
|
||||||
|
// Open a log file
|
||||||
|
|
||||||
|
logFile = new File("./LinkNodeExtensionPatch.log");
|
||||||
|
RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw");
|
||||||
|
channel = outputFile.getChannel();
|
||||||
|
|
||||||
|
// Append to the end of the file
|
||||||
|
|
||||||
|
channel.position(channel.size());
|
||||||
|
|
||||||
|
writeLine("").writeLine("");
|
||||||
|
writeLine("LinkNodeExtensionPatch executing on " + new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
private HibernateHelper write(Object obj) throws IOException
|
||||||
|
{
|
||||||
|
channel.write(ByteBuffer.wrap(obj.toString().getBytes()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
private HibernateHelper writeLine(Object obj) throws IOException
|
||||||
|
{
|
||||||
|
write(obj);
|
||||||
|
write("\n");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
private void closeWriter()
|
||||||
|
{
|
||||||
|
try { channel.close(); } catch (Throwable e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fixNames() throws Exception
|
||||||
|
{
|
||||||
|
// Get the list of nodes to be updated
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
List<NodeImpl> nodes = getInvalidNames();
|
||||||
|
|
||||||
|
int updated = 0;
|
||||||
|
for (NodeImpl node : nodes)
|
||||||
|
{
|
||||||
|
// Check that the node is a link node
|
||||||
|
|
||||||
|
NodeRef nodeRef = node.getNodeRef();
|
||||||
|
|
||||||
|
if ( nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION) != null)
|
||||||
|
{
|
||||||
|
// Get the current file name
|
||||||
|
|
||||||
|
String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
|
||||||
|
if (name != null && name.length() >= 4 && name.endsWith(".lnk"))
|
||||||
|
{
|
||||||
|
// Update the name string, replace '.lnk' with '.url'
|
||||||
|
|
||||||
|
String updatedName = name.substring(0, name.length() - 4) + ".url";
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
boolean applied = false;
|
||||||
|
while (!applied)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, updatedName);
|
||||||
|
applied = true;
|
||||||
|
}
|
||||||
|
catch(DuplicateChildNodeNameException e)
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
if (idx > 10)
|
||||||
|
{
|
||||||
|
writeLine(I18NUtil.getMessage(ERR_UNABLE_TO_FIX, name, updatedName));
|
||||||
|
throw new PatchException(ERR_UNABLE_TO_FIX, logFile);
|
||||||
|
}
|
||||||
|
updatedName += "_" + idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, name ,updatedName));
|
||||||
|
updated++;
|
||||||
|
getSession().flush();
|
||||||
|
getSession().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<NodeImpl> getInvalidNames()
|
||||||
|
{
|
||||||
|
HibernateCallback callback = new HibernateCallback()
|
||||||
|
{
|
||||||
|
public Object doInHibernate(Session session)
|
||||||
|
{
|
||||||
|
Query query = session
|
||||||
|
.createQuery(
|
||||||
|
"select node from org.alfresco.repo.domain.hibernate.NodeImpl as node " +
|
||||||
|
"join node.properties prop where " +
|
||||||
|
" prop.stringValue like '%.lnk' ");
|
||||||
|
return query.list();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
List<NodeImpl> results = (List<NodeImpl>) getHibernateTemplate().execute(callback);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -68,7 +68,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
"./*" +
|
"./*" +
|
||||||
"[like(@cm:name, $cm:name, false)" +
|
"[like(@cm:name, $cm:name, false)" +
|
||||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||||
|
" and (subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||||
|
|
||||||
/** Shallow search for all files and folders */
|
/** Shallow search for all files and folders */
|
||||||
private static final String LUCENE_QUERY_SHALLOW_ALL =
|
private static final String LUCENE_QUERY_SHALLOW_ALL =
|
||||||
@ -77,6 +78,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
"+(" +
|
"+(" +
|
||||||
"TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " +
|
"TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " +
|
||||||
"TYPE:\"" + ContentModel.TYPE_FOLDER + "\" " +
|
"TYPE:\"" + ContentModel.TYPE_FOLDER + "\" " +
|
||||||
|
"TYPE:\"" + ContentModel.TYPE_LINK + "\" " +
|
||||||
")";
|
")";
|
||||||
|
|
||||||
/** Shallow search for all files and folders */
|
/** Shallow search for all files and folders */
|
||||||
@ -96,7 +98,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
".//*" +
|
".//*" +
|
||||||
"[like(@cm:name, $cm:name, false)" +
|
"[like(@cm:name, $cm:name, false)" +
|
||||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||||
|
" and (subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||||
|
|
||||||
/** empty parameters */
|
/** empty parameters */
|
||||||
private static final QueryParameterDefinition[] PARAMS_ANY_NAME = new QueryParameterDefinition[1];
|
private static final QueryParameterDefinition[] PARAMS_ANY_NAME = new QueryParameterDefinition[1];
|
||||||
@ -246,7 +249,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT))
|
else if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT) ||
|
||||||
|
dictionaryService.isSubClass(typeQName, ContentModel.TYPE_LINK))
|
||||||
{
|
{
|
||||||
// it is a regular file
|
// it is a regular file
|
||||||
return false;
|
return false;
|
||||||
|
@ -35,7 +35,9 @@ import org.alfresco.service.namespace.QName;
|
|||||||
public class FileInfoImpl implements FileInfo
|
public class FileInfoImpl implements FileInfo
|
||||||
{
|
{
|
||||||
private NodeRef nodeRef;
|
private NodeRef nodeRef;
|
||||||
|
private NodeRef linkNodeRef;
|
||||||
private boolean isFolder;
|
private boolean isFolder;
|
||||||
|
private boolean isLink;
|
||||||
private Map<QName, Serializable> properties;
|
private Map<QName, Serializable> properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +48,14 @@ public class FileInfoImpl implements FileInfo
|
|||||||
this.nodeRef = nodeRef;
|
this.nodeRef = nodeRef;
|
||||||
this.isFolder = isFolder;
|
this.isFolder = isFolder;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
|
||||||
|
// Check if this is a link node
|
||||||
|
|
||||||
|
if ( properties.containsKey( ContentModel.PROP_LINK_DESTINATION))
|
||||||
|
{
|
||||||
|
isLink = true;
|
||||||
|
linkNodeRef = (NodeRef) properties.get( ContentModel.PROP_LINK_DESTINATION);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,8 +65,15 @@ public class FileInfoImpl implements FileInfo
|
|||||||
sb.append("FileInfo")
|
sb.append("FileInfo")
|
||||||
.append("[name=").append(getName())
|
.append("[name=").append(getName())
|
||||||
.append(", isFolder=").append(isFolder)
|
.append(", isFolder=").append(isFolder)
|
||||||
.append(", nodeRef=").append(nodeRef)
|
.append(", nodeRef=").append(nodeRef);
|
||||||
.append("]");
|
|
||||||
|
if ( isLink())
|
||||||
|
{
|
||||||
|
sb.append(", linkref=");
|
||||||
|
sb.append(linkNodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +87,16 @@ public class FileInfoImpl implements FileInfo
|
|||||||
return isFolder;
|
return isFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLink()
|
||||||
|
{
|
||||||
|
return isLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeRef getLinkNodeRef()
|
||||||
|
{
|
||||||
|
return linkNodeRef;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return (String) properties.get(ContentModel.PROP_NAME);
|
return (String) properties.get(ContentModel.PROP_NAME);
|
||||||
|
@ -43,6 +43,16 @@ public interface FileInfo
|
|||||||
*/
|
*/
|
||||||
public boolean isFolder();
|
public boolean isFolder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this instance represents a link to a node
|
||||||
|
*/
|
||||||
|
public boolean isLink();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Return the reference to the node that this node is linked to
|
||||||
|
*/
|
||||||
|
public NodeRef getLinkNodeRef();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the name of the file or folder within the parent folder
|
* @return Returns the name of the file or folder within the parent folder
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user