org.opencms.jlan.CmsJlanDiskInterface Maven / Gradle / Ivy
Show all versions of opencms-core Show documentation
/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (C) Alkacon Software (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* For further information about Alkacon Software, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.jlan;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsVfsResourceAlreadyExistsException;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.file.wrapper.CmsObjectWrapper;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.security.CmsSecurityException;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.I_CmsRegexSubstitution;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.alfresco.jlan.server.SrvSession;
import org.alfresco.jlan.server.core.DeviceContext;
import org.alfresco.jlan.server.filesys.AccessDeniedException;
import org.alfresco.jlan.server.filesys.DiskInterface;
import org.alfresco.jlan.server.filesys.FileExistsException;
import org.alfresco.jlan.server.filesys.FileInfo;
import org.alfresco.jlan.server.filesys.FileOpenParams;
import org.alfresco.jlan.server.filesys.FileStatus;
import org.alfresco.jlan.server.filesys.NetworkFile;
import org.alfresco.jlan.server.filesys.SearchContext;
import org.alfresco.jlan.server.filesys.TreeConnection;
import org.alfresco.jlan.util.WildCard;
import org.springframework.extensions.config.ConfigElement;
import com.google.common.base.Joiner;
/**
* OpenCms implementation of the JLAN DiskInterface interface.
*
* This class, together with the CmsJlanNetworkFile class, contains the main repository access functionality.
*/
public class CmsJlanDiskInterface implements DiskInterface {
/** Attribute to control whether we need the filesize or not when reading a resource. */
public static final String NO_FILESIZE_REQUIRED = "NO_FILESIZE_REQUIRED";
/** The standard resource filter used for reading resources. */
public static final CmsResourceFilter STANDARD_FILTER = CmsResourceFilter.ONLY_VISIBLE_NO_DELETED;
/** The logger instance for this class. */
private static final Log LOG = CmsLog.getLog(CmsJlanDiskInterface.class);
/**
* Tries to convert a CmsException to the matching exception type from JLAN.
*
* @param e the exception to convert
* @return the converted exception
*/
public static IOException convertCmsException(CmsException e) {
LOG.error(e.getLocalizedMessage(), e);
if (e instanceof CmsSecurityException) {
return new AccessDeniedException(e.getMessage(), e);
} else if (e instanceof CmsVfsResourceAlreadyExistsException) {
return new FileExistsException("File exists: " + e);
} else if (e instanceof CmsVfsResourceNotFoundException) {
return new FileNotFoundException("File does not exist: " + e);
} else {
return new IOException(e);
}
}
/**
* Converts a CIFS path to an OpenCms path by converting backslashes to slashes and translating special characters in the file name.
*
* @param path the path to transform
* @return the OpenCms path for the given path
*/
protected static String getCmsPath(String path) {
String slashPath = path.replace('\\', '/');
// split path into components, translate each of them separately, then combine them again at the end
String[] segments = slashPath.split("/");
List nonEmptySegments = new ArrayList();
for (String segment : segments) {
if (segment.length() > 0) {
String translatedSegment = "*".equals(segment)
? "*"
: OpenCms.getResourceManager().getFileTranslator().translateResource(segment);
nonEmptySegments.add(translatedSegment);
}
}
String result = "/" + Joiner.on("/").join(nonEmptySegments);
return result;
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#closeFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile)
*/
public void closeFile(SrvSession session, TreeConnection connection, NetworkFile file) throws IOException {
file.close();
}
/**
* @see org.alfresco.jlan.server.core.DeviceInterface#createContext(java.lang.String, org.springframework.extensions.config.ConfigElement)
*/
public DeviceContext createContext(String shareName, ConfigElement args) {
return null; // not used, since the repository creates the device context
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#createDirectory(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.FileOpenParams)
*/
public void createDirectory(SrvSession session, TreeConnection connection, FileOpenParams params)
throws IOException {
internalCreateFile(session, connection, params, "folder");
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#createFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.FileOpenParams)
*/
public NetworkFile createFile(SrvSession session, TreeConnection connection, FileOpenParams params)
throws IOException {
return internalCreateFile(session, connection, params, null);
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#deleteDirectory(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String)
*/
public void deleteDirectory(SrvSession session, TreeConnection connection, String path) throws IOException {
deleteFile(session, connection, path);
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#deleteFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String)
*/
public void deleteFile(SrvSession session, TreeConnection connection, String path) throws IOException {
// note: deletion of a file may not necessarily go through this method, instead the client program may open the
// file, set a "delete on close" flag, and then close it.
try {
CmsJlanNetworkFile file = getFileForPath(session, connection, path);
if (file == null) {
// Only log a warning, since if the file doesn't exist, it doesn't really need to be deleted anymore
LOG.warn("Couldn't delete file " + path + " because it doesn't exist anymore.");
} else {
file.delete();
}
} catch (CmsException e) {
throw convertCmsException(e);
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#fileExists(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String)
*/
public int fileExists(SrvSession session, TreeConnection connection, String path) {
try {
CmsObjectWrapper cms = getCms(session, connection);
cms.getRequestContext().setAttribute(NO_FILESIZE_REQUIRED, Boolean.TRUE);
CmsJlanNetworkFile file = getFileForPath(cms, session, connection, path);
if (file == null) {
return FileStatus.NotExist;
} else {
return file.isDirectory() ? FileStatus.DirectoryExists : FileStatus.FileExists;
}
} catch (Exception e) {
System.out.println(e);
return FileStatus.NotExist;
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#flushFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile)
*/
public void flushFile(SrvSession session, TreeConnection connection, NetworkFile file) throws IOException {
file.flushFile();
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#getFileInformation(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String)
*/
public FileInfo getFileInformation(SrvSession session, TreeConnection connection, String path) throws IOException {
try {
if (path == null) {
throw new FileNotFoundException("file not found: " + path);
}
CmsJlanNetworkFile file = getFileForPath(session, connection, path);
if (file == null) {
return null;
//throw new FileNotFoundException("path not found: " + path);
} else {
return file.getFileInfo();
}
} catch (CmsException e) {
throw convertCmsException(e);
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#isReadOnly(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.core.DeviceContext)
*/
public boolean isReadOnly(SrvSession session, DeviceContext context) {
return false;
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#openFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.FileOpenParams)
*/
public NetworkFile openFile(SrvSession session, TreeConnection connection, FileOpenParams params)
throws IOException {
String path = params.getPath();
String cmsPath = getCmsPath(path);
// TODO: Check access control
try {
CmsObjectWrapper cms = getCms(session, connection);
CmsResource resource = cms.readResource(cmsPath, STANDARD_FILTER);
return new CmsJlanNetworkFile(cms, resource, path);
} catch (CmsException e) {
throw convertCmsException(e);
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#readFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile, byte[], int, int, long)
*/
public int readFile(
SrvSession sess,
TreeConnection tree,
NetworkFile file,
byte[] buf,
int bufPos,
int siz,
long filePos)
throws java.io.IOException {
// Check if the file is a directory
if (file.isDirectory()) {
throw new AccessDeniedException();
}
// Read the file
int rdlen = file.readFile(buf, siz, bufPos, filePos);
// If we have reached end of file return a zero length read
if (rdlen < 0) {
rdlen = 0;
}
// Return the actual read length
return rdlen;
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#renameFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String, java.lang.String)
*/
public void renameFile(SrvSession session, TreeConnection connection, String oldName, String newName)
throws IOException {
String cmsNewPath = getCmsPath(newName);
try {
CmsJlanNetworkFile file = getFileForPath(session, connection, oldName);
file.moveTo(cmsNewPath);
} catch (CmsException e) {
throw convertCmsException(e);
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#seekFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile, long, int)
*/
public long seekFile(SrvSession session, TreeConnection connection, NetworkFile file, long pos, int seekMode)
throws IOException {
return file.seekFile(pos, seekMode);
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#setFileInformation(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String, org.alfresco.jlan.server.filesys.FileInfo)
*/
public void setFileInformation(SrvSession session, TreeConnection connection, String path, FileInfo info)
throws IOException {
try {
CmsObjectWrapper cms = getCms(session, connection);
String cmsPath = getCmsPath(path);
CmsResource resource = cms.readResource(cmsPath, STANDARD_FILTER);
CmsJlanNetworkFile file = new CmsJlanNetworkFile(cms, resource, path);
file.setFileInformation(info);
} catch (CmsException e) {
throw convertCmsException(e);
}
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#startSearch(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, java.lang.String, int)
*/
public SearchContext startSearch(
SrvSession session,
TreeConnection connection,
String searchPath,
int searchAttributes) {
try {
String cmsPath = getCmsPath(searchPath);
if (cmsPath.endsWith("/")) {
cmsPath = cmsPath + "*";
}
String name = CmsResource.getName(cmsPath);
String parent = CmsResource.getParentFolder(cmsPath);
if (WildCard.containsWildcards(name)) {
CmsJlanNetworkFile parentFile = getFileForPath(session, connection, parent);
return new CmsJlanSearch(parentFile.search(name, searchAttributes));
} else {
CmsJlanNetworkFile file = getFileForPath(session, connection, cmsPath);
return new CmsJlanSearch(Collections.singletonList(file));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @see org.alfresco.jlan.server.core.DeviceInterface#treeClosed(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection)
*/
public void treeClosed(SrvSession sess, TreeConnection tree) {
// ignore
}
/**
* @see org.alfresco.jlan.server.core.DeviceInterface#treeOpened(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection)
*/
public void treeOpened(SrvSession arg0, TreeConnection arg1) {
// ignore
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#truncateFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile, long)
*/
public void truncateFile(SrvSession session, TreeConnection connection, NetworkFile file, long size)
throws IOException {
file.truncateFile(size);
}
/**
* @see org.alfresco.jlan.server.filesys.DiskInterface#writeFile(org.alfresco.jlan.server.SrvSession, org.alfresco.jlan.server.filesys.TreeConnection, org.alfresco.jlan.server.filesys.NetworkFile, byte[], int, int, long)
*/
public int writeFile(
SrvSession session,
TreeConnection connection,
NetworkFile file,
byte[] data,
int bufferOffset,
int length,
long fileOffset)
throws IOException {
if (file.isDirectory()) {
throw new AccessDeniedException("Can't write data to a directory!");
}
file.writeFile(data, length, bufferOffset, fileOffset);
return length;
}
/**
* Creates a CmsObjectWrapper for the current session.
*
* @param session the current session
* @param connection the tree connection
*
* @return the correctly configured CmsObjectWrapper for this session
*
* @throws CmsException if something goes wrong
*/
protected CmsObjectWrapper getCms(SrvSession session, TreeConnection connection) throws CmsException {
CmsJlanRepository repository = ((CmsJlanDeviceContext)connection.getContext()).getRepository();
CmsObjectWrapper result = repository.getCms(session, connection);
return result;
}
/**
* Helper method to get a network file object given a path.
*
* @param cms the CMS context wrapper
* @param session the current session
* @param connection the current connection
* @param path the file path
*
* @return the network file object for the given path
* @throws CmsException if something goes wrong
*/
protected CmsJlanNetworkFile getFileForPath(
CmsObjectWrapper cms,
SrvSession session,
TreeConnection connection,
String path)
throws CmsException {
try {
String cmsPath = getCmsPath(path);
CmsResource resource = cms.readResource(cmsPath, STANDARD_FILTER);
CmsJlanNetworkFile result = new CmsJlanNetworkFile(cms, resource, path);
return result;
} catch (CmsVfsResourceNotFoundException e) {
return null;
}
}
/**
* Helper method to get a network file object given a path.
*
* @param session the current session
* @param connection the current connection
* @param path the file path
*
* @return the network file object for the given path
* @throws CmsException if something goes wrong
*/
protected CmsJlanNetworkFile getFileForPath(SrvSession session, TreeConnection connection, String path)
throws CmsException {
CmsObjectWrapper cms = getCms(session, connection);
return getFileForPath(cms, session, connection, path);
}
/**
* Internal method for creating a new file.
*
* @param session the session
* @param connection the tree connection
* @param params the parameters for opening the file
* @param typeName the name of the resource type for the new file
*
* @return a NetworkFile instance representing the newly created file
*
* @throws IOException if something goes wrong
*/
protected NetworkFile internalCreateFile(
SrvSession session,
TreeConnection connection,
FileOpenParams params,
String typeName)
throws IOException {
String path = params.getPath();
String cmsPath = getCmsPath(path);
try {
CmsObjectWrapper cms = getCms(session, connection);
if (typeName == null) {
typeName = OpenCms.getResourceManager().getDefaultTypeForName(cmsPath).getTypeName();
}
CmsResource createdResource = cms.createResource(
cmsPath,
OpenCms.getResourceManager().getResourceType(typeName).getTypeId());
tryUnlock(cms, cmsPath);
CmsJlanNetworkFile result = new CmsJlanNetworkFile(cms, createdResource, path);
result.setFullName(params.getPath());
return result;
} catch (CmsVfsResourceAlreadyExistsException e) {
throw new FileExistsException("File exists: " + path);
} catch (CmsException e) {
throw new IOException(e);
}
}
/**
* Translates the last path segment of a path using the configured OpenCms file translations.
*
* @param path the path for which the last segment should be translated
*
* @return the path with the translated last segment
*/
protected String translateName(String path) {
return CmsStringUtil.substitute(Pattern.compile("/([^/]+)$"), path, new I_CmsRegexSubstitution() {
public String substituteMatch(String text, Matcher matcher) {
String name = text.substring(matcher.start(1), matcher.end(1));
return "/" + OpenCms.getResourceManager().getFileTranslator().translateResource(name);
}
});
}
/**
* Tries to unlock the file at the given path.
*
* @param cms the CMS context wrapper
* @param path the path of the resource to unlock
*/
private void tryUnlock(CmsObjectWrapper cms, String path) {
try {
cms.unlockResource(path);
} catch (Throwable e) {
LOG.info(e.getLocalizedMessage(), e);
}
}
}