View Javadoc

    1   package org.example.customer;
    2
    3   /*
    4    * This is free and unencumbered software released into the public domain.
    5    * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software,
    6    * either in source code form or as a compiled binary, for any purpose, commercial or
    7    * non-commercial, and by any means.
    8    *
    9    * In jurisdictions that recognize copyright laws, the author or authors of this
    10   * software dedicate any and all copyright interest in the software to the public domain.
    11   * We make this dedication for the benefit of the public at large and to the detriment of
    12   * our heirs and successors. We intend this dedication to be an overt act of relinquishment in
    13   * perpetuity of all present and future rights to this software under copyright law.
    14   *
    15   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    16   * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
    17   * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES
    18   * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    20   *
    21   * For more information, please refer to: https://unlicense.org/
    22  */
    23
    24  import java.io.Serializable;
    25  import java.time.LocalDate;
    26  import java.time.format.DateTimeFormatter;
    27  import java.util.ArrayList;
    28  import java.util.List;
    29
    30  import org.apache.commons.lang3.builder.EqualsBuilder;
    31  import org.apache.commons.lang3.builder.HashCodeBuilder;
    32  import org.apache.logging.log4j.LogManager;
    33  import org.apache.logging.log4j.Logger;
    34  import org.example.customer.utility.CustomerEntity;
    35  import org.example.websecurity.XssSanitizer;
    36  import org.example.websecurity.XssSanitizerImpl;
    37
    38  /**
    39   * The Order Entity for the Customer application.
    40   * <br>
    41   * <br>
    42   * This class represents the following DB Table:
    43   *
    44   * <pre>
    45   * CREATE TABLE ORDERS (
    46   *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
    47   *      ORDER_DATE DATE NOT NULL,
    48   *      CUSTOMER_ID  INTEGER,
    49   *      TOTAL_AMOUNT DECIMAL(12,2),
    50   *      ORDER_NUMBER VARCHAR(10),
    51   *      CONSTRAINT PK_ORDER PRIMARY KEY (ID)
    52   *   );
    53   * </pre>
    54   *
    55   * @author Jonathan Earl
    56   * @version 1.0
    57   *
    58   */
    59  public final class Order extends CustomerEntity
    60     implements Serializable, Comparable<Order>
    61  {
    62      private static final long serialVersionUID = 1L;
    63
    64      private static final Logger LOG = LogManager.getLogger();
    65
    66      private LocalDate myOrderDate;
    67      private int myCustomerId;
    68      private double myTotalAmount;
    69      private String myOrderNumber;
    70
    71      private XssSanitizer mySanitizer;
    72
    73      private List<OrderItem> myOrderItems;
    74
    75      /**
    76       * The default constructor for the Order class.
    77       * <br>
    78       * <br>
    79       * The initial values are:
    80       * <ul>
    81       *   <li>id: 1</li>
    82       *   <li>orderDate: Current Date</li>
    83       *   <li>customerId: 1</li>
    84       *   <li>totalAmount: 0.00</li>
    85       *   <li>orderNumber: null</li>
    86       *   <li>orderItems: empty</li>
    87       * </ul>
    88       */
    89      public Order()
    90      {
    91          this(new XssSanitizerImpl());
    92          LOG.debug("Finishing the default Constructor");
    93      }
    94
    95      /**
    96       * The overloaded constructor for the order class that takes an XssSanitizer as input.
    97       * <p>
    98       * The initial values are:
    99       * <ul>
    100      *   <li>id: 1</li>
    101      *   <li>orderDate: Current Date</li>
    102      *   <li>customerId: 1</li>
    103      *   <li>totalAmount: 0.00</li>
    104      *   <li>orderNumber: null</li>
    105      *   <li>orderItems: empty</li>
    106      * </ul>
    107      *
    108      * @param sanitizer the XssSanitizer used by this instance
    109      */
    110     public Order(final XssSanitizer sanitizer)
    111     {
    112         LOG.debug("Starting the overloaded Constructor");
    113         final int initialId = 1;
    114         final LocalDate initialOrderDate = LocalDate.now();
    115         final int initialCustomerId = 1;
    116         final String initialOrderNumber = null;
    117         final List<OrderItem> initalOrderItems = new ArrayList<OrderItem>();
    118
    119         mySanitizer = sanitizer;
    120
    121         setId(initialId);
    122         setOrderDate(initialOrderDate);
    123         setCustomerId(initialCustomerId);
    124         setOrderNumber(initialOrderNumber);
    125         setOrderItems(initalOrderItems);
    126     }
    127
    128     /**
    129      * This will enable sorting of Order by Order number concatenated with Order Date.
    130      * <br>
    131      * <br>
    132      * @param other the Order object to compare with
    133      * @return the sort value of negative/zero/positive
    134      */
    135     @Override
    136     public int compareTo(Order other)
    137     {
    138         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd-yyyy");
    139         String thisSortValue = this.getOrderNumber() + " "
    140                 + this.getOrderDate().format(formatter);
    141         String otherSortValue = other.getOrderNumber() + " "
    142                 + other.getOrderDate().format(formatter);
    143         return thisSortValue.compareToIgnoreCase(otherSortValue);
    144     }
    145
    146     /**
    147      * Returns the orderDate value for the Order.
    148      *
    149      * @return the orderDate value for the order
    150      */
    151     public LocalDate getOrderDate()
    152     {
    153         LOG.debug("returning the Oder Date: " + myOrderDate);
    154         return myOrderDate;
    155     }
    156
    157     /**
    158      * Sets the order date value for the Customer.
    159      * <p>
    160      * The business rules are:
    161      * <ul>
    162      *   <li>the order date must <strong>not</strong> be null</li>
    163      *   <li>the order date must <strong>today or earlier</strong></li>
    164      * </ul>
    165      *
    166      * @param orderDate the value to set into the orderDate field
    167      * @throws IllegalArgumentException if the first name is invalid
    168      */
    169     public void setOrderDate(final LocalDate orderDate)
    170     {
    171         LOG.debug("setting the order Date");
    172
    173         if (orderDate == null)
    174         {
    175             LOG.error("Order Date must not be null");
    176             throw new IllegalArgumentException("Order Date must not be null");
    177         }
    178         LocalDate tomorrow = LocalDate.now().plusDays(1);
    179         if (orderDate.isBefore(tomorrow))
    180         {
    181             this.myOrderDate = orderDate;
    182         }
    183         else
    184         {
    185             LOG.error("OrderDate must be today or earlier");
    186             throw new IllegalArgumentException("OrderDate must be today or earlier");
    187         }
    188     }
    189
    190     /**
    191      * Returns the id value for the Customer Id.
    192      *
    193      * @return the id value for the customer id
    194      */
    195     public int getCustomerId()
    196     {
    197         LOG.debug("returning the CustomerId: " + myCustomerId);
    198         return myCustomerId;
    199     }
    200
    201     /**
    202      * Sets the id value for the Customer ID.
    203      * <p>
    204      * The business rules are:
    205      * <ul>
    206      *   <li>the id must be 1 or greater</li>
    207      * </ul>
    208      *
    209      * @param customerId the value to set into the customer id field
    210      * @throws IllegalArgumentException if the customerId is invalid
    211      */
    212     public void setCustomerId(final int customerId)
    213     {
    214         LOG.debug("setting the CustomerId: " + customerId);
    215         final int min = 1;
    216
    217         if (customerId < min)
    218         {
    219             LOG.error("CustomerId must be greater then zero");
    220             throw new IllegalArgumentException("CustomerId must be greater then zero");
    221         }
    222         this.myCustomerId = customerId;
    223     }
    224
    225
    226     /**
    227      * Returns the total amount for the order.
    228      *
    229      * @return the totalAmount value for the order
    230      */
    231     public double getTotalAmount()
    232     {
    233         LOG.debug("returning the totalAmount: " + myTotalAmount);
    234         return myTotalAmount;
    235     }
    236
    237     /**
    238      * Sets the total amount value for the Orde.
    239      * <p>
    240      * The business rules are:
    241      * <ul>
    242      *   <li>the TotalAmount must be 0.01 or greater</li>
    243      * </ul>
    244      *
    245      * @param totalAmount the value to set into the totalAmount field
    246      * @throws IllegalArgumentException if the totalAmount is invalid
    247      */
    248     public void setTotalAmount(final double totalAmount)
    249     {
    250         LOG.debug("setting the totalAmount: " + totalAmount);
    251         final double min = 0.01;
    252
    253         if (totalAmount < min)
    254         {
    255             LOG.error("totalAmount must be greater then zero");
    256             throw new IllegalArgumentException("totalAmount must be greater then zero");
    257         }
    258         this.myTotalAmount = totalAmount;
    259     }
    260
    261     /**
    262      * Returns the orderNumber value for the Order.
    263      *
    264      * @return the orderNumber value for the order
    265      */
    266     public String getOrderNumber()
    267     {
    268         LOG.debug("returning the OrderNumber: " + myOrderNumber);
    269         return myOrderNumber;
    270     }
    271
    272     /**
    273      * Sets the orderNumber value for the Order.
    274      * <p>
    275      * The business rules are:
    276      * <ul>
    277      *   <li>the orderNumber <strong>may</strong> be null</li>
    278      *   <li>the orderNumber must <strong>not</strong> be empty</li>
    279      *   <li>the orderNumber must min length of 2 chars</li>
    280      *   <li>the orderNumber must max length of 10 chars</li>
    281      *   <li>XSS strings within the orderNumber will be removed</li>
    282      * </ul>
    283      *
    284      * @param orderNumber the value to set into the Order Number field
    285      * @throws IllegalArgumentException if the orderNumber is invalid
    286      */
    287     public void setOrderNumber(final String orderNumber)
    288     {
    289         LOG.debug("setting the OrderNumber");
    290         final int max = 10;
    291         final int min = 2;
    292
    293         if (orderNumber == null)
    294         {
    295             LOG.debug("orderNumber is set to null");
    296             this.myOrderNumber = null;
    297             return;
    298         }
    299
    300         String safeOrderNumber = mySanitizer.sanitizeInput(orderNumber);
    301         if (safeOrderNumber.isEmpty())
    302         {
    303             LOG.error("OrderNumber must not be empty");
    304             throw new IllegalArgumentException("OrderNumber must not be empty");
    305         }
    306         if (safeOrderNumber.length() > max || safeOrderNumber.length() < min)
    307         {
    308             LOG.error("OrderNumber must be between 2 and 10 chars in length");
    309             throw new IllegalArgumentException("OrderNumber must be between 2 and 10 chars in length");
    310         }
    311         LOG.debug("setting the OrderNumber to: " + safeOrderNumber);
    312         this.myOrderNumber = safeOrderNumber;
    313     }
    314
    315     /**
    316      * Returns the orderItem list value for the Order.
    317      *
    318      * @return the myOrderItems for the order
    319      */
    320     public List<OrderItem> getOrderItems()
    321     {
    322         LOG.debug("returning the OrderItems: " + myOrderItems);
    323         return myOrderItems;
    324     }
    325
    326     /**
    327      * Sets the orderItem list value for the Order.
    328      * <p>
    329      * The business rules are:
    330      * <ul>
    331      *   <li>the orderItems must <strong>not</strong> be null</li>
    332      *   <li>the orderItems may be empty</li>
    333      * </ul>
    334      *
    335      * @param orderItems the list to set into the orderItems
    336      * @throws IllegalArgumentException if the orderItems is invalid
    337      */
    338 	public void setOrderItems(final List<OrderItem> orderItems)
    339 	{
    340         LOG.debug("setting the Orderitems");
    341         if (orderItems == null)
    342         {
    343             LOG.error("Orderitems must not be null");
    344             throw new IllegalArgumentException("Orderitems must not be null");
    345         }
    346         double total = 0.0;
    347         for (OrderItem current : orderItems)
    348         {
    349             total += current.getSubTotal();
    350         }
    351         this.myTotalAmount = total;
    352         this.myOrderItems = orderItems;
    353     }
    354
    355     /**
    356      * The hashCode() method of the Order class.
    357      * <p>
    358      * <strong>This method uses:</strong>
    359      * <ul>
    360      *  <li>id</li>
    361      *  <li>order date</li>
    362      *  <li>customer id</li>
    363      *  <li>order number</li>
    364      * </ul>
    365      *
    366      * @see java.lang.Object#hashCode()
    367      * @return the hashCode value for this Order object
    368      */
    369     @Override
    370     public int hashCode()
    371     {
    372         LOG.debug("building HashCode");
    373         return new HashCodeBuilder()
    374                 .append(getId())
    375                 .append(myOrderDate)
    376                 .append(myCustomerId)
    377                 .append(myOrderNumber)
    378                 .toHashCode();
    379     }
    380
    381     /**
    382      * The equals() method of the order class.
    383      * <p>
    384      * <strong>This method uses:</strong>
    385      * <ul>
    386      *  <li>id</li>
    387      *  <li>order date</li>
    388      *  <li>customer id</li>
    389      *  <li>order number</li>
    390      * </ul>
    391      *
    392      * @see java.lang.Object#equals(Object obj)
    393      * @param obj the incoming object to compare against
    394      * @return true if the fields being compared are equal
    395      */
    396     @Override
    397     public boolean equals(final Object obj)
    398     {
    399         LOG.debug("checking equals");
    400         if (obj instanceof Order)
    401         {
    402             final Order other = (Order) obj;
    403             return new EqualsBuilder()
    404                     .append(getId(), other.getId())
    405                     .append(myOrderDate, other.myOrderDate)
    406                     .append(myCustomerId, other.myCustomerId)
    407                     .append(myOrderNumber, other.myOrderNumber)
    408                     .isEquals();
    409         }
    410         else
    411         {
    412             return false;
    413         }
    414     }
    415
    416
    417
    418     /**
    419      * The toString method for the Order class.
    420      *
    421      * this method will return:<br>
    422      * Order [Id=xxx, OrderDate=xx/xx/xx, CustomerId=xxx,
    423      *   TotalAmount=xxx, OrderNumber=xxx]
    424      */
    425     @Override
    426     public String toString()
    427     {
    428         return "Order [Id=" + getId() + ", OrderDate=" + myOrderDate + ", CustomerId=" + myCustomerId
    429                 + ", TotalAmount=" + myTotalAmount + ", OrderNumber=" + myOrderNumber
    430                 + ", OrderItems=" + myOrderItems.size() + "]";
    431     }
    432 }