/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 com.alibaba.jstorm.window; import backtype.storm.tuple.Tuple; import com.alibaba.jstorm.transactional.state.ITransactionStateOperator; /** * @author wange * @since 16/12/15 */ public abstract class BaseWindowedBolt<T extends Tuple> implements IWindowedBolt<T> { private static final long serialVersionUID = 1L; public static final long DEFAULT_SLIDE = -1L; public static final long DEFAULT_STATE_SIZE = -1L; private WindowAssigner<T> windowAssigner; private WindowAssigner<T> stateWindowAssigner; private WatermarkGenerator watermarkGenerator; private TimestampExtractor timestampExtractor; private WindowStateMerger windowStateMerger; private Retractor retractor; private ITransactionStateOperator stateOperator; private WatermarkTriggerPolicy watermarkTriggerPolicy; private long maxLagMs; private long size; private long slide; private long stateSize = DEFAULT_STATE_SIZE; /** * define a tumbling count window * * @param size count size */ public BaseWindowedBolt<T> countWindow(long size) { ensurePositiveTime(size); setSizeAndSlide(size, DEFAULT_SLIDE); this.windowAssigner = TumblingCountWindows.create(size); return this; } /** * define a sliding count window * * @param size count size * @param slide slide size */ public BaseWindowedBolt<T> countWindow(long size, long slide) { ensurePositiveTime(size, slide); ensureSizeGreaterThanSlide(size, slide); setSizeAndSlide(size, slide); this.windowAssigner = SlidingCountWindows.create(size, slide); return this; } /** * define a tumbling processing time window * * @param size window size */ public BaseWindowedBolt<T> timeWindow(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); setSizeAndSlide(s, DEFAULT_SLIDE); this.windowAssigner = TumblingProcessingTimeWindows.of(s); return this; } /** * add state window to tumbling windows. * If set, jstorm will use state window size to accumulate user states instead of * deleting the states right after purging a window. * * e.g., if a user defines a window of 10 sec as well as a state window of 60 sec, * then the window will be purged every 10 sec, while the state of the window will be kept (and accumulated) * until 60 sec is due. * * @param size state window size */ public BaseWindowedBolt<T> withStateSize(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); ensureStateSizeGreaterThanWindowSize(this.size, s); this.stateSize = s; if (WindowAssigner.isEventTime(this.windowAssigner)) { this.stateWindowAssigner = TumblingEventTimeWindows.of(s); } else if (WindowAssigner.isProcessingTime(this.windowAssigner)) { this.stateWindowAssigner = TumblingProcessingTimeWindows.of(s); } else if (WindowAssigner.isIngestionTime(this.windowAssigner)) { this.stateWindowAssigner = TumblingIngestionTimeWindows.of(s); } return this; } /** * define a sliding processing time window * * @param size window size * @param slide slide size */ public BaseWindowedBolt<T> timeWindow(Time size, Time slide) { long s = size.toMilliseconds(); long l = slide.toMilliseconds(); ensurePositiveTime(s, l); ensureSizeGreaterThanSlide(s, l); setSizeAndSlide(s, l); this.windowAssigner = SlidingProcessingTimeWindows.of(s, l); return this; } /** * define a tumbling ingestion time window * * @param size window size */ public BaseWindowedBolt<T> ingestionTimeWindow(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); setSizeAndSlide(s, DEFAULT_SLIDE); this.windowAssigner = TumblingIngestionTimeWindows.of(s); return this; } /** * define a sliding ingestion time window * * @param size window size * @param slide slide size */ public BaseWindowedBolt<T> ingestionTimeWindow(Time size, Time slide) { long s = size.toMilliseconds(); long l = slide.toMilliseconds(); ensurePositiveTime(s, l); ensureSizeGreaterThanSlide(s, l); setSizeAndSlide(s, l); this.windowAssigner = SlidingIngestionTimeWindows.of(s, l); return this; } /** * define a tumbling event time window * * @param size window size */ public BaseWindowedBolt<T> eventTimeWindow(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); setSizeAndSlide(s, DEFAULT_SLIDE); this.windowAssigner = TumblingEventTimeWindows.of(s); return this; } /** * define a sliding event time window * * @param size window size * @param slide slide size */ public BaseWindowedBolt<T> eventTimeWindow(Time size, Time slide) { long s = size.toMilliseconds(); long l = slide.toMilliseconds(); ensurePositiveTime(s, l); ensureSizeGreaterThanSlide(s, l); setSizeAndSlide(s, l); this.windowAssigner = SlidingEventTimeWindows.of(s, l); return this; } /** * define a session processing time window * * @param size window size, i.e., session gap */ public BaseWindowedBolt<T> sessionTimeWindow(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); setSizeAndSlide(s, DEFAULT_SLIDE); this.windowAssigner = ProcessingTimeSessionWindows.withGap(s); return this; } /** * define a session event time window * * @param size window size, i.e., session gap */ public BaseWindowedBolt<T> sessionEventTimeWindow(Time size) { long s = size.toMilliseconds(); ensurePositiveTime(s); setSizeAndSlide(s, DEFAULT_SLIDE); this.windowAssigner = EventTimeSessionWindows.withGap(s); return this; } /** * define a timestamp extractor, only for event time windows * * @param timestampExtractor timestamp extractor implementation */ public BaseWindowedBolt<T> withTimestampExtractor(TimestampExtractor timestampExtractor) { this.timestampExtractor = timestampExtractor; return this; } /** * define a watermark generator, only for event time windows * * @param watermarkGenerator watermark generator */ public BaseWindowedBolt<T> withWatermarkGenerator(WatermarkGenerator watermarkGenerator) { this.watermarkGenerator = watermarkGenerator; return this; } /** * define a watermark trigger policy, only for event time windows * * @param triggerPolicy watermark trigger policy */ public BaseWindowedBolt<T> withWatermarkTriggerPolicy(WatermarkTriggerPolicy triggerPolicy) { this.watermarkTriggerPolicy = triggerPolicy; return this; } /** * define a window state merger, only for session time windows */ public BaseWindowedBolt<T> withWindowStateMerger(WindowStateMerger merger) { this.windowStateMerger = merger; return this; } /** * define max lag in ms, only for event time windows * * @param maxLag max lag time */ public BaseWindowedBolt<T> withMaxLagMs(Time maxLag) { this.maxLagMs = maxLag.toMilliseconds(); ensureNonNegativeTime(maxLagMs); return this; } /** * define a retractor which enables re-computing of historic windows, only for event time windows * * @param retractor retractor */ public BaseWindowedBolt<T> withRetractor(Retractor retractor) { this.retractor = retractor; return this; } public BaseWindowedBolt<T> withTransactionStateOperator(ITransactionStateOperator stateOperator) { this.stateOperator = stateOperator; return this; } public WindowAssigner<T> getWindowAssigner() { return this.windowAssigner; } public WindowAssigner<T> getStateWindowAssigner() { return stateWindowAssigner; } public WatermarkGenerator getWatermarkGenerator() { return this.watermarkGenerator; } public WatermarkTriggerPolicy getWatermarkTriggerPolicy() { return this.watermarkTriggerPolicy; } public TimestampExtractor getTimestampExtractor() { return timestampExtractor; } public WindowStateMerger getWindowStateMerger() { return windowStateMerger; } public long getMaxLagMs() { return maxLagMs; } public Retractor getRetractor() { return retractor; } public ITransactionStateOperator getStateOperator() { return this.stateOperator; } private void setSizeAndSlide(long size, long slide) { this.size = size; this.slide = slide; } public long getSize() { return size; } public long getSlide() { return slide; } public long getStateSize() { return stateSize; } private void ensurePositiveTime(long... values) { for (long value : values) { if (value <= 0) { throw new IllegalArgumentException("time or slide must be positive!"); } } } private void ensureSizeGreaterThanSlide(long size, long slide) { if (size <= slide) { throw new IllegalArgumentException("window size must be greater than window slide!"); } } private void ensureStateSizeGreaterThanWindowSize(long winSize, long stateSize) { if (winSize > stateSize) { throw new IllegalArgumentException("state window size must be greater than window size!"); } } private void ensureNonNegativeTime(long... values) { for (long value : values) { if (value < 0) { throw new IllegalArgumentException("time or slide must not be negative!"); } } } @Override public void cleanup() { } }