From cc905ee6f24e96389cabfcb543bcd0cd2b6da3f2 Mon Sep 17 00:00:00 2001 From: Hericode Date: Fri, 28 Nov 2025 11:49:52 +0100 Subject: [PATCH] Basic support for ExtraData --- .../datatransfer/dto/CashRegisterDTO.java | 25 +- .../datatransfer/dto/CashSessionDTO.java | 17 +- .../datatransfer/dto/MovementDTO.java | 17 +- .../coreutil/datatransfer/dto/PaymentDTO.java | 17 +- .../datatransfer/dto/TaxAmountDTO.java | 17 +- .../coreutil/datatransfer/dto/TaxDTO.java | 17 +- .../coreutil/datatransfer/dto/TicketDTO.java | 17 +- .../coreutil/datatransfer/dto/ZTicketDTO.java | 18 +- .../datatransfer/dto/package-info.java | 2 + .../datatransfer/parser/JSONReader.java | 123 ++----- .../coreutil/datatransfer/parser/Reader.java | 10 + .../datatransfer/parser/ReaderHelper.java | 169 +++++++++ .../coreutil/datatransfer/parser/Writer.java | 119 ++++++ .../pasteque/coreutil/extra/ExtraArray.java | 193 ++++++++++ .../pasteque/coreutil/extra/ExtraBoolean.java | 55 +++ .../pasteque/coreutil/extra/ExtraBuilder.java | 348 ++++++++++++++++++ .../pasteque/coreutil/extra/ExtraData.java | 31 ++ .../pasteque/coreutil/extra/ExtraDouble.java | 55 +++ .../org/pasteque/coreutil/extra/ExtraInt.java | 55 +++ .../pasteque/coreutil/extra/ExtraNull.java | 44 +++ .../pasteque/coreutil/extra/ExtraObject.java | 200 ++++++++++ .../pasteque/coreutil/extra/ExtraString.java | 61 +++ .../pasteque/coreutil/extra/ExtraType.java | 116 ++++++ .../pasteque/coreutil/extra/package-info.java | 12 + .../coreutil/transition/LineTransition.java | 9 + .../coreutil/transition/OrderTransition.java | 16 + .../major/domain/MajorCashSession.java | 17 +- .../org/pasteque/major/domain/MajorLine.java | 15 +- .../org/pasteque/major/domain/MajorOrder.java | 34 +- .../pasteque/major/domain/MajorTicket.java | 26 +- .../org/pasteque/major/domain/Movement.java | 20 +- .../org/pasteque/major/domain/Payment.java | 20 +- .../pasteque/major/domain/package-info.java | 1 - 33 files changed, 1765 insertions(+), 131 deletions(-) create mode 100644 src/main/java/org/pasteque/coreutil/datatransfer/parser/ReaderHelper.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraArray.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraBoolean.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraBuilder.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraData.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraDouble.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraInt.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraNull.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraObject.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraString.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/ExtraType.java create mode 100644 src/main/java/org/pasteque/coreutil/extra/package-info.java diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashRegisterDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashRegisterDTO.java index 6d30259..2c0bff7 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashRegisterDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashRegisterDTO.java @@ -8,6 +8,7 @@ import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.integrity.InvalidFieldException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityException; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Physical cash register hardware Data Transfer Object.

@@ -17,28 +18,31 @@ public final class CashRegisterDTO implements DTOInterface, Serializable { private static final long serialVersionUID = 1079581813013284003L; - /** {@see getReference()} */ + /** See {@link getReference()}. */ private String reference; - - /** {@see getLabel()} */ + /** See {@link getLabel()}. */ private String label; - - /** {@see getNextTicketNumber()} */ + /** See {@link getNextTicketNumber()}. */ private int nextTicketNumber; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create from all fields. * @param reference The unique reference. * @param label The display name. * @param nextTicketNumber See {@link getNextTicketNumber}. + * @param extra See {@link getExtra()}. */ public CashRegisterDTO( String reference, String label, - int nextTicketNumber) { + int nextTicketNumber, + ExtraObject extra) { this.reference = reference; this.label = label; this.nextTicketNumber = nextTicketNumber; + this.extra = extra; } /** @@ -51,6 +55,7 @@ public final class CashRegisterDTO implements DTOInterface, Serializable this.reference = reader.readString("reference"); this.label = reader.readString("label"); this.nextTicketNumber = reader.readInt("nextTicketId"); + this.extra = reader.readExtra(); } /** @@ -78,6 +83,14 @@ public final class CashRegisterDTO implements DTOInterface, Serializable return nextTicketNumber; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + /** * Check if the reference and labels are set and nextTicketNumber is * positive or zero. diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashSessionDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashSessionDTO.java index e8c6324..a62f626 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashSessionDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/CashSessionDTO.java @@ -7,6 +7,7 @@ import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.DTOFactory; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Non finished cash session Data Transfer Object.

@@ -31,6 +32,8 @@ public final class CashSessionDTO implements DTOInterface, Serializable private ImmutableList movements; /** See {@link getTickets()}. */ private ImmutableList tickets; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a cash session from all fields. @@ -40,6 +43,7 @@ public final class CashSessionDTO implements DTOInterface, Serializable * @param openDate See {@link getOpenDate()}. * @param movements See {@link getMovements()}. * @param tickets See {@link getTickets()}. + * @param extra See {@link getExtra()}. */ public CashSessionDTO( WeakAssociationDTO cashRegister, @@ -47,13 +51,15 @@ public final class CashSessionDTO implements DTOInterface, Serializable boolean continuous, Date openDate, ImmutableList movements, - ImmutableList tickets) { + ImmutableList tickets, + ExtraObject extra) { this.cashRegister = cashRegister; this.sequence = sequence; this.continuous = continuous; this.openDate = openDate; this.movements = movements; this.tickets = tickets; + this.extra = extra; } /** @@ -73,6 +79,7 @@ public final class CashSessionDTO implements DTOInterface, Serializable this.movements = mvtFacto.immutableReadObjects("movements"); DTOFactory tktFacto = new DTOFactory(reader, FiscalTicketDTO.class); this.tickets = tktFacto.immutableReadObjects("tickets"); + this.extra = reader.readExtra(); } /** @@ -131,6 +138,14 @@ public final class CashSessionDTO implements DTOInterface, Serializable return this.tickets; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/MovementDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/MovementDTO.java index 8b4695f..9999d2d 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/MovementDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/MovementDTO.java @@ -5,6 +5,7 @@ import java.util.Date; import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Change in currency amounts not introduced by the payment of a ticket. @@ -26,6 +27,8 @@ public final class MovementDTO implements DTOInterface, Serializable private double currencyAmount; /** See {@link getDate()}. */ private Date date; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a movement from all fields. @@ -33,16 +36,19 @@ public final class MovementDTO implements DTOInterface, Serializable * @param currency See {@link getCurrency()}. * @param currencyAmount See {@link getCurrencyAmount()}. * @param date See {@link getDate()}. + * @param extra See {@link getExtra()}. */ public MovementDTO( WeakAssociationDTO paymentMode, WeakAssociationDTO currency, double currencyAmount, - Date date) { + Date date, + ExtraObject extra) { this.paymentMode = paymentMode; this.currency = currency; this.currencyAmount = currencyAmount; this.date = date; + this.extra = extra; } /** @@ -60,6 +66,7 @@ public final class MovementDTO implements DTOInterface, Serializable reader.endObject(); this.currencyAmount = reader.readDouble("currencyAmount"); this.date = reader.readDate("date"); + this.extra = reader.readExtra(); } /** @@ -94,6 +101,14 @@ public final class MovementDTO implements DTOInterface, Serializable return this.date; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/PaymentDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/PaymentDTO.java index e712830..afd10e5 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/PaymentDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/PaymentDTO.java @@ -4,6 +4,7 @@ import java.io.Serializable; import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Payment amount Data Transfer Object. A payment may refer to a single one @@ -24,6 +25,8 @@ public final class PaymentDTO implements DTOInterface, Serializable private double amount; /** See {@link getCurrencyAmount()}. */ private double currencyAmount; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a payment from all fields. @@ -31,16 +34,19 @@ public final class PaymentDTO implements DTOInterface, Serializable * @param amount See {@link getAmount()}. * @param currency See {@link getCurrency()}. * @param currencyAmount See {@link getCurrencyAmount()}. + * @param extra See {@link getExtra()}. */ public PaymentDTO( WeakAssociationDTO paymentMode, double amount, WeakAssociationDTO currency, - double currencyAmount) { + double currencyAmount, + ExtraObject extra) { this.paymentMode = paymentMode; this.amount = amount; this.currency = currency; this.currencyAmount = currencyAmount; + this.extra = extra; } /** @@ -58,6 +64,7 @@ public final class PaymentDTO implements DTOInterface, Serializable this.currency = new WeakAssociationDTO(reader); reader.endObject(); this.currencyAmount = reader.readDouble("currencyAmount"); + this.extra = reader.readExtra(); } /** @@ -92,6 +99,14 @@ public final class PaymentDTO implements DTOInterface, Serializable return this.currencyAmount; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxAmountDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxAmountDTO.java index 77aaacd..37bb238 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxAmountDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxAmountDTO.java @@ -4,6 +4,7 @@ import java.io.Serializable; import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Tax amount Data Transfer Object. A tax amount may refer to a single one @@ -26,6 +27,8 @@ public final class TaxAmountDTO implements DTOInterface, Serializable private double amount; /** See {@link getIncludedInBase()}. */ private boolean includedInBase; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a tax from all fields. @@ -34,18 +37,21 @@ public final class TaxAmountDTO implements DTOInterface, Serializable * @param base See {@link getBase()}. * @param amount See {@link getAmount()}. * @param includedInBase See {@link getIncludedInBase()}. + * @param extra See {@link getExtra()}. */ public TaxAmountDTO( WeakAssociationDTO tax, double taxRate, double base, double amount, - boolean includedInBase) { + boolean includedInBase, + ExtraObject extra) { this.tax = tax; this.taxRate = taxRate; this.base = base; this.amount = amount; this.includedInBase = includedInBase; + this.extra = extra; } /** @@ -62,6 +68,7 @@ public final class TaxAmountDTO implements DTOInterface, Serializable this.base = reader.readDouble("base"); this.amount = reader.readDouble("amount"); this.includedInBase = reader.readBoolean("includedInBase"); + this.extra = reader.readExtra(); } /** @@ -106,6 +113,14 @@ public final class TaxAmountDTO implements DTOInterface, Serializable return this.includedInBase; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxDTO.java index 5bc26e8..d40551a 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TaxDTO.java @@ -4,6 +4,7 @@ import java.io.Serializable; import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** * Tax Data Transfer Object. @@ -17,20 +18,25 @@ public final class TaxDTO implements DTOInterface, Serializable private double amount; /** See {@link getIncludedInBase()}. */ private boolean includedInBase; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a tax from all fields. * @param type See {@link getType()}. * @param amount See {@link getAmount()}. * @param includedInBase See {@link getIncludedInBase()}. + * @param extra See {@link getExtra()}. */ public TaxDTO( String type, double amount, - boolean includedInBase) { + boolean includedInBase, + ExtraObject extra) { this.type = type; this.amount = amount; this.includedInBase = includedInBase; + this.extra = extra; } /** @@ -43,6 +49,7 @@ public final class TaxDTO implements DTOInterface, Serializable this.type = reader.readString("type"); this.amount = reader.readDouble("amount"); this.includedInBase = reader.readBoolean("includedInBase"); + this.extra = reader.readExtra(); } /** @@ -75,6 +82,14 @@ public final class TaxDTO implements DTOInterface, Serializable return this.includedInBase; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TicketDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TicketDTO.java index bf839c4..30a7958 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/TicketDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/TicketDTO.java @@ -7,6 +7,7 @@ import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.DTOFactory; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Receipt of a finalized and paid order. Tickets are immutable unless changes @@ -55,6 +56,8 @@ public final class TicketDTO implements DTOInterface, Serializable private double finalPrice; /** See {@link getFinalTaxedPrice()}. */ private double finalTaxedPrice; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create an ticket from all fields. @@ -76,6 +79,7 @@ public final class TicketDTO implements DTOInterface, Serializable * @param discountRate See {@link getDiscountRate()}. * @param finalPrice See {@link getFinalPrice()}. * @param finalTaxedPrice See {@link getFinalTaxedPrice()}. + * @param extra See {@link getExtra()}. */ public TicketDTO( WeakAssociationDTO cashRegister, @@ -95,7 +99,8 @@ public final class TicketDTO implements DTOInterface, Serializable WeakAssociationDTO discountProfile, double discountRate, double finalPrice, - double finalTaxedPrice) { + double finalTaxedPrice, + ExtraObject extra) { this.cashRegister = cashRegister; this.sequence = sequence; this.number = number; @@ -114,6 +119,7 @@ public final class TicketDTO implements DTOInterface, Serializable this.discountRate = discountRate; this.finalPrice = finalPrice; this.finalTaxedPrice = finalTaxedPrice; + this.extra = extra; } /** @@ -146,6 +152,7 @@ public final class TicketDTO implements DTOInterface, Serializable this.taxes = taxFacto.immutableReadObjects("taxes"); DTOFactory pmtFacto = new DTOFactory(reader, PaymentDTO.class); this.payments = pmtFacto.immutableReadObjects("payments"); + this.extra = reader.readExtra(); } /** @@ -311,6 +318,14 @@ public final class TicketDTO implements DTOInterface, Serializable return this.finalTaxedPrice; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/ZTicketDTO.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/ZTicketDTO.java index b4e9e13..0c185a7 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/ZTicketDTO.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/ZTicketDTO.java @@ -7,6 +7,7 @@ import org.pasteque.coreutil.ParseException; import org.pasteque.coreutil.datatransfer.integrity.IntegrityExceptions; import org.pasteque.coreutil.datatransfer.parser.DTOFactory; import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Receipt of a finalized cash session. Once a cash session is closed, @@ -64,6 +65,8 @@ public final class ZTicketDTO implements DTOInterface, Serializable private ImmutableList payments; /** See {@link getCustBalances()}. */ private ImmutableList custBalances; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create an ticket from all fields. @@ -87,6 +90,7 @@ public final class ZTicketDTO implements DTOInterface, Serializable * @param catTaxes See {@link getCatTaxes()}. * @param payments See {@link getPayments()}. * @param custBalances See {@link getCustBalances()}. + * @param extra See {@link getExtra()}. */ public ZTicketDTO( WeakAssociationDTO cashRegister, @@ -108,7 +112,8 @@ public final class ZTicketDTO implements DTOInterface, Serializable ZTicketCatSalesDTO[] catSales, ZTicketCatTaxesDTO[] catTaxes, PaymentDTO[] payments, - ZTicketCustBalanceDTO[] custBalances) { + ZTicketCustBalanceDTO[] custBalances, + ExtraObject extra) { this.cashRegister = cashRegister; this.sequence = sequence; this.continuous = continuous; @@ -129,6 +134,7 @@ public final class ZTicketDTO implements DTOInterface, Serializable this.catTaxes = new ImmutableList(catTaxes); this.payments = new ImmutableList(payments); this.custBalances = new ImmutableList(custBalances); + this.extra = extra; } /** @@ -168,7 +174,7 @@ public final class ZTicketDTO implements DTOInterface, Serializable this.payments = pmtFacto.immutableReadObjects("payments"); DTOFactory custBFacto = new DTOFactory(reader, ZTicketCustBalanceDTO.class); this.custBalances = custBFacto.immutableReadObjects("custBalances"); - reader.startArray("custBalances"); + this.extra = reader.readExtra(); } /** @@ -354,6 +360,14 @@ public final class ZTicketDTO implements DTOInterface, Serializable return this.custBalances; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + @Override public void checkIntegrity() throws IntegrityExceptions { // TODO Auto-generated method stub diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/dto/package-info.java b/src/main/java/org/pasteque/coreutil/datatransfer/dto/package-info.java index 588e65f..f0daf2e 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/dto/package-info.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/dto/package-info.java @@ -4,5 +4,7 @@ *

All the DTO are final to ensure the immutability. Extensions should use * encapsulation to add more data or ease-of-use, to ensure the major package * using them cannot be alterated.

+ *

This objects contains only amounts and minimal content description, all + * other data are stored in extra objects allow extensions.

*/ package org.pasteque.coreutil.datatransfer.dto; diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/parser/JSONReader.java b/src/main/java/org/pasteque/coreutil/datatransfer/parser/JSONReader.java index 4c532d5..44ce918 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/parser/JSONReader.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/parser/JSONReader.java @@ -15,7 +15,7 @@ import org.pasteque.coreutil.datatransfer.format.BinaryDTOFormat; /** * Read values from a JSON representation of data. */ -public class JSONReader implements Reader +public class JSONReader extends ReaderHelper { /** Constant for the state of not having parsed anything yet. */ private static final String ROOT_NAME = "__ROOT__"; @@ -98,13 +98,13 @@ public class JSONReader implements Reader } } - @Override + @Override // from Reader public boolean hasKey(String key) throws ParseException { this.checkCurrentObject(); return this.currentObject.has(key); } - @Override + @Override // from Reader public List listKeys() throws ParseException { this.checkCurrentObject(); Set keySet = this.currentObject.keySet(); @@ -116,25 +116,25 @@ public class JSONReader implements Reader return keys; } - @Override + @Override // from Reader public int getArraySize() throws ParseException { this.checkCurrentArray(); return this.currentArray.length(); } - @Override + @Override // from Reader public boolean isNull(String key) throws ParseException { this.checkCurrentObject(); return this.currentObject.isNull(key); } - @Override + @Override // from Reader public boolean isNull(int index) throws ParseException { this.checkCurrentArrayIndex(index); return this.currentArray.isNull(index); } - @Override + @Override // from Reader public boolean readBoolean(String key) throws ParseException { this.checkCurrentObject(); try { @@ -144,12 +144,7 @@ public class JSONReader implements Reader } } - @Override - public Boolean readBooleanOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : Boolean.valueOf(this.readBoolean(key)); - } - - @Override + @Override // from Reader public boolean readBoolean(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -159,12 +154,7 @@ public class JSONReader implements Reader } } - @Override - public Boolean readBooleanOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : Boolean.valueOf(this.readBoolean(index)); - } - - @Override + @Override // from Reader public String readString(String key) throws ParseException { this.checkCurrentObject(); try { @@ -174,17 +164,7 @@ public class JSONReader implements Reader } } - @Override - public String readStringOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : this.readString(key); - } - - @Override - public String readStringOrEmpty(String key) throws ParseException { - return (this.isNull(key)) ? "" : this.readString(key); - } - - @Override + @Override // from Reader public String readString(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -194,17 +174,7 @@ public class JSONReader implements Reader } } - @Override - public String readStringOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : this.readString(index); - } - - @Override - public String readStringOrEmpty(int index) throws ParseException { - return (this.isNull(index)) ? "" : this.readString(index); - } - - @Override + @Override // from Reader public int readInt(String key) throws ParseException { this.checkCurrentObject(); try { @@ -214,12 +184,7 @@ public class JSONReader implements Reader } } - @Override - public Integer readIntOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : Integer.valueOf(this.readInt(key)); - } - - @Override + @Override // from Reader public int readInt(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -229,13 +194,7 @@ public class JSONReader implements Reader } } - @Override - public Integer readIntOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : Integer.valueOf(this.readInt(index)); - } - - - @Override + @Override // from Reader public double readDouble(String key) throws ParseException { this.checkCurrentObject(); try { @@ -245,12 +204,7 @@ public class JSONReader implements Reader } } - @Override - public Double readDoubleOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : Double.valueOf(this.readDouble(key)); - } - - @Override + @Override // from Reader public double readDouble(int index) throws ParseException { this.checkCurrentArray(); try { @@ -260,12 +214,7 @@ public class JSONReader implements Reader } } - @Override - public Double readDoubleOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : Double.valueOf(this.readDouble(index)); - } - - @Override + @Override // from Reader public Date readDate(String key) throws ParseException { this.checkCurrentObject(); try { @@ -281,12 +230,7 @@ public class JSONReader implements Reader } } - @Override - public Date readDateOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : this.readDate(key); - } - - @Override + @Override // from Reader public Date readDate(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -302,12 +246,7 @@ public class JSONReader implements Reader } } - @Override - public Date readDateOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : this.readDate(index); - } - - @Override + @Override // from Reader public byte[] readBinary(String key) throws ParseException { this.checkCurrentObject(); try { @@ -318,12 +257,7 @@ public class JSONReader implements Reader } } - @Override - public byte[] readBinaryOrNull(String key) throws ParseException { - return (this.isNull(key)) ? null : this.readBinary(key); - } - - @Override + @Override // from Reader public byte[] readBinary(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -334,12 +268,7 @@ public class JSONReader implements Reader } } - @Override - public byte[] readBinaryOrNull(int index) throws ParseException { - return (this.isNull(index)) ? null : this.readBinary(index); - } - - @Override + @Override // from Reader public void startObject() throws ParseException { if (this.currentObject == null && this.currentArray == null && this.mainObject == null && this.mainArray == null) { @@ -350,7 +279,7 @@ public class JSONReader implements Reader } } - @Override + @Override // from Reader public void startObject(String key) throws ParseException { this.checkCurrentObject(); try { @@ -361,7 +290,7 @@ public class JSONReader implements Reader this.path.add(new Path(PathType.OBJECT, key)); } - @Override + @Override // from Reader public void startObject(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -373,14 +302,14 @@ public class JSONReader implements Reader this.path.add(new Path(PathType.OBJECT, index)); } - @Override + @Override // from Reader public void endObject() throws ParseException { this.checkCurrentObject(); this.path.remove(this.path.size() - 1); this.runPath(); } - @Override + @Override // from Reader public void startArray() throws ParseException { if (this.currentObject == null && this.currentArray == null && this.mainObject == null && this.mainArray == null) { @@ -391,7 +320,7 @@ public class JSONReader implements Reader } } - @Override + @Override // from Reader public void startArray(String key) throws ParseException { this.checkCurrentObject(); try { @@ -403,7 +332,7 @@ public class JSONReader implements Reader this.path.add(new Path(PathType.ARRAY, key)); } - @Override + @Override // from Reader public void startArray(int index) throws ParseException { this.checkCurrentArrayIndex(index); try { @@ -414,7 +343,7 @@ public class JSONReader implements Reader this.path.add(new Path(PathType.ARRAY, index)); } - @Override + @Override // from Reader public void endArray() throws ParseException { this.checkCurrentArray(); this.path.remove(this.path.size() - 1); diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/parser/Reader.java b/src/main/java/org/pasteque/coreutil/datatransfer/parser/Reader.java index de516b9..0379f51 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/parser/Reader.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/parser/Reader.java @@ -3,6 +3,7 @@ package org.pasteque.coreutil.datatransfer.parser; import java.util.Date; import java.util.List; import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Data reader.

@@ -268,6 +269,15 @@ public interface Reader */ public byte[] readBinaryOrNull(String key) throws ParseException; + /** + * Read the extra object. + * @return The root extra object. If not present, it must return an empty + * extra object. + * @throws ParseException When an error occurs while reading the extra + * object. + */ + public ExtraObject readExtra() throws ParseException; + /** * Read binary data as base64 at the given index of the current element. * @param index The index to read in the current element. diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/parser/ReaderHelper.java b/src/main/java/org/pasteque/coreutil/datatransfer/parser/ReaderHelper.java new file mode 100644 index 0000000..d2d2bec --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/datatransfer/parser/ReaderHelper.java @@ -0,0 +1,169 @@ +package org.pasteque.coreutil.datatransfer.parser; + +import java.util.Date; +import java.util.List; +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.extra.ExtraObject; + +/** + *

Common behaviour implementation of a data reader.

+ */ +public abstract class ReaderHelper implements Reader +{ + @Override // from Reader + public abstract boolean hasKey(String key) throws ParseException; + + @Override // from Reader + public abstract List listKeys() throws ParseException; + + @Override // from Reader + public abstract int getArraySize() throws ParseException; + + @Override // from Reader + public abstract boolean isNull(String key) throws ParseException; + + @Override // from Reader + public abstract boolean isNull(int index) throws ParseException; + + @Override // from Reader + public abstract boolean readBoolean(String key) throws ParseException; + + @Override // from Reader + public Boolean readBooleanOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : Boolean.valueOf(this.readBoolean(key)); + } + + @Override // from Reader + public abstract boolean readBoolean(int index) throws ParseException; + + @Override // from Reader + public Boolean readBooleanOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : Boolean.valueOf(this.readBoolean(index)); + } + @Override // from Reader + public abstract String readString(String key) throws ParseException; + + @Override // from Reader + public String readStringOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : this.readString(key); + } + + @Override // from Reader + public String readStringOrEmpty(String key) throws ParseException { + return (this.isNull(key)) ? "" : this.readString(key); + } + + @Override // from Reader + public abstract String readString(int index) throws ParseException; + + @Override // from Reader + public String readStringOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : this.readString(index); + } + + @Override // from Reader + public String readStringOrEmpty(int index) throws ParseException { + return (this.isNull(index)) ? "" : this.readString(index); + } + + @Override // from Reader + public abstract int readInt(String key) throws ParseException; + + @Override // from Reader + public Integer readIntOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : Integer.valueOf(this.readInt(key)); + } + + @Override // from Reader + public abstract int readInt(int index) throws ParseException; + + @Override // from Reader + public Integer readIntOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : Integer.valueOf(this.readInt(index)); + } + + @Override // from Reader + public abstract double readDouble(String key) throws ParseException; + + @Override // from Reader + public Double readDoubleOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : Double.valueOf(this.readDouble(key)); + } + + @Override // from Reader + public abstract double readDouble(int index) throws ParseException; + + @Override // from Reader + public Double readDoubleOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : Double.valueOf(this.readDouble(index)); + } + + @Override // from Reader + public abstract Date readDate(String key) throws ParseException; + + @Override // from Reader + public Date readDateOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : this.readDate(key); + } + + @Override // from Reader + public abstract Date readDate(int index) throws ParseException; + + @Override // from Reader + public Date readDateOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : this.readDate(index); + } + + @Override // from Reader + public abstract byte[] readBinary(String key) throws ParseException; + + @Override // from Reader + public byte[] readBinaryOrNull(String key) throws ParseException { + return (this.isNull(key)) ? null : this.readBinary(key); + } + + @Override // from Reader + public abstract byte[] readBinary(int index) throws ParseException; + + @Override // from Reader + public byte[] readBinaryOrNull(int index) throws ParseException { + return (this.isNull(index)) ? null : this.readBinary(index); + } + + @Override // from Reader + public ExtraObject readExtra() throws ParseException { + if (!this.hasKey(ExtraObject.EXTRA_ROOT_FIELD) + || this.isNull(ExtraObject.EXTRA_ROOT_FIELD)) { + return new ExtraObject(); + } else { + this.startObject("extra"); + ExtraObject o = new ExtraObject(this); + this.endObject(); + return o; + } + } + + @Override // from Reader + public abstract void startObject() throws ParseException; + + @Override // from Reader + public abstract void startObject(String key) throws ParseException; + + @Override // from Reader + public abstract void startObject(int index) throws ParseException; + + @Override // from Reader + public abstract void endObject() throws ParseException; + + @Override // from Reader + public abstract void startArray() throws ParseException; + + @Override // from Reader + public abstract void startArray(String key) throws ParseException; + + @Override // from Reader + public abstract void startArray(int index) throws ParseException; + + @Override // from Reader + public abstract void endArray() throws ParseException; +} diff --git a/src/main/java/org/pasteque/coreutil/datatransfer/parser/Writer.java b/src/main/java/org/pasteque/coreutil/datatransfer/parser/Writer.java index 473d02f..3d95c3e 100644 --- a/src/main/java/org/pasteque/coreutil/datatransfer/parser/Writer.java +++ b/src/main/java/org/pasteque/coreutil/datatransfer/parser/Writer.java @@ -1,5 +1,7 @@ package org.pasteque.coreutil.datatransfer.parser; +import org.pasteque.coreutil.ParseException; + /** *

Data writer.

*

A reader must always be initialized from its DTO, typically within @@ -7,6 +9,123 @@ package org.pasteque.coreutil.datatransfer.parser; */ public interface Writer { + /** + * Add an int to the current array. + * @param value The value to write. + * @throws ParseException When writing from outside an array. + */ + public void writeInt(int value) throws ParseException; + + /** + * Add an int to the current object. + * @param key The key of the value to write. + * @param value The value to write. + * @throws ParseException When writing from outside an object. + */ + public void writeInt(String key, int value) throws ParseException; + + /** + * Add an int to the current array. + * @param value The value to write. + * @throws ParseException When writing from outside an array. + */ + public void writeDouble(double value) throws ParseException; + + /** + * Add an int to the current object. + * @param key The key of the value to write. + * @param value The value to write. + * @throws ParseException When writing from outside an object. + */ + public void writeDouble(String key, double value) throws ParseException; + + /** + * Add an int to the current array. + * @param value The value to write. + * @throws ParseException When writing from outside an array. + */ + public void writeBoolean(boolean value) throws ParseException; + + /** + * Add an int to the current object. + * @param key The key of the value to write. + * @param value The value to write. + * @throws ParseException When writing from outside an object. + */ + public void writeBoolean(String key, boolean value) throws ParseException; + + /** + * Add an int to the current array. + * @param value The value to write. + * @throws ParseException When writing from outside an array. + * @throws IllegalArgumentException When the value is null. + * Use {@link writeNull()} instead. + */ + public void writeString(String value) throws ParseException; + + /** + * Add an int to the current object. + * @param key The key of the value to write. + * @param value The value to write. + * @throws ParseException When writing from outside an object. + * @throws IllegalArgumentException When the value is null. + * Use {@link writeNull()} instead. + */ + public void writeString(String key, String value) throws ParseException; + + /** + * Add a null value to the current array. + * @throws ParseException When writing from outside an array. + */ + public void writeNull() throws ParseException; + + /** + * Add a null value to the current object. + * @param key The key of the value to write. + * @throws ParseException When writing from outside an object. + */ + public void writeNull(String key) throws ParseException; + + /** + * Start (create) a dictionary as the root element or inside an array. + * @throws ParseException When the root element is already created or + * not currently inside an array. + */ + public void startObject() throws ParseException; + + /** + * Start (create) a dictionary as a child element. + * @param key The key to read in the current dictionary. + * @throws ParseException When writing a key from outside an object. + */ + public void startObject(String key) throws ParseException; + + /** + * Finalize the current object and return up into the tree. + * @throws ParseException When the current element is not an object. + */ + public void endObject() throws ParseException; + + /** + * Start (create) an array as the root element or inside an array. + * @throws ParseException When the root element is already created + * or not currently inside an array. + */ + public void startArray() throws ParseException; + + /** + * Start (create) an array as a child element. + * @param key The key in the parent dictionary. + * @throws ParseException When writing a key from outside an object. + */ + public void startArray(String key) throws ParseException; + + /** + * Finalize the current array and return up into the tree. + * @throws ParseException When the current element is not an array. + */ + public void endArray() throws ParseException; + /** * Get the encoded data. * @return The encoded data. diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraArray.java b/src/main/java/org/pasteque/coreutil/extra/ExtraArray.java new file mode 100644 index 0000000..e493345 --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraArray.java @@ -0,0 +1,193 @@ +package org.pasteque.coreutil.extra; + +import java.util.ArrayList; +import java.util.List; +import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data as an array. + */ +public final class ExtraArray implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + /** See {@link getValue()}. */ + private final ImmutableList value; + /** See {@link getType()}. */ + private final ExtraType type; + + /** + * Construct an array from a list of values. + * @param field The name of the field. + * @param type The type of data in the array. + * @param value The values in the array. Each data can have the index + * as field name. + * @throws IllegalArgumentException When the type of one value doesn't match + * the type of the array. + * @throws Error When one of the {@link ExtraType} is not handled. + */ + /* package */ ExtraArray(String field, ExtraType type, List value) + throws IllegalArgumentException { + this.field = field; + this.type = type; + for (ExtraData extra : value) { + if (!this.type.checkExtraType(extra)) { + throw new IllegalArgumentException(String.format("Invalid type of data %s, expected %s", extra.getClass().toString(), type.getTypeExtraClass().toString())); + } + } + this.value = new ImmutableList(value); + } + + /** + * Construct an array from a list of values. + * @param field The name of the field. + * @param type The type of data in the array. + * @param value The values in the array. Each data can have the index + * as field name. + * @throws IllegalArgumentException When the type of one value doesn't match + * the type of the array. + * @throws Error When one of the {@link ExtraType} is not handled. + */ + /* package */ ExtraArray(String field, ExtraType type, ImmutableList value) + throws IllegalArgumentException { + this.field = field; + this.type = type; + for (ExtraData extra : value) { + if (!this.type.checkExtraType(extra)) { + throw new IllegalArgumentException(String.format("Invalid type of data %s, expected %s", extra.getClass().toString(), type.getTypeExtraClass().toString())); + } + } + this.value = value; + } + + /** + * Construct an array from a reader. + * @param field The name of the field. + * @param reader The reader to read data from. It must aready be pointing + * to the array. + * @throws ParseException When an error happens while reading the data. + */ + /* package */ ExtraArray(String field, Reader reader) throws ParseException { + ExtraType arrayType = ExtraType.fromCode(reader.readString("ta")); + reader.startArray("v"); + List data = new ArrayList(reader.getArraySize()); + for (int i = 0; i < reader.getArraySize(); i++) { + switch (arrayType) { + case STRING: + data.add(new ExtraString(String.valueOf(i), reader.readString(i))); + break; + case BOOLEAN: + data.add(new ExtraBoolean(String.valueOf(i), reader.readBoolean(i))); + break; + case INTEGER: + data.add(new ExtraInt(String.valueOf(i), reader.readInt(i))); + break; + case DOUBLE: + data.add(new ExtraDouble(String.valueOf(i), reader.readDouble(i))); + break; + case OBJECT: + reader.startObject(i); + try { + data.add(new ExtraObject(String.valueOf(i), reader)); + } catch (ParseException e) { + reader.endObject(); + reader.endArray(); + throw e; + } + reader.endObject(); + break; + case ARRAY: + reader.startObject(i); + try { + data.add(new ExtraArray(String.valueOf(i), reader)); + } catch (ParseException e) { + reader.endObject(); + reader.endArray(); + throw e; + } + reader.endObject(); + break; + case NULL: + data.add(new ExtraNull(String.valueOf(i))); + break; + default: + assert false; + } + } + reader.endArray(); + this.field = field; + this.type = arrayType; + this.value = new ImmutableList(data); + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + /** + * Get the type of value hold. + * @return The type of values. + */ + public ExtraType getType() { + return this.type; + } + + @Override // from ExtraData + public ImmutableList getValue() { + return this.value; + } + + /** + * Write the content of this ExtraArray in the current writer object. + * The Writer must already be inside the object to write. + * @param to The writer to write to. + * @throws ParseException When an error occurs while writing. + */ + private void innerWrite(Writer to) throws ParseException { + to.writeString("t", ExtraType.ARRAY.getTypeCode()); + to.writeString("ta", this.type.getTypeCode()); + to.startArray("v"); + for (ExtraData v : this.value) { + try { + if (v == null || this.type == ExtraType.NULL) { + to.writeNull(); + } else if (this.type == ExtraType.STRING) { + to.writeString((String) v.getValue()); + } else if (this.type == ExtraType.BOOLEAN) { + to.writeBoolean((Boolean) v.getValue()); + } else if (this.type == ExtraType.INTEGER) { + to.writeInt((Integer) v.getValue()); + } else if (this.type == ExtraType.DOUBLE) { + to.writeDouble((Double) v.getValue()); + } else if (this.type == ExtraType.OBJECT) { + ((ExtraObject) v).writeInArray(to); + } else if (this.type == ExtraType.ARRAY) { + to.startObject(); + ((ExtraArray) v).innerWrite(to); + to.endObject(); + } else { + assert false; + } + } catch (ParseException e) { + to.endArray(); + throw e; + } + } + to.endArray(); + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + this.innerWrite(to); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraBoolean.java b/src/main/java/org/pasteque/coreutil/extra/ExtraBoolean.java new file mode 100644 index 0000000..910aa9e --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraBoolean.java @@ -0,0 +1,55 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data as a boolean. + */ +public final class ExtraBoolean implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + /** See {@link getBoolean()}. */ + private final boolean value; + + /** + * Create an extra data. + * @param field The field name. + * @param value the value. + */ + /* package */ ExtraBoolean(String field, boolean value) { + this.field = field; + this.value = value; + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + /** + * Get value. + * @return The value. + */ + public boolean getBoolean() { + return this.value; + } + + @Override // from ExtraData + public Object getValue() { + return Boolean.valueOf(this.value); + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.BOOLEAN.getTypeCode()); + to.writeBoolean("v", this.value); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraBuilder.java b/src/main/java/org/pasteque/coreutil/extra/ExtraBuilder.java new file mode 100644 index 0000000..4186882 --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraBuilder.java @@ -0,0 +1,348 @@ +package org.pasteque.coreutil.extra; + +import java.util.ArrayList; +import java.util.List; + +/** + *

Generator to create and embed {@link org.pasteque.coreutil.extra.ExtraData} + * in a dedicated object.

+ *

Create a builder and add fields for all extra data and close the builder + * to get the root {@link org.pasteque.coreutil.extra.ExtraObject} + * to pass to major objects.

+ */ +public final class ExtraBuilder +{ + /** The current object being built. Null when building an array. */ + private TempExtraObject currentObject; + /** The current array being built. Null when building an object. */ + private TempExtraArray currentArray; + /** The current branch of the tree of objects and array being built. */ + private List path; + + /** + * Create an empty builder to create an {@link ExtraObject}. + */ + public ExtraBuilder() { + this.path = new ArrayList(); + this.currentObject = new TempExtraObject(ExtraObject.EXTRA_ROOT_FIELD); + this.path.add(this.currentObject); + } + + /** + * Check that the builder is currently building an object. + * @throws IllegalStateException When not currently building an object. + */ + private void checkCurrentObject() throws IllegalStateException { + if (this.currentObject == null) { + throw new IllegalStateException("ExtraBuilder is not currently building an object."); + } + } + + /** + * Check that the builder is currently building an array. + * @throws IllegalStateException When not currently building an array. + */ + private void checkCurrentArray() throws IllegalStateException { + if (this.currentArray == null) { + throw new IllegalStateException("ExtraBuilder is not currently building an array."); + } + } + + /** + * End building the current object or array and move up to the path + * to get back to editing the parent object or array. + * @throws IllegalStateException When already at the root object. + * @throws Error When the path contains anything but ExtraObject or ExtraArray. + */ + private void pathUp() throws IllegalStateException { + if (path.size() <= 1) { + throw new IllegalStateException("ExtraBuilder is already building the root object. Use close() instead."); + } + this.path.remove(this.path.size() - 1); + ExtraData last = this.path.get(this.path.size() - 1); + if (last instanceof TempExtraObject) { + this.currentObject = (TempExtraObject) last; + this.currentArray = null; + } else if (last instanceof TempExtraArray) { + this.currentObject = null; + this.currentArray = (TempExtraArray) last; + } else { + throw new Error(String.format("Corrupted ExtraBuilder path. Expecting TempExtraObject or TempExtraArray, found %s", last.getClass().toString())); + } + } + + /** + * Start building a new object as a child of the current array. + * @throws IllegalStateException When not currently building an array. + */ + public void startObject() throws IllegalStateException { + this.checkCurrentArray(); + TempExtraObject newObject = new TempExtraObject(String.valueOf(this.currentArray.size())); + this.currentArray.addValue(newObject); + this.path.add(newObject); + this.currentObject = newObject; + this.currentArray = null; + } + + /** + * Start building a new object as a value of the current object. + * @param field The name of the field of the current object that will hold + * the new object. + * @throws IllegalStateException When not currently building an object. + */ + public void startObject(String field) throws IllegalStateException { + this.checkCurrentObject(); + TempExtraObject newObject = new TempExtraObject(field); + this.currentObject.setValue(newObject); + this.path.add(newObject); + this.currentObject = newObject; + this.currentArray = null; + } + + /** + * End building the current object and get back to editing its parent. + * @throws IllegalStateException When not currently building an object or + * when trying to end the root object. + */ + public void endObject() throws IllegalStateException { + this.checkCurrentObject(); + this.pathUp(); + } + + /** + * Start building a new array as a child of the current array. + * @param type The type of data the array will contain. + * @throws IllegalStateException When not currently building an array. + */ + public void startArray(ExtraType type) throws IllegalStateException { + this.checkCurrentArray(); + TempExtraArray array = new TempExtraArray(this.currentArray.size(), type); + this.currentArray.addValue(array); + this.path.add(array); + this.currentArray = array; + this.currentObject = null; + } + + /** + * Start building a new array as a value of the current object. + * @param field The name of the field of the current object that will hold + * the new array. + * @param type The type of data the array will contain. + * @throws IllegalStateException When not currently building an object. + */ + public void startArray(String field, ExtraType type) throws IllegalStateException { + this.checkCurrentObject(); + TempExtraArray array = new TempExtraArray(field, type); + this.currentObject.setValue(array); + this.path.add(array); + this.currentArray = array; + this.currentObject = null; + } + + /** + * End building the current array and get back to editing its parent. + * @throws IllegalStateException When not currently building an array. + */ + public void endArray() throws IllegalStateException { + this.checkCurrentArray(); + this.pathUp(); + } + + /** + * Add a null value to the current array. + * @throws IllegalStateException When not currently building an array. + */ + public void addNull() throws IllegalStateException { + this.checkCurrentArray(); + this.currentArray.addValue(new ExtraNull(this.currentArray.size())); + } + + /** + * Add a null value to the current object. + * @param field The name of the field that holds the value. + * @throws IllegalStateException When not currently building an object. + */ + public void addNull(String field) throws IllegalStateException { + this.checkCurrentObject(); + ExtraNull value = new ExtraNull(field); + this.currentObject.setValue(value); + } + + /** + * Add a value to the current array. + * @param value The value to add. It adds a null value instead when null. + * @throws IllegalStateException When not currently building an array. + * @throws IllegalArgumentException When not building an array of String. + */ + public void add(String value) throws IllegalStateException { + this.checkCurrentArray(); + if (value == null) { + this.addNull(); + } else { + this.currentArray.addValue(new ExtraString(this.currentArray.size(), value)); + } + } + + /** + * Add a value to the current object. + * @param field The name of the field that holds the value. + * @param value The value to add. It adds a null value instead when null. + * @throws IllegalStateException When not currently building an object. + */ + public void add(String field, String value) throws IllegalStateException { + this.checkCurrentObject(); + if (value == null) { + this.addNull(field); + } else { + this.currentObject.setValue(new ExtraString(field, value)); + } + } + + /** + * Stop building extra data and get the final object. + * Once close is called, no other operation can be done. + * @return The finalized extra data to pass to a major object. + */ + public ExtraObject close() { + TempExtraObject root = (TempExtraObject) this.path.get(0); + this.path.clear(); + this.currentObject = null; + this.currentArray = null; + return (ExtraObject) root.finalizeExtra(); + } + + /** + * Interface to convert local temporary extra object and array + * to the definitive extra data. + */ + private interface TempExtra { + /** + * Convert the temporary extra to the definitive one. + * @return An immutable extra data. + */ + public ExtraData finalizeExtra(); + } + + /** + * A buildable extra object. + */ + private class TempExtraObject implements ExtraData, TempExtra + { + private List data; + private String field; + + public TempExtraObject(String field) { + this.data = new ArrayList(); + this.field = field; + } + + /** + * Set or replace a value to the current object. + * If the field is already set, it is replaced. + * @param value The value to add. + */ + private void setValue(ExtraData value) { + for (int i = 0; i < this.data.size(); i++) { + ExtraData v = this.data.get(i); + if (value.getField().equals(v.getField())) { + this.data.set(i, value); + return; + } + } + this.data.add(value); + } + + @Override // from ExtraData + public String getField() { + return this.field; + } + + @Override // from ExtraData + public ExtraData getValue() { + return this.finalizeExtra(); + } + + /** + * Does nothing. + * @param w Not used. + */ + @Override // from ExtraData + public void write(org.pasteque.coreutil.datatransfer.parser.Writer w) {} + + @Override // from TempExtra + public ExtraData finalizeExtra() { + for (int i = 0; i < this.data.size(); i++) { + ExtraData v = this.data.get(i); + if ((v instanceof TempExtra)) { + this.data.set(i, ((TempExtra) v).finalizeExtra()); + } + } + return new ExtraObject(this.field, this.data); + } + } + + /** + * A buildable extra array. + */ + private class TempExtraArray implements ExtraData, TempExtra + { + private List data; + private String field; + private ExtraType type; + + public TempExtraArray(String field, ExtraType type) { + this.data = new ArrayList(); + this.field = field; + this.type = type; + } + + /** + * Get the size of the array as a string for the name of the next + * element to add. + * @return The size of the array as a string. + */ + public String size() { + return String.valueOf(data.size()); + } + + /** + * Add a value to the array. + * @param value The value to add. + * @throws IllegalArgumentException When the type of one value doesn't match + * the type of the array. + */ + private void addValue(ExtraData value) throws IllegalArgumentException { + if (!this.type.checkExtraType(value)) { + throw new IllegalArgumentException(String.format("Invalid type of data %s, expected %s", value.getClass().toString(), this.type.getTypeExtraClass().toString())); + } + this.data.add(value); + } + + @Override // from ExtraData + public String getField() { + return this.field; + } + + @Override // from ExtraData + public ExtraData getValue() { + return this.finalizeExtra(); + } + + /** + * Does nothing. + * @param w Not used. + */ + @Override // from ExtraData + public void write(org.pasteque.coreutil.datatransfer.parser.Writer w) {} + + @Override // from TempExtra + public ExtraData finalizeExtra() { + for (int i = 0; i < this.data.size(); i++) { + ExtraData v = this.data.get(i); + if ((v instanceof TempExtra)) { + this.data.set(i, ((TempExtra) v).finalizeExtra()); + } + } + return new ExtraArray(this.field, this.type, this.data); + } + }} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraData.java b/src/main/java/org/pasteque/coreutil/extra/ExtraData.java new file mode 100644 index 0000000..739a26d --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraData.java @@ -0,0 +1,31 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Data outside the minimal ones to be passed to the major version. + */ +public interface ExtraData +{ + /** + * Get the name of the field this data belongs to. + * @return The name of the field. + */ + public String getField(); + + /** + * Get the value of the data as an object. + * @return The value. + */ + public Object getValue(); + + /** + * Write the data to a writer. + * @param to The writer to put the data in. The data is not responsible + * of the state of the writer. The object holding the extra data must + * ensure the writer is in a correct state. + * @throws ParseException When the writer is in an incorrect state. + */ + public void write(Writer to) throws ParseException; +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraDouble.java b/src/main/java/org/pasteque/coreutil/extra/ExtraDouble.java new file mode 100644 index 0000000..69f943a --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraDouble.java @@ -0,0 +1,55 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data as a double. + */ +public final class ExtraDouble implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + /** See {@link getDouble()}. */ + private final double value; + + /** + * Create an extra data. + * @param field The field name. + * @param value the value. + */ + /* package */ ExtraDouble(String field, double value) { + this.field = field; + this.value = value; + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + /** + * Get value. + * @return The value. + */ + public double getDouble() { + return this.value; + } + + @Override // from ExtraData + public Object getValue() { + return Double.valueOf(this.value); + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.DOUBLE.getTypeCode()); + to.writeDouble("v", this.value); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraInt.java b/src/main/java/org/pasteque/coreutil/extra/ExtraInt.java new file mode 100644 index 0000000..9ef6508 --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraInt.java @@ -0,0 +1,55 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data as an int. + */ +public final class ExtraInt implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + /** See {@link getInt()}. */ + private final int value; + + /** + * Create an extra data. + * @param field The field name. + * @param value the value. + */ + /* package */ ExtraInt(String field, int value) { + this.field = field; + this.value = value; + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + /** + * Get value. + * @return The value. + */ + public int getInt() { + return this.value; + } + + @Override // from ExtraData + public Object getValue() { + return Integer.valueOf(this.value); + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.INTEGER.getTypeCode()); + to.writeInt("v", this.value); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraNull.java b/src/main/java/org/pasteque/coreutil/extra/ExtraNull.java new file mode 100644 index 0000000..279b22e --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraNull.java @@ -0,0 +1,44 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data holding a null value. Use this class instead of + * typed extra data with a null value. + */ +public final class ExtraNull implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + + /** + * Create an extra data. + * @param field The field name. + */ + /* package */ ExtraNull(String field) { + this.field = field; + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + @Override // from ExtraData + public Object getValue() { + return null; + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.NULL.getTypeCode()); + to.writeNull("v"); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraObject.java b/src/main/java/org/pasteque/coreutil/extra/ExtraObject.java new file mode 100644 index 0000000..83c407a --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraObject.java @@ -0,0 +1,200 @@ +package org.pasteque.coreutil.extra; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Reader; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Collection of {@link org.pasteque.coreutil.extra.ExtraData} + * to extend major classes. An extra object is the root of the extra data + * and can contain other extra objects as well. + */ +public final class ExtraObject implements ExtraData +{ + /** + * The name of the field for the root element of extra data. + */ + public static final String EXTRA_ROOT_FIELD = "extra"; + /** See {@link getField(). */ + private final String field; + /** See {@link getObject(). */ + private final ImmutableList value; + + /** + * Sort extra data by key and return an ordered list of them. + * @param data The maybe unsorted list of extra data. + * @return An immutable list of extra data containing all extra data + * sorted alphabetically by their key. + * @throws IllegalArgumentException When multiple extra data shares the + * same key. + */ + private static ImmutableList sortExtraKeys(Iterable data) + throws IllegalArgumentException { + List keys = new ArrayList(); + List sorted = new ArrayList(); + for (ExtraData d : data) { + keys.add(d.getField()); + } + Collections.sort(keys); + String lastKey = null; + for (String key : keys) { + if (key.equals(lastKey)) { + throw new IllegalArgumentException(String.format("Key %s is set multiple times in extra object.", key)); + } + for (ExtraData d : data) { + if (d.getField().equals(key)) { + sorted.add(d); + break; + } + } + lastKey = key; + } + return new ImmutableList(sorted); + } + + /** + * Create an empty extra data as the root element. + */ + public ExtraObject() { + this(EXTRA_ROOT_FIELD, new ImmutableList()); + } + + /** + * Create an extra data as the root element. + * @param value the value. + * @throws IllegalArgumentException When multiple extra data shares the + * same key. + */ + /* package */ ExtraObject(List data) { + this(EXTRA_ROOT_FIELD, data); + } + + /** + * Create an extra data. + * @param value the value. + * @throws IllegalArgumentException When multiple extra data shares the + * same key. + */ + /* package */ ExtraObject(String field, List data) { + this.field = field; + this.value = sortExtraKeys(data); + } + + /** + * Create an extra data. + * @param value the value. + * @throws IllegalArgumentException When multiple extra data shares the + * same key. + */ + /* package */ ExtraObject(String field, ImmutableList data) { + this.field = field; + this.value = sortExtraKeys(data); + } + + /** + * Instantiate from raw data from a reader. + * @param key The key to assign to this extra object. + * @param reader The reader that must be currently pointing to this object. + * @throws IllegalArgumentException When multiple extra data shares the + * same key. + * @throws ParseException When an error occurs while parsing the object. + * See {@link org.pasteque.coreutil.datatransfer.parser.Reader} for details. + */ + /* package */ ExtraObject(String key, Reader reader) + throws ParseException, IllegalArgumentException { + List keys = reader.listKeys(); + List data = new ArrayList(keys.size()); + for (String extraKey : keys) { + reader.startObject(extraKey); + String typeCode = reader.readString("t"); + ExtraType type = ExtraType.fromCode(typeCode); + switch (type) { + case STRING: + data.add(new ExtraString(extraKey, reader.readString("v"))); + break; + case BOOLEAN: + data.add(new ExtraBoolean(extraKey, reader.readBoolean("v"))); + break; + case INTEGER: + data.add(new ExtraInt(extraKey, reader.readInt("v"))); + break; + case DOUBLE: + data.add(new ExtraDouble(extraKey, reader.readDouble("v"))); + break; + case OBJECT: + data.add(new ExtraObject(extraKey, reader)); + break; + case ARRAY: + data.add(new ExtraArray(extraKey, reader)); + case NULL: + data.add(new ExtraNull(extraKey)); + break; + default: + assert false; + } + reader.endObject(); + } + this.field = key; + this.value = sortExtraKeys(data); + } + + /** + * Instantiate from raw data from a reader. + * @param r The reader that must be currently pointing to this object. + * @throws ParseException When an error occurs while parsing the object. + * See {@link org.pasteque.coreutil.datatransfer.parser.Reader} for details. + */ + public ExtraObject(Reader r) throws ParseException { + this(EXTRA_ROOT_FIELD, r); + } + + @Override // from ExtraData + public String getField() { + return this.field; + } + + @Override // from ExtraData + public Object getValue() { + return this.value; + } + + /** + * Write this object in an {@link ExtraArray} without providing a field + * @param to The write to write this object to. + * @throws ParseException When an error occurs while writing a field. + */ + /* package */ void writeInArray(Writer to) throws ParseException { + to.startObject(); + for (ExtraData d : this.value) { + try { + d.write(to); + } catch (ParseException e) { + to.endObject(); + throw e; + } + } + to.endObject(); + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.OBJECT.getTypeCode()); + to.startObject("v"); + for (ExtraData d : this.value) { + try { + d.write(to); + } catch (ParseException e) { + to.endObject(); + to.endObject(); + throw e; + } + } + to.endObject(); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraString.java b/src/main/java/org/pasteque/coreutil/extra/ExtraString.java new file mode 100644 index 0000000..dc9a5b9 --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraString.java @@ -0,0 +1,61 @@ +package org.pasteque.coreutil.extra; + +import org.pasteque.coreutil.ParseException; +import org.pasteque.coreutil.datatransfer.parser.Writer; + +/** + * Extra data as a {@link java.lang.String}. This can also holds the reference + * of an associated object. + */ +public final class ExtraString implements ExtraData +{ + /** See {@link getField(). */ + private final String field; + /** See {@link getString()}. */ + private final String value; + + /** + * Create an extra data. + * @param field The field name. + * @param value the value. + * @throws InvalidArgumentException When value is null. + * @see org.pasteque.coreutil.extra.ExtraNull + */ + /* package */ ExtraString(String field, String value) { + if (value == null) { + throw new IllegalArgumentException("ExtraData cannot have a null value. Use ExtraNull instead."); + } + this.field = field; + this.value = value; + } + + /** + * Get the field associated to this extra data. + * @return the field name. + */ + @Override // from ExtraData + public String getField() { + return this.field; + } + + /** + * Get value. + * @return The value. + */ + public String getString() { + return this.value; + } + + @Override // from ExtraData + public Object getValue() { + return this.value; + } + + @Override // from ExtraData + public void write(Writer to) throws ParseException { + to.startObject(this.field); + to.writeString("t", ExtraType.STRING.getTypeCode()); + to.writeString("v", this.value); + to.endObject(); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/ExtraType.java b/src/main/java/org/pasteque/coreutil/extra/ExtraType.java new file mode 100644 index 0000000..c983ed2 --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/ExtraType.java @@ -0,0 +1,116 @@ +package org.pasteque.coreutil.extra; + +import java.util.List; +import java.util.Map; + +/** + * Enumeration of available data types}. + */ +public enum ExtraType +{ + /** Type of {@link java.lang.String}, matching {@link ExtraString} data. */ + STRING("s", String.class, ExtraString.class), + /** Type of boolean data. */ + BOOLEAN("b", Boolean.class, ExtraBoolean.class), + /** Type of integer data. */ + INTEGER("i", Integer.class, ExtraInt.class), + /** Type of float/double data. */ + DOUBLE("d", Double.class, ExtraDouble.class), + /** Type of object data. */ + OBJECT("o", Map.class, ExtraObject.class), + /** Type of array data. */ + ARRAY("a", List.class, ExtraArray.class), + /** Type of null data. */ + NULL("n", null, ExtraNull.class); + + /** See {@link getTypeCode()}. */ + private final String typeCode; + /** See {@link getTypeClass()}. */ + private final Class type; + /** See {@link getTypeExtraClass()}. */ + private final Class extraType; + + /** + * Get a type from its type code. + * @param code The code value. + * @return The according enumeration value. + * @throws IllegalArgumentException When code is not found + * within the enumerated values + */ + public static final ExtraType fromCode(String code) throws IllegalArgumentException { + for (ExtraType v : ExtraType.values()) { + if (v.getTypeCode().equals(code)) { + return v; + } + } + throw new IllegalArgumentException(code); + } + + /** + * Get the type of an extra data. + * @param data The extra data to check. + * @return The type of that extra data. + */ + public static final ExtraType fromExtra(ExtraData data) { + for (ExtraType v : ExtraType.values()) { + if (v.checkExtraType(data)) { + return v; + } + } + throw new Error(String.format("Unknown ExtraData type %s", data.getClass().toString())); + } + + /** + * Internal constructor. + * @param typeCode The code to identify the type. + * @param type The expected java class. + * @param extraType The expected {@link ExtraData} implementation class. + */ + private ExtraType(String typeCode, Class type, Class extraType) { + this.typeCode = typeCode; + this.type = type; + this.extraType = extraType; + } + + /** + * Get the associated constant. + * @return The code for DTO. + */ + public String getTypeCode() { + return this.typeCode; + } + + /** + * Get the expected java class of this type. + * @return A java class, like String.class. + */ + public Class getTypeClass() { + return this.type; + } + + /** + * Get the expected {@link ExtraData} implementation class. + * @return An {@link ExtraData} implementation, like {@link ExtraString}. + */ + public Class getTypeExtraClass() { + return this.extraType; + } + + /** + * Check if an object is the same java type as this type expects. + * @param o The object to check. + * @return True if the object is acceptable for this type. + */ + public boolean checkRawType(Object o) { + return this.type.isInstance(o); + } + + /** + * Check if an extra object is the same type as this type expects. + * @param o The extra object. + * @return True if the object is the same extra type or an {@link ExtraNull}. + */ + public boolean checkExtraType(ExtraData o) { + return (this.extraType.isInstance(o)) || (o instanceof ExtraNull); + } +} diff --git a/src/main/java/org/pasteque/coreutil/extra/package-info.java b/src/main/java/org/pasteque/coreutil/extra/package-info.java new file mode 100644 index 0000000..9312c4b --- /dev/null +++ b/src/main/java/org/pasteque/coreutil/extra/package-info.java @@ -0,0 +1,12 @@ +/** + *

Non-mandatory data to pass to the major version. Use an + * {@link org.pasteque.coreutil.extra.ExtraBuilder} to + * remove the semantic from model classes to pass them to major data + * that don't care about their meaning.

+ *

An {@link org.pasteque.coreutil.extra.ExtraObject} is composed of + * types of {@link org.pasteque.coreutil.extra.ExtraData} for typed + * values. All values of {@link org.pasteque.coreutil.extra.ExtraData} + * implementations are non-null. When the value is null, use an explicit + * {@link org.pasteque.coreutil.extra.ExtraNull}.

+ */ +package org.pasteque.coreutil.extra; diff --git a/src/main/java/org/pasteque/coreutil/transition/LineTransition.java b/src/main/java/org/pasteque/coreutil/transition/LineTransition.java index 649a36a..e6e19c5 100644 --- a/src/main/java/org/pasteque/coreutil/transition/LineTransition.java +++ b/src/main/java/org/pasteque/coreutil/transition/LineTransition.java @@ -1,6 +1,7 @@ package org.pasteque.coreutil.transition; import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.extra.ExtraObject; import org.pasteque.coreutil.price.Discount; import org.pasteque.coreutil.price.Price; import org.pasteque.coreutil.price.Quantity; @@ -63,4 +64,12 @@ public interface LineTransition { * @return The full discount applied to the base price. */ public Discount getFinalDiscount(); + + /** + * Get all other data. + * Implementations should use an {@link org.pasteque.coreutil.extra.ExtraBuilder} + * to remove the semantic of all non-mandatory fields. + * @return The root object of extra data. + */ + public ExtraObject getExtra(); } diff --git a/src/main/java/org/pasteque/coreutil/transition/OrderTransition.java b/src/main/java/org/pasteque/coreutil/transition/OrderTransition.java index 135f964..573692b 100644 --- a/src/main/java/org/pasteque/coreutil/transition/OrderTransition.java +++ b/src/main/java/org/pasteque/coreutil/transition/OrderTransition.java @@ -1,6 +1,8 @@ package org.pasteque.coreutil.transition; import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.extra.ExtraObject; +import org.pasteque.coreutil.price.Discount; import org.pasteque.coreutil.price.FinalTaxAmount; import org.pasteque.coreutil.price.Price2; @@ -32,4 +34,18 @@ public interface OrderTransition * @return The content of the order. */ public ImmutableList getLines(); + + /** + * Get the discount applied to the whole order. + * @return The discount applied to the whole order. + */ + public Discount getDiscount(); + + /** + * Get all other data. + * Implementations should use an {@link org.pasteque.coreutil.extra.ExtraBuilder} + * to remove the semantic of all non-mandatory fields. + * @return The root object of extra data. + */ + public ExtraObject getExtra(); } diff --git a/src/main/java/org/pasteque/major/domain/MajorCashSession.java b/src/main/java/org/pasteque/major/domain/MajorCashSession.java index 0ada81c..4b88ead 100644 --- a/src/main/java/org/pasteque/major/domain/MajorCashSession.java +++ b/src/main/java/org/pasteque/major/domain/MajorCashSession.java @@ -3,10 +3,10 @@ package org.pasteque.major.domain; import java.util.Date; import java.util.LinkedList; import java.util.List; - import org.pasteque.coreutil.datatransfer.dto.CashSessionDTO; import org.pasteque.coreutil.datatransfer.dto.FiscalTicketDTO; import org.pasteque.coreutil.datatransfer.dto.MovementDTO; +import org.pasteque.coreutil.extra.ExtraObject; /** *

Ongoing cash session, managing movements and payments.

@@ -32,6 +32,8 @@ public final class MajorCashSession private List tickets; /** See {@link isClosed()}. */ private boolean closed; + /** See {@link getExtra()}. */ + private ExtraObject extra; /** * Create a cash session from all fields. @@ -41,6 +43,7 @@ public final class MajorCashSession * @param openDate See {@link getOpenDate()}. * @param movements The list of movements registered during this session. * @param tickets The list of tickets already registered during this session. + * @param extra See {@link getExtra()}. */ public MajorCashSession( MajorCashRegister cashRegister, @@ -48,7 +51,8 @@ public final class MajorCashSession boolean continuous, Date openDate, List movements, - List tickets) { + List tickets, + ExtraObject extra) { this.cashRegister = cashRegister; this.sequence = sequence; this.continuous = continuous; @@ -56,6 +60,7 @@ public final class MajorCashSession this.movements = movements; this.tickets = tickets; this.closed = false; + this.extra = extra; } /** @@ -239,4 +244,12 @@ public final class MajorCashSession public Date getOpenDate() { return openDate; } + + /** + * Get all other data. + * @return The root object of extra data. + */ + public final ExtraObject getExtra() { + return this.extra; + } } diff --git a/src/main/java/org/pasteque/major/domain/MajorLine.java b/src/main/java/org/pasteque/major/domain/MajorLine.java index 683fd70..3868029 100644 --- a/src/main/java/org/pasteque/major/domain/MajorLine.java +++ b/src/main/java/org/pasteque/major/domain/MajorLine.java @@ -1,6 +1,7 @@ package org.pasteque.major.domain; import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.extra.ExtraObject; import org.pasteque.coreutil.price.Discount; import org.pasteque.coreutil.price.Price; import org.pasteque.coreutil.price.Quantity; @@ -15,7 +16,6 @@ import org.pasteque.coreutil.transition.LineTransition; * @see org.pasteque.major.domain.MajorOrder * @see org.pasteque.major.domain.MajorTicket */ -// TODO add extradata to pass to MajorTicket public final class MajorLine implements LineTransition { /** See {@link getProductReference()}. */ @@ -34,6 +34,8 @@ public final class MajorLine implements LineTransition private final Price totalPrice; /** See {@link getFinalDiscount()}. */ private final Discount finalDiscount; + /** See {@link getExtra()}. */ + private final ExtraObject extra; /** *

Create a major line from outside this package. @@ -61,6 +63,7 @@ public final class MajorLine implements LineTransition * @param totalTaxes See {@link getTotalTaxes()}. * @param totalPrice See {@link getTotalPrice()}. * @param finalDiscount See {@link getFinalDiscount()}. + * @param extra See {@link getExtra()}. */ /* package */ MajorLine( String productReference, @@ -70,7 +73,8 @@ public final class MajorLine implements LineTransition Price price, ImmutableList totalTaxes, Price totalPrice, - Discount finalDiscount) { + Discount finalDiscount, + ExtraObject extra) { this.productReference = productReference; this.productLabel = productLabel; this.unitPrice = unitPrice; @@ -79,6 +83,7 @@ public final class MajorLine implements LineTransition this.totalTaxes = totalTaxes; this.totalPrice = totalPrice; this.finalDiscount = finalDiscount; + this.extra = extra; } /** @@ -94,6 +99,7 @@ public final class MajorLine implements LineTransition this.totalTaxes = source.getTotalTaxes(); this.totalPrice = source.getTotalPrice(); this.finalDiscount = source.getFinalDiscount(); + this.extra = source.getExtra(); } @Override // from LineTransition @@ -135,4 +141,9 @@ public final class MajorLine implements LineTransition public Discount getFinalDiscount() { return this.finalDiscount; } + + @Override // from LineTransition + public ExtraObject getExtra() { + return this.extra; + } } diff --git a/src/main/java/org/pasteque/major/domain/MajorOrder.java b/src/main/java/org/pasteque/major/domain/MajorOrder.java index 56cdfa3..7f5030d 100644 --- a/src/main/java/org/pasteque/major/domain/MajorOrder.java +++ b/src/main/java/org/pasteque/major/domain/MajorOrder.java @@ -1,6 +1,8 @@ package org.pasteque.major.domain; import org.pasteque.coreutil.ImmutableList; +import org.pasteque.coreutil.extra.ExtraObject; +import org.pasteque.coreutil.price.Discount; import org.pasteque.coreutil.price.FinalTaxAmount; import org.pasteque.coreutil.price.Price2; import org.pasteque.coreutil.transition.LineTransition; @@ -13,13 +15,14 @@ import org.pasteque.coreutil.transition.OrderTransition; * for ease of use, but instances are not expected to be generated from * themselves.

*/ -// TODO add extradata to pass to MajorTicket public final class MajorOrder implements OrderTransition { private final Price2 finalPrice; private final ImmutableList taxAmounts; private final Price2 finalTaxedPrice; private final ImmutableList lines; + private final Discount discount; + private final ExtraObject extra; /** * Create a major order from all data. @@ -27,16 +30,22 @@ public final class MajorOrder implements OrderTransition * @param taxAmounts See {@link getTaxAmounts()}. * @param finalTaxedPrice See {@link getFinalTaxedPrice()}. * @param lines See {@link getLines()}. + * @param discount See {@link getDiscount()}. + * @param extra See {@link getExtra()}. */ public MajorOrder( Price2 finalPrice, ImmutableList taxAmounts, Price2 finalTaxedPrice, - ImmutableList lines) { + ImmutableList lines, + Discount discount, + ExtraObject extra) { this.finalPrice = finalPrice; this.taxAmounts = taxAmounts; this.finalTaxedPrice = finalTaxedPrice; this.lines = lines; + this.discount = discount; + this.extra = extra; } /** @@ -60,10 +69,13 @@ public final class MajorOrder implements OrderTransition trans.getPrice(), trans.getTotalTaxes(), trans.getTotalPrice(), - trans.getFinalDiscount()); + trans.getFinalDiscount(), + trans.getExtra()); } this.lines = MajorLine.fromTransition(order.getLines()); + this.discount = order.getDiscount(); + this.extra = order.getExtra(); } /** @@ -110,4 +122,20 @@ public final class MajorOrder implements OrderTransition public ImmutableList getMajorLines() { return this.lines; } + + /** + * Get the discount applied to the whole order. + * @return The discount applied to the whole order. + */ + public Discount getDiscount() { + return this.discount; + } + + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } } diff --git a/src/main/java/org/pasteque/major/domain/MajorTicket.java b/src/main/java/org/pasteque/major/domain/MajorTicket.java index 5b4d6c3..3f9c188 100644 --- a/src/main/java/org/pasteque/major/domain/MajorTicket.java +++ b/src/main/java/org/pasteque/major/domain/MajorTicket.java @@ -3,6 +3,7 @@ package org.pasteque.major.domain; import java.util.Date; import java.util.List; import org.pasteque.coreutil.constants.FiscalTicketType; +import org.pasteque.coreutil.extra.ExtraObject; import org.pasteque.coreutil.price.Price2; import org.pasteque.coreutil.price.TaxAmount; import org.pasteque.coreutil.ImmutableList; @@ -38,7 +39,8 @@ public final class MajorTicket private Price2 finalTaxedPrice; /** See {@link getFinalPrice(). */ private Price2 finalPrice; - // TODO: add extra data + /** See {@link getExtra(). */ + private ExtraObject extra; /** * Create by linking an order and payments. It will create the associated @@ -115,7 +117,7 @@ public final class MajorTicket * @return The payment date, when the ticket was created.. */ public Date getDate() { - return date; + return this.date; } /** @@ -123,7 +125,7 @@ public final class MajorTicket * @return The content of the ticket. */ public ImmutableList getLines() { - return lines; + return this.lines; } /** @@ -131,7 +133,7 @@ public final class MajorTicket * @return The list of payments used to pay the ticket. */ public ImmutableList getPayments() { - return payments; + return this.payments; } /** @@ -139,7 +141,7 @@ public final class MajorTicket * @return The list of tax amounts. */ public ImmutableList getTaxAmounts() { - return taxAmounts; + return this.taxAmounts; } /** @@ -147,7 +149,7 @@ public final class MajorTicket * @return The total price. */ public Price2 getFinalTaxedPrice() { - return finalTaxedPrice; + return this.finalTaxedPrice; } /** @@ -155,6 +157,14 @@ public final class MajorTicket * @return The total price without taxes. */ public Price2 getFinalPrice() { - return finalPrice; + return this.finalPrice; } -} \ No newline at end of file + + /** + * Get the non mandatory extra data. + * @return The root object containing all the extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } +} diff --git a/src/main/java/org/pasteque/major/domain/Movement.java b/src/main/java/org/pasteque/major/domain/Movement.java index cb3699a..dde1e55 100644 --- a/src/main/java/org/pasteque/major/domain/Movement.java +++ b/src/main/java/org/pasteque/major/domain/Movement.java @@ -1,6 +1,7 @@ package org.pasteque.major.domain; import java.util.Date; +import org.pasteque.coreutil.extra.ExtraObject; import org.pasteque.coreutil.datatransfer.dto.MovementDTO; import org.pasteque.coreutil.datatransfer.dto.WeakAssociationDTO; import org.pasteque.coreutil.price.Price2; @@ -25,6 +26,8 @@ public class Movement private final Price2 currencyAmount; /** See {@link getDate()}. */ private Date date; + /** See {@link getExtra()}. */ + private final ExtraObject extra; /** * Create a payment from all fields. @@ -34,6 +37,7 @@ public class Movement * @param currencyLabel See {@link getCurrencyLabel()}. * @param currencyAmount See {@link getCurrencyAmount()}. * @param date See {@link getDate()}. + * @param extra See {@link getExtra()}. */ public Movement( String paymentModeReference, @@ -41,13 +45,15 @@ public class Movement String currencyReference, String currencyLabel, Price2 currencyAmount, - Date date) { + Date date, + ExtraObject extra) { this.paymentModeReference = paymentModeReference; this.paymentModeLabel = paymentModeLabel; this.currencyReference = currencyReference; this.currencyLabel = currencyLabel; this.currencyAmount = currencyAmount; this.date = date; + this.extra = extra; } /** @@ -61,6 +67,7 @@ public class Movement this.currencyLabel = dto.getCurrency().getLabel(); this.currencyAmount = new Price2(dto.getCurrencyAmount()); this.date = new Date(dto.getDate().getTime()); + this.extra = dto.getExtra(); } /** @@ -116,6 +123,14 @@ public class Movement return this.date; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public final ExtraObject getExtra() { + return this.extra; + } + /** * Get a DTO from this object. * @return The content of this object as a DTO. @@ -129,6 +144,7 @@ public class Movement this.currencyReference, this.currencyLabel), this.currencyAmount.toDouble(), - this.date); + this.date, + this.extra); } } diff --git a/src/main/java/org/pasteque/major/domain/Payment.java b/src/main/java/org/pasteque/major/domain/Payment.java index 69f66f9..2e185ea 100644 --- a/src/main/java/org/pasteque/major/domain/Payment.java +++ b/src/main/java/org/pasteque/major/domain/Payment.java @@ -1,6 +1,7 @@ package org.pasteque.major.domain; import org.pasteque.coreutil.datatransfer.dto.WeakAssociationDTO; +import org.pasteque.coreutil.extra.ExtraObject; import org.pasteque.coreutil.price.Price2; import org.pasteque.coreutil.datatransfer.dto.PaymentDTO; @@ -24,6 +25,8 @@ public final class Payment private final String currencyLabel; /** See {@link getCurrencyAmount()}. */ private final Price2 currencyAmount; + /** See {@link getExtra()}. */ + private final ExtraObject extra; /** * Create a payment from all fields. @@ -33,6 +36,7 @@ public final class Payment * @param currencyReference See {@link getCurrencyReference()}. * @param currencyLabel See {@link getCurrencyLabel()}. * @param currencyAmount See {@link getCurrencyAmount()}. + * @param extra See {@link getExtra()}. */ public Payment( String paymentModeReference, @@ -40,13 +44,15 @@ public final class Payment String currencyReference, String currencyLabel, Price2 amount, - Price2 currencyAmount) { + Price2 currencyAmount, + ExtraObject extra) { this.paymentModeReference = paymentModeReference; this.paymentModeLabel = paymentModeLabel; this.currencyReference = currencyReference; this.currencyLabel = currencyLabel; this.amount = amount; this.currencyAmount = currencyAmount; + this.extra = extra; } /** @@ -60,6 +66,7 @@ public final class Payment this.currencyReference = dto.getCurrency().getReference(); this.currencyLabel = dto.getCurrency().getLabel(); this.currencyAmount = new Price2(dto.getCurrencyAmount()); + this.extra = dto.getExtra(); } /** @@ -116,6 +123,14 @@ public final class Payment return currencyAmount; } + /** + * Get all other data. + * @return The root object of extra data. + */ + public ExtraObject getExtra() { + return this.extra; + } + /** * Get a DTO from this object. * @return The content of this object as a DTO. @@ -129,6 +144,7 @@ public final class Payment new WeakAssociationDTO( this.currencyReference, this.currencyLabel), - this.currencyAmount.toDouble()); + this.currencyAmount.toDouble(), + this.extra); } } diff --git a/src/main/java/org/pasteque/major/domain/package-info.java b/src/main/java/org/pasteque/major/domain/package-info.java index 052eb36..60cf814 100644 --- a/src/main/java/org/pasteque/major/domain/package-info.java +++ b/src/main/java/org/pasteque/major/domain/package-info.java @@ -5,5 +5,4 @@ * but not modified. All properties and methods are then final but the class * may be extended to include more data.

*/ -// TODO: add a way to propagate extra data to the DTO package org.pasteque.major.domain;