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

rapture.repo.postgres.PostgresFolderHandler Maven / Gradle / Ivy

/**
 * Copyright (C) 2011-2015 Incapture Technologies LLC
 *
 * This is an autogenerated license statement. When copyright notices appear below
 * this one that copyright supercedes this statement.
 *
 * Unless required by applicable law or agreed to in writing, software is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied.
 *
 * Unless explicit permission obtained in writing this software cannot be distributed.
 */
package rapture.repo.postgres;

import rapture.common.RaptureFolderInfo;
import rapture.common.exception.ExceptionToString;
import rapture.postgres.PostgresException;
import rapture.postgres.PostgresFactory;
import rapture.postgres.PostgresHelper;
import rapture.postgres.TemplateLoader;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
 *
 * @author alanmoore
 */
public class PostgresFolderHandler {
    private static Logger log = Logger.getLogger(PostgresFolderHandler.class);
    private String tableName;
    private String folderTable;
    private Cache seriesCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(20000).expireAfterAccess(1,
            TimeUnit.MINUTES).build();
    private NamedParameterJdbcTemplate namedJdbcTemplate;

    public PostgresFolderHandler(String instanceName, String tableName) {
        PostgresSanitizer sanitizer = PostgresFactory.getSanitizer(instanceName);
        this.tableName = sanitizer.sanitizeTableName(tableName);
        this.folderTable = sanitizer.sanitizeTableName(tableName + "_folder");
    }

    public void setDataSource(DataSource dataSource) {
        this.namedJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    }

    private void setupEnum() {
        try {
            Boolean exists = namedJdbcTemplate.getJdbcOperations()
                    .queryForObject("SELECT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'foldertype')", Boolean.class);
            if (!exists) {
                log.debug("folderType enum does not exist, creating");
                namedJdbcTemplate.getJdbcOperations().execute("CREATE TYPE folderType as ENUM ('folder', 'doc');");
            }
        } catch (DataAccessException e) {
            log.error("Could not create folder type enum: " + ExceptionToString.format(e));
        }
    }

    public void initialize() {
        // Check to see if the tables exist. If they don't, create them
        setupEnum();
        log.debug("Checking that " + folderTable + " exists");
        boolean exists = false;
        boolean skip = false;
        try {
            exists = PostgresHelper.tableExists(namedJdbcTemplate, folderTable);
        } catch (PostgresException e) {
            log.error(ExceptionToString.format(e));
            skip = true; //skip, stuff is broken!
        }

        if (!skip) {
            if (!exists) {
                log.info("Table " + folderTable + " does not exist, creating");
                namedJdbcTemplate.getJdbcOperations().execute(String.format("CREATE TABLE %s (\n"
                        + "    ID VARCHAR(1024) NOT NULL,\n"
                        + "    SUB VARCHAR(1024) NOT NULL,\n"
                        + "    N folderType NOT NULL,\n"
                        + "    PRIMARY KEY(ID, SUB)\n"
                        + ");\n", folderTable));
            }
            String sql = String.format(TemplateLoader.getResourceAsString("/sqltemplates/insertFolderFunc.sql"), tableName, folderTable);
            namedJdbcTemplate.update(sql, new MapSqlParameterSource());
        }
    }

    public void removeKey(String key) {
        if (key.contains("/")) {
            int lastIndex = key.lastIndexOf("/");
            if (lastIndex > 0) {
                String parent = StringUtils.prependIfMissing(key.substring(0, lastIndex), "/");
                if (lastIndex < key.length() - 1) {
                    String child = key.substring(lastIndex + 1, key.length());
                    delete(parent, child);

                    if (getChildren(parent).size() == 0){
                        lastIndex = parent.lastIndexOf("/");
                        String parentFolder = parent.substring(lastIndex+1);
                        String grandParent = StringUtils.prependIfMissing(parent.substring(0, lastIndex), "/");
                        delete(grandParent, parentFolder);
                    }
                } else {
                    log.error(String.format("Cannot delete key ending in slash, bad input: [%s]", key));
                }
            } else {
                delete("/", key);
            }
        }
    }

    private void delete(String parent, String child) {
        String sql = String.format("DELETE FROM %s\n"
                + "WHERE id=:parent AND sub=:child", folderTable);

        MapSqlParameterSource parameterSource = new MapSqlParameterSource().addValue("parent", parent, Types.VARCHAR).addValue("child", child, Types.VARCHAR);
        namedJdbcTemplate.update(sql, parameterSource);
    }

    public List getChildren(String prefix) {
        if (!prefix.startsWith("/")) {
            prefix = "/" + prefix;
        }
        String sql = String.format("SELECT SUB, N FROM %s WHERE ID=:prefix;", folderTable);
        SqlParameterSource paramSource = new MapSqlParameterSource("prefix", prefix);
        RowMapper rowMapper = new RowMapper() {
            @Override
            public RaptureFolderInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                String value = rs.getString(1);
                String nature = rs.getObject(2).toString();
                RaptureFolderInfo info = new RaptureFolderInfo();
                info.setName(value);
                info.setFolder(nature.equals("folder"));
                return info;

            }
        };
        return namedJdbcTemplate.query(sql, paramSource, rowMapper);
    }

    public boolean drop() {
        String sql = String.format("DROP TABLE %2$s;\n"
                + "DROP FUNCTION IF EXISTS rap_insertf_%1$s(character, character, text);\n", tableName, folderTable);
        namedJdbcTemplate.getJdbcOperations().execute(sql);
        return true;
    }

    public void addKey(String key) {
        boolean isPresent = seriesCache.getIfPresent(key) != null;
        if (!isPresent) {
            // A key is x/y/z
            // We need to add / - x
            // Then x -> y
            // y -> z (doc)
            log.debug("Key is " + key);
            String[] parts = key.split("/");
            String parent = "/";
            for (int i = 0; i < parts.length; i++) {
                String sub = parts[i];
                String nature = (i < parts.length - 1) ? "folder" : "doc";
                log.debug(String.format("Would add %s -> %s as %s", parent, sub, nature));
                String sql = String.format("SELECT rap_insertF_%s(:parent, :sub, :nature);", tableName);
                log.debug("SQL is " + sql);
                SqlParameterSource paramSource = new MapSqlParameterSource("parent", parent).addValue("sub", sub).addValue("nature", nature);
                RowMapper rowMapper = new RowMapper() {
                    @Override
                    public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return true;
                    }
                };
                namedJdbcTemplate.query(sql, paramSource, rowMapper);
                parent = parent + (parent.endsWith("/") ? "" : "/") + sub;
            }
            seriesCache.put(key, true);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy