WebDavServiceImpl.java
/*
* Copyright (C) 2003-2009 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.cms.webdav;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import javax.jcr.Item;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.common.http.HTTPStatus;
import org.exoplatform.common.util.HierarchicalProperty;
import org.exoplatform.commons.utils.MimeTypeResolver;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.ecm.utils.text.Text;
import org.exoplatform.services.cms.CmsService;
import org.exoplatform.services.cms.documents.AutoVersionService;
import org.exoplatform.services.cms.drives.DriveData;
import org.exoplatform.services.cms.drives.ManageDriveService;
import org.exoplatform.services.cms.impl.Utils;
import org.exoplatform.services.cms.jcrext.activity.ActivityCommonService;
import org.exoplatform.services.cms.link.LinkUtils;
import org.exoplatform.services.cms.link.NodeFinder;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.ext.app.ThreadLocalSessionProviderService;
import org.exoplatform.services.jcr.webdav.util.InitParamsDefaults;
import org.exoplatform.services.jcr.webdav.util.TextUtil;
import org.exoplatform.services.listener.ListenerService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.rest.ExtHttpHeaders;
import org.exoplatform.services.rest.ext.webdav.method.ACL;
import org.exoplatform.services.rest.ext.webdav.method.CHECKIN;
import org.exoplatform.services.rest.ext.webdav.method.CHECKOUT;
import org.exoplatform.services.rest.ext.webdav.method.COPY;
import org.exoplatform.services.rest.ext.webdav.method.LOCK;
import org.exoplatform.services.rest.ext.webdav.method.MKCOL;
import org.exoplatform.services.rest.ext.webdav.method.MOVE;
import org.exoplatform.services.rest.ext.webdav.method.OPTIONS;
import org.exoplatform.services.rest.ext.webdav.method.ORDERPATCH;
import org.exoplatform.services.rest.ext.webdav.method.PROPFIND;
import org.exoplatform.services.rest.ext.webdav.method.PROPPATCH;
import org.exoplatform.services.rest.ext.webdav.method.REPORT;
import org.exoplatform.services.rest.ext.webdav.method.SEARCH;
import org.exoplatform.services.rest.ext.webdav.method.UNCHECKOUT;
import org.exoplatform.services.rest.ext.webdav.method.UNLOCK;
import org.exoplatform.services.rest.ext.webdav.method.VERSIONCONTROL;
import org.exoplatform.services.rest.impl.MultivaluedMapImpl;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;
/**
* This class is used to override the default WebDavServiceImpl in order to support symlinks
*
* Created by The eXo Platform SAS
* Author : eXoPlatform
* nicolas.filotto@exoplatform.com
* 9 avr. 2009
*/
@Path("/jcr/")
public class WebDavServiceImpl extends org.exoplatform.services.jcr.webdav.WebDavServiceImpl {
/**
* Logger.
*/
private static final Log LOG = ExoLogger.getLogger(WebDavServiceImpl.class.getName());
private final String POST_UPLOAD_CONTENT_EVENT = "WebDavService.event.postUpload";
private final String PERSONAL_DRIVE_PREFIX = "/Users/${userId}/Private";
private final String GROUP_DRIVE_PREFIX = "/Groups${groupId}/Documents";
private final String PERSONAL_GROUP_DRIVE_WORKSPACE = "collaboration";
private final NodeFinder nodeFinder;
private final RepositoryService repositoryService;
private ListenerService listenerService;
private final MimeTypeResolver mimeTypeResolver;
public WebDavServiceImpl(InitParams params,
RepositoryService repositoryService,
ThreadLocalSessionProviderService sessionProviderService,
NodeFinder nodeFinder, AutoVersionService autoVersionService, ManageDriveService manageDriveService) throws Exception
{
super(params, repositoryService, sessionProviderService);
this.repositoryService = repositoryService;
this.nodeFinder = nodeFinder;
this.listenerService = WCMCoreUtils.getService(ListenerService.class);
this.mimeTypeResolver = new MimeTypeResolver();
this.mimeTypeResolver.setDefaultMimeType(InitParamsDefaults.FILE_MIME_TYPE);
List<String> lstDriveAutoVersion = autoVersionService.getDriveAutoVersion();
MultivaluedMap<String, String> allowedAutoVersionPath = new MultivaluedMapImpl();
if (!lstDriveAutoVersion.isEmpty())
{
for (String driverName : lstDriveAutoVersion)
{
DriveData driveData = manageDriveService.getDriveByName(StringUtils.trim(driverName));
if (driveData != null)
{
String driveHome = driveData.getHomePath();
String workspace = driveData.getWorkspace();
if (driveHome.startsWith(PERSONAL_DRIVE_PREFIX) && PERSONAL_GROUP_DRIVE_WORKSPACE.equals(workspace))
{
allowedAutoVersionPath.add(driveData.getWorkspace(), "/Users");
}
else if (driveHome.startsWith(GROUP_DRIVE_PREFIX) && PERSONAL_GROUP_DRIVE_WORKSPACE.equals(workspace))
{
allowedAutoVersionPath.add(driveData.getWorkspace(), "/Groups");
}
else
{
allowedAutoVersionPath.add(driveData.getWorkspace(), driveHome);
}
}
}
}
webDavServiceInitParams.setAllowedAutoVersionPath(allowedAutoVersionPath);
webDavServiceInitParams.setEnableAutoVersion(true);
}
private String getRealDestinationHeader(String baseURI, String repoName, String destinationHeader) {
String serverURI = baseURI + "/jcr/" + repoName;
destinationHeader = TextUtil.unescape(destinationHeader, '%');
if (!destinationHeader.startsWith(serverURI)) {
return null;
}
String destPath = destinationHeader.substring(serverURI.length() + 1);
try {
Item item = nodeFinder.getItem(workspaceName(destPath),
LinkUtils.getParentPath(path(destPath)),
true);
return item.getSession().getWorkspace().getName()
+ LinkUtils.createPath(item.getPath(), LinkUtils.getItemName(path(destPath)));
} catch (RepositoryException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + destPath, e);
}
return null;
}
}
@CHECKIN
@Path("/{repoName}/{repoPath:.*}/")
public Response checkin(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.checkin(repoName, repoPath, lockTokenHeader, ifHeader);
}
@CHECKOUT
@Path("/{repoName}/{repoPath:.*}/")
public Response checkout(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.checkout(repoName, repoPath, lockTokenHeader, ifHeader);
}
@COPY
@Path("/{repoName}/{repoPath:.*}/")
public Response copy(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.DESTINATION) String destinationHeader,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@HeaderParam(ExtHttpHeaders.DEPTH) String depthHeader,
@HeaderParam(ExtHttpHeaders.OVERWRITE) String overwriteHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoPath = convertRepoPath(repoPath, false);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
String realDestinationHeader = getRealDestinationHeader(uriInfo.getPath(), repoName, destinationHeader);
if (realDestinationHeader != null) {
destinationHeader = realDestinationHeader;
}
return super.copy(repoName,
repoPath,
destinationHeader,
lockTokenHeader,
ifHeader,
depthHeader,
overwriteHeader,
uriInfo,
body);
}
@GET
@Path("/{repoName}/{repoPath:.*}/")
public Response get(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.RANGE) String rangeHeader,
@HeaderParam(ExtHttpHeaders.IF_MODIFIED_SINCE) String ifModifiedSince,
@HeaderParam(ExtHttpHeaders.IF_NONE_MATCH) String ifNoneMatch,
@QueryParam("version") String version,
@Context UriInfo uriInfo) {
try {
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
Response response = super.get(repoName, repoPath, rangeHeader, ifModifiedSince, ifNoneMatch, version, uriInfo);
if(HTTPStatus.OK == response.getStatus()) {
return Response.fromResponse(response)
.header("Access-Control-Allow-Origin", uriInfo.getRequestUri().getHost())
.header("Access-Control-Allow-Credentials", true)
.header("Access-Control-Allow-Methods", "ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, " +
"MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL")
.header("Access-Control-Allow-Headers", "Overwrite, Destination, Content-Type, Depth, User-Agent, Translate, Range, Content-Range," +
" Timeout, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Location, Lock-Token, If")
.header("Access-Control-Expose-Header", "DAV, content-length, Allow")
.header("Access-Control-Max-Age", 3600)
.build();
}
return response;
}
@HEAD
@Path("/{repoName}/{repoPath:.*}/")
public Response head(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@Context UriInfo uriInfo) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.head(repoName, repoPath, uriInfo);
}
@LOCK
@Path("/{repoName}/{repoPath:.*}/")
public Response lock(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@HeaderParam(ExtHttpHeaders.DEPTH) String depthHeader,
HierarchicalProperty body) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.lock(repoName, repoPath, lockTokenHeader, ifHeader, depthHeader, body);
}
@UNLOCK
@Path("/{repoName}/{repoPath:.*}/")
public Response unlock(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.unlock(repoName, repoPath, lockTokenHeader, ifHeader);
}
@OPTIONS
@Path("/{repoName}/{path:.*}/")
public Response options(@PathParam("path") String path) {
return super.options(path);
}
@ORDERPATCH
@Path("/{repoName}/{repoPath:.*}/")
public Response order(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.order(repoName, repoPath, lockTokenHeader, ifHeader, uriInfo, body);
}
@PROPFIND
@Path("/{repoName}/{repoPath:.*}/")
public Response propfind(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.DEPTH) String depthHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.propfind(repoName, repoPath, depthHeader, uriInfo, body);
}
@PROPPATCH
@Path("/{repoName}/{repoPath:.*}/")
public Response proppatch(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.proppatch(repoName, repoPath, lockTokenHeader, ifHeader, uriInfo, body);
}
@PUT
@Path("/{repoName}/{repoPath:.*}/")
public Response put(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@HeaderParam(ExtHttpHeaders.FILE_NODETYPE) String fileNodeTypeHeader,
@HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String nodeTypeHeader,
@HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypes,
@HeaderParam(ExtHttpHeaders.CONTENTTYPE) MediaType mediaType,
@HeaderParam(ExtHttpHeaders.USER_AGENT) String userAgent,
InputStream inputStream,
@Context UriInfo uriInfo) {
Session session = null;
Item item = null;
boolean isCreating = false;
ActivityCommonService activityService = null;
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
try {
item = nodeFinder.getItem(workspaceName(repoPath),
LinkUtils.getParentPath(path(normalizePath(repoPath))),
true);
repoPath = item.getSession().getWorkspace().getName()
+ LinkUtils.createPath(item.getPath(), Text.escapeIllegalJcrChars(LinkUtils.getItemName(path(repoPath))));
session = item.getSession();
} catch (PathNotFoundException e) {
item = nodeFinder.getItem(workspaceName(repoPath),
LinkUtils.getParentPath(path(Text.escapeIllegalJcrChars(repoPath))),
true);
repoPath = item.getSession().getWorkspace().getName()
+ LinkUtils.createPath(item.getPath(), Text.escapeIllegalJcrChars(LinkUtils.getItemName(path(repoPath))));
session = item.getSession();
}
activityService = WCMCoreUtils.getService(ActivityCommonService.class);
if (!session.itemExists(path(repoPath))) {
isCreating = true;
}
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
Response res = super.put(repoName,
repoPath,
lockTokenHeader,
ifHeader,
null,
nodeTypeHeader,
mixinTypes,
mediaType,
userAgent,
inputStream,
uriInfo);
try {
boolean pushAs = markTempFilesToHidden(repoPath);
Node currentNode = (Node) session.getItem(path(repoPath));
if (isCreating) {
if (userAgent!= null && userAgent.contains("Microsoft")) {
activityService.setCreating(currentNode, true);
}
}else {
activityService.setCreating(currentNode, false);
}
try {
if(isCreating && pushAs)
listenerService.broadcast(ActivityCommonService.FILE_CREATED_ACTIVITY, null, currentNode);
if (currentNode.isCheckedOut() && !activityService.isCreating(currentNode) && pushAs)
listenerService.broadcast(this.POST_UPLOAD_CONTENT_EVENT, this, currentNode);
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot broadcast file create activity for the item at " + currentNode.getPath(), e);
}
}
} catch (PathNotFoundException npfe) {
return Response.status(HTTPStatus.NOT_FOUND).entity(npfe.getMessage()).build();
} catch (RepositoryException re) {
return Response.status(HTTPStatus.NOT_FOUND).entity(re.getMessage()).build();
} catch (Exception e) {
return Response.serverError().build();
}
return res;
}
@REPORT
@Path("/{repoName}/{repoPath:.*}/")
public Response report(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.DEPTH) String depthHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.report(repoName, repoPath, depthHeader, uriInfo, body);
}
@SEARCH
@Path("/{repoName}/{repoPath:.*}/")
public Response search(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.search(repoName, repoPath, uriInfo, body);
}
@UNCHECKOUT
@Path("/{repoName}/{repoPath:.*}/")
public Response uncheckout(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.uncheckout(repoName, repoPath, lockTokenHeader, ifHeader);
}
@VERSIONCONTROL
@Path("/{repoName}/{repoPath:.*}/")
public Response versionControl(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.versionControl(repoName, repoPath, lockTokenHeader, ifHeader);
}
@ACL
@Path("/{repoName}/{repoPath:.*}/")
public Response acl(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
HierarchicalProperty body) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.acl(repoName, repoPath, lockTokenHeader, ifHeader, body);
}
@MOVE
@Path("/{repoName}/{repoPath:.*}/")
public Response move(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.DESTINATION) String destinationHeader,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@HeaderParam(ExtHttpHeaders.DEPTH) String depthHeader,
@HeaderParam(ExtHttpHeaders.OVERWRITE) String overwriteHeader,
@Context UriInfo uriInfo,
HierarchicalProperty body) {
try {
repoPath = convertRepoPath(repoPath, true);
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
Response response = super.move(repoName,
repoPath,
destinationHeader,
lockTokenHeader,
ifHeader,
depthHeader,
overwriteHeader,
uriInfo,
body);
if (response.getStatus() == HTTPStatus.CREATED) {
updateProperties(destinationHeader, repoName);
}
markTempFilesToHidden(repoPath);
return response;
}
/**
* update exo:name, exo:title and jcr:mimeType when rename a node
*
* @param destinationHeader
* @param repoName
*/
private void updateProperties(String destinationHeader, String repoName) {
try {
URI dest = buildURI(destinationHeader);
String destPath = dest.getPath();
int repoIndex = destPath.indexOf(repoName);
destPath = normalizePath(repoIndex == -1 ? destPath : destPath.substring(repoIndex + repoName.length() + 1));
String destNodePath = path(destPath);
Node destNode = (Node) nodeFinder.getItem(workspaceName(destPath), path(normalizePath(destNodePath)), true);
String nodeName = Text.escapeIllegalJcrChars(destNode.getName());
destNode.setProperty("exo:name", nodeName);
destNode.setProperty("exo:title", nodeName);
if (!Utils.isFolder(destNode)) {
Node content = destNode.getNode("jcr:content");
String mimeType = mimeTypeResolver.getMimeType(nodeName);
content.setProperty("jcr:mimeType", mimeType);
// Change publication status
ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
if (destNode.isNodeType("exo:datetime")) {
destNode.setProperty("exo:dateModified", new GregorianCalendar());
}
listenerService.broadcast(CmsService.POST_EDIT_CONTENT_EVENT, destNode.getParent(), destNode);
}
destNode.save();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot change property of destNode" + destinationHeader, e);
}
}
}
/**
* Build URI from string.
*/
private URI buildURI(String path) throws URISyntaxException {
try {
return new URI(path);
}
catch (URISyntaxException e) {
return new URI(TextUtil.escape(path, '%', true));
}
}
/**
* {@inheritDoc}
*/
@MKCOL
@Path("/{repoName}/{repoPath:.*}/")
public Response mkcol(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader,
@HeaderParam(ExtHttpHeaders.CONTENT_NODETYPE) String nodeTypeHeader,
@HeaderParam(ExtHttpHeaders.CONTENT_MIXINTYPES) String mixinTypesHeader,
@Context UriInfo uriInfo) {
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
Item item = nodeFinder.getItem(workspaceName(repoPath), LinkUtils.getParentPath(path(normalizePath(repoPath))), true);
repoPath =
item.getSession().getWorkspace().getName() + LinkUtils.createPath(item.getPath(),
LinkUtils.getItemName(path(repoPath)));
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.CONFLICT).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.CONFLICT).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
return super.mkcol(repoName,
repoPath,
lockTokenHeader,
ifHeader,
nodeTypeHeader,
mixinTypesHeader,
uriInfo);
}
@DELETE
@Path("/{repoName}/{repoPath:.*}/")
public Response delete(@PathParam("repoName") String repoName,
@PathParam("repoPath") String repoPath,
@HeaderParam(ExtHttpHeaders.LOCKTOKEN) String lockTokenHeader,
@HeaderParam(ExtHttpHeaders.IF) String ifHeader) {
Item item = null;
try {
repoName = repositoryService.getCurrentRepository().getConfiguration().getName();
repoPath = convertRepoPath(repoPath, false);
try {
item = nodeFinder.getItem(workspaceName(repoPath),
path(normalizePath(repoPath)),
true);
} catch (PathNotFoundException e) {
item = nodeFinder.getItem(workspaceName(repoPath),
path(Text.escapeIllegalJcrChars(repoPath)),
true);
}
} catch (PathNotFoundException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (NoSuchWorkspaceException exc) {
return Response.status(HTTPStatus.NOT_FOUND).entity(exc.getMessage()).build();
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find the item at " + repoName + "/" + repoPath, e);
}
return Response.serverError().build();
}
try {
//Broadcast the event when user move node to Trash
Node node = (Node)item;
ListenerService listenerService = WCMCoreUtils.getService(ListenerService.class);
ActivityCommonService activityService = WCMCoreUtils.getService(ActivityCommonService.class);
Node parent = node.getParent();
if (node.getPrimaryNodeType().getName().equals(NodetypeConstant.NT_FILE)) {
if (activityService.isBroadcastNTFileEvents(node)) {
listenerService.broadcast(ActivityCommonService.FILE_REMOVE_ACTIVITY, parent, node);
}
} else if(!WCMCoreUtils.isDocumentNodeType(node)){
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
//Broadcast event to remove file activities
Node tempNode = null;
try {
while (!queue.isEmpty()) {
tempNode = queue.poll();
if (WCMCoreUtils.isDocumentNodeType(tempNode)
|| tempNode.getPrimaryNodeType().getName().equals(NodetypeConstant.NT_FILE)) {
listenerService.broadcast(ActivityCommonService.FILE_REMOVE_ACTIVITY, tempNode.getParent(), tempNode);
} else {
for (NodeIterator iter = tempNode.getNodes(); iter.hasNext(); ) {
Node childNode = iter.nextNode();
if(WCMCoreUtils.isDocumentNodeType(childNode) || childNode.isNodeType(NodetypeConstant.NT_UNSTRUCTURED)
|| childNode.isNodeType(NodetypeConstant.NT_FOLDER))
queue.add(childNode);
}
}
}
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn(e.getMessage());
}
}
}
//Remove the symlinks of deleted node.
Utils.removeSymlinks(node);
} catch(Exception ex) {
if (LOG.isWarnEnabled()) {
LOG.warn(ex.getMessage());
}
}
return super.delete(repoName, repoPath, lockTokenHeader, ifHeader);
}
private String convertRepoPath(String repoPath, boolean giveTarget) throws Exception{
try {
Item item = nodeFinder.getItem(workspaceName(repoPath), path(normalizePath(repoPath)), giveTarget);
return item.getSession().getWorkspace().getName() + item.getPath();
} catch (PathNotFoundException e) {
Item item = nodeFinder.getItem(workspaceName(repoPath), path(Text.escapeIllegalJcrChars(repoPath)), giveTarget);
return item.getSession().getWorkspace().getName() + item.getPath();
}
}
/**
* hidden temporary files/folders
* @param repoPath
*/
private boolean markTempFilesToHidden(String repoPath){
if(StringUtils.isBlank(repoPath)) return false;
String tempNodeFolder = ".TemporaryItems";
String tempNodeFileChild = "._folders.501";
String tempNodeFile = "._.TemporaryItems";
String txtTempRegex = "/._";
try {
String txtTemp = repoPath.substring(repoPath.lastIndexOf("/"), repoPath.length());
boolean isTxtTemp = txtTemp.startsWith(txtTempRegex)?true:false;
if(repoPath.contains(tempNodeFile) || isTxtTemp){
Node _tempNodeFile = (Node)nodeFinder.getItem(workspaceName(repoPath), path(repoPath), true);
_tempNodeFile.remove();
_tempNodeFile.getSession().save();
return false;
}else if(repoPath.contains(tempNodeFolder)) {
String currentNodePath = repoPath.substring(0, repoPath.indexOf(tempNodeFolder));
Node currentNode = (Node)nodeFinder.getItem(workspaceName(repoPath), path(currentNodePath), true);
//make tmp folder to hidden
if(currentNode.hasNode(tempNodeFolder)){
Node _tmpFolderNode = currentNode.getNode(tempNodeFolder);
if(_tmpFolderNode.canAddMixin(NodetypeConstant.EXO_HIDDENABLE)) _tmpFolderNode.addMixin(NodetypeConstant.EXO_HIDDENABLE);
if (_tmpFolderNode.hasNode(tempNodeFileChild)){
Node _tempNodeFileChild = _tmpFolderNode.getNode(tempNodeFileChild);
_tempNodeFileChild.remove();
}
_tmpFolderNode.save();
}
return false;
}
}catch(RepositoryException ex){
if (LOG.isWarnEnabled()) {
LOG.warn("The hidden temp files has been ignored " + ex.getMessage());
}
}
return true;
}
}