Supplier.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;
import org.example.customer.utility.Location;
import org.example.customer.utility.Phone;
import org.example.websecurity.XssSanitizer;
import org.example.websecurity.XssSanitizerImpl;

/**
 * The Supplier Entity for the Customer application.
 * <p>
 * This class represents the following DB Table:
 * 
 * <pre>
 * CREATE TABLE SUPPLIER (
 *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
 *      COMPANY_NAME VARCHAR(40) NOT NULL,
 *      CONTACT_NAME VARCHAR(50),
 *      CITY VARCHAR(40),
 *      COUNTRY VARCHAR(40),
 *      PHONE VARCHAR(20),
 *      FAX VARCHAR(30),
 *      CONSTRAINT PK_SUPPLIER PRIMARY KEY (ID)
 *   );
 * </pre>
 * 
 * @author Jonathan Earl
 * @version 1.0
 *
 */
public class Supplier extends CustomerEntity
   implements Serializable, Comparable<Supplier>
{
    private static final long serialVersionUID = 1L;

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

    private String myCompanyName; 
    private String myContactName;
    private Location myLocation;
    private Phone myPhone;
    private Phone myFax;

    private XssSanitizer mySanitizer;
    
    /**
     * The default constructor for the Supplier class.
     * <p>
     * The initial values are:
     * <ul>
     *   <li>id: 1</li>
     *   <li>first name: ABC Inc.</li>
     *   <li>last name: John Smith</li>
     *   <li>city: New York City</li>
     *   <li>country: United States of America</li>
     *   <li>phone: null</li>
     *   <li>fax: null</li>
     * </ul>
     */
    public Supplier()
    {
        this(new XssSanitizerImpl());
        LOG.debug("Finishing the default Constructor");
    }
    
    /**
     * The overloaded constructor for the Supplier class that takes an XssSanitizer as input.
     * <p>
     * The initial values are:
     * <ul>
     *   <li>id: 1</li>
     *   <li>first name: ABC Inc.</li>
     *   <li>last name: John Smith</li>
     *   <li>city: New York City</li>
     *   <li>country: United States of America</li>
     *   <li>phone: null</li>
     *   <li>fax: null</li>
     * </ul>
     * 
     * @param sanitizer the XssSanitizer used by this instance
     */
    public Supplier(final XssSanitizer sanitizer)
    {
        LOG.debug("Starting the overloaded Constructor");
        final int initialId = 1;
        final String initialCompanyName = "ABC Inc.";
        final String initialContactName = "John Smith";
        final String initialCity = "New York City";
        final String initialCountry = "United States of America";
        final String initialPhoneNumber = null;
        final String initialFaxNumber = null;
        
        mySanitizer = sanitizer;
        
        setId(initialId);
        setCompanyName(initialCompanyName);
        setContactName(initialContactName);
        Location temp = new Location();
        temp.setCity(initialCity);
        temp.setCountry(initialCountry);
        setLocation(temp); 
        Phone temp2 = new Phone();
        temp2.setNumber(initialPhoneNumber);
        setPhone(temp2);
        Phone temp3 = new Phone();
        temp3.setNumber(initialFaxNumber);
        setFax(temp2);
    }

    /**
     * Returns the company name value for the Supplier.
     *  
     * @return the company name value for the Supplier
     */
    public String getCompanyName()
    {
        LOG.debug("returning the Company Name: " + myCompanyName);
        return myCompanyName;
    }
    
    /**
     * This will enable sorting of Suppliers by company name.
     * <br>
     * <br>
     * @param other the Supplier object to compare with
     * @return the sort value of negative/zero/positive
     */
    @Override
    public int compareTo(Supplier other)
    {
        return this.getCompanyName().compareToIgnoreCase(other.getCompanyName());
    }

    /**
     * Sets the company name value for the Supplier.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the company name must <strong>not</strong> be null</li>
     *   <li>the company name must <strong>not</strong> be empty</li>
     *   <li>the company name must max length of 40 chars</li>
     *   <li>XSS strings within the company name will be removed</li>
     * </ul>
     * 
     * @param companyName the value to set into the customer company name field
     * @throws IllegalArgumentException if the company name is invalid
     */
    public void setCompanyName(final String companyName)
    {
        LOG.debug("setting the Company Name");
        final int max = 40;
        
        if (companyName == null)
        {
            LOG.error("Company Name must not be null");
            throw new IllegalArgumentException("Company Name must not be null");
        }
        
        String safeCompanyName = mySanitizer.sanitizeInput(companyName);
        if (safeCompanyName.isEmpty())
        {
            LOG.error("Company Name must not be empty");
            throw new IllegalArgumentException("Company Name must not be empty");
        }
        if (safeCompanyName.length() > max)
        {
            LOG.error("Company Name must be up to 40 chars in length");
            throw new IllegalArgumentException("Company Name must be up to 40 chars in length");
        }
        LOG.debug("setting the First Name to: " + safeCompanyName);
        this.myCompanyName = safeCompanyName;
    }

    /**
     * Returns the contactName value for the Supplier.
     *  
     * @return the contactName value for the Supplier
     */
    public String getContactName()
    {
        LOG.debug("returning the contactName: " + myContactName);
        return myContactName;
    }

    /**
     * Sets the contactName value for the Supplier.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the contactName <strong>may</strong> be null</li>
     *   <li>the contactName must <strong>not</strong> be empty</li>
     *   <li>the contactName must min length of 2 chars</li>
     *   <li>the contactName must max length of 50 chars</li>
     *   <li>XSS strings within the contactName will be removed</li>
     * </ul>
     * 
     * @param contactName the value to set into the customer city field
     * @throws IllegalArgumentException if the city is invalid
     */
    public void setContactName(final String contactName)
    {
        LOG.debug("setting the ContactName");
        final int max = 50;
        final int min = 2;
        
        if (contactName == null)
        {
            LOG.debug("ContactName is set to null");
            this.myContactName = null;
            return;
        }
        
        String safeContactName = mySanitizer.sanitizeInput(contactName);
        if (safeContactName.isEmpty())
        {
            LOG.error("ContactName must not be empty");
            throw new IllegalArgumentException("ContactName must not be empty");
        }
        if (safeContactName.length() > max || safeContactName.length() < min)
        {
            LOG.error("ContactName must be between 2 and 40 chars in length");
            throw new IllegalArgumentException("ContactName must be between 2 and 40 chars in length");
        }
        LOG.debug("setting the ContactName to: " + safeContactName);
        this.myContactName = safeContactName;
    }

    /**
     * Return the Location for the Supplier.
     * <br>
     * <br>
     * @return the myLocation
     */
    public Location getLocation()
    {
        LOG.debug("returning the Location: " + myLocation);
        return myLocation;
    }

    /**
     * Sets the location value for the Supplier.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the location <strong>may</strong> be null</li>
     * </ul>
     * 
     * @param location the value to set into the supplier location field
     * @throws IllegalArgumentException if the location is invalid
     */
    public void setLocation(final Location location)
    {
        LOG.debug("setting the Location");
        if (location == null)
        {
            LOG.error("Location must not be null");
            throw new IllegalArgumentException("Location must not be null");
        }
        this.myLocation = location;
    }

    /**
     * Returns the phone value for the Supplier.
     *  
     * @return the phone value for the supplier
     */
    public Phone getPhone()
    {
        LOG.debug("returning the Phone: " + myPhone);
        return myPhone;
    }

    /**
     * Sets the phone value for the Supplier.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the phone <strong>may</strong> be null</li>
     * </ul>
     * 
     * @param phone the value to set into the supplier phone field
     * @throws IllegalArgumentException if the phone is invalid
     */
    public void setPhone(final Phone phone)
    {
        LOG.debug("setting the Phone");
        this.myPhone = phone;
    }

    /**
     * Returns the fax value for the Supplier.
     *  
     * @return the fax value for the supplier
     */
    public Phone getFax()
    {
        LOG.debug("returning the Fax: " + myPhone);
        return myFax;
    }

    /**
     * Sets the fax value for the Supplier.
     * <p>
     * The business rules are:
     * <ul>
     *   <li>the fax <strong>may</strong> be null</li>
     * </ul>
     * 
     * @param fax the value to set into the supplier fax field
     * @throws IllegalArgumentException if the phone is invalid
     */
    public void setFax(final Phone fax)
    {
        LOG.debug("setting the Fax");
        this.myFax = fax;
    }

    /**
     * The hashCode() method of the Supplier class.
     * <p>
     * <strong>This method uses:</strong>
     * <ul>
     *  <li>id</li>
     *  <li>company name</li>
     *  <li>city</li>
     *  <li>country</li>
     *  <li>phone</li>
     * </ul>
     * 
     * @see java.lang.Object#hashCode()
     * @return the hashCode value for this Customer object
     */
    @Override
    public int hashCode()
    {
        LOG.debug("building HashCode");
        return new HashCodeBuilder()
                .append(getId())
                .append(myCompanyName)
                .append(myLocation.getCity())
                .append(myLocation.getCountry())
                .append(myPhone)
                .toHashCode();
    }

    /**
     * The equals() method of the Supplier class.
     * <p>
     * <strong>This method uses:</strong>
     * <ul>
     *  <li>id</li>
     *  <li>company name</li>
     *  <li>city</li>
     *  <li>country</li>
     *  <li>phone</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 Supplier)
        {
            final Supplier other = (Supplier) obj;
            return new EqualsBuilder()
                    .append(getId(), other.getId())
                    .append(myCompanyName, other.myCompanyName)
                    .append(myLocation.getCity(), other.myLocation.getCity())
                    .append(myLocation.getCountry(), other.myLocation.getCountry())
                    .append(myPhone, other.myPhone)
                    .isEquals();
        }
        else
        {
            return false;
        }
    }

    /**
     * The toString method for the Supplier class.
     * 
     * this method will return:<br>
     * Supplier [Id=xxx, CompanyName=xxx, City=xxx, 
     *           myCountry=xxx, myPhone=xxx]
     */
    @Override
    public String toString()
    {
        return "Supplier [Id=" + getId() + ", CompanyName=" + myCompanyName + ", City=" + myLocation.getCity() 
                + ", Country=" + myLocation.getCountry() + ", Phone=" + myPhone.getNumber() + "]";
    }
}