blob: 82868949e9fbf38046548a6a32c7406f81b2dcfa [file] [log] [blame]
/**
* 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 org.apache.lens.cube.metadata;
import static org.apache.lens.cube.metadata.DateUtil.ABSDATE_PARSER;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import org.apache.lens.cube.error.LensCubeErrorCode;
import org.apache.lens.server.api.error.LensException;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import lombok.Data;
import lombok.Getter;
/**
* Timerange data structure
*/
@JsonIgnoreProperties({"astNode", "parent"})
@Data
public class TimeRange {
private String partitionColumn;
private Date toDate;
private Date fromDate;
private ASTNode astNode;
private ASTNode parent;
private int childIndex;
public boolean isCoverableBy(Set<UpdatePeriod> updatePeriods) {
return DateUtil.isCoverableBy(fromDate, toDate, updatePeriods);
}
/**
* Truncate time range using the update period.
* The lower value of the truncated time range is the smallest date value equal to or larger than original
* time range's lower value which lies at the update period's boundary. Similarly for higher value.
* @param updatePeriod Update period to truncate time range with
* @return truncated time range
* @throws LensException If the truncated time range is invalid.
*/
public TimeRange truncate(UpdatePeriod updatePeriod) throws LensException {
TimeRange timeRange = new TimeRangeBuilder().partitionColumn(partitionColumn)
.fromDate(updatePeriod.getCeilDate(fromDate)).toDate(updatePeriod.getFloorDate(toDate)).build();
timeRange.validate();
return timeRange;
}
public long milliseconds() {
return toDate.getTime() - fromDate.getTime();
}
public static class TimeRangeBuilder {
private final TimeRange range;
public TimeRangeBuilder() {
this.range = new TimeRange();
}
public TimeRangeBuilder partitionColumn(String col) {
range.partitionColumn = col;
return this;
}
public TimeRangeBuilder toDate(Date to) {
range.toDate = to;
return this;
}
public TimeRangeBuilder fromDate(Date from) {
range.fromDate = from;
return this;
}
public TimeRangeBuilder astNode(ASTNode node) {
range.astNode = node;
return this;
}
public TimeRangeBuilder parent(ASTNode parent) {
range.parent = parent;
return this;
}
public TimeRangeBuilder childIndex(int childIndex) {
range.childIndex = childIndex;
return this;
}
public TimeRange build() {
return range;
}
}
public static TimeRangeBuilder getBuilder() {
return new TimeRangeBuilder();
}
private TimeRange() {
}
public void validate() throws LensException {
if (partitionColumn == null || fromDate == null || toDate == null || fromDate.equals(toDate)) {
throw new LensException(LensCubeErrorCode.INVALID_TIME_RANGE.getLensErrorInfo());
}
if (fromDate.after(toDate)) {
throw new LensException(LensCubeErrorCode.FROM_AFTER_TO.getLensErrorInfo(),
fromDate.toString(), toDate.toString());
}
}
public String toTimeDimWhereClause() {
return toTimeDimWhereClause(null, partitionColumn);
}
public String toTimeDimWhereClause(String prefix, String column) {
if (StringUtils.isNotBlank(column)) {
column = prefix + "." + column;
}
return new StringBuilder()
.append(column).append(" >= '").append(DateUtil.HIVE_QUERY_DATE_PARSER.get().format(fromDate)).append("'")
.append(" AND ")
.append(column).append(" < '").append(DateUtil.HIVE_QUERY_DATE_PARSER.get().format(toDate)).append("'")
.toString();
}
@Override
public String toString() {
return partitionColumn + " [" + ABSDATE_PARSER.get().format(fromDate) + " to "
+ ABSDATE_PARSER.get().format(toDate) + ")";
}
/** iterable from fromDate(including) to toDate(excluding) incrementing increment units of updatePeriod */
public static Iterable iterable(Date fromDate, Date toDate, UpdatePeriod updatePeriod, int increment) {
return TimeRange.getBuilder().fromDate(fromDate).toDate(toDate).build().iterable(updatePeriod, increment);
}
/** iterable from fromDate(including) incrementing increment units of updatePeriod. Do this numIters times */
public static Iterable iterable(Date fromDate, int numIters, UpdatePeriod updatePeriod, int increment) {
return TimeRange.getBuilder().fromDate(fromDate).build().iterable(updatePeriod, numIters, increment);
}
private Iterable iterable(UpdatePeriod updatePeriod, int numIters, int increment) {
return new Iterable(updatePeriod, numIters, increment);
}
public Iterable iterable(UpdatePeriod updatePeriod, int increment) {
if (increment == 0) {
throw new UnsupportedOperationException("Can't iterate if iteration increment is zero");
}
long numIters = DateUtil.getTimeDiff(fromDate, toDate, updatePeriod) / increment;
return new Iterable(updatePeriod, numIters, increment);
}
/** Iterable so that foreach is supported */
public class Iterable implements java.lang.Iterable<Date> {
private UpdatePeriod updatePeriod;
private long numIters;
private int increment;
public Iterable(UpdatePeriod updatePeriod, long numIters, int increment) {
this.updatePeriod = updatePeriod;
this.numIters = numIters;
if (this.numIters < 0) {
this.numIters = 0;
}
this.increment = increment;
}
@Override
public Iterator iterator() {
return new Iterator();
}
public class Iterator implements java.util.Iterator<Date> {
Calendar calendar;
// Tracks the index of the item returned after the last next() call.
// Index here refers to the index if the iterator were iterated and converted into a list.
@Getter
int counter = -1;
public Iterator() {
calendar = Calendar.getInstance();
calendar.setTime(fromDate);
}
@Override
public boolean hasNext() {
return counter < numIters - 1;
}
@Override
public Date next() {
Date cur = calendar.getTime();
updatePeriod.increment(calendar, increment);
counter++;
return cur;
}
public Date peekNext() {
return calendar.getTime();
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove from timerange iterator");
}
public long getNumIters() {
return numIters;
}
}
}
}