org.easyrec.store.dao.plugin.impl.LogEntryDAOMysqlImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.easyrec.store.dao.plugin.impl.LogEntryDAOMysqlImpl.java

Source

/*
 * Copyright 2011 Research Studios Austria Forschungsgesellschaft mBH
 *
 * This file is part of easyrec.
 *
 * easyrec is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * easyrec 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with easyrec.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.easyrec.store.dao.plugin.impl;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easyrec.model.plugin.LogEntry;
import org.easyrec.plugin.container.PluginRegistry;
import org.easyrec.plugin.generator.Generator;
import org.easyrec.plugin.generator.GeneratorConfiguration;
import org.easyrec.plugin.generator.GeneratorConfigurationConstants;
import org.easyrec.plugin.model.PluginId;
import org.easyrec.plugin.stats.GeneratorStatistics;
import org.easyrec.plugin.stats.StatisticsConstants;
import org.easyrec.store.dao.plugin.LogEntryDAO;
import org.easyrec.utils.spring.store.dao.DaoUtils;
import org.easyrec.utils.spring.store.dao.impl.AbstractTableCreatingDAOImpl;
import org.easyrec.utils.spring.store.service.sqlscript.SqlScriptService;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlFunction;
import org.springframework.jdbc.object.SqlUpdate;

import javax.sql.DataSource;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author patrick
 */
public class LogEntryDAOMysqlImpl extends AbstractTableCreatingDAOImpl implements LogEntryDAO {

    private static Log logger = LogFactory.getLog(LogEntryDAOMysqlImpl.class);

    private static GeneratorConfiguration unmarshalConfiguration(String pluginIdAndVersion,
            String configurationString, PluginRegistry pluginRegistry) {
        try {
            Generator<?, ?> generator = Preconditions
                    .checkNotNull(pluginRegistry.getGenerators().get(PluginId.parsePluginId(pluginIdAndVersion)));

            StringReader xmlRepresentation = new StringReader(configurationString);
            StreamSource streamSource = new StreamSource(xmlRepresentation);
            JAXBContext jaxbContext = JAXBContext.newInstance(generator.getConfigurationClass(),
                    GeneratorConfigurationConstants.CONF_MARSHAL_FAILED.getClass(),
                    GeneratorConfigurationConstants.CONF_UNMARSHAL_FAILED.getClass());
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            JAXBElement<? extends GeneratorConfiguration> jaxbElement = unmarshaller.unmarshal(streamSource,
                    generator.getConfigurationClass());

            return jaxbElement.getValue();
        } catch (Exception e) {
            logger.warn("Unable to unmarshal configuration");
            return GeneratorConfigurationConstants.CONF_UNMARSHAL_FAILED;
        }
    }

    private static GeneratorStatistics unmarshalStatistics(String pluginIdAndVersion, String statisticsString,
            PluginRegistry pluginRegistry) {
        try {
            Generator<?, ?> generator = Preconditions
                    .checkNotNull(pluginRegistry.getGenerators().get(PluginId.parsePluginId(pluginIdAndVersion)));

            StringReader xmlRepresentation = new StringReader(statisticsString);
            StreamSource streamSource = new StreamSource(xmlRepresentation);
            JAXBContext jaxbContext = JAXBContext.newInstance(generator.getStatisticsClass(),
                    StatisticsConstants.STATS_MARSHAL_FAILED.getClass(),
                    StatisticsConstants.STATS_FORCED_END.getClass(),
                    StatisticsConstants.STATS_UNMARSHAL_FAILED.getClass(),
                    StatisticsConstants.STATS_EXECUTION_FAILED.getClass());
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

            JAXBElement<? extends GeneratorStatistics> jaxbElement = unmarshaller.unmarshal(streamSource,
                    generator.getStatisticsClass());

            return jaxbElement.getValue();
        } catch (Exception e) {
            logger.warn("Unable to unmarshal configuration");
            return StatisticsConstants.STATS_UNMARSHAL_FAILED;
        }
    }

    private static final String FORCED_END_MARSHALED = StatisticsConstants.STATS_FORCED_END.marshal();

    private SqlUpdate startEntry;
    private SqlUpdate endEntry;
    private SqlUpdate endAllEntries;
    private MappingSqlQuery<Integer> getRunningTenants;
    private GetLogEntriesStatement getLogEntries;
    private GetLogEntriesStatement getLogEntriesWithAssocType;
    private GetLogEntriesStatement getLogEntriesForTenant;
    private SqlFunction<Integer> getNumberOfLogEntries;
    private SqlFunction<Integer> getNumberOfLogEntriesForTenant;
    private GetLogEntriesStatement getLogEntriesForTenantWithAssocType;
    private SqlUpdate deleteLogEntries;
    private SqlFunction<Integer> getComputationDurationForDate;
    private SqlUpdate deleteLogEntryStatement;

    protected LogEntryDAOMysqlImpl(DataSource dataSource, SqlScriptService sqlScriptService,
            PluginRegistry pluginRegistry) {
        super(sqlScriptService);
        setDataSource(dataSource);

        startEntry = new SqlUpdate(dataSource,
                "INSERT INTO plugin_log(tenantId, pluginId, pluginVersion, startDate, assocTypeId, "
                        + "configuration) VALUES (?, ?, ?, ?, ?, ?)",
                new int[] { Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR,
                        Types.BLOB });
        startEntry.compile();

        endEntry = new SqlUpdate(dataSource,
                "INSERT INTO plugin_log(tenantId, pluginId, pluginVersion, startDate, assocTypeId, configuration, "
                        + "endDate, statistics) VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
                        + "ON DUPLICATE KEY UPDATE endDate = ?, statistics = ?",
                new int[] { Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR, Types.BLOB,
                        Types.TIMESTAMP, Types.BLOB, Types.TIMESTAMP, Types.BLOB });
        endEntry.compile();

        endAllEntries = new SqlUpdate(dataSource,
                "UPDATE plugin_log SET endDate = ?, statistics = ? WHERE endDate IS NULL",
                new int[] { Types.TIMESTAMP, Types.BLOB });
        endAllEntries.compile();

        getRunningTenants = new MappingSqlQuery<Integer>(dataSource,
                "SELECT tenantId FROM plugin_log WHERE endDate IS NULL") {
            @Override
            protected Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
                return rs.getInt("tenantId");
            }
        };
        getRunningTenants.compile();

        getLogEntries = new GetLogEntriesStatement(dataSource, pluginRegistry,
                "SELECT * FROM plugin_log ORDER BY endDate DESC, id DESC LIMIT ?, ?");
        getLogEntries.declareParameter(new SqlParameter("offset", Types.INTEGER));
        getLogEntries.declareParameter(new SqlParameter("limit", Types.INTEGER));
        getLogEntries.compile();

        getLogEntriesForTenant = new GetLogEntriesStatement(dataSource, pluginRegistry,
                "SELECT * FROM plugin_log WHERE tenantId = ? ORDER BY startDate DESC, id DESC LIMIT ?, ?");
        getLogEntriesForTenant.declareParameter(new SqlParameter("tenantId", Types.INTEGER));
        getLogEntriesForTenant.declareParameter(new SqlParameter("offset", Types.INTEGER));
        getLogEntriesForTenant.declareParameter(new SqlParameter("limit", Types.INTEGER));
        getLogEntriesForTenant.compile();

        getLogEntriesWithAssocType = new GetLogEntriesStatement(dataSource, pluginRegistry,
                "SELECT * FROM plugin_log WHERE assocTypeId = ? ORDER BY startDate DESC, id DESC LIMIT ?, ?");
        getLogEntriesWithAssocType.declareParameter(new SqlParameter("assocTypeId", Types.INTEGER));
        getLogEntriesWithAssocType.declareParameter(new SqlParameter("offset", Types.INTEGER));
        getLogEntriesWithAssocType.declareParameter(new SqlParameter("limit", Types.INTEGER));
        getLogEntriesWithAssocType.compile();

        getLogEntriesForTenantWithAssocType = new GetLogEntriesStatement(dataSource, pluginRegistry,
                "SELECT * FROM plugin_log WHERE tenantId = ? AND assocTypeId = ? ORDER BY startDate DESC, id DESC LIMIT ?, ?");
        getLogEntriesForTenantWithAssocType.declareParameter(new SqlParameter("tenantId", Types.INTEGER));
        getLogEntriesForTenantWithAssocType.declareParameter(new SqlParameter("assocTypeId", Types.INTEGER));
        getLogEntriesForTenantWithAssocType.declareParameter(new SqlParameter("offset", Types.INTEGER));
        getLogEntriesForTenantWithAssocType.declareParameter(new SqlParameter("limit", Types.INTEGER));
        getLogEntriesForTenantWithAssocType.compile();

        getNumberOfLogEntries = new SqlFunction<Integer>(dataSource,
                "SELECT count(*) AS entry_count FROM plugin_log");
        getNumberOfLogEntries.compile();

        getNumberOfLogEntriesForTenant = new SqlFunction<Integer>(dataSource,
                "SELECT count(*) AS entry_count FROM plugin_log WHERE tenantId = ?");
        getNumberOfLogEntriesForTenant.setResultType(Integer.class);
        getNumberOfLogEntriesForTenant.declareParameter(new SqlParameter("tenantId", Types.INTEGER));
        getNumberOfLogEntriesForTenant.compile();

        deleteLogEntries = new SqlUpdate(dataSource, "TRUNCATE plugin_log");
        deleteLogEntries.compile();

        getComputationDurationForDate = new SqlFunction<Integer>(dataSource,
                "SELECT sum(timestampdiff(second, startDate, endDate)) AS sum_seconds FROM plugin_log WHERE endDate BETWEEN ? AND ?");
        getComputationDurationForDate.setResultType(Integer.class);
        getComputationDurationForDate.declareParameter(new SqlParameter("start", Types.DATE));
        getComputationDurationForDate.declareParameter(new SqlParameter("end", Types.DATE));
        getComputationDurationForDate.compile();

        deleteLogEntryStatement = new SqlUpdate(dataSource,
                "DELETE FROM plugin_log WHERE tenantId = ? AND pluginId = ? AND pluginVersion = ? AND startDate = ? AND assocTypeId = ?");
        deleteLogEntryStatement.declareParameter(new SqlParameter("tenantId", Types.INTEGER));
        deleteLogEntryStatement.declareParameter(new SqlParameter("pluginId", Types.VARCHAR));
        deleteLogEntryStatement.declareParameter(new SqlParameter("pluginVersion", Types.VARCHAR));
        deleteLogEntryStatement.declareParameter(new SqlParameter("startDate", Types.TIMESTAMP));
        deleteLogEntryStatement.declareParameter(new SqlParameter("assocTypeId", Types.VARCHAR));
        deleteLogEntryStatement.compile();
    }

    @Override
    public String getDefaultTableName() {
        return "plugin_log";
    }

    @Override
    public String getTableCreatingSQLScriptName() {
        return "classpath:sql/pluginContainer/PluginLog.sql";
    }

    @Override
    public void startEntry(LogEntry entry) {
        Preconditions.checkNotNull(entry);
        Preconditions.checkNotNull(entry.getPluginId());
        Preconditions.checkNotNull(entry.getPluginId().getUri());
        Preconditions.checkNotNull(entry.getPluginId().getVersion());
        Preconditions.checkNotNull(entry.getStartDate());
        Preconditions.checkNotNull(entry.getConfiguration());

        String serializedConfiguration = entry.getConfiguration().marshal();

        startEntry.update(entry.getTenantId(), entry.getPluginId().getUri().toASCIIString(),
                entry.getPluginId().getVersion().toString(), entry.getStartDate(), entry.getAssocTypeId(),
                serializedConfiguration);
    }

    @Override
    public void endEntry(LogEntry entry) {
        Preconditions.checkNotNull(entry);
        Preconditions.checkNotNull(entry.getPluginId());
        Preconditions.checkNotNull(entry.getPluginId().getUri());
        Preconditions.checkNotNull(entry.getPluginId().getVersion());
        Preconditions.checkNotNull(entry.getStartDate());
        Preconditions.checkNotNull(entry.getConfiguration());
        Preconditions.checkNotNull(entry.getStatistics());
        Preconditions.checkArgument(
                entry.getStartDate().before(entry.getEndDate()) || entry.getStartDate().equals(entry.getEndDate()),
                "startDate must be before endDate, or startDate = endDate");

        String serializedConfiguration = entry.getConfiguration().marshal();
        String serializedStatistics = entry.getStatistics().marshal();

        endEntry.update(entry.getTenantId(), entry.getPluginId().getUri().toASCIIString(),
                entry.getPluginId().getVersion().toString(), entry.getStartDate(), entry.getAssocTypeId(),
                serializedConfiguration, entry.getEndDate(), serializedStatistics, entry.getEndDate(),
                serializedStatistics);
    }

    @Override
    public void endAllEntries(Date endDate) {
        Preconditions.checkNotNull(endDate);

        endAllEntries.update(endDate, FORCED_END_MARSHALED);
    }

    @Override
    public void endAllEntries() {
        Date endDate = new Date();

        endAllEntries(endDate);
    }

    @Override
    public void deleteEntry(LogEntry entry) {
        deleteLogEntryStatement.update(entry.getTenantId(), entry.getPluginId().getUri().toASCIIString(),
                entry.getPluginId().getVersion().toString(), entry.getStartDate(), entry.getAssocTypeId());
    }

    @Override
    public List<Integer> getRunningTenants() {
        return getRunningTenants.execute();
    }

    @Override
    public List<LogEntry> getLogEntries(int offset, int limit) {
        Preconditions.checkArgument(offset >= 0, "offset must be greater than or equal to 0");
        Preconditions.checkArgument(limit >= 0, "limit must be greater than or equal to 0");

        return getLogEntries.execute(offset, limit);
    }

    @Override
    public List<LogEntry> getLogEntriesForTenant(int tenantId, int offset, int limit) {
        Preconditions.checkArgument(offset >= 0, "offset must be greater than or equal to 0");
        Preconditions.checkArgument(limit >= 0, "limit must be greater than or equal to 0");

        return getLogEntriesForTenant.execute(tenantId, offset, limit);
    }

    @Override
    public List<LogEntry> getLogEntries(int assocTypeId, int offset, int limit) {
        Preconditions.checkArgument(offset >= 0, "offset must be greater than or equal to 0");
        Preconditions.checkArgument(limit >= 0, "limit must be greater than or equal to 0");

        return getLogEntriesWithAssocType.execute(assocTypeId, offset, limit);
    }

    @Override
    public List<LogEntry> getLogEntriesForTenant(int tenantId, int assocTypeId, int offset, int limit) {
        Preconditions.checkArgument(offset >= 0, "offset must be greater than or equal to 0");
        Preconditions.checkArgument(limit >= 0, "limit must be greater than or equal to 0");

        return getLogEntriesForTenantWithAssocType.execute(tenantId, assocTypeId, offset, limit);
    }

    @Override
    public int getNumberOfLogEntries() {
        return getNumberOfLogEntries.run();
    }

    @Override
    public int getNumberOfLogEntriesForTenant(int tenantId) {
        return getNumberOfLogEntriesForTenant.run(tenantId);
    }

    @Override
    public void deleteLogEntries() {
        deleteLogEntries.update();
    }

    @Override
    public int getComputationDurationForDate(Date date) {
        Preconditions.checkNotNull(date);

        //following looks unneccesary complicated but is used to avoid SQL Date() function and thus use index on endDate!
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date);
        cal2.set(Calendar.HOUR, 23);
        cal2.set(Calendar.MINUTE, 59);
        cal2.set(Calendar.SECOND, 59);
        cal2.set(Calendar.MILLISECOND, 999);

        Integer result = getComputationDurationForDate.findObject(cal.getTime(), cal2.getTime());

        return Objects.firstNonNull(result, 0);
    }

    @Override
    public int getComputationDurationForDate() {
        Date date = new Date();

        return getComputationDurationForDate(date);
    }

    private static class GetLogEntriesStatement extends MappingSqlQuery<LogEntry> {
        private PluginRegistry pluginRegistry;

        public GetLogEntriesStatement(DataSource ds, PluginRegistry pluginRegistry, String sql) {
            super(ds, sql);
            this.pluginRegistry = pluginRegistry;
        }

        @Override
        public LogEntry mapRow(ResultSet rs, int rowNum) throws SQLException {
            int id = rs.getInt("id");
            int tenantId = rs.getInt("tenantId");
            Date startDate = DaoUtils.getDateIfPresent(rs, "startDate");
            Date endDate = DaoUtils.getDateIfPresent(rs, "endDate");
            int assocTypeId = rs.getInt("assocTypeId");
            String pluginIdStr = rs.getString("pluginId");
            String pluginVersionStr = rs.getString("pluginVersion");
            String configurationStr = rs.getString("configuration");
            String statisticsStr = rs.getString("statistics");
            PluginId pluginId = null;

            try {
                pluginId = new PluginId(pluginIdStr, pluginVersionStr);
            } catch (IllegalArgumentException e) {
                logger.warn("unable to parse pluginId", e);
            }

            String pluginIdAndVersion = pluginIdStr + "/" + pluginVersionStr;

            GeneratorConfiguration configuration = unmarshalConfiguration(pluginIdAndVersion, configurationStr,
                    pluginRegistry);
            GeneratorStatistics statistics = null;

            if (statisticsStr != null)
                statistics = unmarshalStatistics(pluginIdAndVersion, statisticsStr, pluginRegistry);

            return new LogEntry(id, tenantId, pluginId, startDate, endDate, assocTypeId, configuration, statistics);
        }
    }
}