Skip to content

Commit

Permalink
Merge branch 'develop' into feature/jsr-310-localdate
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/main/java/net/fortuna/ical4j/model/NumberList.java
#	src/main/java/net/fortuna/ical4j/model/Recur.java
  • Loading branch information
benfortuna committed Jul 6, 2021
2 parents f032f57 + 4a90a53 commit 4ed6bec
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 11 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Expand Up @@ -49,6 +49,9 @@ dependencies {
// optional timezone caching..
implementation 'javax.cache:cache-api:1.1.1', optional

// optional support for non-Gregorian chronologies..
implementation "org.threeten:threeten-extra:$threetenExtraVersion", optional

// optional groovy DSL for calendar builder..
implementation "org.codehaus.groovy:groovy:$groovyVersion", optional

Expand Down
56 changes: 49 additions & 7 deletions src/main/java/net/fortuna/ical4j/model/NumberList.java
Expand Up @@ -35,9 +35,7 @@

import java.io.Serializable;
import java.time.temporal.ValueRange;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -59,15 +57,28 @@ public class NumberList extends ArrayList<Integer> implements Serializable {
* Default constructor.
*/
public NumberList() {
this(Integer.MIN_VALUE, Integer.MAX_VALUE, true);
this(ValueRange.of(Integer.MIN_VALUE, Integer.MAX_VALUE), true);
}

/**
* Construct a number list restricted by the specified {@link ValueRange}.
* @param valueRange a range defining the lower and upper bounds of allowed values
* @param allowsNegativeValues allow negative values, where abs(value) is within the specified range
*/
public NumberList(ValueRange valueRange, boolean allowsNegativeValues) {
this.valueRange = valueRange;
this.allowsNegativeValues = allowsNegativeValues;
}

/**
* Constructor with limits.
* @param minValue the minimum allowable value
* @param maxValue the maximum allowable value
* @param allowsNegativeValues indicates whether negative values are allowed
*
* @deprecated use {@link NumberList#NumberList(ValueRange, boolean)}
*/
@Deprecated
public NumberList(int minValue, int maxValue, boolean allowsNegativeValues) {
this(ValueRange.of(minValue, maxValue), allowsNegativeValues);
}
Expand All @@ -82,15 +93,29 @@ public NumberList(ValueRange range, boolean allowsNegativeValues) {
* @param aString a string representation of a number list
*/
public NumberList(final String aString) {
this(aString, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
this(aString, ValueRange.of(Integer.MIN_VALUE, Integer.MAX_VALUE), true);
}


/**
* Construct a number list restricted by the specified {@link ValueRange}.
* @param aString a string representation of a list of values
* @param valueRange a range defining the lower and upper bounds of allowed values
* @param allowsNegativeValues allow negative values, where abs(value) is within the specified range
*/
public NumberList(final String aString, ValueRange valueRange, boolean allowsNegativeValues) {
this(valueRange, allowsNegativeValues);
addAll(Arrays.stream(aString.split(",")).map(Numbers::parseInt).collect(Collectors.toList()));
}

/**
* @param aString a string representation of a number list
* @param minValue the minimum allowable value
* @param maxValue the maximum allowable value
* @param allowsNegativeValues indicates whether negative values are allowed
*
* @deprecated use {@link NumberList#NumberList(String, ValueRange, boolean)}
*/
@Deprecated
public NumberList(final String aString, int minValue, int maxValue, boolean allowsNegativeValues) {
this(minValue, maxValue, allowsNegativeValues);
addAll(Arrays.stream(aString.split(",")).parallel().map(Numbers::parseInt).collect(Collectors.toList()));
Expand All @@ -111,11 +136,28 @@ public final boolean add(final Integer aNumber) {
}
if (!range.isValidIntValue(abs)) {
throw new IllegalArgumentException(
"Value not in range [" + range.getMinimum() + ".." + range.getMaximum() + "]: " + aNumber);
"Value not in range [" + range + "]: " + aNumber);
}
return super.add(aNumber);
}

@Override
public boolean addAll(Collection<? extends Integer> c) {
Optional<? extends Integer> negativeValue = c.stream().filter(v -> (v >> 31 | -v >>> 31) < 0)
.findFirst();
if (!allowsNegativeValues && negativeValue.isPresent()) {
throw new IllegalArgumentException("Negative value not allowed: " + negativeValue.get());
}

Optional<? extends Integer> invalidValue = c.stream().filter(v -> !valueRange.isValidValue(Math.abs(v)))
.findFirst();
if (invalidValue.isPresent()) {
throw new IllegalArgumentException(
"Value not in range [" + valueRange + "]: " + invalidValue);
}
return super.addAll(c);
}

/**
* {@inheritDoc}
*/
Expand Down
45 changes: 41 additions & 4 deletions src/main/java/net/fortuna/ical4j/model/Recur.java
Expand Up @@ -39,6 +39,8 @@

import java.io.IOException;
import java.io.Serializable;
import java.time.chrono.Chronology;
import java.time.temporal.ChronoField;
import java.time.LocalDate;
import java.time.temporal.*;
import java.util.*;
Expand Down Expand Up @@ -182,6 +184,30 @@ public class Recur<T extends Temporal> implements Serializable {

private static final String SKIP = "SKIP";

public enum RScale {

JAPANESE("Japanese"),
BUDDHIST("ThaiBuddhist"),
ROC("Minguo"),
ISLAMIC("islamic"),
ISO8601("ISO"),

CHINESE("ISO"),
ETHIOPIC("Ethiopic"),
HEBREW("ISO"),
GREGORIAN("ISO");

private final String chronology;

RScale(String chronology) {
this.chronology = chronology;
}

public String getChronology() {
return chronology;
}
}

public enum Skip {
OMIT, BACKWARD, FORWARD;
}
Expand Down Expand Up @@ -259,7 +285,7 @@ public enum Skip {

private TemporalAdapter<T> until;

private String rscale;
private RScale rscale;

private Integer count;

Expand Down Expand Up @@ -302,6 +328,7 @@ private Recur() {
* @param aValue a string representation of a recurrence.
*/
public Recur(final String aValue) {
Chronology chronology = Chronology.ofLocale(Locale.getDefault());
Iterator<String> tokens = Arrays.asList(aValue.split("[;=]")).iterator();
while (tokens.hasNext()) {
final String token = tokens.next();
Expand All @@ -310,7 +337,8 @@ public Recur(final String aValue) {
} else if (SKIP.equals(token)) {
skip = Skip.valueOf(nextToken(tokens, token));
} else if (RSCALE.equals(token)) {
rscale = nextToken(tokens, token);
rscale = RScale.valueOf(nextToken(tokens, token));
chronology = Chronology.of(rscale.getChronology());
} else if (UNTIL.equals(token)) {
final String untilString = nextToken(tokens, token);
until = TemporalAdapter.parse(untilString);
Expand All @@ -320,22 +348,30 @@ public Recur(final String aValue) {
interval = Integer.parseInt(nextToken(tokens, token));
} else if (BYSECOND.equals(token)) {
secondList.addAll(NumberList.parse(nextToken(tokens, token)));
secondList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.SECOND_OF_MINUTE), false);
} else if (BYMINUTE.equals(token)) {
minuteList.addAll(NumberList.parse(nextToken(tokens, token)));
minuteList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.MINUTE_OF_HOUR), false);
} else if (BYHOUR.equals(token)) {
hourList.addAll(NumberList.parse(nextToken(tokens, token)));
hourList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.HOUR_OF_DAY), false);
} else if (BYDAY.equals(token)) {
dayList.addAll(new WeekDayList(nextToken(tokens, token)));
} else if (BYMONTHDAY.equals(token)) {
monthDayList.addAll(NumberList.parse(nextToken(tokens, token)));
monthDayList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.DAY_OF_MONTH), true);
} else if (BYYEARDAY.equals(token)) {
yearDayList.addAll(NumberList.parse(nextToken(tokens, token)));
yearDayList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.DAY_OF_YEAR), true);
} else if (BYWEEKNO.equals(token)) {
weekNoList.addAll(NumberList.parse(nextToken(tokens, token)));
weekNoList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.ALIGNED_WEEK_OF_YEAR), true);
} else if (BYMONTH.equals(token)) {
monthList.addAll(new MonthList(nextToken(tokens, token), ValueRange.of(1, 12, 13)));
monthList = new MonthList(nextToken(tokens, token), chronology.range(ChronoField.MONTH_OF_YEAR));
} else if (BYSETPOS.equals(token)) {
setPosList.addAll(NumberList.parse(nextToken(tokens, token)));
setPosList = new NumberList(nextToken(tokens, token), chronology.range(ChronoField.DAY_OF_YEAR), true);
} else if (WKST.equals(token)) {
weekStartDay = WeekDay.getWeekDay(WeekDay.Day.valueOf(nextToken(tokens, token)));
} else {
Expand Down Expand Up @@ -1058,7 +1094,7 @@ public static class Builder<T extends Temporal> {

private T until;

private String rscale;
private RScale rscale;

private Integer count;

Expand Down Expand Up @@ -1099,7 +1135,7 @@ public Builder<T> until(T until) {
return this;
}

public Builder rscale(String rscale) {
public Builder rscale(RScale rscale) {
this.rscale = rscale;
return this;
}
Expand Down Expand Up @@ -1167,6 +1203,7 @@ public Builder<T> weekStartDay(WeekDay weekStartDay) {
public Recur<T> build() {
Recur<T> recur = new Recur<>();
recur.frequency = frequency;
recur.rscale = rscale;
recur.skip = skip;
if (until != null) {
recur.until = new TemporalAdapter<T>(until);
Expand Down

0 comments on commit 4ed6bec

Please sign in to comment.