StaticDataRepositoryImpl.java

package com.tradecloud.repository.staticdata;

import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.StaticDataEntityBase;
import com.tradecloud.common.externalreference.ExternalReference;
import com.tradecloud.domain.common.IntegratedStaticDataEntityBase;
import com.tradecloud.domain.configuration.report.ReportTemplate;
import com.tradecloud.domain.configuration.report.ReportTemplateType;
import com.tradecloud.domain.container.ContainerType;
import com.tradecloud.domain.costing.CostingContextType;
import com.tradecloud.domain.infrastructure.persistence.CriteriaBuilder;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.model.shipment.ShippingMode;
import com.tradecloud.domain.place.*;
import com.tradecloud.dto.place.RouteSearch;
import com.tradecloud.repository.base.impl.RepositoryBaseImpl;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.query.NativeQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 */
@Repository(value = "staticDataRepository")
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public class StaticDataRepositoryImpl extends RepositoryBaseImpl<StaticDataEntityBase, Object> implements StaticDataRepository {

    private static final long serialVersionUID = 1L;

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> X findByCode(String code, Class<X> c) {
        Criteria searchCriteria = getSessionCustom().createCriteria(c);
        searchCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        searchCriteria.add(Restrictions.eq("code", code != null ? code.trim() : null));
        return (X) searchCriteria.uniqueResult();
    }

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> List<X> findByCodes(Class<X> c, String... code) {
        Criteria searchCriteria = getSessionCustom().createCriteria(c);
        searchCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        searchCriteria.add(Restrictions.in("code", code));
        return (List<X>) searchCriteria.list();
    }

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> X findByName(String name, Class<X> c) {
        Criteria searchCriteria = getSessionCustom().createCriteria(c);
        searchCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        searchCriteria.add(Restrictions.eq("name", name));
        return (X) searchCriteria.uniqueResult();
    }

    @Override
    @Transactional(readOnly = true)
    public List<FinalDestination> findFinalDestinationsByOrgUnitId(Long id) {
        Criteria searchCriteria = getSessionCustom().createCriteria(FinalDestination.class);
        searchCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        searchCriteria.add(Restrictions.eq("active", true));
        List<FinalDestination> finalDests = searchCriteria.list();

        List<FinalDestination> matchingFinalDests = new ArrayList<FinalDestination>();
        for (FinalDestination finalDestination : finalDests) {
            for (OrganisationalUnit organisationalUnit : finalDestination.getOrganisationalUnits()) {
                if (organisationalUnit.getId().equals(id)) {
                    matchingFinalDests.add(finalDestination);
                    break;
                }
            }
        }
        return matchingFinalDests;
    }

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> X findByExternalReference(Class<X> c, ExternalReference externalReference) {
        DetachedCriteria criteria = DetachedCriteria.forClass(c);
        criteria.add(Restrictions.eq("active", true));
        DetachedCriteria extRefCrit = criteria.createCriteria("externalReferenceWrapper");
        DetachedCriteria referencesCrit = extRefCrit.createCriteria("externalReferences")
                .add(Restrictions.eq("integratedSystem", externalReference.getIntegratedSystem()))
                .add(Restrictions.eq("referenceValue", externalReference.getReferenceValue()));

        referencesCrit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        X result = (X) criteria.getExecutableCriteria(getSessionCustom()).uniqueResult();
        return result;
    }

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> List<X> findByExternalReferenceList(Class<X> c, ExternalReference externalReference) {
        DetachedCriteria criteria = DetachedCriteria.forClass(c);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        criteria.add(Restrictions.eq("active", true));
        DetachedCriteria extRefCrit = criteria.createCriteria("externalReferenceWrapper");
        DetachedCriteria referencesCrit = extRefCrit.createCriteria("externalReferences")
                .add(Restrictions.eq("integratedSystem", externalReference.getIntegratedSystem()))
                .add(Restrictions.eq("referenceValue", externalReference.getReferenceValue()));

//        referencesCrit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        return criteria.getExecutableCriteria(getSessionCustom()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<ContainerType> findAllContainerTypesExcludeLcl() {
        String query = "from ContainerType  WHERE lclChecked='f' ORDER BY code ASC";
        @SuppressWarnings("unchecked")
        List<ContainerType> results = getCurrentSession().createQuery(query).list();
        return results;
    }

    @Override
    @Transactional(readOnly = true)
    public List<PlaceOfLoading> findAllPlaceOfLoading(ShippingMode shippingMode) {
        DetachedCriteria criteria = DetachedCriteria.forClass(PlaceOfLoading.class);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        criteria = placeOfDischargeAndLoadingRestrictions(criteria, shippingMode);
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    public List<PlaceOfLoading> findAllPlaceOfLoading(RouteSearch search) {
        Criteria criteria = getSession().createCriteria(PlaceOfLoading.class);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        criteria = placeOfDischargeAndLoadingRestrictions(criteria, search.getShippingMode(), search.getOriginCountry());
        return criteria.list();
    }

    private void validateExternalReferences(StaticDataEntityBase staticDataEntityBase, Serializable id) {
        if (HibernateUtils.proxyClassInstanceOf(staticDataEntityBase, IntegratedStaticDataEntityBase.class)) {
            IntegratedStaticDataEntityBase integratedSDEB = (IntegratedStaticDataEntityBase) staticDataEntityBase;
            validateISDEBExternalReferenceList(HibernateProxyHelper.getClassWithoutInitializingProxy(integratedSDEB),
                    integratedSDEB.getExternalReferenceList(), id);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public List<PlaceOfDischarge> findAllPlaceOfDischarge(ShippingMode shippingMode) {
        DetachedCriteria criteria = DetachedCriteria.forClass(PlaceOfDischarge.class);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        criteria = placeOfDischargeAndLoadingRestrictions(criteria, shippingMode);
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    public List<PlaceOfDischarge> findAllPlaceOfDischarge(RouteSearch search) {
        Criteria criteria = getSession().createCriteria(PlaceOfDischarge.class);
        criteria = placeOfDischargeAndLoadingRestrictions(criteria, search.getShippingMode(), search.getDestinationCountry());
        return criteria.list();
    }

    private DetachedCriteria placeOfDischargeAndLoadingRestrictions(DetachedCriteria criteria, ShippingMode shippingMode) {
        CriteriaBuilder.addEqRestriction(criteria, "shippingMode", shippingMode);
        CriteriaBuilder.addEqRestriction(criteria, "active", true);
        criteria.addOrder(org.hibernate.criterion.Order.asc("name"));
        return criteria;
    }

    private Criteria placeOfDischargeAndLoadingRestrictions(Criteria criteria, ShippingMode shippingMode, Country country) {
        criteria.add(Restrictions.eq("shippingMode", shippingMode));
        criteria.add(Restrictions.eq("country", country));
        criteria.add(Restrictions.eq("active", true));
        criteria.addOrder(org.hibernate.criterion.Order.asc("name"));
        return criteria;
    }

    @Override
    @Transactional(readOnly = true)
    public <X extends StaticDataEntityBase> X findByNameCaseInsensitive(String name, Class<X> c) {
        Criteria searchCriteria = getSessionCustom().createCriteria(c);
        searchCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        searchCriteria.add(Restrictions.eq("name", name).ignoreCase()).uniqueResult();
        return (X) searchCriteria.uniqueResult();
    }

    @Override
    @Transactional(readOnly = true)
    public List<PlaceOfLoading> findAllPlaceOfLoading(CostingContextType costingContextType) {
        DetachedCriteria criteria = DetachedCriteria.forClass(PlaceOfLoading.class);
        if (costingContextType.equals(CostingContextType.IMPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "importPlace", true);
        } else if (costingContextType.equals(CostingContextType.EXPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "exportPlace", true);
        }
        criteria.addOrder(org.hibernate.criterion.Order.asc("name"));
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<PlaceOfDischarge> findAllPlaceOfDischarge(CostingContextType costingContextType) {
        DetachedCriteria criteria = DetachedCriteria.forClass(PlaceOfDischarge.class);
        if (costingContextType.equals(CostingContextType.IMPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "importPlace", true);
        } else if (costingContextType.equals(CostingContextType.EXPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "exportPlace", true);
        }
        criteria.addOrder(org.hibernate.criterion.Order.asc("name"));
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<FinalDestination> findAllFinalDestination(CostingContextType costingContextType) {
        DetachedCriteria criteria = DetachedCriteria.forClass(FinalDestination.class);
        if (costingContextType.equals(CostingContextType.IMPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "importPlace", true);
        } else if (costingContextType.equals(CostingContextType.EXPORT)) {
            CriteriaBuilder.addEqRestriction(criteria, "exportPlace", true);
        }
        criteria.addOrder(org.hibernate.criterion.Order.asc("name"));
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<ReportTemplate> findAllTemplate(ReportTemplateType reportTemplateType) {
        DetachedCriteria criteria = DetachedCriteria.forClass(ReportTemplate.class);
        if (reportTemplateType != null) {
            CriteriaBuilder.addEqRestriction(criteria, "reportTemplateType", reportTemplateType);
        }
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<City> findAllByCountry(Country country) {
        DetachedCriteria criteria = DetachedCriteria.forClass(City.class);
        if (country != null) {
            CriteriaBuilder.addEqRestriction(criteria, "country", country);
        }
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public Depot findDepotByCity(City city) {
        DetachedCriteria criteria = DetachedCriteria.forClass(Depot.class);
        if (city != null) {
            CriteriaBuilder.addEqRestriction(criteria, "city", city);
        }
        List<Depot> result = criteria.getExecutableCriteria(getSession()).list();

        return result != null && !result.isEmpty() ? result.get(0) : null;
    }

    @Override
    @Transactional(readOnly = true)
    public List<NamedPlace> findAllNamedPlace(City city) {
        DetachedCriteria criteria = DetachedCriteria.forClass(NamedPlace.class);
        if (city != null) {
            CriteriaBuilder.addEqRestriction(criteria, "city", city);
        }
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    public void save(StaticDataEntityBase staticDataEntityBase) {
        validateExternalReferences(staticDataEntityBase, null);
        super.save(staticDataEntityBase);
    }

    @Override
    public Serializable save2(StaticDataEntityBase staticDataEntityBase) {
        validateExternalReferences(staticDataEntityBase, null);
        return super.save2(staticDataEntityBase);
    }

    @Override
    public void update(StaticDataEntityBase staticDataEntityBase) {
        validateExternalReferences(staticDataEntityBase, staticDataEntityBase.getCode());
        super.update(staticDataEntityBase);
    }

    @Override
    public List<PlaceOfCustom> getPlaceOfCustomByType(PlaceOfCustom.Type type) {
        DetachedCriteria criteria = DetachedCriteria.forClass(PlaceOfCustom.class);
        if (type != null) {
            CriteriaBuilder.addEqRestriction(criteria, "type", type);
        }
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    public List<PlaceOfCustom> getPlaceOfCustomByType(PlaceOfCustom.Type type, PlaceOfCustom districtOffice) {
        StringBuilder sql = new StringBuilder("select code, active, created, name,updated, externalReferenceWrapper_id, type\n" +
                "from placeofcustom  \n" +
                "left join placeofcustom_placeofcustom on placeofcustom.code = placeofcustom_placeofcustom.placeofcustom_code \n");

        if (type != null || districtOffice != null)
            sql.append("where ");
        if (type != null)
            sql.append("placeofcustom.type = :type \n");
        if (type != null && districtOffice != null)
            sql.append("and ");
        if (districtOffice != null)
            sql.append("placeofcustom_placeofcustom.districtoffices_code = :dof");
        sql.append(" order by name asc ");

        NativeQuery<PlaceOfCustom> nativeQuery = getSession().createNativeQuery(sql.toString());
        nativeQuery.addEntity(PlaceOfCustom.class);

        if (type != null) {
            nativeQuery.setParameter("type", type.name());
        }
        if (districtOffice != null) {
            nativeQuery.setParameter("dof", districtOffice.getCode());
        }

        return nativeQuery.list();
    }

    @Override
    public List<NamedPlace> findNamedPlaces(NamedPlace.Type type) {
        DetachedCriteria criteria = DetachedCriteria.forClass(NamedPlace.class);
        if (type != null) {
            CriteriaBuilder.addEqRestriction(criteria, "type", type);
        }
        return criteria.getExecutableCriteria(getSession()).list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<Region> findRegionsLinkedToFinalDestinations() {
        String query = "SELECT DISTINCT fd.region FROM FinalDestination fd WHERE fd.region IS NOT NULL";
        @SuppressWarnings("unchecked")
        List<Region> results = getCurrentSession().createQuery(query).list();
        return results;
    }

    @Override
    @Transactional(readOnly = true)
    public Set<FinalDestination> findFinalDestinationsByRegions(Set<Region> regions) {
        String query = "FROM FinalDestination fd WHERE fd.region IN (:regions)";
        @SuppressWarnings("unchecked")
        List<FinalDestination> results = getCurrentSession().createQuery(query).setParameterList("regions", regions).list();
        return new HashSet<>(results);
    }
}