org.jumpmind.symmetric.service.impl.IncomingBatchService.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.service.impl.IncomingBatchService.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jumpmind.symmetric.service.impl;

import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.db.sql.ISqlRowMapper;
import org.jumpmind.db.sql.ISqlTransaction;
import org.jumpmind.db.sql.Row;
import org.jumpmind.db.sql.UniqueKeyException;
import org.jumpmind.db.sql.mapper.DateMapper;
import org.jumpmind.db.sql.mapper.StringMapper;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.db.ISymmetricDialect;
import org.jumpmind.symmetric.model.BatchId;
import org.jumpmind.symmetric.model.IncomingBatch;
import org.jumpmind.symmetric.model.IncomingBatch.Status;
import org.jumpmind.symmetric.service.IClusterService;
import org.jumpmind.symmetric.service.IIncomingBatchService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.util.FormatUtils;

/**
 * @see IIncomingBatchService
 */
public class IncomingBatchService extends AbstractService implements IIncomingBatchService {

    protected IClusterService clusterService;

    @Override
    public List<String> getNodesInError() {
        return sqlTemplate.query(getSql("selectNodesInErrorSql"), new StringMapper());
    }

    public IncomingBatchService(IParameterService parameterService, ISymmetricDialect symmetricDialect,
            IClusterService clusterService) {
        super(parameterService, symmetricDialect);
        this.clusterService = clusterService;
        setSqlMap(new IncomingBatchServiceSqlMap(symmetricDialect.getPlatform(), createSqlReplacementTokens()));
    }

    public void refreshIncomingBatch(IncomingBatch batch) {
        sqlTemplate.queryForObject(getSql("selectIncomingBatchPrefixSql", "findIncomingBatchSql"),
                new IncomingBatchMapper(batch), batch.getBatchId(), batch.getNodeId());
    }

    public IncomingBatch findIncomingBatch(long batchId, String nodeId) {
        if (nodeId != null) {
            return sqlTemplate.queryForObject(getSql("selectIncomingBatchPrefixSql", "findIncomingBatchSql"),
                    new IncomingBatchMapper(), batchId, nodeId);
        } else {
            return sqlTemplate.queryForObject(
                    getSql("selectIncomingBatchPrefixSql", "findIncomingBatchByBatchIdSql"),
                    new IncomingBatchMapper(), batchId);
        }
    }

    public int countIncomingBatchesInError() {
        return sqlTemplate.queryForInt(getSql("countIncomingBatchesErrorsSql"));
    }

    public int countIncomingBatchesInError(String channelId) {
        return sqlTemplate.queryForInt(getSql("countIncomingBatchesErrorsOnChannelSql"), channelId);
    }

    public List<IncomingBatch> findIncomingBatchErrors(int maxRows) {
        return sqlTemplate.query(getSql("selectIncomingBatchPrefixSql", "findIncomingBatchErrorsSql"), maxRows,
                new IncomingBatchMapper());
    }

    public void markIncomingBatchesOk(String nodeId) {
        List<IncomingBatch> batches = listIncomingBatchesInErrorFor(nodeId);
        for (IncomingBatch incomingBatch : batches) {
            if (isRecordOkBatchesEnabled()) {
                incomingBatch.setErrorFlag(false);
                incomingBatch.setStatus(Status.OK);
                updateIncomingBatch(incomingBatch);
            } else {
                deleteIncomingBatch(incomingBatch);
            }
        }
    }

    public void removingIncomingBatches(String nodeId) {
        sqlTemplate.update(getSql("deleteIncomingBatchByNodeSql"), nodeId);
    }

    public List<IncomingBatch> listIncomingBatchesInErrorFor(String nodeId) {
        return sqlTemplate.query(getSql("selectIncomingBatchPrefixSql", "listIncomingBatchesInErrorForNodeSql"),
                new IncomingBatchMapper(), nodeId);
    }

    @SuppressWarnings("deprecation")
    public boolean isRecordOkBatchesEnabled() {
        boolean enabled = true;
        if (!parameterService.is(ParameterConstants.INCOMING_BATCH_RECORD_OK_ENABLED, true)) {
            enabled = false;
        }
        if (parameterService.is(ParameterConstants.INCOMING_BATCH_DELETE_ON_LOAD, false)) {
            enabled = false;
        }
        return enabled;
    }

    public List<Date> listIncomingBatchTimes(List<String> nodeIds, List<String> channels,
            List<IncomingBatch.Status> statuses, boolean ascending) {

        String whereClause = buildBatchWhere(nodeIds, channels, statuses);

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("NODES", nodeIds);
        params.put("CHANNELS", channels);
        params.put("STATUSES", toStringList(statuses));

        String sql = getSql("selectCreateTimePrefixSql", whereClause,
                ascending ? " order by create_time" : " order by create_time desc");
        return sqlTemplate.query(sql, new DateMapper(), params);
    }

    public List<IncomingBatch> listIncomingBatches(List<String> nodeIds, List<String> channels,
            List<IncomingBatch.Status> statuses, Date startAtCreateTime, final int maxRowsToRetrieve,
            boolean ascending) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("NODES", nodeIds);
        params.put("CHANNELS", channels);
        params.put("STATUSES", toStringList(statuses));
        params.put("CREATE_TIME", startAtCreateTime);

        String where = buildBatchWhere(nodeIds, channels, statuses);

        String createTimeLimiter = "";
        if (startAtCreateTime != null) {
            if (StringUtils.isBlank(where)) {
                where = " where 1=1 ";
            }
            createTimeLimiter = " and create_time " + (ascending ? ">=" : "<=") + " :CREATE_TIME";
        }

        String sql = getSql("selectIncomingBatchPrefixSql", where, createTimeLimiter,
                ascending ? " order by create_time" : " order by create_time desc");

        return sqlTemplate.query(sql, maxRowsToRetrieve, new IncomingBatchMapper(), params);

    }

    protected boolean containsOnlyErrorStatus(List<IncomingBatch.Status> statuses) {
        return statuses.size() == 1 && statuses.get(0) == IncomingBatch.Status.ER;
    }

    protected List<String> toStringList(List<IncomingBatch.Status> statuses) {
        List<String> statusStrings = new ArrayList<String>(statuses.size());
        for (Status status : statuses) {
            statusStrings.add(status.name());
        }
        return statusStrings;

    }

    public boolean acquireIncomingBatch(IncomingBatch batch) {
        boolean okayToProcess = true;
        if (batch.isPersistable()) {
            IncomingBatch existingBatch = null;

            if (isRecordOkBatchesEnabled()) {
                try {
                    insertIncomingBatch(batch);
                } catch (UniqueKeyException e) {
                    batch.setRetry(true);
                    existingBatch = findIncomingBatch(batch.getBatchId(), batch.getNodeId());
                }
            } else {
                existingBatch = findIncomingBatch(batch.getBatchId(), batch.getNodeId());
                if (existingBatch != null) {
                    batch.setRetry(true);
                }
            }

            if (batch.isRetry()) {
                if (existingBatch.getStatus() == Status.ER || existingBatch.getStatus() == Status.LD
                        || !parameterService.is(ParameterConstants.INCOMING_BATCH_SKIP_DUPLICATE_BATCHES_ENABLED)) {
                    okayToProcess = true;
                    existingBatch.setStatus(Status.LD);
                    log.info("Retrying batch {}", batch.getNodeBatchId());
                } else if (existingBatch.getStatus() == Status.IG) {
                    okayToProcess = false;
                    batch.setStatus(Status.OK);
                    batch.incrementIgnoreCount();
                    existingBatch.setStatus(Status.OK);
                    existingBatch.incrementIgnoreCount();
                    log.info("Ignoring batch {}", batch.getNodeBatchId());
                } else {
                    okayToProcess = false;
                    batch.setStatus(existingBatch.getStatus());
                    batch.setByteCount(existingBatch.getByteCount());
                    batch.setDatabaseMillis(existingBatch.getDatabaseMillis());
                    batch.setNetworkMillis(existingBatch.getNetworkMillis());
                    batch.setFilterMillis(existingBatch.getFilterMillis());
                    batch.setSkipCount(existingBatch.getSkipCount() + 1);
                    batch.setStatementCount(existingBatch.getStatementCount());

                    existingBatch.setSkipCount(existingBatch.getSkipCount() + 1);
                    log.info("Skipping batch {}", batch.getNodeBatchId());
                }
                updateIncomingBatch(existingBatch);
            }
        }
        return okayToProcess;
    }

    public void insertIncomingBatch(ISqlTransaction transaction, IncomingBatch batch) {
        if (batch.isPersistable()) {
            batch.setLastUpdatedHostName(clusterService.getServerId());
            batch.setLastUpdatedTime(new Date());
            transaction.prepareAndExecute(getSql("insertIncomingBatchSql"),
                    new Object[] { batch.getBatchId(), batch.getNodeId(), batch.getChannelId(),
                            batch.getStatus().name(), batch.getNetworkMillis(), batch.getFilterMillis(),
                            batch.getDatabaseMillis(), batch.getFailedRowNumber(), batch.getFailedLineNumber(),
                            batch.getByteCount(), batch.getStatementCount(), batch.getFallbackInsertCount(),
                            batch.getFallbackUpdateCount(), batch.getIgnoreCount(), batch.getMissingDeleteCount(),
                            batch.getSkipCount(), batch.getSqlState(), batch.getSqlCode(),
                            FormatUtils.abbreviateForLogging(batch.getSqlMessage()), batch.getLastUpdatedHostName(),
                            batch.getLastUpdatedTime() },
                    new int[] { Types.NUMERIC, Types.VARCHAR, Types.VARCHAR, Types.CHAR, Types.NUMERIC,
                            Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC,
                            Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC,
                            Types.NUMERIC, Types.VARCHAR, Types.NUMERIC, Types.VARCHAR, Types.VARCHAR,
                            Types.TIMESTAMP });
        }
    }

    public void insertIncomingBatch(IncomingBatch batch) {
        ISqlTransaction transaction = null;
        try {
            transaction = sqlTemplate.startSqlTransaction();
            insertIncomingBatch(transaction, batch);
            transaction.commit();
        } catch (Error ex) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw ex;
        } catch (RuntimeException ex) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw ex;
        } finally {
            close(transaction);
        }
    }

    public int deleteIncomingBatch(IncomingBatch batch) {
        return sqlTemplate.update(getSql("deleteIncomingBatchSql"),
                new Object[] { batch.getBatchId(), batch.getNodeId() },
                new int[] { symmetricDialect.getSqlTypeForIds(), Types.VARCHAR });
    }

    public int updateIncomingBatch(IncomingBatch batch) {
        ISqlTransaction transaction = null;
        try {
            transaction = sqlTemplate.startSqlTransaction();
            int count = updateIncomingBatch(transaction, batch);
            transaction.commit();
            return count;
        } catch (Error ex) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw ex;
        } catch (RuntimeException ex) {
            if (transaction != null) {
                transaction.rollback();
            }
            throw ex;
        } finally {
            close(transaction);
        }
    }

    public int updateIncomingBatch(ISqlTransaction transaction, IncomingBatch batch) {
        int count = 0;
        if (batch.isPersistable()) {
            if (batch.getStatus() == IncomingBatch.Status.ER) {
                batch.setErrorFlag(true);
            } else if (batch.getStatus() == IncomingBatch.Status.OK) {
                batch.setErrorFlag(false);
            }
            batch.setLastUpdatedHostName(clusterService.getServerId());
            batch.setLastUpdatedTime(new Date());
            count = transaction.prepareAndExecute(getSql("updateIncomingBatchSql"),
                    new Object[] { batch.getStatus().name(), batch.isErrorFlag() ? 1 : 0, batch.getNetworkMillis(),
                            batch.getFilterMillis(), batch.getDatabaseMillis(), batch.getFailedRowNumber(),
                            batch.getFailedLineNumber(), batch.getByteCount(), batch.getStatementCount(),
                            batch.getFallbackInsertCount(), batch.getFallbackUpdateCount(), batch.getIgnoreCount(),
                            batch.getMissingDeleteCount(), batch.getSkipCount(), batch.getSqlState(),
                            batch.getSqlCode(), FormatUtils.abbreviateForLogging(batch.getSqlMessage()),
                            batch.getLastUpdatedHostName(), batch.getLastUpdatedTime(), batch.getBatchId(),
                            batch.getNodeId() },
                    new int[] { Types.CHAR, Types.SMALLINT, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC,
                            Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC,
                            Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.VARCHAR,
                            Types.NUMERIC, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP,
                            symmetricDialect.getSqlTypeForIds(), Types.VARCHAR });
        }
        return count;
    }

    public Map<String, BatchId> findMaxBatchIdsByChannel() {
        Map<String, BatchId> ids = new HashMap<String, BatchId>();
        sqlTemplate.query(getSql("maxBatchIdsSql"), new BatchIdMapper(ids), IncomingBatch.Status.OK.name());
        return ids;
    }

    class BatchIdMapper implements ISqlRowMapper<BatchId> {
        Map<String, BatchId> ids;

        public BatchIdMapper(Map<String, BatchId> ids) {
            this.ids = ids;
        }

        public BatchId mapRow(Row rs) {
            BatchId batch = new BatchId();
            batch.setBatchId(rs.getLong("batch_id"));
            batch.setNodeId(rs.getString("node_id"));
            ids.put(rs.getString("channel_id"), batch);
            return batch;
        }
    }

    class IncomingBatchMapper implements ISqlRowMapper<IncomingBatch> {

        IncomingBatch batchToRefresh = null;

        public IncomingBatchMapper(IncomingBatch batchToRefresh) {
            this.batchToRefresh = batchToRefresh;
        }

        public IncomingBatchMapper() {
        }

        public IncomingBatch mapRow(Row rs) {
            IncomingBatch batch = batchToRefresh != null ? batchToRefresh : new IncomingBatch();
            batch.setBatchId(rs.getLong("batch_id"));
            batch.setNodeId(rs.getString("node_id"));
            batch.setChannelId(rs.getString("channel_id"));
            batch.setStatus(IncomingBatch.Status.valueOf(rs.getString("status")));
            batch.setNetworkMillis(rs.getLong("network_millis"));
            batch.setFilterMillis(rs.getLong("filter_millis"));
            batch.setDatabaseMillis(rs.getLong("database_millis"));
            batch.setFailedRowNumber(rs.getLong("failed_row_number"));
            batch.setFailedLineNumber(rs.getLong("failed_line_number"));
            batch.setByteCount(rs.getLong("byte_count"));
            batch.setStatementCount(rs.getLong("statement_count"));
            batch.setFallbackInsertCount(rs.getLong("fallback_insert_count"));
            batch.setFallbackUpdateCount(rs.getLong("fallback_update_count"));
            batch.setIgnoreCount(rs.getLong("ignore_count"));
            batch.setMissingDeleteCount(rs.getLong("missing_delete_count"));
            batch.setSkipCount(rs.getLong("skip_count"));
            batch.setSqlState(rs.getString("sql_state"));
            batch.setSqlCode(rs.getInt("sql_code"));
            batch.setSqlMessage(rs.getString("sql_message"));
            batch.setLastUpdatedHostName(rs.getString("last_update_hostname"));
            batch.setLastUpdatedTime(rs.getDateTime("last_update_time"));
            batch.setCreateTime(rs.getDateTime("create_time"));
            batch.setErrorFlag(rs.getBoolean("error_flag"));
            return batch;
        }
    }

}