@Override
    public void putEvents(final List<StatisticEvent> statisticEvents,
                          final StatisticStore statisticStore) {
        Objects.requireNonNull(statisticEvents);
        Objects.requireNonNull(statisticStore);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("putEvents - count={}", statisticEvents.size());
        }

        if (!isShutdown.get()) {
            final StatisticStoreDoc entity = (StatisticStoreDoc) statisticStore;

            // validate the first stat in the batch to check we have a statistic
            // data source for it.
            if (!validateStatisticDataSource(statisticEvents.iterator().next(), entity)) {
                // no StatisticsDataSource entity so don't record the stat as we
                // will have no way of querying the stat
                throw new RuntimeException(String.format("Invalid or missing statistic data source with name %s",
                        entity.getName()));
            }

            final Predicate<StatisticEvent> insideProcessingThresholdPredicate =
                    getInsideProcessingThresholdPredicate();

            try {
                final SQLStatisticAggregateMap statisticAggregateMap = objectPool.borrowObject();
                try {
                    for (final StatisticEvent statisticEvent : statisticEvents) {
                        // Only process a stat if it is inside the processing
                        // threshold

                        if (insideProcessingThresholdPredicate.test(statisticEvent)) {
                            final RolledUpStatisticEvent rolledUpStatisticEvent = generateTagRollUps(statisticEvent,
                                    entity);
                            statisticAggregateMap.addRolledUpEvent(rolledUpStatisticEvent, entity.getPrecision());
                        }
                    }
                } finally {
                    objectPool.returnObject(statisticAggregateMap);
                }
            } catch (final InterruptedException e) {
                Thread.currentThread().interrupt();
                LOGGER.error("putEvent()", e);
            } catch (final Exception e) {
                throw new RuntimeException("Exception adding statistics to the aggregateMap: " + e.getMessage(), e);
            }
        } else {
            LOGGER.error("Unable to proccess batch of statistic events with size {} as the system is shutting down",
                    statisticEvents.size());
        }
    }
@return A predicate that will test if an event is within the processing age threshold, or if there
is no configured max age then process all events
stroom-statistics/stroom-statistics-impl-sql/src/main/java/stroom/statistics/impl/sql/SQLStatisticEventStore.java