GeoRegionServiceImpl.java
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.server.service.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.parsers.ParserConfigurationException;
import org.genesys.server.exception.NotFoundElement;
import org.genesys.server.model.impl.Country;
import org.genesys.server.model.impl.GeoRegion;
import org.genesys.server.model.impl.QGeoRegion;
import org.genesys.server.persistence.CountryRepository;
import org.genesys.server.persistence.GeoRegionRepository;
import org.genesys.server.service.GeoRegionService;
import org.genesys.server.service.worker.GeoRegionDataCLDR;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xml.sax.SAXException;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
/**
* GeoRegion service.
*/
@Service
@Transactional(readOnly = true)
public class GeoRegionServiceImpl implements GeoRegionService {
/** The Constant LOG. */
private static final Logger LOG = LoggerFactory.getLogger(GeoRegionServiceImpl.class);
/** The country repository. */
@Autowired
CountryRepository countryRepository;
/** The geo region repository. */
@Autowired
GeoRegionRepository geoRegionRepository;
/** The geo region data CLDR. */
@Autowired
GeoRegionDataCLDR geoRegionDataCLDR;
/** The jpa query factory. */
@Autowired
private JPAQueryFactory jpaQueryFactory;
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#find(java.lang.String)
*/
@Override
public GeoRegion find(String regionIsoCode) {
GeoRegion geoRegion = geoRegionRepository.findByIsoCode(regionIsoCode);
if (geoRegion == null) {
throw new NotFoundElement("Can't find region for region code " + regionIsoCode);
}
geoRegion.getCountries().size();
return geoRegion;
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#save(org.genesys.server.model.impl.GeoRegion)
*/
@Override
@Transactional(readOnly = false)
public void save(GeoRegion geoRegion) {
geoRegionRepository.save(geoRegion);
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#delete(org.genesys.server.model.impl.GeoRegion)
*/
@Override
@Transactional(readOnly = false)
public void delete(GeoRegion geoRegion) {
geoRegionRepository.delete(geoRegion);
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#getRegion(org.genesys.server.model.impl.Country)
*/
@Override
public GeoRegion getRegion(Country country) {
// NPE check
country.getId();
GeoRegion geoRegion = geoRegionRepository.findByCountry(country);
if (geoRegion != null) {
geoRegion.getCountries().size();
}
return geoRegion;
}
@Override
public GeoRegion get(long id) {
return geoRegionRepository.findById(id).orElseThrow(() -> {
throw new NotFoundElement("No region with id=" + id);
});
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#getChildren(java.lang.String)
*/
@Override
public List<GeoRegion> getChildren(String regionIsoCode) {
List<GeoRegion> all = findAll();
GeoRegion region = find(regionIsoCode);
List<GeoRegion> geoRegions = new ArrayList<>();
geoRegions.addAll(all.stream().filter(reg -> isChild(reg, region.getIsoCode())).collect(Collectors.toList()));
return geoRegions;
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#findAll()
*/
@Override
public List<GeoRegion> findAll() {
return geoRegionRepository.findAll();
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#findAll(java.util.Locale)
*/
@Override
public List<GeoRegion> findAll(final Locale locale) {
final List<GeoRegion> all = findAll();
Collections.sort(all, new Comparator<GeoRegion>() {
@Override
public int compare(GeoRegion o1, GeoRegion o2) {
return o1.getName(locale).compareTo(o2.getName(locale));
}
});
return all;
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#updateGeoRegionData()
*/
@Override
@Transactional(readOnly = false)
public void updateGeoRegionData() throws IOException, ParserConfigurationException, SAXException {
// update current geoRegions
if (geoRegionDataCLDR == null) {
LOG.warn("unicode.org geoRegions source not available");
return;
}
List<GeoRegion> existingRegions = geoRegionRepository.findAll();
for (final GeoRegion src : geoRegionDataCLDR.getGeoRegionDataCLDR()) {
GeoRegion geoRegionForUpdate = null;
Optional<GeoRegion> match = existingRegions.stream().filter(r -> r.getIsoCode().equals(src.getIsoCode())).findFirst();
if (match.isPresent()) {
geoRegionForUpdate = match.get();
} else {
geoRegionForUpdate = new GeoRegion();
geoRegionForUpdate.setIsoCode(src.getIsoCode());
}
geoRegionForUpdate.setName(src.getName());
geoRegionForUpdate.setNameL(src.getNameL());
geoRegionForUpdate.setCountries(src.getCountries());
if (src.getParentRegion() == null) {
geoRegionForUpdate.setParentRegion(null);
} else {
geoRegionForUpdate.setParentRegion(geoRegionRepository.findByIsoCode(src.getParentRegion().getIsoCode()));
}
geoRegionRepository.save(geoRegionForUpdate);
if (null != geoRegionForUpdate.getCountries()) {
for (Country country : geoRegionForUpdate.getCountries()) {
if (null != country) {
country.setRegion(geoRegionForUpdate);
countryRepository.save(country);
}
}
}
}
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#getGeoRegionsForFilter()
*/
@Override
public List<GeoRegion> getGeoRegionsForFilter() {
List<GeoRegion> geoRegionList = findAll();
geoRegionList.removeIf(geoRegion -> geoRegion.getName().equals("World") || geoRegion.getName().equals("Americas"));
List<GeoRegion> resultList = new ArrayList<>();
for (GeoRegion geoRegion : geoRegionList) {
GeoRegion parentRegion = geoRegion.getParentRegion();
if (parentRegion != null && (parentRegion.getName().equals("World") || parentRegion.getName().equals("Americas"))) {
geoRegion.setParentRegion(null);
resultList.add(geoRegion);
} else
resultList.add(geoRegion);
}
Locale locale = LocaleContextHolder.getLocale();
resultList.sort(Comparator.comparing(o -> o.getName(locale)));
return resultList;
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#countryCodesFor(java.util.Set)
*/
@Override
public Collection<String> countryCodesFor(Set<String> regionCodes) {
JPAQuery<String> x = jpaQueryFactory.selectFrom(QGeoRegion.geoRegion)
// Select ISO3 country codes
.select(QGeoRegion.geoRegion.countries.any().code3)
// distinct
.distinct()
// where
.where(QGeoRegion.geoRegion.isoCode.in(regionCodes).or(QGeoRegion.geoRegion.parentRegion().isoCode.in(regionCodes)));
return x.fetch();
}
@Override
public RegionDetails getDetails(final String isoCode) {
GeoRegion region = find(isoCode);
region.setCountries(region.getCountries().stream().filter(Country::isCurrent).collect(Collectors.toList()));
List<GeoRegion> subRegions = getChildren(region.getIsoCode());
return RegionDetails.from(region, subRegions);
}
/* (non-Javadoc)
* @see org.genesys.server.service.GeoRegionService#conversionToSubRegionsList(org.genesys.server.model.impl.GeoRegion)
*/
@Override
public List<GeoRegion> conversionToSubRegionsList(final GeoRegion parentGeo) {
List<GeoRegion> geoRegionList = findAll();
List<GeoRegion> subRegionsList = new ArrayList<>();
geoRegionList.removeIf(geoRegion -> geoRegion.getName().equals("World"));
subRegionsList.addAll(geoRegionList.stream().filter(geoRegion -> parentGeo.getName().equals(geoRegion.getParentRegion().getName())).collect(Collectors.toList()));
return subRegionsList;
}
/**
* Checks if is child.
*
* @param region the region
* @param parentIsoCode the parent iso code
* @return true, if is child
*/
private boolean isChild(GeoRegion region, String parentIsoCode) {
return region.getParentRegion() != null && (region.getParentRegion().getIsoCode().equals(parentIsoCode) || isChild(region.getParentRegion(), parentIsoCode));
}
}