Repository: incubator-apex-malhar Updated Branches: refs/heads/devel-3 e79025359 -> f9c7992e4
- MLHR-1832 Added Custom TimeBuckets Project: http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/commit/b3b7c5b1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/tree/b3b7c5b1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/diff/b3b7c5b1 Branch: refs/heads/devel-3 Commit: b3b7c5b1dac79c0130a700ec7e0e91de554b06b4 Parents: d710af9 Author: Timothy Farkas <[email protected]> Authored: Mon Aug 31 18:31:20 2015 -0700 Committer: Timothy Farkas <[email protected]> Committed: Thu Sep 24 01:03:48 2015 -0700 ---------------------------------------------------------------------- .../lib/appdata/schemas/CustomTimeBucket.java | 192 +++++++++++++++++++ .../lib/appdata/schemas/TimeBucket.java | 51 ++++- .../appdata/schemas/CustomTimeBucketTest.java | 62 ++++++ 3 files changed, 299 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/blob/b3b7c5b1/library/src/main/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucket.java ---------------------------------------------------------------------- diff --git a/library/src/main/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucket.java b/library/src/main/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucket.java new file mode 100644 index 0000000..21ae425 --- /dev/null +++ b/library/src/main/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucket.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015 DataTorrent + * + * Licensed 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.datatorrent.lib.appdata.schemas; + +import java.io.Serializable; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.base.Preconditions; + +/** + * This represents a {@link TimeBucket} which can be a multiple of a time unit. + */ +public class CustomTimeBucket implements Serializable +{ + private static final long serialVersionUID = 201509221545L; + + public static final String TIME_BUCKET_NAME_REGEX = "(\\d+)([a-zA-Z]+)"; + public static final Pattern TIME_BUCKET_NAME_PATTERN = Pattern.compile(TIME_BUCKET_NAME_REGEX); + + private TimeBucket timeBucket; + private long count; + private String text; + private long numMillis; + + private CustomTimeBucket() + { + //For kryo + } + + public CustomTimeBucket(String timeBucketText) + { + if (timeBucketText.equals(TimeBucket.ALL.getText())) { + initialize(TimeBucket.ALL, 0L); + } else { + Matcher matcher = TIME_BUCKET_NAME_PATTERN.matcher(timeBucketText); + + if (!matcher.matches()) { + throw new IllegalArgumentException("The given text for the variable time bucket " + timeBucketText + + " does not match the regex for a variable time bucket " + TIME_BUCKET_NAME_REGEX); + } + + String amountString = matcher.group(1); + long amount = Long.parseLong(amountString); + + String suffix = matcher.group(2); + @SuppressWarnings("LocalVariableHidesMemberVariable") + TimeBucket timeBucket = TimeBucket.getTimeBucketForSuffixEx(suffix); + + initialize(timeBucket, + amount); + } + } + + public CustomTimeBucket(TimeBucket timeBucket, + long count) + { + initialize(timeBucket, + count); + } + + public CustomTimeBucket(TimeBucket timeBucket) + { + if (timeBucket == TimeBucket.ALL) { + initialize(timeBucket, + 0L); + } else { + initialize(timeBucket, + 1L); + } + } + + private void initialize(TimeBucket timeBucket, + long count) + { + this.timeBucket = Preconditions.checkNotNull(timeBucket); + this.count = count; + + if (timeBucket != TimeBucket.ALL) { + Preconditions.checkArgument(count > 0, "The TimeBucket cannot be ALL."); + } else { + Preconditions.checkArgument(count == 0, "The count must be zero for the all TimeBucket."); + } + + if (timeBucket != TimeBucket.ALL) { + text = count + timeBucket.getSuffix(); + numMillis = timeBucket.getTimeUnit().toMillis(1) * count; + } else { + text = TimeBucket.ALL.getText(); + } + } + + public boolean isUnit() + { + return count == 1; + } + + public TimeBucket getTimeBucket() + { + return timeBucket; + } + + public long getCount() + { + return count; + } + + public long getNumMillis() + { + return numMillis; + } + + public long toMillis(long multCount) + { + return numMillis * multCount; + } + + /** + * Rounds down the given time stamp to the nearest {@link TimeUnit} corresponding + * to this TimeBucket. + * + * @param timestamp The timestamp to round down. + * @return The rounded down timestamp. + */ + public long roundDown(long timestamp) + { + if (timeBucket == TimeBucket.ALL) { + return 0; + } + + return (timestamp / numMillis) * numMillis; + } + + public String getText() + { + return text; + } + + @Override + public String toString() + { + if (timeBucket == TimeBucket.ALL) { + return TimeBucket.ALL.getText(); + } else { + return count + timeBucket.getSuffix(); + } + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 97 * hash + Objects.hashCode(this.timeBucket); + hash = 97 * hash + (int)(this.count ^ (this.count >>> 32)); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CustomTimeBucket other = (CustomTimeBucket)obj; + if (this.timeBucket != other.timeBucket) { + return false; + } + if (this.count != other.count) { + return false; + } + return true; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/blob/b3b7c5b1/library/src/main/java/com/datatorrent/lib/appdata/schemas/TimeBucket.java ---------------------------------------------------------------------- diff --git a/library/src/main/java/com/datatorrent/lib/appdata/schemas/TimeBucket.java b/library/src/main/java/com/datatorrent/lib/appdata/schemas/TimeBucket.java index f2d2501..01ff4a0 100644 --- a/library/src/main/java/com/datatorrent/lib/appdata/schemas/TimeBucket.java +++ b/library/src/main/java/com/datatorrent/lib/appdata/schemas/TimeBucket.java @@ -17,10 +17,13 @@ package com.datatorrent.lib.appdata.schemas; import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; /** * This enum represents a TimeBucket that is supported by AppData @@ -28,6 +31,7 @@ import com.google.common.collect.Maps; * <br/> * The currently supported buckets are: * <ul> + * <li>s - second</li> * <li>m - minute</li> * <li>h - hour</li> * <li>d - day</li> @@ -51,23 +55,28 @@ public enum TimeBucket /** * No time bucketing. */ - ALL("all", null), + ALL("all", null, null), /** * Second time bucketing. */ - SECOND("1s", TimeUnit.SECONDS), + SECOND("1s", TimeUnit.SECONDS, "s"), /** * Minute time bucketing. */ - MINUTE("1m", TimeUnit.MINUTES), + MINUTE("1m", TimeUnit.MINUTES, "m"), /** * Hour time bucketing. */ - HOUR("1h", TimeUnit.HOURS), + HOUR("1h", TimeUnit.HOURS, "h"), /** * Day time bucketing. */ - DAY("1d", TimeUnit.DAYS); + DAY("1d", TimeUnit.DAYS, "d"); + + public static final String TIME_BUCKET_NAME_REGEX = "1[a-zA-Z]+"; + public static final Pattern TIME_BUCKET_NAME_PATTERN = Pattern.compile(TIME_BUCKET_NAME_REGEX); + public static final Set<String> SUFFIXES; + public static final Map<String, TimeBucket> SUFFIX_TO_TIME_BUCKET; /** * A map from the test/name of the bucket to the {@link TimeBucket}. @@ -91,8 +100,20 @@ public enum TimeBucket BUCKET_TO_TYPE = Collections.unmodifiableMap(bucketToType); TIME_UNIT_TO_TIME_BUCKET = Collections.unmodifiableMap(timeUnitToTimeBucket); + + Set<String> suffixes = Sets.newHashSet(); + Map<String, TimeBucket> suffixToTimeBucket = Maps.newHashMap(); + + for (TimeBucket timeBucket: TimeBucket.values()) { + suffixes.add(timeBucket.getSuffix()); + suffixToTimeBucket.put(timeBucket.getSuffix(), timeBucket); + } + + SUFFIXES = Sets.newHashSet(suffixes); + SUFFIX_TO_TIME_BUCKET = Maps.newHashMap(suffixToTimeBucket); } + private final String suffix; private String text; private TimeUnit timeUnit; @@ -100,11 +121,13 @@ public enum TimeBucket * Create a time bucket with the given corresponding text and {@link TimeUnit} * @param text The text or name corresponding to the TimeBucket. * @param timeUnit The {@link TimeUnit} that the TimeBucket represents. + * @param suffix The suffix used to denote this {@link TimeBucket} */ - TimeBucket(String text, TimeUnit timeUnit) + TimeBucket(String text, TimeUnit timeUnit, String suffix) { setText(text); setTimeUnit(timeUnit); + this.suffix = suffix; } /** @@ -127,6 +150,15 @@ public enum TimeBucket } /** + * This method gets the suffix for the {@link TimeBucket}. + * @return The suffix for this {@link TimeBucket}. + */ + public String getSuffix() + { + return this.suffix; + } + + /** * Gets the name or text corresponding to this TimeBucket. * @return The name or text corresponding to this TimeBucket. */ @@ -186,4 +218,11 @@ public enum TimeBucket name + " is not a valid bucket type."); return bucket; } + + public static TimeBucket getTimeBucketForSuffixEx(String suffix) + { + Preconditions.checkNotNull(suffix); + Preconditions.checkArgument(SUFFIXES.contains(suffix)); + return SUFFIX_TO_TIME_BUCKET.get(suffix); + } } http://git-wip-us.apache.org/repos/asf/incubator-apex-malhar/blob/b3b7c5b1/library/src/test/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucketTest.java ---------------------------------------------------------------------- diff --git a/library/src/test/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucketTest.java b/library/src/test/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucketTest.java new file mode 100644 index 0000000..1fac867 --- /dev/null +++ b/library/src/test/java/com/datatorrent/lib/appdata/schemas/CustomTimeBucketTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 DataTorrent + * + * Licensed 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.datatorrent.lib.appdata.schemas; + +import org.junit.Assert; +import org.junit.Test; + +public class CustomTimeBucketTest +{ + @Test + public void stringCreationTest() + { + CustomTimeBucket customTimeBucket = new CustomTimeBucket("5m"); + + Assert.assertEquals(5L, customTimeBucket.getCount()); + Assert.assertEquals("5m", customTimeBucket.getText()); + Assert.assertEquals(TimeBucket.MINUTE, customTimeBucket.getTimeBucket()); + } + + @Test + public void stringCreationTest2() + { + CustomTimeBucket customTimeBucket = new CustomTimeBucket("6h"); + + Assert.assertEquals(6L, customTimeBucket.getCount()); + Assert.assertEquals("6h", customTimeBucket.getText()); + Assert.assertEquals(TimeBucket.HOUR, customTimeBucket.getTimeBucket()); + } + + @Test + public void testToMillis() + { + CustomTimeBucket customTimeBucket = new CustomTimeBucket("5m"); + + Assert.assertEquals(5L * 60L * 1000L, customTimeBucket.getNumMillis()); + } + + @Test + public void roundDownTest() + { + CustomTimeBucket customTimeBucket = new CustomTimeBucket("5m"); + + long expected = 5 * 60 * 1000; + long val = expected + 300; + + Assert.assertEquals(expected, customTimeBucket.roundDown(val)); + } +}
