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-94f89814c4df
jensp 2018-05-25 14:38:15 +00:00
parent d462677598
commit 4b1ce34f51
3 changed files with 214 additions and 6 deletions

View File

@ -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);
}
}

View File

@ -41,16 +41,24 @@ import org.libreccm.theming.ThemeInfo;
import org.libreccm.theming.ThemeVersion;
import org.libreccm.theming.Themes;
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.Depth;
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.Prop;
import org.libreccm.webdav.xml.elements.PropStat;
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.properties.DisplayName;
import org.libreccm.webdav.xml.properties.GetContentLength;
import org.libreccm.webdav.xml.properties.GetContentType;
import org.libreccm.webdav.xml.properties.LockDiscovery;
import java.util.LinkedList;
import java.util.List;
@ -72,13 +80,16 @@ import javax.ws.rs.ext.Providers;
public class ThemeFiles {
@Inject
private Themes themes;
private HttpServletRequest request;
@Inject
private ServletContext servletContext;
@Inject
private HttpServletRequest request;
private Themes themes;
@Inject
private ThemeFilesLockManager lockManager;
@GET
@Path("/{path}")
@ -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
public Response options() {

View File

@ -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);
}
}