Created
February 21, 2017 00:45
-
-
Save deyindra/f54171e01bbfe694930f24843daba4cd to your computer and use it in GitHub Desktop.
AssertJ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.util; | |
import java.util.function.Predicate; | |
/** | |
* Assertion Utility class which will Assert statement in case statement is false, | |
* it will throw IllegalArgument Exception. | |
*/ | |
public class AssertJ { | |
private AssertJ(){ | |
throw new AssertionError("Invalid Access"); | |
} | |
/** | |
* | |
* @param object which will satisfy following code | |
* <pre> | |
* new Predicate<T>(){ | |
* public boolean test(T t){ | |
* return t!=null; | |
* } | |
* } | |
* </pre> | |
* @param message Error message in case Predicate fails | |
* @param <T> describe the type of the object | |
* @throws IllegalArgumentException in case passed object is null | |
*/ | |
public static <T> void notNull(T object, String message){ | |
assertTrue(t -> t!=null,object,message); | |
} | |
/** | |
* | |
* @param predicate {@link Predicate} to test the condition | |
* @param object Object which will satisfy the predicate | |
* @param message Error message | |
* @param args Argument to format the message | |
* @param <T> describe the type of the object | |
* @throws IllegalArgumentException throws {@link IllegalArgumentException} in case Asserttion fails | |
*/ | |
public static <T> void assertTrue(Predicate<? super T> predicate, T object, String message, Object... args){ | |
if(!predicate.test(object)){ | |
message = getFinalErrorMessage(message, args); | |
if(message==null){ | |
throw new IllegalArgumentException(); | |
}else{ | |
throw new IllegalArgumentException(message); | |
} | |
} | |
} | |
/** | |
* | |
* @param message Error Message in can be null or empty | |
* @param args Arguments for format the error message | |
* @return Empty Error Message in case this is null or empty or actual error message | |
*/ | |
private static String getFinalErrorMessage(String message, Object... args){ | |
String actualMessage=null; | |
if(message!=null && !("").equals(message.trim())){ | |
message = message.trim(); | |
if(args!=null && args.length>0) { | |
actualMessage = String.format(message, args); | |
}else{ | |
actualMessage = message; | |
} | |
} | |
return actualMessage; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.iterator.peek; | |
import java.util.Iterator; | |
/** | |
* Special Iterator which will provide addiotnal method {@link PeekIterator#peek()} | |
* @param <T> return the current object | |
* | |
*/ | |
public interface PeekIterator<T> extends Iterator<T> { | |
/** | |
* This method always current element from the iterator. During the process of peeking element it will not | |
* advance the iterator | |
* @return T current object | |
* @throws java.util.NoSuchElementException in case there is no more elements or the iterator is null | |
*/ | |
T peek(); | |
/** | |
* @throws UnsupportedOperationException as this is not supported | |
*/ | |
default void remove() { | |
throw new UnsupportedOperationException("Invalid Operations"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.iterator.peek; | |
import java.util.Iterator; | |
import java.util.NoSuchElementException; | |
/** | |
* Special Iterator which will provide addiotnal method {@link SimplePeekIterator#peek()} | |
* @param <T> element of the iterator | |
* @see PeekIterator | |
*/ | |
public class SimplePeekIterator<T> implements PeekIterator<T> { | |
private Iterator<T> iterator; | |
private T element; | |
/** | |
* @param iterator underlying iterator | |
*/ | |
public SimplePeekIterator(Iterator<T> iterator) { | |
this.iterator = iterator; | |
if (iterator!=null && iterator.hasNext()) { | |
element = iterator.next(); | |
} | |
} | |
/** | |
* this method will not advance to next element | |
* @return T current element | |
* @throws NoSuchElementException in case hasNext return false | |
*/ | |
@Override | |
public T peek() { | |
if(!hasNext()){ | |
throw new NoSuchElementException("No more element"); | |
} | |
return element; | |
} | |
/** | |
* | |
* @return false whem element is null | |
*/ | |
@Override | |
public boolean hasNext() { | |
return element != null; | |
} | |
/** | |
* @return T next element | |
* @throws NoSuchElementException in case hasNext return false | |
*/ | |
@Override | |
public T next() { | |
if(!hasNext()){ | |
throw new NoSuchElementException("No more element"); | |
} | |
T ret = element; | |
element = this.iterator.hasNext() ? iterator.next() : null; | |
return ret; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.iterator.timeseries; | |
import org.idey.algo.iterator.peek.PeekIterator; | |
import org.idey.algo.iterator.peek.SimplePeekIterator; | |
import org.idey.algo.util.AssertJ; | |
import java.time.Instant; | |
import java.util.Collections; | |
import java.util.Deque; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.Map; | |
import java.util.NoSuchElementException; | |
import java.util.Optional; | |
import java.util.SortedSet; | |
import java.util.TreeSet; | |
/** | |
* {@link TimeSeries} based Sliding window {@link Iterator} which will return all elements based on | |
* {@link SlidingTimeSeriesIterator#size} and then slide by {@link SlidingTimeSeriesIterator#step} | |
*/ | |
public class SlidingTimeSeriesIterator<T extends Comparable<T>> implements Iterator<Map<Long, SortedSet<TimeSeries<T>>>> { | |
private final TimeWindow timeWindow; | |
private final PeekIterator<TimeSeries<T>> iterator; | |
private final int size; | |
//Steps from from where window start | |
private final int step; | |
private final Deque<Long> deque; | |
private final Map<Long, SortedSet<TimeSeries<T>>> map; | |
private final Instant startDuration; | |
private boolean hasNext; | |
/** | |
* | |
* @param timeWindow unit size of time window it will be either {@link TimeWindow#SECONDS}, | |
* {@link TimeWindow#MINUTES}, {@link TimeWindow#HOURS}, {@link TimeWindow#DAYS} | |
* @param iterator {@link TimeSeries} {@link Iterator} | |
* @param size size of the time window | |
* @param step Step by which window will slide | |
*/ | |
public SlidingTimeSeriesIterator(TimeWindow timeWindow, | |
Iterator<TimeSeries<T>> iterator, | |
int size, int step) { | |
AssertJ.notNull(timeWindow, "Invalid time window"); | |
AssertJ.notNull(iterator, "ietartor can not be null"); | |
AssertJ.assertTrue(i->i>0, size, "size can not be zero or negative"); | |
AssertJ.assertTrue(i->i>0, step, "step can not be zero or negative"); | |
this.timeWindow = timeWindow; | |
this.iterator = new SimplePeekIterator<>(iterator); | |
this.size = size; | |
this.step = step; | |
map = new HashMap<>(); | |
deque = new LinkedList<>(); | |
hasNext=false; | |
startDuration = this.iterator.peek().getTs(); | |
setAdvance(); | |
} | |
@Override | |
public boolean hasNext() { | |
return hasNext; | |
} | |
@Override | |
public Map<Long, SortedSet<TimeSeries<T>>> next() { | |
if(!hasNext()){ | |
throw new NoSuchElementException("No more elements"); | |
} | |
Map<Long,SortedSet<TimeSeries<T>>> returnMap = Collections.unmodifiableMap(new HashMap<>(map)); | |
setAdvance(); | |
return returnMap; | |
} | |
@Override | |
public void remove() { | |
throw new UnsupportedOperationException("Invalid operations...."); | |
} | |
private void setAdvance() { | |
hasNext = false; | |
long nextValue=0; | |
if (iterator.hasNext()) { | |
if (!deque.isEmpty()) { | |
if(size>step){ | |
for(int count=0;!deque.isEmpty() && count<step; count++){ | |
long value = deque.poll(); | |
map.remove(value); | |
} | |
nextValue = deque.peekLast(); | |
}else if(size<=step){ | |
nextValue = deque.peekLast(); | |
long endStepValue = nextValue + step - size; | |
deque.clear(); | |
map.clear(); | |
while(iterator.hasNext()){ | |
nextValue = calculateTimeDifference(); | |
if(nextValue>endStepValue){ | |
nextValue = endStepValue; | |
break; | |
} | |
iterator.next(); | |
} | |
} | |
} | |
//Fill the gap here | |
while (iterator.hasNext() && deque.size()<size){ | |
long timeDifference = calculateTimeDifference(); | |
if(nextValue+1<timeDifference){ | |
nextValue++; | |
while (nextValue<timeDifference && deque.size()<size){ | |
deque.add(nextValue); | |
populateMap(nextValue); | |
nextValue++; | |
} | |
} | |
if(deque.size()<size){ | |
if(!map.containsKey(timeDifference)){ | |
deque.add(timeDifference); | |
} | |
populateMap(timeDifference,Optional.of(iterator.next())); | |
nextValue = timeDifference; | |
} | |
} | |
if(!deque.isEmpty()) { | |
hasNext = true; | |
} | |
} | |
} | |
private long calculateTimeDifference(){ | |
TimeSeries<T> currentTsData = iterator.peek(); | |
return timeWindow.calculate(startDuration,currentTsData.getTs()); | |
} | |
private void populateMap(long count){ | |
populateMap(count,Optional.empty()); | |
} | |
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") | |
private void populateMap(long count, Optional<TimeSeries<T>> timeSeries){ | |
SortedSet<TimeSeries<T>> sortedSet = map.computeIfAbsent(count, k -> new TreeSet<>()); | |
timeSeries.ifPresent(sortedSet::add); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.iterator.timeseries; | |
import org.idey.algo.util.AssertJ; | |
import java.time.Instant; | |
/** | |
* TimeSeries data which will contain {@link Comparable} object and {@link Instant} | |
* @param <T> object which implements {@link Comparable} | |
*/ | |
public class TimeSeries<T extends Comparable<T>> implements Comparable<TimeSeries<T>> { | |
private T object; | |
private Instant ts; | |
/** | |
* @param object {@link Comparable} and with {@link Instant#now()} | |
*/ | |
public TimeSeries(T object) { | |
this(object, Instant.now()); | |
} | |
public TimeSeries(T object, Instant d){ | |
AssertJ.notNull(object, "Object can not be null"); | |
AssertJ.notNull(d, "Date can not be null"); | |
this.object = object; | |
this.ts = d; | |
} | |
public T getObject() { | |
return object; | |
} | |
public Instant getTs() { | |
return ts; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
TimeSeries<?> that = (TimeSeries<?>) o; | |
return (object != null ? object.equals(that.object) : that.object == null) | |
&& (ts != null ? ts.equals(that.ts) : that.ts == null); | |
} | |
@Override | |
public int hashCode() { | |
int result = object != null ? object.hashCode() : 0; | |
result = 31 * result + (ts != null ? ts.hashCode() : 0); | |
return result; | |
} | |
@SuppressWarnings("ConstantConditions") | |
@Override | |
public int compareTo(TimeSeries<T> o) { | |
if(o==null){ | |
return 1; | |
}else if(this==o){ | |
return 0; | |
}else{ | |
Instant thisDate = this.ts; | |
Instant otherDate = o.ts; | |
if(thisDate==null){ | |
return -1; | |
}else{ | |
int retValue = thisDate.compareTo(otherDate); | |
if(retValue==0){ | |
T obj = this.object; | |
T anotherObject = o.object; | |
if(obj==null){ | |
return -1; | |
}else{ | |
return obj.compareTo(anotherObject); | |
} | |
} | |
return retValue; | |
} | |
} | |
} | |
@Override | |
public String toString() { | |
return "TimeSeries{" + | |
"object=" + object + | |
", ts=" + ts + | |
'}'; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.idey.algo.iterator.timeseries; | |
import org.idey.algo.util.AssertJ; | |
import java.time.Instant; | |
import java.time.temporal.ChronoUnit; | |
/** | |
* TimeWindow which will define difference between two {@link Instant} | |
* @see TimeWindow#SECONDS | |
* @see TimeWindow#MINUTES | |
* @see TimeWindow#HOURS | |
* @see TimeWindow#DAYS | |
*/ | |
public enum TimeWindow { | |
//Return time difference in seconds | |
SECONDS{ | |
@Override | |
public long calculate(Instant t1, Instant t2) { | |
checkValidity(t1, t2); | |
return ChronoUnit.SECONDS.between(t1, t2); | |
} | |
}, | |
//Return time difference in minutes | |
MINUTES{ | |
@Override | |
public long calculate(Instant t1, Instant t2) { | |
checkValidity(t1, t2); | |
return ChronoUnit.MINUTES.between(t1, t2); | |
} | |
}, | |
//Return time difference in hours | |
HOURS{ | |
@Override | |
public long calculate(Instant t1, Instant t2) { | |
checkValidity(t1, t2); | |
return ChronoUnit.HOURS.between(t1, t2); | |
} | |
}, | |
//Return time difference in days | |
DAYS{ | |
@Override | |
public long calculate(Instant t1, Instant t2) { | |
checkValidity(t1, t2); | |
return ChronoUnit.DAYS.between(t1, t2); | |
} | |
}; | |
private static void checkValidity(Instant t1, Instant t2){ | |
AssertJ.notNull(t1, "Duration can not be null"); | |
AssertJ.notNull(t2, "Duration can not be null"); | |
} | |
public abstract long calculate(final Instant t1, final Instant t2); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment