use of org.alfresco.jlan.server.locking.OpLockInterface in project alfresco-repository by Alfresco.
the class ContentDiskDriver method closeFile.
/**
* Close the file.
*
* @param sess Server session
* @param tree Tree connection.
* @param file Network file context.
* @exception java.io.IOException If an error occurs.
*/
public void closeFile(SrvSession sess, TreeConnection tree, final NetworkFile file) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Close file: file" + file);
}
// Get the associated file state
final ContentContext ctx = (ContentContext) tree.getContext();
FileState toUpdate = null;
if (file instanceof ContentNetworkFile) {
if (ctx.hasStateCache()) {
FileState fstate = ctx.getStateCache().findFileState(file.getFullName());
if (fstate != null) {
if (file.getGrantedAccess() > NetworkFile.ATTRIBUTESONLY && fstate.decrementOpenCount() == 0)
fstate.setSharedAccess(SharingMode.READWRITE + SharingMode.DELETE);
if (file.hasOpLock()) {
// Release the oplock
OpLockInterface flIface = (OpLockInterface) this;
OpLockManager oplockMgr = flIface.getOpLockManager(sess, tree);
oplockMgr.releaseOpLock(file.getOpLock().getPath());
if (logger.isDebugEnabled())
logger.debug("Released oplock for closed file, file=" + file.getFullName());
}
if (file.hasDeleteOnClose() == false && fstate.hasModifyDateTime() && fstate.hasFilesystemObject() && fstate.isDirectory() == false) {
// Update the modification date on the file/folder node
toUpdate = fstate;
}
}
}
// Decrement the file open count
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if (contentFile.decrementOpenCount() > 0) {
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Deferred file close, path=" + file.getFullName() + ", openCount=" + contentFile.getOpenCount());
return;
} else if (logger.isDebugEnabled())
logger.debug("Last reference to file, closing, path=" + file.getFullName() + ", access=" + file.getGrantedAccessAsString() + ", fid=" + file.getProtocolId() + ", modified=" + contentFile.isModified());
}
// Check if there is a quota manager enabled
long fileSize = 0L;
if (ctx.hasQuotaManager() && file.hasDeleteOnClose()) {
if (file instanceof ContentNetworkFile) {
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if (contentFile.hasContent() == false)
contentFile.openContent(false, false);
// Save the current file size
fileSize = contentFile.getFileSize();
}
}
// Depending on whether the node has the NO_CONTENT aspect, we may have to wipe it out on error
final CallableIO<Void> errorHandler = new CallableIO<Void>() {
public Void call() throws IOException {
if (file instanceof NodeRefNetworkFile) {
NodeRef nodeRef = ((NodeRefNetworkFile) file).getNodeRef();
if (nodeService.exists(nodeRef) && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_NO_CONTENT)) {
logger.debug("No content - delete");
fileFolderService.delete(nodeRef);
}
}
return null;
}
};
try {
// Perform repository updates in a retryable write transaction
final FileState finalFileState = toUpdate;
Pair<NodeRef, Boolean> result = doInWriteTransaction(sess, new CallableIO<Pair<NodeRef, Boolean>>() {
public Pair<NodeRef, Boolean> call() throws IOException {
if (file instanceof OpenOfficeContentNetworkFile) {
OpenOfficeContentNetworkFile ooFile = (OpenOfficeContentNetworkFile) file;
if (ooFile.truncatedToZeroLength()) {
// Inhibit versioning for this transaction
getPolicyFilter().disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("OpenOffice file truncation update only, inhibit versioning, " + file.getFullName());
}
}
// Update the modification date on the file/folder node
if (finalFileState != null && file instanceof ContentNetworkFile) {
NodeRef nodeRef = (NodeRef) finalFileState.getFilesystemObject();
// Check if the file data has been updated, if not then inhibit versioning for this txn
// so the timestamp update does not generate a new file version
ContentNetworkFile contentFile = (ContentNetworkFile) file;
if (contentFile.isModified() == false && nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE)) {
// Stop a new file version being generated
getPolicyFilter().disableBehaviour(ContentModel.ASPECT_VERSIONABLE);
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Timestamp update only, inhibit versioning, " + file.getFullName());
}
// Update the modification timestamp
getPolicyFilter().disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
if (permissionService.hasPermission((NodeRef) finalFileState.getFilesystemObject(), PermissionService.WRITE_PROPERTIES) == AccessStatus.ALLOWED) {
nodeService.setProperty(nodeRef, ContentModel.PROP_MODIFIER, authService.getCurrentUserName());
Date modifyDate = new Date(finalFileState.getModifyDateTime());
nodeService.setProperty(nodeRef, ContentModel.PROP_MODIFIED, modifyDate);
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Updated modification timestamp, " + file.getFullName() + ", modTime=" + modifyDate);
}
}
// Defer to the network file to close the stream and remove the content
file.close();
if (file.hasDeleteOnClose()) {
logger.debug("File has delete on close");
if (file instanceof NodeRefNetworkFile) {
NodeRefNetworkFile nodeNetFile = (NodeRefNetworkFile) file;
final NodeRef nodeRef = nodeNetFile.getNodeRef();
if (fileFolderService.exists(nodeRef)) {
try {
boolean isVersionable = nodeService.hasAspect(nodeRef, ContentModel.ASPECT_VERSIONABLE);
try {
// Delete the file
FileState fileState = ctx.getStateCache().findFileState(file.getFullName());
if (fileState != null && fileState.findAttribute(CanDeleteWithoutPerms) != null) {
// Has CanDeleteWithoutPerms attribute, so delete from system user
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>() {
@Override
public Object doWork() throws Exception {
logger.debug("delete as system" + nodeRef);
fileFolderService.delete(nodeRef);
return null;
}
}, AuthenticationUtil.getSystemUserName());
} else {
logger.debug("delete nodeRef:" + nodeRef);
fileFolderService.delete(nodeRef);
}
} catch (Exception ex) {
logger.debug("on delete on close", ex);
// Propagate retryable errors. Log the rest.
if (RetryingTransactionHelper.extractRetryCause(ex) != null) {
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
} else {
throw new AlfrescoRuntimeException("Error during delete on close, " + file.getFullName(), ex);
}
}
if (logger.isWarnEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.warn("Error during delete on close, " + file.getFullName(), ex);
}
// Return a node ref to update in the state table
return new Pair<NodeRef, Boolean>(nodeRef, isVersionable);
} catch (org.alfresco.repo.security.permissions.AccessDeniedException ex) {
if (logger.isDebugEnabled() && ctx.hasDebug(AlfrescoContext.DBG_FILE))
logger.debug("Delete on close - access denied, " + file.getFullName());
throw new AccessDeniedException("Delete on close " + file.getFullName());
}
}
}
}
return null;
}
});
if (result != null) {
if (ctx.hasQuotaManager())
ctx.getQuotaManager().releaseSpace(sess, tree, file.getFileId(), file.getFullName(), fileSize);
if (ctx.hasStateCache()) {
if (result.getSecond()) {
// Get, or create, the file state
FileState fState = ctx.getStateCache().findFileState(file.getFullName(), true);
// Indicate that the file was deleted via a delete on close request
fState.setFileStatus(DeleteOnClose);
// Make sure the file state is cached for a short while, save the noderef details
fState.setExpiryTime(System.currentTimeMillis() + FileState.RenameTimeout);
fState.setFilesystemObject(result.getFirst());
} else {
// Remove the file state
ctx.getStateCache().removeFileState(file.getFullName());
}
}
}
if (logger.isDebugEnabled() && (ctx.hasDebug(AlfrescoContext.DBG_FILE) || ctx.hasDebug(AlfrescoContext.DBG_RENAME))) {
logger.debug("Closed file: network file=" + file + " delete on close=" + file.hasDeleteOnClose());
if (file.hasDeleteOnClose() == false && file instanceof ContentNetworkFile) {
ContentNetworkFile cFile = (ContentNetworkFile) file;
logger.debug(" File " + file.getFullName() + ", version=" + nodeService.getProperty(cFile.getNodeRef(), ContentModel.PROP_VERSION_LABEL));
}
}
}// Make sure we clean up before propagating exceptions
catch (IOException e) {
try {
doInWriteTransaction(sess, errorHandler);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
throw e;
} catch (RuntimeException e) {
try {
doInWriteTransaction(sess, errorHandler);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
throw e;
} catch (Error e) {
try {
doInWriteTransaction(sess, errorHandler);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
throw e;
}
}
Aggregations