All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.time4j.engine.ChronoEntity Maven / Gradle / Ivy

There is a newer version: 4.38
Show newest version
/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2016 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (ChronoEntity.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 net.time4j.tz.TZID;

import java.util.Set;


/**
 * 

Represents a temporal object which associates partial temporal values * with chronological elements and also allows some manipulations of these * element values.

* *

A {@code ChronoEntity} is usually a {@code TimePoint}, where the * (primary) element values determine the position on a time axis such * that a time arithmetic is possible. Alternatively a {@code ChronoEntity} * can also represent a partial information like the combination of month * and day-of-month for a simple display of a birthday.

* *

Chronological elements are either statically registered such that * a direct access is enabled, or there is an (external) rule which * enables read- and write-access. If no element rule can be found a * {@code RuleNotFoundException} will be thrown.

* * @param generic type of self reference * @author Meno Hochschild * @doctags.spec All public implementations must be immutable. */ /*[deutsch] *

Repräsentiert ein Zeitwertobjekt, das einzelne Werte mit * chronologischen Elementen assoziiert und einen Zugriff auf diese * Werte erlaubt.

* *

Eine {@code ChronoEntity} ist gewöhnlich ein {@code TimePoint}, * bei dem die (primären) Elementwerte zusammen die Position auf einem * Zeitstrahl festlegen, so daß auch eine Zeitarithmetik möglich * ist. Alternativ kann eine {@code ChronoEntity} eine chronologische * Teilinformation wie z.B. die Kombination aus Monat und Tag zur einfachen * Darstellung eines Geburtstags repräsentieren.

* *

Chronologische Elemente sind entweder vorab registriert, so daß * ein Zugriff direkt möglich ist, oder es gibt eine Regel, die den * Lese- bzw. Schreibzugriff ermöglicht. Ist die Regel nicht vorhanden, * wird eine {@code RuleNotFoundException} geworfen.

* * @param generic type of self reference * @author Meno Hochschild * @doctags.spec All public implementations must be immutable. */ public abstract class ChronoEntity> implements ChronoDisplay { //~ Methoden ---------------------------------------------------------- @Override public boolean contains(ChronoElement element) { return this.getChronology().isSupported(element); } @Override public V get(ChronoElement element) { return this.getRule(element).getValue(this.getContext()); } @Override public int getInt(ChronoElement element) { IntElementRule intRule = this.getChronology().getIntegerRule(element); try { if (intRule == null) { return this.get(element).intValue(); } else { return intRule.getInt(this.getContext()); } } catch (ChronoException ex) { return Integer.MIN_VALUE; } } @Override public V getMinimum(ChronoElement element) { return this.getRule(element).getMinimum(this.getContext()); } @Override public V getMaximum(ChronoElement element) { return this.getRule(element).getMaximum(this.getContext()); } /** *

Lets given query evaluate this entity.

* *

Is equivalent to {@code function.apply(this)}. The applied * strategy pattern hereby enables the externalization of querying * the interpretation and evaluation of this entity, consequently * enabling user-defined queries with arbitrary result types R. * Main difference to chronological elements is read-only access. * Users have to consult the documentation of given query to decide * if this method will yield {@code null} or throws an exception * if the result is undefined or otherwise not obtainable.

* * @param generic type of result of query * @param function time query * @return result of query or {@code null} if undefined * @throws ChronoException if the given query is not executable */ /*[deutsch] *

Läßt die angegebene Abfrage diese Entität * auswerten.

* *

Entspricht {@code function.apply(this)}. Hierüber wird der * Vorgang der Zeitinterpretation externalisiert und ermöglicht * so benutzerdefinierte Abfragen mit beliebigen Ergebnistypen. Anders * als bei chronologischen Elementen ist hier nur ein Lesezugriff * möglich. In der Dokumentation der jeweiligen {@code ChronoFunction} * ist nachzuschauen, ob diese Methode im Fall undefinierter Ergebnisse * {@code null} zurückgibt oder eine Ausnahme wirft.

* * @param generic type of result of query * @param function time query * @return result of query or {@code null} if undefined * @throws ChronoException if the given query is not executable */ public final R get(ChronoFunction function) { return function.apply(this.getContext()); } /** *

Queries if this entity matches given condition.

* *

Is equivalent to {@code condition.test(this)}. This method * will never throw an exception. This behaviour is in contrast * to that of {@code ChronoFunction}.

* * @param condition temporal condition * @return {@code true} if the given condition is matched by this * entity else {@code false} * @see #get(ChronoFunction) */ /*[deutsch] *

Genügt diese Instanz der angegebenen Bedingung?

* *

Entspricht {@code condition.test(this)}. Diese Methode wirft * anders als eine allgemeine {@code ChronoFunction} keine Ausnahme.

* * @param condition temporal condition * @return {@code true} if the given condition is matched by this * entity else {@code false} * @see #get(ChronoFunction) */ public boolean matches(ChronoCondition condition) { return condition.test(this.getContext()); } /** *

Tests if the value for given chronological value is invalid.

* *

Notes: This method tests if given value to be in question can * be set via the expression {@code with(element, value)}. A numerical * overflow situation (causing an {@code ArithmeticException}) will * usually not be checked.

* * @param generic type of element value * @param element element the given value shall be assigned to * @param value candidate value to be validated (optional) * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, Object) with(ChronoElement, V) */ /*[deutsch] *

Ist der Wert zum angegebenen chronologischen Element gültig?

* *

Hinweise: Diese Methode testet, ob der fragliche Wert mittels des * Ausdrucks {@code with(element, value)} überhaupt gesetzt werden * kann. Eine numerische Überlaufsituation im Hinblick auf eine * {@code ArithmeticException} wird in der Regel nicht geprüft.

* * @param generic type of element value * @param element element the given value shall be assigned to * @param value candidate value to be validated (optional) * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, Object) with(ChronoElement, V) */ public boolean isValid( ChronoElement element, V value ) { if (element == null) { throw new NullPointerException("Missing chronological element."); } return ( this.contains(element) && this.getRule(element).isValid(this.getContext(), value) ); } /** *

Tests if the value for given chronological value is invalid.

* *

Notes: This method tests if given value to be in question can * be set via the expression {@code with(element, value)}. A numerical * overflow situation (causing an {@code ArithmeticException}) will * usually not be checked.

* * @param element element the given value shall be assigned to * @param value candidate value to be validated * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, int) */ /*[deutsch] *

Ist der Wert zum angegebenen chronologischen Element gültig?

* *

Hinweis: Eine numerische Überlaufsituation im Hinblick auf eine * {@code ArithmeticException} wird nicht geprüft.

* * @param element element the given value shall be assigned to * @param value candidate value to be validated * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, int) */ public boolean isValid( ChronoElement element, int value ) { IntElementRule intRule = this.getChronology().getIntegerRule(element); if (intRule != null) { return intRule.isValid(this.getContext(), value); } return this.isValid(element, Integer.valueOf(value)); } /** *

Tests if the value for given chronological value is invalid.

* *

Notes: This method tests if given value to be in question can * be set via the expression {@code with(element, value)}. A numerical * overflow situation (causing an {@code ArithmeticException}) will * usually not be checked.

* * @param element element the given value shall be assigned to * @param value candidate value to be validated * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, long) */ /*[deutsch] *

Ist der Wert zum angegebenen chronologischen Element gültig?

* *

Hinweis: Eine numerische Überlaufsituation im Hinblick auf eine * {@code ArithmeticException} wird nicht geprüft.

* * @param element element the given value shall be assigned to * @param value candidate value to be validated * @return {@code true} if the method {@code with()} can be called * without exception else {@code false} * @see #with(ChronoElement, long) */ public boolean isValid( ChronoElement element, long value ) { return this.isValid(element, Long.valueOf(value)); } /** *

Creates a copy of this instance with the changed element value.

* *

A {@code null} value will almost ever be seen as invalid causing an * {@code IllegalArgumentException}. Subclasses which permit {@code null} * must explicitly document this feature.

* * @param generic type of element value * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ /*[deutsch] *

Erstellt eine Kopie dieser Instanz mit dem geänderten * Elementwert.

* *

Ein {@code null}-Wert wird fast immer als ungültig angesehen, * also zu einer {@code IllegalArgumentException} führen. Subklassen, * die {@code null} zulassen, müssen das explizit dokumentieren.

* * @param generic type of element value * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ public T with( ChronoElement element, V value ) { return this.getRule(element).withValue( this.getContext(), value, element.isLenient() ); } /** *

Creates a copy of this instance with the changed element value.

* * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ /*[deutsch] *

Erstellt eine Kopie dieser Instanz mit dem geänderten * Elementwert.

* * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ public T with( ChronoElement element, int value ) { IntElementRule intRule = this.getChronology().getIntegerRule(element); if (intRule != null) { return intRule.withValue(this.getContext(), value, element.isLenient()); } return this.with(element, Integer.valueOf(value)); } /** *

Creates a copy of this instance with the changed element value.

* * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ /*[deutsch] *

Erstellt eine Kopie dieser Instanz mit dem geänderten * Elementwert.

* * @param element chronological element * @param value new element value * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if the element is not registered and there * is no element rule for setting the value * @throws IllegalArgumentException if the value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #isValid(ChronoElement, Object) isValid(ChronoElement, V) */ public T with( ChronoElement element, long value ) { return this.with(element, Long.valueOf(value)); } /** *

Creates a copy of this instance which is adjusted by given * {@code ChronoOperator} using a strategy pattern approach.

* *

Is equivalent to {@code operator.apply(this)}. Hereby a user-defined * manipulation will be externalized and is semantically similar to the * reading counterpart {@code ChronoFunction}.

* * @param operator operator for adjusting the element values * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if no element rule exists for setting the values * @throws IllegalArgumentException if any new value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #get(ChronoFunction) */ /*[deutsch] *

Liefert eine Kopie dieser Instanz zurück, die mit Hilfe * eines {@code ChronoOperator}-Objekts angepasst wird.

* *

Entspricht {@code operator.apply(this)}. Hierüber wird eine * benutzerdefinierte Manipulation externalisiert und ist semantisch * ähnlich wie im lesenden Gegenstück {@code ChronoFunction}.

* * @param operator operator for adjusting the element values * @return changed copy of the same type, this instance remains unaffected * @throws ChronoException if no element rule exists for setting the values * @throws IllegalArgumentException if any new value is not valid * @throws ArithmeticException in case of arithmetic overflow * @see #get(ChronoFunction) */ public T with(ChronoOperator operator) { return operator.apply(this.getContext()); } /** *

Queries if this entity contains a timezone for display purposes.

* *

This implementation has no timezone by default and yields * {@code false}. Subclasses with a timezone reference intended for * formatted output will override the method in a suitable way.

* * @return {@code true} if a timezone is available and can be achieved * with {@link #getTimezone()} else {@code false} */ /*[deutsch] *

Ermittelt, ob eine Zeitzone für Anzeigezwecke vorhanden ist.

* *

Diese Implementierung kennt standardmäßig keine Zeitzone * und liefert {@code false}. Subklassen mit einem Zeitzonenbezug gedacht * für formatierte Darstellungen werden die Methode in geeigneter Weise * überschreiben.

* * @return {@code true} if a timezone is available and can be achieved * with {@link #getTimezone()} else {@code false} */ @Override public boolean hasTimezone() { return false; } /** *

Returns the associated timezone ID for display purposes * if available.

* *

This implementation throws a {@code ChronoException} * by default. Subclasses with a timezone reference intended for * formatted output will override the method in a suitable way.

* * @return timezone identifier if available * @throws ChronoException if the timezone is not available * @see #hasTimezone() */ /*[deutsch] *

Liefert die assoziierte Zeitzonen-ID für Anzeigezwecke, * wenn vorhanden.

* *

Diese Implementierung wirft standardmäßig eine * {@code ChronoException}. Subklassen mit einem Zeitzonenbezug * gedacht für formatierte Darstellungen werden die Methode * in geeigneter Weise überschreiben.

* * @return timezone identifier if available * @throws ChronoException if the timezone is not available * @see #hasTimezone() */ @Override public TZID getTimezone() { throw new ChronoException("Timezone not available: " + this); } /** *

Yields all registered elements of this instance.

* *

Note that some (external) elements can be supported but not registered.

* * @return unmodifiable set of internally registered elements * @since 3.13/4.10 */ /*[deutsch] *

Liefert alle registrierten Elemente dieser Instanz.

* *

Hinweis: Einige (externe) Elemente können unterstützt werden, sind aber nicht * registriert.

* * @return unmodifiable set of internally registered elements * @since 3.13/4.10 */ public Set> getRegisteredElements() { return this.getChronology().getRegisteredElements(); } /** *

Returns the assigned chronology which contains all necessary * chronological rules.

* *

Concrete subclasses must create in a static initializer a * chronology by help of {@code Chronology.Builder}, keep it as static * constant and make it available here. Using the procedure guarantees * that a basic set of registered elements and rules will be installed.

* * @return chronological system * @throws UnsupportedOperationException if not available (subclasses * must document this extreme rare case) * @see Chronology.Builder */ /*[deutsch] *

Liefert die zugehörige Chronologie, die alle notwendigen * chronologischen Regeln enthält.

* *

Konkrete Subklassen müssen in einem static initializer * mit Hilfe von {@code Chronology.Builder} oder {@code TimeAxis.Builder} * eine Chronologie bauen, in einer eigenen Konstanten halten und hier * verfügbar machen. Über dieses Verfahren wird zugleich ein * Basissatz von Elementen und chronologischen Regeln vorinstalliert.

* * @return chronological system * @throws UnsupportedOperationException if not available (subclasses * must document this rare case) * @see Chronology.Builder */ protected abstract Chronology getChronology(); /** *

Liefert den Selbstbezug.

* * @return time context (usually this instance) */ protected T getContext() { Chronology c = this.getChronology(); Class type = c.getChronoType(); if (type.isInstance(this)) { return type.cast(this); } else { for (ChronoElement element : c.getRegisteredElements()) { if (type == element.getType()) { return type.cast(this.get(element)); } } } throw new IllegalStateException( "Implementation error: Cannot find entity context."); } /** * Determines the associated element rule. * * @param value type of element * @param element chronological element to be evaluated * @return element rule * @throws RuleNotFoundException if a rule cannot be determined */ ElementRule getRule(ChronoElement element) { return this.getChronology().getRule(element); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy