/**
* 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.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
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.mapper.StringMapper;
import org.jumpmind.symmetric.common.Constants;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.db.ISymmetricDialect;
import org.jumpmind.symmetric.ext.IOutgoingBatchFilter;
import org.jumpmind.symmetric.model.Channel;
import org.jumpmind.symmetric.model.NodeChannel;
import org.jumpmind.symmetric.model.NodeGroupChannelWindow;
import org.jumpmind.symmetric.model.NodeGroupLinkAction;
import org.jumpmind.symmetric.model.NodeHost;
import org.jumpmind.symmetric.model.NodeSecurity;
import org.jumpmind.symmetric.model.OutgoingBatch;
import org.jumpmind.symmetric.model.OutgoingBatch.Status;
import org.jumpmind.symmetric.model.OutgoingBatchByNodeChannelCount;
import org.jumpmind.symmetric.model.OutgoingBatchSummary;
import org.jumpmind.symmetric.model.OutgoingBatches;
import org.jumpmind.symmetric.model.OutgoingLoadSummary;
import org.jumpmind.symmetric.service.IClusterService;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IExtensionService;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IOutgoingBatchService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.service.ISequenceService;
import org.jumpmind.util.AppUtils;
import org.jumpmind.util.FormatUtils;
/**
* @see IOutgoingBatchService
*/
public class OutgoingBatchService extends AbstractService implements IOutgoingBatchService {
private INodeService nodeService;
private IConfigurationService configurationService;
private ISequenceService sequenceService;
private IClusterService clusterService;
private IExtensionService extensionService;
public OutgoingBatchService(IParameterService parameterService,
ISymmetricDialect symmetricDialect, INodeService nodeService,
IConfigurationService configurationService, ISequenceService sequenceService,
IClusterService clusterService, IExtensionService extensionService) {
super(parameterService, symmetricDialect);
this.nodeService = nodeService;
this.configurationService = configurationService;
this.sequenceService = sequenceService;
this.clusterService = clusterService;
this.extensionService = extensionService;
setSqlMap(new OutgoingBatchServiceSqlMap(symmetricDialect.getPlatform(),
createSqlReplacementTokens()));
}
@Override
public int cancelLoadBatches(long loadId) {
return sqlTemplate.update(getSql("cancelLoadBatchesSql"), loadId);
}
public void markAllAsSentForNode(String nodeId, boolean includeConfigChannel) {
OutgoingBatches batches = null;
int configCount;
do {
configCount = 0;
batches = getOutgoingBatches(nodeId, true);
List<OutgoingBatch> list = batches.getBatches();
/*
* Sort in reverse order so we don't get fk errors for batches that
* are currently processing. We don't make the update transactional
* to prevent contention in highly loaded systems
*/
Collections.sort(list, new Comparator<OutgoingBatch>() {
public int compare(OutgoingBatch o1, OutgoingBatch o2) {
return -new Long(o1.getBatchId()).compareTo(o2.getBatchId());
}
});
for (OutgoingBatch outgoingBatch : list) {
if (includeConfigChannel || !outgoingBatch.getChannelId().equals(Constants.CHANNEL_CONFIG)) {
outgoingBatch.setStatus(Status.OK);
outgoingBatch.setErrorFlag(false);
updateOutgoingBatch(outgoingBatch);
} else {
configCount++;
}
}
} while (batches.getBatches().size() > configCount);
}
public void markAllConfigAsSentForNode(String nodeId) {
int updateCount;
do {
updateCount = 0;
OutgoingBatches batches = getOutgoingBatches(nodeId, false);
List<OutgoingBatch> list = batches.getBatches();
for (OutgoingBatch outgoingBatch : list) {
if (outgoingBatch.getChannelId().equals(Constants.CHANNEL_CONFIG)) {
outgoingBatch.setStatus(Status.OK);
outgoingBatch.setErrorFlag(false);
outgoingBatch.setIgnoreCount(1);
updateOutgoingBatch(outgoingBatch);
updateCount++;
}
}
} while (updateCount > 0);
}
public void copyOutgoingBatches(String channelId, long startBatchId, String fromNodeId, String toNodeId) {
log.info("Copying outgoing batches for channel '{}' from node '{}' to node '{}' starting at {}", new Object[] {channelId, fromNodeId, toNodeId, startBatchId});
sqlTemplate.update(getSql("deleteOutgoingBatchesForNodeSql"), toNodeId, channelId, fromNodeId, channelId);
int count = sqlTemplate.update(getSql("copyOutgoingBatchesSql"), toNodeId, fromNodeId, channelId, startBatchId);
log.info("Copied {} outgoing batches for channel '{}' from node '{}' to node '{}'", new Object[] {count, channelId, fromNodeId, toNodeId});
}
public void updateAbandonedRoutingBatches() {
int count = sqlTemplate.queryForInt(getSql("countOutgoingBatchesWithStatusSql"), Status.RT.name());
if (count > 0) {
log.info("Cleaning up {} batches that were abandoned by a failed or aborted attempt at routing", count);
sqlTemplate.update(getSql("updateOutgoingBatchesStatusSql"), Status.OK.name(),
Status.RT.name());
}
}
public void updateOutgoingBatches(List<OutgoingBatch> outgoingBatches) {
for (OutgoingBatch batch : outgoingBatches) {
updateOutgoingBatch(batch);
}
}
public void updateOutgoingBatch(OutgoingBatch outgoingBatch) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
updateOutgoingBatch(transaction, outgoingBatch);
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 void updateOutgoingBatch(ISqlTransaction transaction, OutgoingBatch outgoingBatch) {
outgoingBatch.setLastUpdatedTime(new Date());
outgoingBatch.setLastUpdatedHostName(clusterService.getServerId());
transaction.prepareAndExecute(
getSql("updateOutgoingBatchSql"),
new Object[] { outgoingBatch.getStatus().name(), outgoingBatch.getLoadId(),
outgoingBatch.isExtractJobFlag() ? 1: 0,
outgoingBatch.isLoadFlag() ? 1 : 0, outgoingBatch.isErrorFlag() ? 1 : 0,
outgoingBatch.getByteCount(), outgoingBatch.getExtractCount(),
outgoingBatch.getSentCount(), outgoingBatch.getLoadCount(),
outgoingBatch.getDataEventCount(), outgoingBatch.getReloadEventCount(),
outgoingBatch.getInsertEventCount(), outgoingBatch.getUpdateEventCount(),
outgoingBatch.getDeleteEventCount(), outgoingBatch.getOtherEventCount(),
outgoingBatch.getIgnoreCount(), outgoingBatch.getRouterMillis(),
outgoingBatch.getNetworkMillis(), outgoingBatch.getFilterMillis(),
outgoingBatch.getLoadMillis(), outgoingBatch.getExtractMillis(),
outgoingBatch.getSqlState(), outgoingBatch.getSqlCode(),
FormatUtils.abbreviateForLogging(outgoingBatch.getSqlMessage()),
outgoingBatch.getFailedDataId(), outgoingBatch.getLastUpdatedHostName(),
outgoingBatch.getLastUpdatedTime(), outgoingBatch.getBatchId(),
outgoingBatch.getNodeId() }, new int[] { Types.CHAR, Types.BIGINT,
Types.NUMERIC, Types.NUMERIC, Types.NUMERIC, Types.BIGINT, Types.BIGINT, Types.BIGINT,
Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT,
Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.BIGINT,
Types.BIGINT, Types.BIGINT, Types.BIGINT, Types.VARCHAR, Types.NUMERIC,
Types.VARCHAR, Types.BIGINT, Types.VARCHAR, Types.TIMESTAMP, symmetricDialect.getSqlTypeForIds(),
Types.VARCHAR });
}
public void insertOutgoingBatch(final OutgoingBatch outgoingBatch) {
ISqlTransaction transaction = null;
try {
transaction = sqlTemplate.startSqlTransaction();
insertOutgoingBatch(transaction, outgoingBatch);
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 void insertOutgoingBatch(ISqlTransaction transaction, OutgoingBatch outgoingBatch) {
outgoingBatch.setLastUpdatedHostName(clusterService.getServerId());
long batchId = outgoingBatch.getBatchId();
if (batchId <= 0) {
batchId = sequenceService.nextVal(transaction, Constants.SEQUENCE_OUTGOING_BATCH);
}
transaction.prepareAndExecute(getSql("insertOutgoingBatchSql"), batchId, outgoingBatch
.getNodeId(), outgoingBatch.getChannelId(), outgoingBatch.getStatus().name(),
outgoingBatch.getLoadId(), outgoingBatch.isExtractJobFlag() ? 1: 0, outgoingBatch.isLoadFlag() ? 1 : 0, outgoingBatch
.isCommonFlag() ? 1 : 0, outgoingBatch.getReloadEventCount(), outgoingBatch
.getOtherEventCount(), outgoingBatch.getLastUpdatedHostName(),
outgoingBatch.getCreateBy());
outgoingBatch.setBatchId(batchId);
}
public OutgoingBatch findOutgoingBatch(long batchId, String nodeId) {
List<OutgoingBatch> list = null;
if (StringUtils.isNotBlank(nodeId)) {
list = (List<OutgoingBatch>) sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "findOutgoingBatchSql"),
new OutgoingBatchMapper(true), new Object[] { batchId, nodeId },
new int[] { symmetricDialect.getSqlTypeForIds(), Types.VARCHAR });
} else {
/*
* Pushing to an older version of symmetric might result in a batch
* without the node id
*/
list = (List<OutgoingBatch>) sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "findOutgoingBatchByIdOnlySql"),
new OutgoingBatchMapper(true), new Object[] { batchId },
new int[] { symmetricDialect.getSqlTypeForIds() });
}
if (list != null && list.size() > 0) {
return list.get(0);
} else {
return null;
}
}
public int countOutgoingBatchesInError() {
return sqlTemplate.queryForInt(getSql("countOutgoingBatchesErrorsSql"));
}
public int countOutgoingBatchesInError(String channelId) {
return sqlTemplate.queryForInt(getSql("countOutgoingBatchesErrorsOnChannelSql"), channelId);
}
public int countOutgoingBatchesUnsent() {
return sqlTemplate.queryForInt(getSql("countOutgoingBatchesUnsentSql"));
}
public int countOutgoingBatchesUnsent(String channelId) {
return sqlTemplate.queryForInt(getSql("countOutgoingBatchesUnsentOnChannelSql"), channelId);
}
public int countOutgoingBatches(List<String> nodeIds, List<String> channels,
List<OutgoingBatch.Status> statuses) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("NODES", nodeIds);
params.put("CHANNELS", channels);
params.put("STATUSES", toStringList(statuses));
return sqlTemplate
.queryForInt(
getSql("selectCountBatchesPrefixSql",
buildBatchWhere(nodeIds, channels, statuses)), params);
}
public List<OutgoingBatch> listOutgoingBatches(List<String> nodeIds, List<String> channels,
List<OutgoingBatch.Status> statuses, long startAtBatchId, final int maxRowsToRetrieve,
boolean ascending) {
String where = 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 startAtBatchIdSql = null;
if (startAtBatchId > 0) {
if (StringUtils.isBlank(where)) {
where = " where 1=1 ";
}
params.put("BATCH_ID", startAtBatchId);
startAtBatchIdSql = " and batch_id = :BATCH_ID ";
}
String sql = getSql("selectOutgoingBatchPrefixSql", where, startAtBatchIdSql,
ascending ? " order by batch_id asc" : " order by batch_id desc");
return sqlTemplate.query(sql, maxRowsToRetrieve, new OutgoingBatchMapper(true),
params);
}
protected List<String> toStringList(List<OutgoingBatch.Status> statuses) {
List<String> statusStrings = new ArrayList<String>(statuses.size());
for (Status status : statuses) {
statusStrings.add(status.name());
}
return statusStrings;
}
protected boolean containsOnlyStatus(OutgoingBatch.Status status,
List<OutgoingBatch.Status> statuses) {
return statuses.size() == 1 && statuses.get(0) == status;
}
/**
* Select batches to process. Batches that are NOT in error will be returned
* first. They will be ordered by batch id as the batches will have already
* been created by {@link #buildOutgoingBatches(String)} in channel priority
* order.
*/
public OutgoingBatches getOutgoingBatches(String nodeId, boolean includeDisabledChannels) {
long ts = System.currentTimeMillis();
final int maxNumberOfBatchesToSelect = parameterService.getInt(
ParameterConstants.OUTGOING_BATCH_MAX_BATCHES_TO_SELECT, 1000);
List<OutgoingBatch> list = (List<OutgoingBatch>) sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchSql"),
maxNumberOfBatchesToSelect,
new OutgoingBatchMapper(includeDisabledChannels),
new Object[] { nodeId, OutgoingBatch.Status.RQ.name(), OutgoingBatch.Status.NE.name(),
OutgoingBatch.Status.QY.name(), OutgoingBatch.Status.SE.name(),
OutgoingBatch.Status.LD.name(), OutgoingBatch.Status.ER.name(),
OutgoingBatch.Status.IG.name() }, null);
OutgoingBatches batches = new OutgoingBatches(list);
List<NodeChannel> channels = new ArrayList<NodeChannel>(configurationService.getNodeChannels(nodeId, true));
batches.sortChannels(channels);
List<IOutgoingBatchFilter> filters = extensionService.getExtensionPointList(IOutgoingBatchFilter.class);
List<OutgoingBatch> keepers = new ArrayList<OutgoingBatch>();
for (NodeChannel channel : channels) {
List<OutgoingBatch> batchesForChannel = getBatchesForChannelWindows(
batches.getBatches(),
nodeId,
channel,
configurationService.getNodeGroupChannelWindows(
parameterService.getNodeGroupId(), channel.getChannelId()));
if (filters != null) {
for (IOutgoingBatchFilter filter : filters) {
batchesForChannel = filter.filter(channel, batchesForChannel);
}
}
if (parameterService.is(ParameterConstants.DATA_EXTRACTOR_ENABLED)
|| channel.getChannelId().equals(Constants.CHANNEL_CONFIG)) {
keepers.addAll(batchesForChannel);
}
}
batches.setBatches(keepers);
long executeTimeInMs = System.currentTimeMillis() - ts;
if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) {
log.info("Selecting {} outgoing batch rows for node {} took {} ms", list.size(), nodeId, executeTimeInMs);
}
return batches;
}
public List<OutgoingBatch> getOutgoingBatchesForNodeChannel(String nodeId, NodeChannel nodeChannel) {
if (parameterService.is(ParameterConstants.DATA_EXTRACTOR_ENABLED) || nodeChannel.getChannelId().equals(Constants.CHANNEL_CONFIG)) {
long ts = System.currentTimeMillis();
//final int maxNumberOfBatchesToSelect = parameterService.getInt(ParameterConstants.OUTGOING_BATCH_MAX_BATCHES_TO_SELECT, 1000);
List<OutgoingBatch> list = (List<OutgoingBatch>) sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchForChannelSql"),
nodeChannel.getMaxBatchToSend(),
new OutgoingBatchMapper(true),
new Object[] { nodeId, nodeChannel.getChannelId(), OutgoingBatch.Status.RQ.name(), OutgoingBatch.Status.NE.name(),
OutgoingBatch.Status.QY.name(), OutgoingBatch.Status.SE.name(), OutgoingBatch.Status.LD.name(),
OutgoingBatch.Status.ER.name(), OutgoingBatch.Status.IG.name() }, null);
long executeTimeInMs = System.currentTimeMillis() - ts;
if (executeTimeInMs > Constants.LONG_OPERATION_THRESHOLD) {
log.info("Selecting {} outgoing batch rows for node {} took {} ms", list.size(), nodeId, executeTimeInMs);
}
List<IOutgoingBatchFilter> filters = extensionService.getExtensionPointList(IOutgoingBatchFilter.class);
list = getBatchesForChannelWindows(list, nodeId, nodeChannel,
configurationService.getNodeGroupChannelWindows(parameterService.getNodeGroupId(), nodeChannel.getChannelId()));
if (filters != null) {
for (IOutgoingBatchFilter filter : filters) {
list = filter.filter(nodeChannel, list);
}
}
return list;
} else {
return Collections.emptyList();
}
}
public List<OutgoingBatch> getBatchesForChannelWindows(List<OutgoingBatch> current,
String targetNodeId, NodeChannel channel, List<NodeGroupChannelWindow> windows) {
List<OutgoingBatch> keeping = new ArrayList<OutgoingBatch>();
if (current != null && current.size() > 0) {
if (inTimeWindow(windows, targetNodeId)) {
int maxBatchesToSend = channel.getMaxBatchToSend();
for (OutgoingBatch outgoingBatch : current) {
if (channel.getChannelId().equals(outgoingBatch.getChannelId())
&& maxBatchesToSend > 0) {
keeping.add(outgoingBatch);
maxBatchesToSend--;
}
}
}
}
return keeping;
}
/**
* If {@link NodeGroupChannelWindow}s are defined for this channel, then
* check to see if the time (according to the offset passed in) is within on
* of the configured windows.
*/
public boolean inTimeWindow(List<NodeGroupChannelWindow> windows, String targetNodeId) {
if (windows != null && windows.size() > 0) {
for (NodeGroupChannelWindow window : windows) {
String timezoneOffset = null;
List<NodeHost> hosts = nodeService.findNodeHosts(targetNodeId);
if (hosts.size() > 0) {
timezoneOffset = hosts.get(0).getTimezoneOffset();
} else {
timezoneOffset = AppUtils.getTimezoneOffset();
}
if (window.inTimeWindow(timezoneOffset)) {
return true;
}
}
return false;
} else {
return true;
}
}
public OutgoingBatches getOutgoingBatchRange(String nodeId, Date startDate, Date endDate, String... channels) {
OutgoingBatches batches = new OutgoingBatches();
List<OutgoingBatch> batchList = new ArrayList<OutgoingBatch>();
for (String channel : channels) {
batchList.addAll(sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchTimeRangeSql"),
new OutgoingBatchMapper(true), nodeId, channel, startDate, endDate));
}
batches.setBatches(batchList);
return batches;
}
public OutgoingBatches getOutgoingBatchRange(long startBatchId, long endBatchId) {
OutgoingBatches batches = new OutgoingBatches();
batches.setBatches(sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchRangeSql"),
new OutgoingBatchMapper(true), startBatchId,
endBatchId));
return batches;
}
public OutgoingBatches getOutgoingBatchErrors(int maxRows) {
OutgoingBatches batches = new OutgoingBatches();
batches.setBatches(sqlTemplate.query(
getSql("selectOutgoingBatchPrefixSql", "selectOutgoingBatchErrorsSql"), maxRows,
new OutgoingBatchMapper(true), null, null));
return batches;
}
public List<OutgoingBatchByNodeChannelCount> getOutgoingBatchByNodeChannelCount(int maxRows, NodeGroupLinkAction linkType, boolean readyToSendOnly) {
List<OutgoingBatchByNodeChannelCount> forReturn = new ArrayList<OutgoingBatchByNodeChannelCount>();
List<OutgoingBatchByNodeChannelCount> allNodeChannels = sqlTemplate.query(getSql("selectPendingOutgoingBatchByChannelCountSql"), maxRows,
new OutgoingBatchByNodeChannelCountMapper(), new Object[] {linkType.name()});
if (readyToSendOnly) {
Set<String> nodeIdHasReloadsNotInError = new HashSet<String>();
for (OutgoingBatchByNodeChannelCount outgoingBatchByNodeChannelCount : allNodeChannels) {
Channel channel = configurationService.getChannel(outgoingBatchByNodeChannelCount.getChannelId());
if (channel.isReloadFlag() && !outgoingBatchByNodeChannelCount.isInError()) {
nodeIdHasReloadsNotInError.add(outgoingBatchByNodeChannelCount.getNodeId());
}
}
for (OutgoingBatchByNodeChannelCount outgoingBatchByNodeChannelCount : allNodeChannels) {
Channel channel = configurationService.getChannel(outgoingBatchByNodeChannelCount.getChannelId());
if (!nodeIdHasReloadsNotInError.contains(outgoingBatchByNodeChannelCount.getNodeId()) ||
channel.isReloadFlag()) {
forReturn.add(outgoingBatchByNodeChannelCount);
}
}
} else {
forReturn.addAll(allNodeChannels);
}
return forReturn;
}
public List<String> getNodesInError() {
return sqlTemplate.query(getSql("selectNodesInErrorSql"), new StringMapper());
}
public List<OutgoingBatch> getNextOutgoingBatchForEachNode() {
return sqlTemplate.query(
getSql("getNextOutgoingBatchForEachNodeSql"),
new OutgoingBatchMapper(true, true));
}
public boolean isInitialLoadComplete(String nodeId) {
return areAllLoadBatchesComplete(nodeId)
&& !isUnsentDataOnChannelForNode(Constants.CHANNEL_CONFIG, nodeId);
}
public boolean areAllLoadBatchesComplete(String nodeId) {
NodeSecurity security = nodeService.findNodeSecurity(nodeId);
if (security == null || security.isInitialLoadEnabled()) {
return false;
}
List<String> statuses = (List<String>) sqlTemplate.query(getSql("initialLoadStatusSql"),
new StringMapper(), nodeId, 1);
if (statuses == null || statuses.size() == 0) {
throw new RuntimeException("The initial load has not been started for " + nodeId);
}
for (String status : statuses) {
if (!Status.OK.name().equals(status)) {
return false;
}
}
return true;
}
public boolean isUnsentDataOnChannelForNode(String channelId, String nodeId) {
int unsentCount = sqlTemplate.queryForInt(getSql("unsentBatchesForNodeIdChannelIdSql"),
new Object[] { nodeId, channelId });
if (unsentCount > 0) {
return true;
}
// Do we need to check for unbatched data?
return false;
}
public List<OutgoingBatchSummary> findOutgoingBatchSummary(Status... statuses) {
Object[] args = new Object[statuses.length];
StringBuilder inList = new StringBuilder();
for (int i = 0; i < statuses.length; i++) {
args[i] = statuses[i].name();
inList.append("?,");
}
String sql = getSql("selectOutgoingBatchSummaryByStatusSql").replace(":STATUS_LIST",
inList.substring(0, inList.length() - 1));
return sqlTemplate.query(sql, new OutgoingBatchSummaryMapper(), args);
}
public List<OutgoingLoadSummary> getLoadSummaries(boolean activeOnly) {
final Map<String, OutgoingLoadSummary> loadSummaries = new TreeMap<String, OutgoingLoadSummary>();
sqlTemplate.query(getSql("getLoadSummariesSql"), new ISqlRowMapper<OutgoingLoadSummary>() {
public OutgoingLoadSummary mapRow(Row rs) {
long loadId = rs.getLong("load_id");
String nodeId = rs.getString("node_id");
String loadNodeId = String.format("%010d-%s", loadId, nodeId);
OutgoingLoadSummary summary = loadSummaries.get(loadNodeId);
if (summary == null) {
summary = new OutgoingLoadSummary();
summary.setLoadId(loadId);
summary.setNodeId(nodeId);
summary.setCreateBy(rs.getString("create_by"));
loadSummaries.put(loadNodeId, summary);
}
Status status = Status.valueOf(rs.getString("status"));
int count = rs.getInt("cnt");
Date lastUpdateTime = rs.getDateTime("last_update_time");
if (summary.getLastUpdateTime() == null
|| summary.getLastUpdateTime().before(lastUpdateTime)) {
summary.setLastUpdateTime(lastUpdateTime);
}
Date createTime = rs.getDateTime("create_time");
if (summary.getCreateTime() == null || summary.getCreateTime().after(createTime)) {
summary.setCreateTime(createTime);
}
summary.setReloadBatchCount(summary.getReloadBatchCount() + count);
if (status == Status.OK || status == Status.IG) {
summary.setFinishedBatchCount(summary.getFinishedBatchCount() + count);
} else {
summary.setPendingBatchCount(summary.getPendingBatchCount() + count);
boolean inError = rs.getBoolean("error_flag");
summary.setInError(inError || summary.isInError());
if (status != Status.NE && count == 1) {
summary.setCurrentBatchId(rs.getLong("current_batch_id"));
summary.setCurrentDataEventCount(rs.getLong("current_data_event_count"));
}
}
return null;
}
});
List<OutgoingLoadSummary> loads = new ArrayList<OutgoingLoadSummary>(loadSummaries.values());
Iterator<OutgoingLoadSummary> it = loads.iterator();
while (it.hasNext()) {
OutgoingLoadSummary loadSummary = it.next();
if (activeOnly && !loadSummary.isActive()) {
it.remove();
}
}
return loads;
}
class OutgoingBatchByNodeChannelCountMapper implements ISqlRowMapper<OutgoingBatchByNodeChannelCount> {
@Override
public OutgoingBatchByNodeChannelCount mapRow(Row row) {
OutgoingBatchByNodeChannelCount count = new OutgoingBatchByNodeChannelCount();
count.setBatchCount(row.getInt("batch_count"));
count.setChannelId(row.getString("channel_id"));
count.setDataCount(row.getInt("data_event_count"));
count.setEarliestCreateTime(row.getDateTime("earliest_create_time"));
count.setInError(row.getBoolean("error_flag"));
count.setLatestUpdateTime(row.getDateTime("latest_update_time"));
count.setMaxSentCount(row.getInt("sent_count"));
count.setNodeId(row.getString("node_id"));
return count;
}
}
class OutgoingBatchSummaryMapper implements ISqlRowMapper<OutgoingBatchSummary> {
public OutgoingBatchSummary mapRow(Row rs) {
OutgoingBatchSummary summary = new OutgoingBatchSummary();
summary.setBatchCount(rs.getInt("batches"));
summary.setDataCount(rs.getInt("data"));
summary.setStatus(Status.valueOf(rs.getString("status")));
summary.setNodeId(rs.getString("node_id"));
summary.setOldestBatchCreateTime(rs.getDateTime("oldest_batch_time"));
summary.setLatestUpdateTime(rs.getDateTime("latest_update_time"));
return summary;
}
}
class OutgoingBatchMapper implements ISqlRowMapper<OutgoingBatch> {
private boolean statusOnly = false;
private boolean includeDisabledChannels = false;
private Map<String, Channel> channels;
public OutgoingBatchMapper(boolean includeDisabledChannels, boolean statusOnly) {
this.includeDisabledChannels = includeDisabledChannels;
this.statusOnly = statusOnly;
this.channels = configurationService.getChannels(false);
}
public OutgoingBatchMapper(boolean includeDisabledChannels) {
this(includeDisabledChannels, false);
}
public OutgoingBatch mapRow(Row rs) {
String channelId = rs.getString("channel_id");
Channel channel = channels.get(channelId);
if (channel != null && (includeDisabledChannels || channel.isEnabled())) {
OutgoingBatch batch = new OutgoingBatch();
batch.setNodeId(rs.getString("node_id"));
batch.setStatus(rs.getString("status"));
batch.setBatchId(rs.getLong("batch_id"));
if (!statusOnly) {
batch.setChannelId(channelId);
batch.setByteCount(rs.getLong("byte_count"));
batch.setExtractCount(rs.getLong("extract_count"));
batch.setSentCount(rs.getLong("sent_count"));
batch.setLoadCount(rs.getLong("load_count"));
batch.setDataEventCount(rs.getLong("data_event_count"));
batch.setReloadEventCount(rs.getLong("reload_event_count"));
batch.setInsertEventCount(rs.getLong("insert_event_count"));
batch.setUpdateEventCount(rs.getLong("update_event_count"));
batch.setDeleteEventCount(rs.getLong("delete_event_count"));
batch.setOtherEventCount(rs.getLong("other_event_count"));
batch.setIgnoreCount(rs.getLong("ignore_count"));
batch.setRouterMillis(rs.getLong("router_millis"));
batch.setNetworkMillis(rs.getLong("network_millis"));
batch.setFilterMillis(rs.getLong("filter_millis"));
batch.setLoadMillis(rs.getLong("load_millis"));
batch.setExtractMillis(rs.getLong("extract_millis"));
batch.setSqlState(rs.getString("sql_state"));
batch.setSqlCode(rs.getInt("sql_code"));
batch.setSqlMessage(rs.getString("sql_message"));
batch.setFailedDataId(rs.getLong("failed_data_id"));
batch.setLastUpdatedHostName(rs.getString("last_update_hostname"));
batch.setLastUpdatedTime(rs.getDateTime("last_update_time"));
batch.setCreateTime(rs.getDateTime("create_time"));
batch.setLoadFlag(rs.getBoolean("load_flag"));
batch.setErrorFlag(rs.getBoolean("error_flag"));
batch.setCommonFlag(rs.getBoolean("common_flag"));
batch.setExtractJobFlag(rs.getBoolean("extract_job_flag"));
batch.setLoadId(rs.getLong("load_id"));
batch.setCreateBy(rs.getString("create_by"));
}
return batch;
} else {
return null;
}
}
}
}