package cz.benky.webdav.dao;
import com.netflix.astyanax.Keyspace;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
import com.netflix.astyanax.model.CqlResult;
import com.netflix.astyanax.model.Row;
import cz.benky.webdav.util.CassandraUtils;
import cz.benky.webdav.util.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import static cz.benky.webdav.util.PathUtils.removeFirstSlash;
import static cz.benky.webdav.util.CassandraUtils.ROOT_UUID;
public class CassandraDao {
protected static final String CURRENT_DIR = ".";
private final Keyspace keyspace;
public CassandraDao() {
this.keyspace = CassandraUtils.getConnection();
}
public boolean isFile(String path) {
try {
final UUID entryId = getResourceUUID(ROOT_UUID, path);
if (entryId == null) {
return false;
}
final OperationResult<CqlResult<String, String>> execute = keyspace
.prepareQuery(CassandraUtils.CQL3_CF)
.withCql("SELECT file FROM file WHERE file=?")
.asPreparedStatement()
.withUUIDValue(entryId)
.execute();
return !execute.getResult().getRows().isEmpty();
} catch (ConnectionException ignore) {
return false;
}
}
public List<String> getSiblings(final String path) {
final List<String> result = new LinkedList<String>();
try {
final UUID resourceUUID = getResourceUUID(ROOT_UUID, path);
final OperationResult<CqlResult<String, String>> execute = keyspace
.prepareQuery(CassandraUtils.CQL3_CF)
.withCql("SELECT child FROM directory WHERE pathId=?")
.asPreparedStatement()
.withUUIDValue(resourceUUID)
.execute();
for (Row<String, String> row : execute.getResult().getRows()) {
final String fileName = row.getColumns().getStringValue("child", null);
if (CURRENT_DIR.equals(fileName)) {
continue;
}
result.add(fileName);
}
return result;
} catch (ConnectionException e) {
throw new RuntimeException(e);
}
}
public boolean resourceExists(String path) {
try {
return getResourceUUID(ROOT_UUID, path) != null;
} catch (ConnectionException ignore) {
return false;
}
}
private UUID createSubdirectory(UUID root, String name) throws ConnectionException {
final UUID newResourceId = UUID.randomUUID();
createEntityInDirectory(root, name, newResourceId);
createEntityInDirectory(newResourceId, ".", newResourceId);
return newResourceId;
}
public void createEntityInDirectory(UUID root, String name, UUID newResourceId) throws ConnectionException {
keyspace
.prepareQuery(CassandraUtils.CQL3_CF)
.withCql("INSERT INTO directory (pathId, child, childId) VALUES (?, ?, ?)")
.asPreparedStatement()
.withUUIDValue(root)
.withStringValue(name)
.withUUIDValue(newResourceId)
.execute();
}
public UUID getFile(final String path) {
try {
return getResourceUUID(ROOT_UUID, path);
} catch (ConnectionException e) {
throw new RuntimeException(e);
}
}
public void createDirectory(String path) {
path = StringUtils.chomp(path, "/");
if (StringUtils.isEmpty(path)) {
return;
}
try {
String tmpPath = path;
UUID rootDir = ROOT_UUID;
do {
final String[] directories = StringUtils.split(removeFirstSlash(tmpPath), "/", 2);
if (StringUtils.isEmpty(ArrayUtils.get(directories, 0))) {
break;
}
final String directoryName = directories[0];
final UUID resourceUUID = getResourceUUID(rootDir, directoryName);
if (resourceUUID != null) {
rootDir = resourceUUID;
} else {
createSubdirectory(rootDir, directoryName);
}
tmpPath = ArrayUtils.get(directories, 1);
} while (true);
} catch (ConnectionException e) {
e.printStackTrace();
}
}
private UUID getResourceUUID(final UUID root, final String path) throws ConnectionException {
final String[] split = StringUtils.split(removeFirstSlash(path), "/", 2);
if (StringUtils.isEmpty(ArrayUtils.get(split, 0))) {
return root;
}
final UUID childId = getChildUUID(root, split[0]);
if (childId == null) {
return null;
} else {
final String restOfPath = ArrayUtils.get(split, 1);
return !StringUtils.isEmpty(restOfPath) ? getResourceUUID(childId, restOfPath) : childId;
}
}
private UUID getChildUUID(final UUID root, final String directoryName) throws ConnectionException {
final OperationResult<CqlResult<String, String>> execute = keyspace
.prepareQuery(CassandraUtils.CQL3_CF)
.withCql("SELECT childid FROM directory WHERE pathId=? AND child=?")
.asPreparedStatement()
.withUUIDValue(root)
.withStringValue(directoryName)
.execute();
for (Row<String, String> row : execute.getResult().getRows()) {
return row.getColumns().getUUIDValue("childid", null);
}
return null;
}
public void deleteFromDirectory(UUID parent, String fileName) throws ConnectionException {
keyspace
.prepareQuery(CassandraUtils.CQL3_CF)
.withCql("DELETE FROM directory WHERE pathId=? AND child=?")
.asPreparedStatement()
.withUUIDValue(parent)
.withStringValue(fileName)
.execute();
}
}