org.kuali.coeus.common.impl.attachment.KcAttachmentDataDaoImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.coeus.common.impl.attachment.KcAttachmentDataDaoImpl.java

Source

/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 * 
 * Copyright 2005-2015 Kuali, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kuali.coeus.common.impl.attachment;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.kuali.coeus.common.framework.attachment.KcAttachmentDataDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Component("kcAttachmentDataDao")
public class KcAttachmentDataDaoImpl implements KcAttachmentDataDao {

    private static Log LOG = LogFactory.getLog(KcAttachmentDataDaoImpl.class);

    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;

    private Set<TableReference> tableReferences;

    @Override
    public byte[] getData(String id) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Fetching attachment data existing id: " + id);
        }

        if (StringUtils.isNotBlank(id)) {
            try (Connection connection = getDataSource().getConnection();
                    PreparedStatement stmt = connection
                            .prepareStatement("select data from file_data where id = ?")) {
                stmt.setString(1, id);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        return rs.getBytes(1);
                    } else {
                        return null;
                    }
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        } else {
            return null;
        }
    }

    @Override
    public String saveData(byte[] attachmentData, String id) {
        if (ArrayUtils.isEmpty(attachmentData)) {
            throw new IllegalArgumentException("attachmentData is null");
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Saving attachment data, existing id: " + id);
        }

        try (Connection connection = getDataSource().getConnection()) {
            try (PreparedStatement stmt = connection
                    .prepareStatement("insert into file_data (id, data) values (?, ?)")) {
                String newId = UUID.randomUUID().toString();
                stmt.setString(1, newId);
                try (ByteArrayInputStream is = new ByteArrayInputStream(attachmentData)) {
                    stmt.setBinaryStream(2, is, attachmentData.length);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                stmt.executeUpdate();

                if (LOG.isDebugEnabled()) {
                    LOG.debug("Created attachment data, new id: " + newId);
                }

                if (StringUtils.isNotBlank(id)) {
                    deleteAttachment(connection, id);
                }

                return newId;
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void removeData(String id) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Removing attachment data, existing id: " + id);
        }

        if (StringUtils.isNotBlank(id)) {
            try (Connection conn = dataSource.getConnection()) {
                deleteAttachment(conn, id);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    protected void deleteAttachment(Connection conn, String id) throws SQLException {
        if (countReferences(conn, id) == 0) {
            try (PreparedStatement stmt = conn.prepareStatement("delete from file_data where id = ?")) {
                stmt.setString(1, id);
                stmt.executeUpdate();
            }
        }
    }

    protected int countReferences(Connection conn, String id) throws SQLException {
        if (tableReferences == null) {
            populateReferences(conn);
        }
        int count = 0;
        for (TableReference ref : tableReferences) {
            try (PreparedStatement stmt = conn.prepareStatement(
                    "select count(*) from " + ref.tableName + " where " + ref.columnName + " = ?")) {
                stmt.setString(1, id);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        count += rs.getInt(1);
                    }
                }
            }
        }
        return count;
    }

    protected void populateReferences(Connection conn) throws SQLException {
        tableReferences = new HashSet<>();
        String catalog = conn.getCatalog();
        String schema = catalog;

        // this indicates a non-mysql db, so try oracle.
        if (catalog == null) {
            schema = conn.getSchema();
        }
        try {
            if (conn.getMetaData().getSchemas().next()) {
                schema = conn.getSchema();
            }
        } catch (AbstractMethodError e) {
            LOG.info("Unable to retrieve schema, using catalog " + e.getMessage());
        }

        // The Oracle database stores its table names as Upper-Case,
        // if you pass a table name in lowercase characters, it will not work.
        // MySQL does not care.
        ResultSet rs = conn.getMetaData().getExportedKeys(catalog, schema, "FILE_DATA");
        while (rs.next()) {
            tableReferences.add(new TableReference(rs.getString("FKTABLE_NAME"), rs.getString("FKCOLUMN_NAME")));
        }
    }

    public DataSource getDataSource() {
        return dataSource;
    }

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

    class TableReference {
        public String tableName;
        public String columnName;

        public TableReference(String tableName, String columnName) {
            this.tableName = tableName;
            this.columnName = columnName;
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37).append(tableName).append(columnName).toHashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            final TableReference other = (TableReference) obj;
            return new EqualsBuilder().append(tableName, other.tableName).append(columnName, other.columnName)
                    .isEquals();
        }
    }

    public Set<TableReference> getTableReferences() {
        return tableReferences;
    }

    public void setTableReferences(Set<TableReference> tableReferences) {
        this.tableReferences = tableReferences;
    }
}