CcmNG: Implementation of the lock method for WebDAV access to theme files
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5450 8810af33-2d31-482b-a856-94f89814c4dfccm-docs
parent
6e1b5e3fd6
commit
e27bbad3a5
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 LibreCCM Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.libreccm.theming.webdav;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
class AlreadyLockedException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of <code>AlreadyLockedException</code> without detail message.
|
||||||
|
*/
|
||||||
|
public AlreadyLockedException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>AlreadyLockedException</code> with the specified detail message.
|
||||||
|
*
|
||||||
|
* @param msg The detail message.
|
||||||
|
*/
|
||||||
|
public AlreadyLockedException(final String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>AlreadyLockedException</code> which wraps the
|
||||||
|
* specified exception.
|
||||||
|
*
|
||||||
|
* @param exception The exception to wrap.
|
||||||
|
*/
|
||||||
|
public AlreadyLockedException(final Exception exception) {
|
||||||
|
super(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>AlreadyLockedException</code> with the specified message which also wraps the
|
||||||
|
* specified exception.
|
||||||
|
*
|
||||||
|
* @param msg The detail message.
|
||||||
|
* @param exception The exception to wrap.
|
||||||
|
*/
|
||||||
|
public AlreadyLockedException(final String msg, final Exception exception) {
|
||||||
|
super(msg, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,16 +41,24 @@ import org.libreccm.theming.ThemeInfo;
|
||||||
import org.libreccm.theming.ThemeVersion;
|
import org.libreccm.theming.ThemeVersion;
|
||||||
import org.libreccm.theming.Themes;
|
import org.libreccm.theming.Themes;
|
||||||
import org.libreccm.webdav.ResponseStatus;
|
import org.libreccm.webdav.ResponseStatus;
|
||||||
|
import org.libreccm.webdav.methods.LOCK;
|
||||||
|
import org.libreccm.webdav.xml.elements.ActiveLock;
|
||||||
import org.libreccm.webdav.xml.elements.Collection;
|
import org.libreccm.webdav.xml.elements.Collection;
|
||||||
|
import org.libreccm.webdav.xml.elements.Depth;
|
||||||
import org.libreccm.webdav.xml.elements.HRef;
|
import org.libreccm.webdav.xml.elements.HRef;
|
||||||
|
import org.libreccm.webdav.xml.elements.LockInfo;
|
||||||
|
import org.libreccm.webdav.xml.elements.LockRoot;
|
||||||
|
import org.libreccm.webdav.xml.elements.LockToken;
|
||||||
import org.libreccm.webdav.xml.elements.MultiStatus;
|
import org.libreccm.webdav.xml.elements.MultiStatus;
|
||||||
import org.libreccm.webdav.xml.elements.Prop;
|
import org.libreccm.webdav.xml.elements.Prop;
|
||||||
import org.libreccm.webdav.xml.elements.PropStat;
|
import org.libreccm.webdav.xml.elements.PropStat;
|
||||||
import org.libreccm.webdav.xml.elements.Status;
|
import org.libreccm.webdav.xml.elements.Status;
|
||||||
|
import org.libreccm.webdav.xml.elements.TimeOut;
|
||||||
import org.libreccm.webdav.xml.elements.WebDavResponse;
|
import org.libreccm.webdav.xml.elements.WebDavResponse;
|
||||||
import org.libreccm.webdav.xml.properties.DisplayName;
|
import org.libreccm.webdav.xml.properties.DisplayName;
|
||||||
import org.libreccm.webdav.xml.properties.GetContentLength;
|
import org.libreccm.webdav.xml.properties.GetContentLength;
|
||||||
import org.libreccm.webdav.xml.properties.GetContentType;
|
import org.libreccm.webdav.xml.properties.GetContentType;
|
||||||
|
import org.libreccm.webdav.xml.properties.LockDiscovery;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -72,14 +80,17 @@ import javax.ws.rs.ext.Providers;
|
||||||
public class ThemeFiles {
|
public class ThemeFiles {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Themes themes;
|
private HttpServletRequest request;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ServletContext servletContext;
|
private ServletContext servletContext;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private HttpServletRequest request;
|
private Themes themes;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ThemeFilesLockManager lockManager;
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/{path}")
|
@Path("/{path}")
|
||||||
public Response getFile(@PathParam("theme") final String theme,
|
public Response getFile(@PathParam("theme") final String theme,
|
||||||
|
|
@ -117,6 +128,38 @@ public class ThemeFiles {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LOCK
|
||||||
|
@Path("/{path}")
|
||||||
|
public Prop lock(@PathParam("theme")
|
||||||
|
final String theme,
|
||||||
|
@PathParam("path")
|
||||||
|
final String path,
|
||||||
|
final LockInfo lockInfo) {
|
||||||
|
|
||||||
|
final String lockedPath = String.format("%s/path",
|
||||||
|
theme,
|
||||||
|
path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String lockToken = lockManager.lockFile(lockedPath);
|
||||||
|
|
||||||
|
return new Prop(new LockDiscovery(
|
||||||
|
new ActiveLock(lockInfo.getLockScope(),
|
||||||
|
lockInfo.getLockType(),
|
||||||
|
Depth.ZERO,
|
||||||
|
lockInfo.getOwner(),
|
||||||
|
new TimeOut(3600),
|
||||||
|
new LockToken(new HRef(String
|
||||||
|
.format("opaquelocktoken:%s",
|
||||||
|
lockToken))),
|
||||||
|
new LockRoot(new HRef(lockedPath)))));
|
||||||
|
|
||||||
|
} catch (AlreadyLockedException ex) {
|
||||||
|
throw new WebApplicationException(
|
||||||
|
ResponseStatus.LOCKED.getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OPTIONS
|
@OPTIONS
|
||||||
public Response options() {
|
public Response options() {
|
||||||
|
|
||||||
|
|
@ -209,10 +252,10 @@ public class ThemeFiles {
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WebDavResponse buildWebDavResponse(final String basePath,
|
private WebDavResponse buildWebDavResponse(final String basePath,
|
||||||
final ThemeFileInfo fileInfo) {
|
final ThemeFileInfo fileInfo) {
|
||||||
|
|
||||||
final PropStat propStat;
|
final PropStat propStat;
|
||||||
if (fileInfo.isDirectory()) {
|
if (fileInfo.isDirectory()) {
|
||||||
propStat = new PropStat(
|
propStat = new PropStat(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 LibreCCM Foundation.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.libreccm.theming.webdav;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import javax.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the locks on files for WebDAV.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
class ThemeFilesLockManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping between file path and lock token
|
||||||
|
*/
|
||||||
|
private final Map<String, String> lockedFiles = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping between lock token and file.
|
||||||
|
*/
|
||||||
|
private final Map<String, String> locks = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock a file
|
||||||
|
*
|
||||||
|
* @param file Path of the file to lock.
|
||||||
|
*
|
||||||
|
* @return The lock token.
|
||||||
|
*
|
||||||
|
* @throws AlreadyLockedException If the file is already locked.
|
||||||
|
*/
|
||||||
|
protected String lockFile(final String file) throws AlreadyLockedException {
|
||||||
|
|
||||||
|
if (lockedFiles.containsKey(file)) {
|
||||||
|
throw new AlreadyLockedException(String.format(
|
||||||
|
"File %s is already locked.", file));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
final String lockToken = UUID.randomUUID().toString();
|
||||||
|
lockedFiles.put(file, lockToken);
|
||||||
|
locks.put(lockToken, file);
|
||||||
|
|
||||||
|
return lockToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a file is locked.
|
||||||
|
*
|
||||||
|
* @param file The file to check for a lock.
|
||||||
|
*
|
||||||
|
* @return An {@link Optional} with the lock token of the file if the file
|
||||||
|
* is locked, an empty {@code Optional} otherwise.
|
||||||
|
*/
|
||||||
|
protected Optional<String> isLocked(final String file) {
|
||||||
|
if (lockedFiles.containsKey(file)) {
|
||||||
|
return Optional.of(lockedFiles.get(file));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the lock from a file.
|
||||||
|
*
|
||||||
|
* @param lockToken The token of the lock to remove.
|
||||||
|
*/
|
||||||
|
protected void unlock(final String lockToken) {
|
||||||
|
|
||||||
|
final String file = locks.get(lockToken);
|
||||||
|
locks.remove(lockToken);
|
||||||
|
lockedFiles.remove(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue