
net.time4j.engine.CalendarFamily Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2017 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (CalendarFamily.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see .
* -----------------------------------------------------------------------
*/
package net.time4j.engine;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* Represents a set of various calendar systems as members of a family.
*
* @param generic type compatible to {@link CalendarVariant}
* @author Meno Hochschild
* @since 3.4/4.3
*/
/*[deutsch]
* Repräsentiert eine Familie von miteinander verwandten Kalendersystemen.
*
* @param generic type compatible to {@link CalendarVariant}
* @author Meno Hochschild
* @since 3.4/4.3
*/
public final class CalendarFamily>
extends Chronology {
//~ Instanzvariablen --------------------------------------------------
private final Map> calendars; // must never be exposed
//~ Konstruktoren -----------------------------------------------------
private CalendarFamily(
Class chronoType,
ChronoMerger chronoMerger,
Map, ElementRule> ruleMap,
List extensions,
Map> calendars
) {
super(chronoType, chronoMerger, ruleMap, extensions);
this.calendars = calendars;
}
//~ Methoden ----------------------------------------------------------
@Override
public boolean hasCalendarSystem() {
return true;
}
@Override
public CalendarSystem getCalendarSystem() {
if (this.calendars.size() == 1) {
return this.calendars.values().iterator().next();
} else {
throw new ChronoException("Cannot determine calendar system without variant.");
}
}
@Override
public CalendarSystem getCalendarSystem(String variant) {
if (variant.isEmpty()) {
return this.getCalendarSystem();
}
CalendarSystem result = this.calendars.get(variant);
if (result == null) {
return super.getCalendarSystem(variant);
} else {
return result;
}
}
/**
* Obtains an object which is useful for generic interval support.
*
* @param variant name of calendar variant
* @return serializable timeline which is variant-specific
* @since 3.36/4.31
*/
/*[deutsch]
* Liefert ein Objekt, das für die allgemeine Intervallunterstützung nützlich ist.
*
* @param variant name of calendar variant
* @return serializable timeline which is variant-specific
* @since 3.36/4.31
*/
public TimeLine getTimeLine(String variant) {
return new CalendarTimeLine<>(this, variant);
}
@Override
public boolean isSupported(ChronoElement> element) {
return super.isSupported(element) || (element instanceof EpochDays);
}
//~ Innere Klassen ----------------------------------------------------
/**
* Creates a builder for a new calendar family
* and will only be used during loading a class of a calendar variant
* in a static initializer.
*
* Instances of this class will be created by the static factory method {@code setUp()}.
*
* @param generic type of time context
* @author Meno Hochschild
* @see #setUp(Class,ChronoMerger,Map)
* @since 3.4/4.3
* @doctags.concurrency {mutable}
*/
/*[deutsch]
* Erzeugt einen Builder für eine neue Kalenderfamilie und wird ausschließlich beim Laden einer
* Klasse zu einer Kalendervariante in einem static initializer benutzt.
*
* Instanzen dieser Klasse werden über die statische {@code setUp()}-Fabrikmethode erzeugt.
*
* @param generic type of time context
* @author Meno Hochschild
* @see #setUp(Class,ChronoMerger,Map)
* @since 3.4/4.3
* @doctags.concurrency {mutable}
*/
public static final class Builder>
extends Chronology.Builder {
//~ Instanzvariablen ----------------------------------------------
private final Map> calendars;
//~ Konstruktoren -------------------------------------------------
private Builder(
Class chronoType,
ChronoMerger merger,
Map> calendars
) {
super(chronoType, merger);
if (calendars.isEmpty()) {
throw new IllegalArgumentException("Missing calendar variants.");
}
this.calendars = calendars;
}
//~ Methoden ------------------------------------------------------
/**
* Creates a builder for building a calendar family.
*
* @param generic type of time context
* @param chronoType reified chronological type
* @param merger generic replacement for static creation of variant objects
* @param calendars map of variant names to calendar systems
* @return new {@code Builder} object
* @throws IllegalArgumentException if no calendar system is specified
* @since 3.4/4.3
*/
/*[deutsch]
* Erzeugt ein Hilfsobjekt zum Bauen einer Kalenderfamilie.
*
* @param generic type of time context
* @param chronoType reified chronological type
* @param merger generic replacement for static creation of variant objects
* @param calendars map of variant names to calendar systems
* @return new {@code Builder} object
* @throws IllegalArgumentException if no calendar system is specified
* @since 3.4/4.3
*/
public static > Builder setUp(
Class chronoType,
ChronoMerger merger,
Map> calendars
) {
return new Builder<>(chronoType, merger, calendars);
}
@Override
public Builder appendElement(
ChronoElement element,
ElementRule rule
) {
super.appendElement(element, rule);
return this;
}
@Override
public Builder appendExtension(ChronoExtension extension) {
super.appendExtension(extension);
return this;
}
/**
* Creates and registers a calendar family.
*
* @return new chronology as calendar family
* @throws IllegalStateException if already registered or in case of inconsistencies
* @since 3.4/4.3
*/
/*[deutsch]
* Erzeugt und registriert eine Kalenderfamilie.
*
* @return new chronology as calendar family
* @throws IllegalStateException if already registered or in case of inconsistencies
* @since 3.4/4.3
*/
@Override
public CalendarFamily build() {
CalendarFamily engine =
new CalendarFamily<>(
this.chronoType,
this.merger,
this.ruleMap,
this.extensions,
this.calendars
);
Chronology.register(engine);
return engine;
}
}
private static class CalendarTimeLine>
implements TimeLine, Serializable {
//~ Instanzvariablen ----------------------------------------------
private transient final CalendarSystem calsys;
// only for deserialization
private final Class chronoType;
private final String variant;
//~ Konstruktoren -------------------------------------------------
private CalendarTimeLine(
Chronology chronology,
String variant
) {
super();
this.calsys = chronology.getCalendarSystem(variant);
this.chronoType = chronology.getChronoType();
this.variant = variant;
}
//~ Methoden ------------------------------------------------------
@Override
public D stepForward(D timepoint) {
if (timepoint.getDaysSinceEpochUTC() == this.calsys.getMaximumSinceUTC()) {
return null;
}
return timepoint.plus(CalendarDays.ONE);
}
@Override
public D stepBackwards(D timepoint) {
if (timepoint.getDaysSinceEpochUTC() == this.calsys.getMinimumSinceUTC()) {
return null;
}
return timepoint.minus(CalendarDays.ONE);
}
@Override
public boolean isCalendrical() {
return true;
}
@Override
public int compare(D o1, D o2) {
// pure time comparison, we don't take into account the variant in context of timeline
return Long.compare(o1.getDaysSinceEpochUTC(), o2.getDaysSinceEpochUTC());
}
@Override
public D getMinimum() {
return this.calsys.transform(this.calsys.getMinimumSinceUTC());
}
@Override
public D getMaximum() {
return this.calsys.transform(this.calsys.getMaximumSinceUTC());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof CalendarTimeLine) {
CalendarTimeLine> that = (CalendarTimeLine>) obj;
return this.chronoType == that.chronoType && this.variant.equals(that.variant);
} else {
return false;
}
}
@Override
public int hashCode() {
return this.chronoType.hashCode() + 31 * this.variant.hashCode();
}
// reconstruct the calendar system in deserialization
private Object readResolve() throws ObjectStreamException {
Chronology chronology = Chronology.lookup(this.chronoType);
return new CalendarTimeLine<>(chronology, this.variant);
}
}
}