All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rapture.repo.cassandra.CassandraKeyStore Maven / Gradle / Ivy

The newest version!
/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2011-2016 Incapture Technologies LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package rapture.repo.cassandra;

import rapture.cassandra.CassandraConstants;
import rapture.common.RaptureFolderInfo;
import rapture.common.RaptureNativeQueryResult;
import rapture.common.RaptureQueryResult;
import rapture.common.exception.RaptNotSupportedException;
import rapture.common.exception.RaptureExceptionFactory;
import rapture.common.impl.jackson.JsonContent;
import rapture.index.IndexProducer;
import rapture.index.IndexHandler;
import rapture.repo.KeyStore;
import rapture.repo.RepoLockHandler;
import rapture.repo.RepoVisitor;
import rapture.repo.StoreKeyVisitor;
import rapture.repo.cassandra.key.PathBuilder;

import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/*
 * A key store is a relation store. The keys will be rows, the value will be in a special column
 * storing a document (the string)
 * 
 * The folderHandling needs to solve the main request problem - what are the immediate children of the
 * given folder, and are those children themselves folders or documents. The prefix will be a row, the
 * children will be named columns associated with that row, the data will be a structure that determines
 * how many hits there are (so we can update it and possibly remove it) or, if the content is -1 then the child
 * is a document.
 */

public class CassandraKeyStore implements KeyStore {

    private CassFolderHandler folderHandler;
    private AstyanaxRepoConnection repoConnection;
    private String instance = "default";
    private Map config;
    private boolean usesFolderHandling = true;
    private boolean useVersionedRepoConnection = false;

    @Override
    public void setConfig(Map config) {
        this.config = config;
        if (useVersionedRepoConnection) {
            repoConnection = new AstyanaxVersionedRepoConnection(instance, this.config);
        }
        else {
            repoConnection = new AstyanaxRepoConnection(instance, this.config);
        }

        folderHandler = new CassFolderHandler(repoConnection, repoConnection.getColumnFamilyName());
    }

    public void setUseVersionedRepoConnection(Boolean useIt) {
        useVersionedRepoConnection = useIt;
    }

    @Override
    public void resetFolderHandling() {
        usesFolderHandling = false;
    }

    @Override
    public boolean containsKey(String ref) {
        // Is the given row available with the column name 'data'
        return get(ref) != null;
    }

    @Override
    public long countKeys() throws RaptNotSupportedException {
        // This is a bit tricky - it is basically "how many rows do we have"
        return 0;
    }

    @Override
    public KeyStore createRelatedKeyStore(String relation) {
        // Setup a config like this, but with the columnFamily adjusted to add
        // the relation, then
        // fire it up.
        Map configCopy = new HashMap(config);
        configCopy.put(CassandraConstants.CFCFG, repoConnection.getColumnFamilyName() + "_" + relation);
        if (repoConnection.getPKeyPrefix().isPresent()) {
            configCopy.put(CassandraConstants.PARTITION_KEY_PREFIX, repoConnection.getPKeyPrefix().get());
        }

        CassandraKeyStore ret = new CassandraKeyStore();
        ret.setInstanceName(this.instance);
        if (relation.equals("version") || relation.equals("meta")) {
            ret.setUseVersionedRepoConnection(true);
        }
        ret.setConfig(configCopy);
        if (!usesFolderHandling) {
            ret.resetFolderHandling();
        }
        return ret;
    }

    @Override
    public boolean delete(String key) {
        // Remove the data column for this row
        // Also update folder handling
        if (usesFolderHandling) {
            folderHandler.removeDocument(key);
        }
        return repoConnection.deleteEntry(key);
    }

    @Override
    public boolean delete(List keys) {
        if (usesFolderHandling) {
            for (String key : keys) {
                folderHandler.removeDocument(key);
            }
        }
        return repoConnection.deleteEntries(keys);
    }

    @Override
    public boolean deleteUpTo(String key, long millisTimestamp) {
        return repoConnection.deleteVersionsUpTo(key, "" + millisTimestamp);
    }

    @Override
    public boolean dropKeyStore() {
        if (usesFolderHandling) {
            folderHandler.drop();
        }
        repoConnection.dropRepo();
        return true;
    }

    @Override
    public String get(String k) {
        return repoConnection.get(k);
    }

    @Override
    public String get(String k, long millisTimestamp) {
        return repoConnection.get(k, Long.toString(millisTimestamp));
    }

    @Override
    public List getBatch(List keys) {
        return repoConnection.batchGet(keys);
    }

    @Override
    public String getStoreId() {
        return repoConnection.getUniqueId();
    }

    @Override
    public void put(String k, String v) {
        repoConnection.putData(k, v);
        if (usesFolderHandling) {
            folderHandler.registerDocument(k);
        }
    }

    @Override
    public void put(String k, long millisTimestamp, String v) {
        repoConnection.putData(k, "" + millisTimestamp, v);
        if (usesFolderHandling) {
            folderHandler.registerDocument(k);
        }
    }

    @Override
    public RaptureQueryResult runNativeQuery(String repoType, List queryParams) {
        throw new UnsupportedOperationException("Native queries not supported in Cassandra yet!");
    }

    @Override
    public RaptureNativeQueryResult runNativeQueryWithLimitAndBounds(String repoType, List queryParams, int limit, int offset) {
        throw new UnsupportedOperationException("Native queries not supported in Cassandra yet!");
    }

    @Override
    public void setInstanceName(String instanceName) {
        this.instance = instanceName;
    }

    @Override
    public void visit(String folderPrefix, RepoVisitor iRepoVisitor) {
        // Look for rows with a data column, starting with the row
        // "folderPrefix" and ending when we
        // see a row key that doesn't begin with folderPrefix
        // Use the folder handling for this.
        if (!usesFolderHandling) {
            throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "No folder handling");
        }
        List thisFolder = folderHandler.getChildren(folderPrefix);
        for (RaptureFolderInfo folder : thisFolder) {
            String fullName = new PathBuilder(folderPrefix).subPath(folder.getName()).build();
            String content = folder.isFolder() ? null : get(fullName);
            JsonContent jc = new JsonContent(content);
            if (!iRepoVisitor.visit(fullName, jc, folder.isFolder())) break;
        }
    }

    @Override
    public void visitKeys(String prefix, StoreKeyVisitor iStoreKeyVisitor) {
        List docKeys = getAllSubKeys(prefix);
        for (String dK : docKeys) {
            String content = get(dK);
            if (!iStoreKeyVisitor.visit(dK, content)) {
                break;
            }
        }
    }

    @Override
    public void visitKeysFromStart(String startPoint, StoreKeyVisitor iStoreKeyVisitor) {
        visitKeys(startPoint, iStoreKeyVisitor);
    }

    @Override
    public List getSubKeys(String prefix) {
        if (usesFolderHandling) {
            return folderHandler.getChildren(prefix);
        }
        throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "No folder handling supported");
    }

    @Override
    public List removeSubKeys(String folder, Boolean force) {
        if (usesFolderHandling) {
            return folderHandler.removeChildren(folder, force);
        }
        throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "No folder handling supported");
    }

    @Override
    public boolean matches(String key, String value) {
        String v = get(key);
        if (v != null) {
            return v.equals(value);
        }
        return false;
    }

    @Override
    public List getAllSubKeys(String prefix) {
        // Recursively retrieve the documents below this displayNamePart by
        // calling getSubKeys multiple times
        // OR use folder handling to store this information during a save (why
        // not... ?)
        if (usesFolderHandling) {
            return folderHandler.getAllChildren(prefix);
        }
        throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "No folder handling supported");
    }

    @Override
    public IndexHandler createIndexHandler(IndexProducer indexProducer) {
        // TODO AM - return an instance of a perspective table store using some
        // prefix
        // from this key store
        return null;
    }

    @Override
    public Boolean validate() {
        return repoConnection.validate();
    }

    @Override
    public long getSize() {
        long result = repoConnection.getRowNumber();
        return result;
    }

    @Override
    public void setRepoLockHandler(RepoLockHandler repoLockHandler) {

    }

    @Override
    public boolean supportsVersionLookupByTime() {
        return true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy