OrderItem.java

package org.example.customer;

/*
 * This is free and unencumbered software released into the public domain.
 * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, 
 * either in source code form or as a compiled binary, for any purpose, commercial or 
 * non-commercial, and by any means.
 * 
 * In jurisdictions that recognize copyright laws, the author or authors of this 
 * software dedicate any and all copyright interest in the software to the public domain. 
 * We make this dedication for the benefit of the public at large and to the detriment of 
 * our heirs and successors. We intend this dedication to be an overt act of relinquishment in 
 * perpetuity of all present and future rights to this software under copyright law.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES 
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 * For more information, please refer to: https://unlicense.org/
*/

import java.io.Serializable;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.example.customer.utility.CustomerEntity;

/**
 * The OrderItem Entity for the Customer application.
 * <p>
 * This class represents the following DB Table:
 * 
 * <pre>
 * CREATE TABLE ORDER_ITEM (
 *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
 *      ORDER_ID INTEGER NOT NULL,
 *      PRODUCT_ID INTEGER NOT NULL,
 *      UNIT_PRICE DECIMAL(12,2) NOT NULL,
 *      QUANTITY INTEGER NOT NULL,
 *      CONSTRAINT PK_ORDERITEM PRIMARY KEY (ID)
 *   );
 * </pre>
 * 
 * @author Jonathan Earl
 * @version 1.0
 *
 */
public final class OrderItem extends CustomerEntity
    implements Serializable
{
    private static final long serialVersionUID = 1L;

    private static final Logger LOG = LogManager.getLogger();

    private int myOrderId;
    private int myProductId;
    private double myUnitPrice;
    private int myQuantity;
    private double mySubTotal;

    /**
     * The default constructor for the OrderItem class.
     * <p>
     * The initial values are:
     * <ul>
     * <li>id: 1</li>
     * <li>orderId: 1</li>
     * <li>productId: 1</li>
     * <li>unitPrice: 0.01</li>
     * <li>quantity: 1</li>
     * <li>subTotal: unitPrice * quantity</li>
     * </ul>
     */
    public OrderItem()
    {
        LOG.debug("Starting the default Constructor");
        final int initialId = 1;
        final int initialOrderId = 1;
        final int initialProductId = 1;
        final double initialUnitPrice = 0.01;
        final int initialQuantity = 1;

        setId(initialId);
        setOrderId(initialOrderId);
        setProductId(initialProductId);
        setUnitPrice(initialUnitPrice);
        setQuantity(initialQuantity);
        computeSubTotal();
    }

    /**
     * Computes the OrderItem subTotal as quantity * unitPrice.
     */
    private void computeSubTotal()
    {
        LOG.debug("Computing the subTotal");
        mySubTotal = myQuantity * myUnitPrice;

    }

    /**
     * Returns the orderId value for the Order.
     *  
     * @return the orderId value for the order
     */
    public int getOrderId()
    {
        LOG.debug("returning the OrderId: " + myOrderId);
        return myOrderId;
    }

    /**
     * Sets the orderId value for the OrderItem.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the orderId must be 1 or greater</li>
     * </ul>
     * 
     * @param orderId the value to set into the orderId field
     * @throws IllegalArgumentException if the orderId is invalid
     */
    public void setOrderId(final int orderId)
    {
        LOG.debug("setting the OrderId: " + orderId);
        final int min = 1;
        
        if (orderId < min)
        {
            LOG.error("OrderId must be greater then zero");
            throw new IllegalArgumentException("OrderId must be greater then zero");
        }
        this.myOrderId = orderId;
    }

    /**
     * Returns the productId value for the OrderItem.
     *  
     * @return the productId value for the OrderItem
     */
    public int getProductId()
    {
        LOG.debug("returning the ProductId: " + myProductId);
        return myProductId;
    }

    /**
     * Sets the productId value for the Order.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the productId must be 1 or greater</li>
     * </ul>
     * 
     * @param productId the value to set into the productId field
     * @throws IllegalArgumentException if the productId is invalid
     */
    public void setProductId(final int productId)
    {
        LOG.debug("setting the productId: " + productId);
        final int min = 1;
        
        if (productId < min)
        {
            LOG.error("productId must be greater then zero");
            throw new IllegalArgumentException("productId must be greater then zero");
        }
        this.myProductId = productId;
    }

    /**
     * Returns the UnitPrice value for the OrderItem.
     *  
     * @return the UnitPrice value for the OrderItem
     */
    public double getUnitPrice()
    {
        LOG.debug("returning the UnitPrice: " + myUnitPrice);
        return myUnitPrice;
    }

    /**
     * Sets the UnitPrice value for the OrderItem.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the UnitPrice must be 0.01 or greater</li>
     * </ul>
     * This will also recompute the subTotal value.
     * 
     * @param unitPrice the value to set into the unitPrice field
     * @throws IllegalArgumentException if the UnitPrice is invalid
     */
    public void setUnitPrice(final double unitPrice)
    {
        LOG.debug("setting the unitPrice: " + unitPrice);
        final double min = 0.01;
        
        if (unitPrice < min)
        {
            LOG.error("unitPrice must be greater then zero");
            throw new IllegalArgumentException("unitPrice must be greater then zero");
        }
        this.myUnitPrice = unitPrice;
        computeSubTotal();
    }

    /**
     * Returns the Quantity value for the OrderItem.
     *  
     * @return the Quantity value for the OrderItem
     */
    public int getQuantity()
    {
        LOG.debug("returning the Quantity: " + myQuantity);
        return myQuantity;
    }

    /**
     * Sets the Quantity value for the OrderItem.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the Quantity must be 1 or greater</li>
     * </ul>
     * This will also recompute the subTotal value.
     * 
     * @param quantity the value to set into the Quantity field
     * @throws IllegalArgumentException if the Quantity is invalid
     */
    public void setQuantity(final int quantity)
    {
        LOG.debug("setting the Quantity: " + quantity);
        final int min = 1;
        
        if (quantity < min)
        {
            LOG.error("Quantity must be greater then zero");
            throw new IllegalArgumentException("Quantity must be greater then zero");
        }
        this.myQuantity = quantity;
        computeSubTotal();
    }

    /**
     * Returns the SubTotal value for the OrderItem.
     * 
     * The SunTotal will be recomputed any time the UnitPrice or Quantity changes.
     *  
     * @return the SubTotal value for the OrderItem
     */
    public double getSubTotal()
    {
        LOG.debug("returning the SubTotal: " + mySubTotal);
        return mySubTotal;
    }
    
    /**
     * The hashCode() method of the OrderItem class.
     * <p>
     * <strong>This method uses:</strong>
     * <ul>
     *  <li>id</li>
     *  <li>order id</li>
     *  <li>product id</li>
     *  <li>unit price</li>
     *  <li>quantity</li>
     * </ul>
     * 
     * @see java.lang.Object#hashCode()
     * @return the hashCode value for this Order object
     */
    @Override
    public int hashCode()
    {
        LOG.debug("building HashCode");
        return new HashCodeBuilder()
                .append(getId())
                .append(myOrderId)
                .append(myProductId)
                .append(myUnitPrice)
                .append(myQuantity)
                .toHashCode();
    }

    /**
     * The equals() method of the OrderItem class.
     * <p>
     * <strong>This method uses:</strong>
     * <ul>
     *  <li>id</li>
     *  <li>order id</li>
     *  <li>product id</li>
     *  <li>unit price</li>
     *  <li>quantity</li>
     * </ul>
     * 
     * @see java.lang.Object#equals(Object obj)
     * @param obj the incoming object to compare against
     * @return true if the fields being compared are equal
     */
    @Override
    public boolean equals(final Object obj)
    {
        LOG.debug("checking equals");
        if (obj instanceof OrderItem)
        {
            final OrderItem other = (OrderItem) obj;
            return new EqualsBuilder()
                    .append(getId(), other.getId())
                    .append(myOrderId, other.myOrderId)
                    .append(myProductId, other.myProductId)
                    .append(myUnitPrice, other.myUnitPrice)
                    .append(myQuantity, other.myQuantity)
                    .isEquals();
        }
        else
        {
            return false;
        }
    }


    /**
     * The toString method for the OrderItem class.
     * 
     * this method will return:<br>
     * OrderItem [Id=xxx", OrderId=xxx, ProductId=xxx,
               UnitPrice=xxx, Quantity=xxx, SubTotal=xxx]
     */
    @Override
    public String toString()
    {
        return "OrderItem [Id=" + getId() + ", OrderId=" + myOrderId 
                + ", ProductId=" + myProductId
                + ", UnitPrice=" + myUnitPrice + ", Quantity=" 
                + myQuantity + ", SubTotal=" + mySubTotal + "]";
    }

}