package org.basex.http.webdav;
import static org.basex.http.webdav.WebDAVUtils.*;
import static org.basex.util.Token.*;
import java.io.*;
import java.util.Map.Entry;
import java.util.*;
import org.basex.core.*;
import org.basex.http.*;
import org.basex.io.*;
import org.basex.io.out.*;
import org.basex.io.serial.*;
import org.basex.query.*;
import org.basex.query.value.item.*;
import org.basex.util.*;
import org.basex.util.list.*;
/**
* Service managing the WebDAV locks.
*
* @author BaseX Team 2005-17, BSD License
* @author Dimitar Popov
*/
final class WebDAVLockService {
/** Path to WebDAV module. */
private static final String FILE = "xquery/webdav.xqm";
/** Module contents. */
private static String module;
/** HTTP connection. */
private final HTTPConnection conn;
/**
* Constructor.
* @param conn HTTP connection
*/
WebDAVLockService(final HTTPConnection conn) {
this.conn = conn;
}
/**
* Releases the lock for the given token.
* @param token lock token
* @throws IOException I/O exception
*/
void unlock(final String token) throws IOException {
execute(new WebDAVQuery("w:delete-lock($token)").bind("token", token));
}
/**
* Renews the lock with the given token.
* @param token lock token
* @throws IOException I/O exception
*/
void refreshLock(final String token) throws IOException {
execute(new WebDAVQuery("w:refresh-lock($token)").bind("token", token));
}
/**
* Creates a new lock for the specified resource.
* @param db database
* @param p path
* @param scope lock scope
* @param type lock type
* @param depth lock depth
* @param user lock user
* @param to lock timeout
* @return lock token
* @throws IOException I/O exception
*/
String lock(final String db, final String p, final String scope, final String type,
final String depth, final String user, final Long to) throws IOException {
initLockDb();
final String token = UUID.randomUUID().toString();
final WebDAVQuery query = new WebDAVQuery("w:create-lock(" +
"$path, $token, $scope, $type, $depth, $owner, $timeout)");
query.bind("path", db + SEP + p);
query.bind("token", token);
query.bind("scope", scope);
query.bind("type", type);
query.bind("depth", depth);
query.bind("owner", user);
query.bind("timeout", to == null ? Long.toString(Long.MAX_VALUE) : to.toString());
execute(query);
return token;
}
/**
* Gets lock with given token.
* @param token lock token
* @return lock
* @throws IOException I/O exception
*/
String lock(final String token) throws IOException {
final StringList locks = execute(new WebDAVQuery("w:lock($token)").bind("token", token));
return locks.isEmpty() ? null : locks.get(0);
}
/**
* Gets active locks for the given resource.
* @param db database
* @param path path
* @return locks
* @throws IOException I/O exception
*/
String lock(final String db, final String path) throws IOException {
final WebDAVQuery query = new WebDAVQuery("w:locks-on($path)").bind("path", db + SEP + path);
final StringList sl = execute(query);
return sl.isEmpty() ? null : sl.get(0);
}
/**
* Checks if there are active conflicting locks for the given resource.
* @param db database
* @param p path
* @return {@code true} if there active conflicting locks
* @throws IOException I/O exception
*/
boolean conflictingLocks(final String db, final String p) throws IOException {
return !execute(new WebDAVQuery("w:conflicting-locks(" +
"<w:lockinfo>" +
"<w:path>{ $path }</w:path>" +
"<w:scope>exclusive</w:scope>" +
"<w:depth>infinity</w:depth>" +
"<w:owner>{ $owner }</w:owner>" +
"</w:lockinfo>)").bind("path", db + SEP + p).
bind("owner", conn.context.user().name())).isEmpty();
}
/**
* Creates the lock database if it does not exist.
* @throws IOException I/O exception
*/
private void initLockDb() throws IOException {
execute(new WebDAVQuery("w:init-lock-db()"));
}
/**
* Executes a query.
* @param query query to be executed
* @return list of serialized result items
* @throws IOException error during query execution
*/
private StringList execute(final WebDAVQuery query) throws IOException {
if(module == null) {
final ClassLoader cl = getClass().getClassLoader();
final InputStream is = cl.getResourceAsStream(FILE);
if(is == null) throw new IOException("WebDAV module not found: " + FILE);
module = string(new IOStream(is).read());
}
try(QueryProcessor qp = new QueryProcessor(query.toString(), conn.context)) {
for(final Entry<String, String> entry : query.entries()) {
qp.bind(entry.getKey(), entry.getValue());
}
qp.qc.parseLibrary(module, FILE, qp.sc);
final StringList items = new StringList();
final ArrayOutput ao = new ArrayOutput();
final Serializer ser = qp.getSerializer(ao);
for(final Item it : qp.value()) {
ser.serialize(it);
items.add(ao.toString());
ao.reset();
}
return items;
} catch(final Exception ex) {
Util.errln(ex.getMessage());
throw new BaseXException(ex);
}
}
}