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
    26  import org.apache.commons.lang3.builder.EqualsBuilder;
    27  import org.apache.commons.lang3.builder.HashCodeBuilder;
    28  import org.apache.logging.log4j.LogManager;
    29  import org.apache.logging.log4j.Logger;
    30  import org.example.customer.utility.CustomerEntity;
    31  import org.example.websecurity.XssSanitizer;
    32  import org.example.websecurity.XssSanitizerImpl;
    33
    34  //CREATE TABLE PRODUCT (
    35  //        ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
    36  //        PRODUCT_NAME VARCHAR(50) NOT NULL,
    37  //        SUPPLIER_ID INTEGER NOT NULL,
    38  //        UNIT_PRICE DECIMAL(12,2),
    39  //        PACKAGE  VARCHAR(30),
    40  //        IS_DISCONTINUED BOOLEAN,
    41  //        CONSTRAINT PK_PRODUCT PRIMARY KEY (ID)
    42  //     );
    43
    44  /**
    45   * The Product Entity for the Customer application.
    46   * <p>
    47   * This class represents the following DB Table:
    48   *
    49   * <pre>
    50   * CREATE TABLE PRODUCT (
    51   *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
    52   *      PRODUCT_NAME VARCHAR(50) NOT NULL,
    53   *      SUPPLIER_ID INTEGER NOT NULL,
    54   *      UNIT_PRICE DECIMAL(12,2),
    55   *      PACKAGE  VARCHAR(30),
    56   *      IS_DISCONTINUED BOOLEAN,
    57   *      CONSTRAINT PK_PRODUCT PRIMARY KEY (ID)
    58   *   );
    59   * </pre>
    60   *
    61   * @author Jonathan Earl
    62   * @version 1.0
    63   *
    64   */
    65  public final class Product extends CustomerEntity
    66      implements Serializable, Comparable<Product>
    67  {
    68  	private static final long serialVersionUID = 1L;
    69
    70  	private static final Logger LOG = LogManager.getLogger();
    71
    72      private String myProductName;
    73      private int mySupplierId;
    74      private double myUnitPrice;
    75      private String myPackaging;
    76      private boolean myDiscontinued;
    77
    78      private XssSanitizer mySanitizer;
    79
    80      /**
    81       * The default constructor for the Product class.
    82       * <p>
    83       * The initial values are:
    84       * <ul>
    85       *   <li>id: 1</li>
    86       *   <li>product name: Paper Envelope</li>
    87       *   <li>supplier id: 1</li>
    88       *   <li>unit price: 0.01</li>
    89       *   <li>packaging: single</li>
    90       *   <li>discontinued: false</li>
    91       * </ul>
    92       */
    93      public Product()
    94      {
    95          this(new XssSanitizerImpl());
    96          LOG.debug("Finishing the default Constructor");
    97      }
    98
    99      /**
    100      * The overloaded constructor for the Product class that takes an XssSanitizer as input.
    101      * <p>
    102      * The initial values are:
    103      * <ul>
    104      *   <li>id: 1</li>
    105      *   <li>product name: Paper Envelope</li>
    106      *   <li>supplier id: 1</li>
    107      *   <li>unit price: 0.01</li>
    108      *   <li>packaging: single</li>
    109      *   <li>discontinued: false</li>
    110      * </ul>
    111      *
    112      * @param sanitizer the XssSanitizer used by this instance
    113      */
    114     public Product(final XssSanitizer sanitizer)
    115     {
    116         LOG.debug("Starting the overloaded Constructor");
    117         final int initialId = 1;
    118         final String initialProductName = "Paper Envelope";
    119         final int initialSupplierId = 1;
    120         final double initialUnitPrice = 0.01;
    121         final String initialPackaging = "single";
    122         final boolean initialDiscontinued = false;
    123
    124         mySanitizer = sanitizer;
    125
    126         setId(initialId);
    127         setProductName(initialProductName);
    128         setSupplierId(initialSupplierId);
    129         setUnitPrice(initialUnitPrice);
    130         setPackaging(initialPackaging);
    131         setDiscontinued(initialDiscontinued);
    132     }
    133
    134     /**
    135      * This will enable sorting of Products by name.
    136      * <br>
    137      * <br>
    138      * @param other the Product object to compare with
    139      * @return the sort value of negative/zero/positive
    140      */
    141     @Override
    142     public int compareTo(Product other)
    143     {
    144         return this.getProductName().compareToIgnoreCase(other.getProductName());
    145     }
    146
    147     /**
    148      * Returns the product name value for the Product.
    149      *
    150      * @return the product name value for the Product
    151      */
    152     public String getProductName()
    153     {
    154         LOG.debug("returning the Product Name: " + myProductName);
    155         return myProductName;
    156     }
    157
    158     /**
    159      * Sets the product name value for the Product.
    160      * <p>
    161      * The business rules are:
    162      * <ul>
    163      *   <li>the product name must <strong>not</strong> be null</li>
    164      *   <li>the product name must <strong>not</strong> be empty</li>
    165      *   <li>the product name must max length of 50 chars</li>
    166      *   <li>XSS strings within the product name will be removed</li>
    167      * </ul>
    168      *
    169      * @param productName the value to set into the product name field
    170      * @throws IllegalArgumentException if the product name is invalid
    171      */
    172     public void setProductName(final String productName)
    173     {
    174         LOG.debug("setting the Product Name");
    175         final int max = 50;
    176
    177         if (productName == null)
    178         {
    179             LOG.error("Product Name must not be null");
    180             throw new IllegalArgumentException("Product Name must not be null");
    181         }
    182
    183         String safeProductName = mySanitizer.sanitizeInput(productName);
    184         if (safeProductName.isEmpty())
    185         {
    186             LOG.error("Product Name must not be empty");
    187             throw new IllegalArgumentException("Product Name must not be empty");
    188         }
    189         if (safeProductName.length() > max)
    190         {
    191             LOG.error("Product Name must be up to 50 chars in length");
    192             throw new IllegalArgumentException("Product Name must be up to 50 chars in length");
    193         }
    194         LOG.debug("setting the Product Name to: " + safeProductName);
    195         this.myProductName = safeProductName;
    196     }
    197
    198     /**
    199      * Returns the SupplierId value for the Product.
    200      *
    201      * @return the supplierId value for the Product
    202      */
    203     public int getSupplierId()
    204     {
    205         LOG.debug("returning the SupplierId: " + mySupplierId);
    206         return mySupplierId;
    207     }
    208
    209     /**
    210      * Sets the SupplierId value for the Product.
    211      * <p>
    212      * The business rules are:
    213      * <ul>
    214      *   <li>the SupplierId must be 1 or greater</li>
    215      * </ul>
    216      *
    217      * @param supplierId the value to set into the supplier id field
    218      * @throws IllegalArgumentException if the id is invalid
    219      */
    220     public void setSupplierId(final int supplierId)
    221     {
    222         LOG.debug("setting the SuppliierId: " + supplierId);
    223         final int min = 1;
    224
    225         if (supplierId < min)
    226         {
    227             LOG.error("SupplierId must be greater then zero");
    228             throw new IllegalArgumentException("SupplierId must be greater then zero");
    229         }
    230         this.mySupplierId = supplierId;
    231     }
    232
    233     /**
    234      * Returns the UnitPrice value for the Product.
    235      *
    236      * @return the UnitPrice value for the Product
    237      */
    238     public double getUnitPrice()
    239     {
    240         LOG.debug("returning the UnitPrice: " + myUnitPrice);
    241         return myUnitPrice;
    242     }
    243
    244     /**
    245      * Sets the UnitPrice value for the Product.
    246      * <p>
    247      * The business rules are:
    248      * <ul>
    249      *   <li>the UnitPrice must be 0.01 or greater</li>
    250      * </ul>
    251      *
    252      * @param unitPrice the value to set into the unitPrice field
    253      * @throws IllegalArgumentException if the UnitPrice is invalid
    254      */
    255     public void setUnitPrice(final double unitPrice)
    256     {
    257         LOG.debug("setting the unitPrice: " + unitPrice);
    258         final double min = 0.01;
    259
    260         if (unitPrice < min)
    261         {
    262             LOG.error("unitPrice must be greater then zero");
    263             throw new IllegalArgumentException("unitPrice must be greater then zero");
    264         }
    265         this.myUnitPrice = unitPrice;
    266     }
    267
    268     /**
    269      * Returns the packaging value for the Product.
    270      *
    271      * @return the packaging value for the Product
    272      */
    273     public String getPackaging()
    274     {
    275         LOG.debug("returning the Packaging: " + myPackaging);
    276         return myPackaging;
    277     }
    278
    279     /**
    280      * Sets the packaging value for the Product.
    281      * <p>
    282      * The business rules are:
    283      * <ul>
    284      *   <li>the packaging <strong>may</strong> be null</li>
    285      *   <li>the packaging must <strong>not</strong> be empty</li>
    286      *   <li>the packaging must min length of 2 chars</li>
    287      *   <li>the packaging must max length of 30 chars</li>
    288      *   <li>XSS strings within the packaging will be removed</li>
    289      * </ul>
    290      *
    291      * @param packaging the value to set into the Product packaging field
    292      * @throws IllegalArgumentException if the packaging is invalid
    293      */
    294     public void setPackaging(final String packaging)
    295     {
    296         LOG.debug("setting the Packaging");
    297         final int max = 30;
    298         final int min = 2;
    299
    300         if (packaging == null)
    301         {
    302             LOG.debug("Packaging is set to null");
    303             this.myPackaging = null;
    304             return;
    305         }
    306
    307         String safePackaging = mySanitizer.sanitizeInput(packaging);
    308         if (safePackaging.isEmpty())
    309         {
    310             LOG.error("Packaging must not be empty");
    311             throw new IllegalArgumentException("Packaging must not be empty");
    312         }
    313         if (safePackaging.length() > max || safePackaging.length() < min)
    314         {
    315             LOG.error("Packaging must be between 2 and 30 chars in length");
    316             throw new IllegalArgumentException("Packaging must be between 2 and 30 chars in length");
    317         }
    318         LOG.debug("setting the Packaging to: " + safePackaging);
    319         this.myPackaging = safePackaging;
    320     }
    321
    322     /**
    323      * Returns the Discontinued value for the Product.
    324      *
    325      * @return the discontinued value for the Product
    326      */
    327     public boolean isDiscontinued()
    328     {
    329         LOG.debug("returning the Discontinued: " + myDiscontinued);
    330         return myDiscontinued;
    331     }
    332
    333     /**
    334      * Sets the Discontinued value for the Product.
    335      *
    336      * @param discontinued the value to set field
    337       */
    338     public void setDiscontinued(final boolean discontinued)
    339     {
    340         LOG.debug("setting the discontinued value to: " + discontinued);
    341         this.myDiscontinued = discontinued;
    342     }
    343
    344     /**
    345      * The hashCode() method of the Product class.
    346      * <p>
    347      * <strong>This method uses:</strong>
    348      * <ul>
    349      *  <li>id</li>
    350      *  <li>product name</li>
    351      *  <li>supplier id</li>
    352      *  <li>unit price</li>
    353      *  <li>packaging</li>
    354      * </ul>
    355      *
    356      * @see java.lang.Object#hashCode()
    357      * @return the hashCode value for this Product object
    358      */
    359     @Override
    360     public int hashCode()
    361     {
    362         LOG.debug("building HashCode");
    363         return new HashCodeBuilder()
    364                 .append(getId())
    365                 .append(myProductName)
    366                 .append(mySupplierId)
    367                 .append(myUnitPrice)
    368                 .append(myPackaging)
    369                 .toHashCode();
    370     }
    371
    372     /**
    373      * The equals() method of the Product class.
    374      * <p>
    375      * <strong>This method uses:</strong>
    376      * <ul>
    377      *  <li>id</li>
    378      *  <li>product name</li>
    379      *  <li>supplier id</li>
    380      *  <li>unit price</li>
    381      *  <li>packaging</li>
    382      * </ul>
    383      *
    384      * @see java.lang.Object#equals(Object obj)
    385      * @param obj the incoming object to compare against
    386      * @return true if the fields being compared are equal
    387      */
    388     @Override
    389     public boolean equals(final Object obj)
    390     {
    391         LOG.debug("checking equals");
    392         if (obj instanceof Product)
    393         {
    394             final Product other = (Product) obj;
    395             return new EqualsBuilder()
    396                     .append(getId(), other.getId())
    397                     .append(myProductName, other.myProductName)
    398                     .append(mySupplierId, other.mySupplierId)
    399                     .append(myUnitPrice, other.myUnitPrice)
    400                     .append(myPackaging, other.myPackaging)
    401                     .isEquals();
    402         }
    403         else
    404         {
    405             return false;
    406         }
    407     }
    408
    409     /**
    410      * The toString method for the Product class.
    411      *
    412      * this method will return:<br>
    413      * Product [myId=xxx, myProductName=xxx, mySupplierId=xxx,
    414      *          myUnitPrice=xxx, myPackaging=xxx, myDiscontinued=xxx]
    415      */
    416     @Override
    417     public String toString()
    418     {
    419     	 LOG.debug("calling toString()");
    420         return "Product [Id=" + getId() + ", ProductName=" + myProductName
    421                 + ", SupplierId=" + mySupplierId
    422                 + ", UnitPrice=" + myUnitPrice + ", Packaging=" + myPackaging
    423                 + ", Discontinued=" + myDiscontinued + "]";
    424     }
    425 }