SupplierDAOImpl.java

package org.example.customerdao;


/*
 * 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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/*
 * 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.util.List;

import javax.sql.DataSource;

import org.apache.commons.dbutils.DbUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.example.customer.Supplier;
import org.example.customer.utility.CustomerEntity;
import org.example.customer.utility.Location;
import org.example.customer.utility.Phone;
import org.example.customerdao.utility.ErrorFormatter;
import org.example.customerdao.utility.NonDeleteableRecordException;
import org.example.websecurity.UserCredentials;

/**
 * This is the SupplierDAO Implementation for the Customer DAO component of the
 * Customer Web Application. This will be the primary Supplier database exposure
 * for the Customer Web Layer.
 * 
 * @author Jonathan Earl
 * @since 1.0
 * 
 */
public class SupplierDAOImpl 
    implements SupplierDAO
{
    private static final Logger LOG = LogManager.getLogger();

    private DataSource myReadOnlyDS = null;
    private DataSource myReadWriteDS = null;

    private static final String FIND_ALL_SQL = "Select * from Supplier";
    private static final String FIND_BY_ID_SQL = "Select * from Supplier where ID = ?";
    private static final String FIND_BY_COMPANY_SQL = "Select * from Supplier where COMPANY_NAME Like ?";
    private static final String ADD_SQL = "Insert into Supplier(COMPANY_NAME,CONTACT_NAME,CITY,COUNTRY,PHONE, FAX)"
            + " VALUES(?,?,?,?,?,?)";
    private static final String UPDATE_SQL = "Update Supplier set COMPANY_NAME = ?, CONTACT_NAME = ?, "
            + "CITY = ?, COUNTRY = ?, PHONE = ?, FAX = ?" + " WHERE ID = ?";
    private static final String IS_DELETEABLE_SUPPLIER_SQL = "Select COUNT(*) from Product where SUPPLIER_ID = ?";
    private static final String DELETE_SQL = "Delete from Supplier where id = ?";

    /**
     * {@inheritDoc}
     */
    @Override
    public void setReadOnlyDS(final DataSource readOnlyDS)
    {
        LOG.debug("Setting the ReadOnly DataSource");
        this.myReadOnlyDS = readOnlyDS;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setReadWriteDS(final DataSource readWriteDS)
    {
        LOG.debug("Setting the ReadWrite DataSource");
        this.myReadWriteDS = readWriteDS;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<Supplier> findAllSuppliers(final UserCredentials credentials)
    {
      LOG.debug("findAllSuppliers");
        
        if (credentials == null || !credentials.hasRole("worker"))
        {
            LOG.error("findAllSuppliers - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
          
        PreparedStatement findAll = null;
        Connection conn = null;
        ResultSet results = null;
        List<Supplier> data = new ArrayList<Supplier>();
        try
        {
            conn = myReadOnlyDS.getConnection();
            findAll = conn.prepareStatement(FIND_ALL_SQL);

            results = findAll.executeQuery();

            while (results.next())
            {
                data.add(buildSupplier(results));
            }
        }
        catch (SQLException sqle)
        {
            LOG.error("Error finding all Suppliers");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(conn, findAll, results);
        }
        return data;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Supplier findSupplierById(final UserCredentials credentials, final int id)
    {
        LOG.debug("findSupplierById");

        if (credentials == null || !credentials.hasRole("worker"))
        {
            LOG.error("findSupplierById - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
                 
        PreparedStatement findById = null;
        Connection conn = null;
        ResultSet results = null;
        Supplier supplier = null;
        try
        {
            conn = myReadOnlyDS.getConnection();
            findById = conn.prepareStatement(FIND_BY_ID_SQL);

            findById.setInt(1, id);
            results = findById.executeQuery();

            if (results.next())
            {
                supplier = buildSupplier(results);
            }
        }
        catch (SQLException sqle)
        {
            LOG.error("Error finding Supplier by id");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(conn, findById, results);
        }
        return supplier;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<Supplier> findSuppliersByCompanyName(final UserCredentials credentials, final String name)
    {
        LOG.debug("findSuppliersByComapanyName");
        
        if (credentials == null || !credentials.hasRole("worker"))
        {
            LOG.error("findSuppliersByComapanyName - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
          
        PreparedStatement findByName = null;
        Connection conn = null;
        ResultSet results = null;
        List<Supplier> data = new ArrayList<Supplier>();
        try
        {
            conn = myReadOnlyDS.getConnection();
            findByName = conn.prepareStatement(FIND_BY_COMPANY_SQL);
            findByName.setString(1, "%" + name + "%");

            results = findByName.executeQuery();

            while (results.next())
            {
                data.add(buildSupplier(results));
            }
        }
        catch (SQLException sqle)
        {
            LOG.error("Error finding all Suppliers");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(conn, findByName, results);
        }
        return data;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int addSupplier(final UserCredentials credentials, final Supplier supplier)
    {
        LOG.debug("addSupplier");
        
        if (credentials == null || !credentials.hasRole("manager"))
        {
            LOG.error("addSupplier - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
          
        if (supplier == null)
        {
            LOG.error("addSupplier - null Supplier was provided");
            throw new IllegalArgumentException("A Supplier must be provided");
        }

        PreparedStatement addSupplier = null;
        Connection conn = null;
        ResultSet results = null;
        int generatedId = 0;
        try
        {
            conn = myReadWriteDS.getConnection();
            addSupplier = conn.prepareStatement(ADD_SQL, PreparedStatement.RETURN_GENERATED_KEYS);           
            
            String company = supplier.getCompanyName();
            String contact = supplier.getContactName();
            Location location = supplier.getLocation();
            String city = location.getCity();
            String country = location.getCountry();
            Phone phone = supplier.getPhone();
            String number = phone.getNumber();
            Phone fax = supplier.getFax();
            String faxNumber = fax.getNumber();
                              
            addSupplier.setString(1, company);
            addSupplier.setString(2, contact);
            addSupplier.setString(3, city);
            addSupplier.setString(4, country);
            addSupplier.setString(5, number);
            addSupplier.setString(6, faxNumber);

            addSupplier.executeUpdate();
            results = addSupplier.getGeneratedKeys();
            if (results.next())
            {   
                generatedId = results.getInt(1);
            }
        }
        catch (SQLException sqle)
        {
            LOG.error("Error adding Supplier");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(conn, addSupplier, results);
        }
        return generatedId;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updateSupplier(final UserCredentials credentials, final Supplier supplier)
    {
        LOG.debug("updateSupplier");
        
        if (credentials == null || !credentials.hasRole("manager"))
        {
            LOG.error("updateSupplier - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
          
        if (supplier == null)
        {
            LOG.error("updateSupplier - null Supplier was provided");
            throw new IllegalArgumentException("A Supplier must be provided");
        }

        PreparedStatement updateSupplier = null;
        Connection conn = null;
        try
        {
            conn = myReadWriteDS.getConnection();
            updateSupplier = conn.prepareStatement(UPDATE_SQL);           
            
            int id = supplier.getId();
            String company = supplier.getCompanyName();
            String contact = supplier.getContactName();
            Location location = supplier.getLocation();
            String city = location.getCity();
            String country = location.getCountry();
            String number = null;
            Phone phone = supplier.getPhone();
            if (phone != null)
            {
                number = phone.getNumber();
            }
            String faxNumber = null;
            Phone fax = supplier.getFax();
            if (fax != null)
            {
                faxNumber = fax.getNumber();
            }
                              
            updateSupplier.setString(1, company);
            updateSupplier.setString(2, contact);
            updateSupplier.setString(3, city);
            updateSupplier.setString(4, country);
            updateSupplier.setString(5, number);
            updateSupplier.setString(6, faxNumber);
            updateSupplier.setInt(7, id);

            updateSupplier.executeUpdate();
        }
        catch (SQLException sqle)
        {
            LOG.error("Error updating Supplier");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(updateSupplier);
            DbUtils.closeQuietly(conn);
        } 
    }

    /**
     * {@inheritDoc}
     * <p>
     * Suppliers with Products are not deleteable.
     */
    @Override
    public boolean isDeleteable(final UserCredentials credentials, final CustomerEntity entity)
    {
        LOG.debug("isDeleteable");
        
        if (credentials == null || entity == null)
        {
            LOG.error("isDeleteable - null Supplier was provided");
            throw new IllegalArgumentException("A Supplier must be provided");
        }
       return isDeleteable(credentials, entity.getId());
    }

    /**
     * {@inheritDoc}
     * <p>
     * Suppliers with Products are not deleteable.
     */
    @Override
    public boolean isDeleteable(final UserCredentials credentials, final int id)
    {
        LOG.debug("isDeleteable");
        
        if (credentials == null || !credentials.hasRole("worker"))
        {
            LOG.error("isDeleteable - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }
          
        PreparedStatement isDeleteable = null;
        Connection conn = null;
        ResultSet results = null;
        boolean isDeleteableResult = false;
        try
        {
            conn = myReadOnlyDS.getConnection();
            isDeleteable = conn.prepareStatement(IS_DELETEABLE_SUPPLIER_SQL);
 
            isDeleteable.setInt(1, id);
            results = isDeleteable.executeQuery();

            if (results.next())
            {
                int count = results.getInt(1);
                if (count == 0)
                {
                    isDeleteableResult = true;
                }
            }
        }
        catch (SQLException sqle)
        {
            LOG.error("Error finding Product by Supplier");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(conn, isDeleteable, results);
        }
        return isDeleteableResult;    
    }

    /**
     * {@inheritDoc}
     * <p>
     * Suppliers with Products are not deleteable.
     */
    @Override
    public void deleteEntity(final UserCredentials credentials, final CustomerEntity entity)
            throws NonDeleteableRecordException
    {
        LOG.debug("deleteSupplier");
        
        if (entity == null)
        {
            LOG.error("deleteSupplier - null Supplier was provided");
            throw new IllegalArgumentException("A Supplier must be provided");
        }
        if (!(entity instanceof Supplier))
        {
            LOG.error("deleteSupplier - invalid CustomerEntity was provided");
            throw new IllegalArgumentException("A Supplier must be provided");
        } 
        deleteEntity(credentials, entity.getId());     
    }

    /**
     * {@inheritDoc}
     * <p>
     * Suppliers with Products are not deleteable.
     */
    @Override
    public void deleteEntity(final UserCredentials credentials, final int id) 
            throws NonDeleteableRecordException
    {
       LOG.debug("deleteSupplier");
        
        if (credentials == null || !credentials.hasRole("manager"))
        {
            LOG.error("deleteSupplier - Permission refused");
            throw new IllegalArgumentException("Permission refused for this operation");
        }

        if (!isDeleteable(credentials, id))
        {
            LOG.error("Supplier not deleteable");
            throw new NonDeleteableRecordException("This Supplier is not deletable");
        }

        PreparedStatement deleteSupplier = null;
        Connection conn = null;
        try
        {
            conn = myReadWriteDS.getConnection();
            deleteSupplier = conn.prepareStatement(DELETE_SQL);           
         
            deleteSupplier.setInt(1, id);

            deleteSupplier.executeUpdate();
        }
        catch (SQLException sqle)
        {
            LOG.error("Error updating Supplier");
            LOG.error(ErrorFormatter.extractError(sqle));
            throw new IllegalArgumentException(sqle);
        }
        finally
        {
            DbUtils.closeQuietly(deleteSupplier);
            DbUtils.closeQuietly(conn);
        }  
        
    }
    
    private Supplier buildSupplier(final ResultSet results) throws SQLException
    {
        Supplier current = new Supplier();

        current.setId(results.getInt("ID"));
        current.setCompanyName(results.getString("COMPANY_NAME").trim());
        current.setContactName(results.getString("CONTACT_NAME").trim());
        Location location = new Location();
        location.setCity(results.getString("CITY").trim());
        location.setCountry(results.getString("COUNTRY").trim());
        current.setLocation(location);
        String temp = results.getString("Phone");
        if (temp != null)
        {
            Phone phone = new Phone();
            phone.setNumber(temp.trim());
            current.setPhone(phone);
        }
        else
        {
            current.setPhone(null);
        }
        
        temp = results.getString("Fax");
        if (temp != null)
        {
            Phone fax = new Phone();
            fax.setNumber(temp.trim());
            current.setFax(fax);
        }
        else
        {
            current.setFax(null);
        }        
        LOG.trace("Found Supplier: " + current.toString());
        
        return current;
    }
}