r1696 - in trunk: . wao-persistence/src/main/java/fr/ifremer/wao/entity wao-services/src/main/java/fr/ifremer/wao/services/service wao-services/src/main/resources/i18n wao-web/src/main/java/fr/ifremer/wao/web wao-web/src/main/java/fr/ifremer/wao/web/action/administration wao-web/src/main/resources/i18n wao-web/src/main/webapp/WEB-INF wao-web/src/main/webapp/WEB-INF/content wao-web/src/main/webapp/WEB-INF/content/administration wao-web/src/main/webapp/WEB-INF/decorators
Author: bleny Date: 2014-02-28 15:23:50 +0100 (Fri, 28 Feb 2014) New Revision: 1696 Url: http://codelutin.com/projects/wao/repository/revisions/1696 Log: refs #4482 introduce import for fishing zones, terrestrial locations, terrestrial divisions, obsdeb codes, contact state motives, DCF codes, show referential states Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialDivisionTopiaDao.java trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialLocationTopiaDao.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialService.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialState.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/AbstractImportReferentialAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportContactStateMotivesAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportFishingZonesAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportObsdebCodesAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialDivisionsAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialLocationsAction.java trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ReferentialManagementAction.java trunk/wao-web/src/main/webapp/WEB-INF/content/administration/ trunk/wao-web/src/main/webapp/WEB-INF/content/administration/referential-management.jsp Modified: trunk/pom.xml trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/InitWaoService.java trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/WaoServiceSupport.java trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoJspActionSupport.java trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp trunk/wao-web/src/main/webapp/WEB-INF/web.xml Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/pom.xml 2014-02-28 14:23:50 UTC (rev 1696) @@ -114,7 +114,7 @@ <nuitonWebVersion>1.15-SNAPSHOT</nuitonWebVersion> <nuitonI18nVersion>3.0</nuitonI18nVersion> <nuitonConfigVersion>3.0-alpha-1</nuitonConfigVersion> - <nuitonCsvVersion>3.0-alpha-1</nuitonCsvVersion> + <nuitonCsvVersion>3.0-alpha-3</nuitonCsvVersion> <nuitonUtilsVersion>3.0-SNAPSHOT</nuitonUtilsVersion> <eugeneVersion>2.7.3</eugeneVersion> <topiaVersion>3.0-SNAPSHOT</topiaVersion> Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -49,4 +49,17 @@ public String getShortCode() { return shortCode; } + + public boolean isObsMer() { + return OBSMER == this; + } + + public boolean isObsVente() { + return OBSVENTE == this; + } + + public boolean isObsDeb() { + return OBSDEB == this; + } + } Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialDivisionTopiaDao.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialDivisionTopiaDao.java (rev 0) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialDivisionTopiaDao.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,14 @@ +package fr.ifremer.wao.entity; + +import java.util.Collections; + +public class TerrestrialDivisionTopiaDao extends AbstractTerrestrialDivisionTopiaDao<TerrestrialDivision> { + + public long countDistinctTerrestrialDivision() { + String hql = " select distinct td.code" + + " " + newFromClause("td") + + " where td.code is not null"; + return count(hql, Collections.<String, Object>emptyMap()); + } + +} Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialLocationTopiaDao.java =================================================================== --- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialLocationTopiaDao.java (rev 0) +++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/TerrestrialLocationTopiaDao.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,21 @@ +package fr.ifremer.wao.entity; + +import org.nuiton.topia.persistence.TopiaQueryBuilderAddCriteriaOrRunQueryStep; + +import java.util.Collections; +import java.util.List; + +public class TerrestrialLocationTopiaDao extends AbstractTerrestrialLocationTopiaDao<TerrestrialLocation> { + + public List<String> findAllDistinctDistrictCodesUsedInLocations() { + String hql = " select distinct tl.districtCode" + + " " + newFromClause("tl") + + " where tl." + TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL + " is not null"; + return findAll(hql, Collections.<String, Object>emptyMap()); + } + + public TopiaQueryBuilderAddCriteriaOrRunQueryStep<TerrestrialLocation> forLocationTypeEquals(LocationType locationType) { + return forLocationTypeOrdinalEquals(locationType.ordinal()); + } + +} Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ImportErrorException.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,23 @@ +package fr.ifremer.wao.services.service; + +import fr.ifremer.wao.WaoException; +import org.nuiton.csv.ImportRuntimeException; +import org.nuiton.i18n.I18n; + +/** + * Une erreur est survenue lors d'un import CSV. + */ +public class ImportErrorException extends WaoException { + + protected static final String MESSAGE = I18n.t("wao.import.failure"); + + public ImportErrorException(ImportRuntimeException e) { + super(e); + } + + @Override + public String getMessage() { + return MESSAGE + " " + getCause().getMessage(); + } + +} Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/InitWaoService.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/InitWaoService.java 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/InitWaoService.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -4,6 +4,10 @@ public void init() { + ReferentialService referentialService = getReferentialService(); + + referentialService.initialImport(); + } } Copied: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialService.java (from rev 1687, tags/wao-3.4.1/wao-business/src/main/java/fr/ifremer/wao/service/ServiceReferentialImpl.java) =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialService.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialService.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,824 @@ +/* + * #%L + * Wao :: Business + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2009 - 2010 Ifremer + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * #L% + */ + +package fr.ifremer.wao.services.service; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import fr.ifremer.wao.WaoTechnicalException; +import fr.ifremer.wao.entity.Boat; +import fr.ifremer.wao.entity.BoatGroup; +import fr.ifremer.wao.entity.ContactState; +import fr.ifremer.wao.entity.ContactStateMotif; +import fr.ifremer.wao.entity.ContactStateMotifTopiaDao; +import fr.ifremer.wao.entity.DCF5Code; +import fr.ifremer.wao.entity.FishingGearDCF; +import fr.ifremer.wao.entity.FishingGearDCFTopiaDao; +import fr.ifremer.wao.entity.FishingZone; +import fr.ifremer.wao.entity.FishingZoneTopiaDao; +import fr.ifremer.wao.entity.LocationType; +import fr.ifremer.wao.entity.ObsDebCode; +import fr.ifremer.wao.entity.ObsDebCodeDetails; +import fr.ifremer.wao.entity.ObsDebCodeDetailsImpl; +import fr.ifremer.wao.entity.ObsDebCodeDetailsTopiaDao; +import fr.ifremer.wao.entity.ObsDebCodeImpl; +import fr.ifremer.wao.entity.ObsDebCodeTopiaDao; +import fr.ifremer.wao.entity.ObsProgram; +import fr.ifremer.wao.entity.ReferentialMeta; +import fr.ifremer.wao.entity.ReferentialMetaImpl; +import fr.ifremer.wao.entity.ReferentialMetaTopiaDao; +import fr.ifremer.wao.entity.SampleRow; +import fr.ifremer.wao.entity.SampleRowTopiaDao; +import fr.ifremer.wao.entity.TargetSpeciesDCF; +import fr.ifremer.wao.entity.TargetSpeciesDCFTopiaDao; +import fr.ifremer.wao.entity.TerrestrialDivision; +import fr.ifremer.wao.entity.TerrestrialDivisionImpl; +import fr.ifremer.wao.entity.TerrestrialDivisionTopiaDao; +import fr.ifremer.wao.entity.TerrestrialLocation; +import fr.ifremer.wao.entity.TerrestrialLocationImpl; +import fr.ifremer.wao.entity.TerrestrialLocationTopiaDao; +import fr.ifremer.wao.services.service.csv.ContactStateMotivesImportModel; +import fr.ifremer.wao.services.service.csv.FishingZoneImportModel; +import fr.ifremer.wao.services.service.csv.RawObsDebCode; +import fr.ifremer.wao.services.service.csv.RawObsDebCodesImportModel; +import fr.ifremer.wao.services.service.csv.TerrestrialDivisionImportModel; +import fr.ifremer.wao.services.service.csv.TerrestrialLocationImportModel; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.csv.Import; +import org.nuiton.csv.ImportModel; +import org.nuiton.csv.ImportRuntimeException; +import org.nuiton.i18n.I18n; +import org.nuiton.topia.persistence.TopiaDao; +import org.nuiton.topia.persistence.TopiaEntity; +import org.nuiton.topia.persistence.TopiaQueryBuilderAddCriteriaOrRunQueryStep; +import org.nuiton.util.beans.Binder; +import org.nuiton.util.beans.BinderFactory; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Service permettant la gestion des différents référentiels. + */ +public class ReferentialService extends WaoServiceSupport { + + private static final Log log = LogFactory.getLog(ReferentialService.class); + + /** Pour chaque programme, les référentiels utilisés par ce programme. */ + protected static final Map<ObsProgram, List<String>> PER_PROGRAM_REFERENTIAL; + + static { + Map<ObsProgram, List<String>> perProgramReferential = new HashMap<>(); + + perProgramReferential.put(ObsProgram.OBSMER, Arrays.asList( + FishingZone.class.getName(), + ContactStateMotif.class.getName(), + TerrestrialLocation.class.getName(), + Boat.class.getName())); + + perProgramReferential.put(ObsProgram.OBSVENTE, Arrays.asList( + FishingZone.class.getName(), + TerrestrialLocation.class.getName(), + Boat.class.getName())); + + perProgramReferential.put(ObsProgram.OBSDEB, Arrays.asList( + FishingZone.class.getName(), + TerrestrialLocation.class.getName(), + TerrestrialDivision.class.getName(), + ObsDebCode.class.getName(), + Boat.class.getName(), + BoatGroup.class.getName())); + + PER_PROGRAM_REFERENTIAL = Collections.unmodifiableMap(perProgramReferential); + } + + /** + * Permet de maintenir à jour les informations sur les référentiels. À + * chaque import de référentiel par Wao, il faut appeler cette méthode en + * indiquant quel référentiel a été mis à jour. + * + * Cela aura pour effet de sauvegarder la date de dernière mise à jour du + * référentiel lorsqu'il faudra l'indiquer aux administrateurs plus tard. + * + * @param entityClassFqn le FQN de la classe-entité du référentiel modifié. + * Il doit être parmi les classe listées dans #PER_PROGRAM_REFERENTIAL + */ + protected void updateReferentialMeta(String entityClassFqn) { + + Class<?> entityClass; + try { + entityClass = getClass().getClassLoader().loadClass(entityClassFqn); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException(entityClassFqn); + } + + if ( ! TopiaEntity.class.isAssignableFrom(entityClass)) { + throw new IllegalArgumentException("il faut passer le FQN d'une classe d'entité"); + } + + ReferentialMetaTopiaDao dao = getPersistenceContext().getReferentialMetaDao(); + ReferentialMeta referentialMeta = dao.findByEntityClassFqn(entityClassFqn); + + if (referentialMeta == null) { + referentialMeta = dao.create( + ReferentialMeta.PROPERTY_ENTITY_CLASS_FQN, entityClassFqn); + } + + referentialMeta.setLastUpdate(getNow()); + + dao.update(referentialMeta); + + } + + /** + * Import des zones de pêche. + */ + public void importFishingZones(InputStream input) throws ImportErrorException { + + FishingZoneImportModel model = new FishingZoneImportModel(); + Import<FishingZone> fishingZoneImport = Import.newImport(model, input); + + FishingZoneTopiaDao dao = getPersistenceContext().getFishingZoneDao(); + + try { + for (FishingZone fishingZone : fishingZoneImport) { + + FishingZone existingFishingZone = + dao.forDistrictCodeEquals(fishingZone.getDistrictCode()).findUniqueOrNull(); + + if (existingFishingZone == null) { + dao.create(fishingZone); + } else { + existingFishingZone.setFacadeName(fishingZone.getFacadeName()); + existingFishingZone.setSectorName(fishingZone.getSectorName()); + existingFishingZone.setLatitude(fishingZone.getLatitude()); + existingFishingZone.setLongitude(fishingZone.getLongitude()); + dao.update(existingFishingZone); + } + + } + } catch (ImportRuntimeException e) { + throw new ImportErrorException(e); + } + + updateReferentialMeta(FishingZone.class.getName()); + + commit(); + + } + + /** + * Import des lieux terrestres (ports et criées). + */ + public void importTerrestrialLocations(InputStream input) throws ImportErrorException { + + TerrestrialLocationTopiaDao dao = getPersistenceContext().getTerrestrialLocationDao(); + + // first, we will read the CSV file, line by line + // at, each line, we will look if the location is already in database + // if yes, some attribute may have change, so we use a binder to copy all field + // if no, add the new location in database + + ImportModel<TerrestrialLocation> model = new TerrestrialLocationImportModel(); + Import<TerrestrialLocation> terrestrialLocationImport = Import.newImport(model, input); + + // we will need a binder, to copy location for an update + Binder<TerrestrialLocation, TerrestrialLocation> locationBinder = + BinderFactory.newBinder(TerrestrialLocation.class); + // some counts for logging purpose + int locationAdded = 0, locationUpdated = 0; + + // for each line of the CSV + try { + Iterator<TerrestrialLocation> locationIterator = terrestrialLocationImport.iterator(); + while (locationIterator.hasNext()) { + // location is a line of the CSV + TerrestrialLocation location = locationIterator.next(); + + // look if already exists and update existing or add new + TerrestrialLocation existingLocation = dao.forProperties( + TerrestrialLocation.PROPERTY_CODE, location.getCode(), + TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, location.getLocationTypeOrdinal()).findUniqueOrNull(); + if (existingLocation == null) { + dao.create(location); + locationAdded += 1; + } else { + locationBinder.copyExcluding(location, existingLocation,TopiaEntity.PROPERTY_TOPIA_ID, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION); + dao.update(existingLocation); + locationUpdated += 1; + } + } + } catch (ImportRuntimeException e) { + throw new ImportErrorException(e); + } + + // now, all the CSV file has been read and dumped into database, + // Now, we need to update database by adding any missing district + // Each location has a district (identified by a district code) + // We must find all the distinct district ids and check that + // we have an entity representing it. In database a disctrict can + // be distinguished from a location by having it's + // locationTypeOrdinal null. + List<String> districtCodes = dao.findAllDistinctDistrictCodesUsedInLocations(); + + // a binder, needed for update + Binder<TerrestrialLocation, TerrestrialLocation> districtBinder = + BinderFactory.newBinder(TerrestrialLocation.class); + // counts for logging + int districtAdded = 0, districtUpdated = 0; + int regionAdded = 0, regionUpdated = 0; + + for (String districtCode : districtCodes) { // for each district code found + + // let's find a location which is in this particular district + TerrestrialLocation location = dao.forDistrictCodeEquals(districtCode).findAny(); + + // create the district by copying region, country etc. from location + TerrestrialLocation district = new TerrestrialLocationImpl(); + districtBinder.copyExcluding(location, district, TerrestrialLocation.PROPERTY_NAME, + TerrestrialLocation.PROPERTY_CODE, TerrestrialLocation.PROPERTY_PORT_CODE, + TerrestrialLocation.PROPERTY_PORT_NAME, TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, + TopiaEntity.PROPERTY_TOPIA_ID, TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, + TerrestrialLocation.PROPERTY_TOPIA_VERSION); + district.setLocationType(LocationType.DISTRICT); + + // A particular case, some location (not in France) has no + // district (district code null), so we must add a district + // for them + if (StringUtils.isEmpty(district.getDistrictCode())) { + // distinct will select a random place with no district code + // it can be in England, Sweden or whatever. It's bad for us + // because we don't want some data not to be filtered when looking + // for England while we want to filter on all country except France + district.setCountryCode(null); + district.setCountryName("Hors France"); + district.setSeaboardCode(null); + district.setSeaboardName(null); + district.setCoastFAOCode(null); + district.setCoastFAOName(null); + district.setDistrictCode(null); + } + + // now, we have the 'district' object we want to have in the + // database. Now let's add it if not already in or update + // it already in + TerrestrialLocation existingDistrict = + dao.forProperties( + TerrestrialLocation.PROPERTY_DISTRICT_CODE, district.getDistrictCode(), + TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, LocationType.DISTRICT.ordinal()).findUniqueOrNull(); + if (existingDistrict == null) { + dao.create(district); + districtAdded += 1; + } else { + locationBinder.copyExcluding(district, existingDistrict, TopiaEntity.PROPERTY_TOPIA_ID, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION); + dao.update(existingDistrict); + districtUpdated += 1; + } + + // creating a region object for this district + TerrestrialLocation region = dao.newInstance(); + locationBinder.copyExcluding(district, region, TopiaEntity.PROPERTY_TOPIA_ID, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION, + TerrestrialLocation.PROPERTY_DISTRICT_CODE, TerrestrialLocation.PROPERTY_DISTRICT_NAME, + TerrestrialLocation.PROPERTY_DEPARTMENT_CODE, TerrestrialLocation.PROPERTY_DEPARTMENT_NAME, + TerrestrialLocation.PROPERTY_SUB_REGION_IFREMER_CODE, TerrestrialLocation.PROPERTY_SUB_REGION_IFREMER_NAME); + region.setLocationType(LocationType.REGION); + + // prevent to deal with case "Hors France" + if (region.getRegionIfremerCode() != null) { + + // try to find it if it's already in DB + TerrestrialLocation existingRegion = dao.forProperties( + TerrestrialLocation.PROPERTY_REGION_IFREMER_CODE, region.getRegionIfremerCode(), + TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, LocationType.REGION.ordinal()).findUniqueOrNull(); + + // create or update + if (existingRegion == null) { + dao.create(region); + regionAdded += 1; + } else { + locationBinder.copyExcluding(region, existingRegion, TopiaEntity.PROPERTY_TOPIA_ID, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION); + dao.update(existingRegion); + regionUpdated += 1; + } + } + } + + if (log.isInfoEnabled()) { + log.info(locationAdded + " terrestrial locations added, " + locationUpdated + " updated"); + log.info(districtAdded + " terrestrial district added, " + districtUpdated + " updated"); + log.info(regionAdded + " terrestrial region added, " + regionUpdated + " updated"); + } + + updateReferentialMeta(TerrestrialLocation.class.getName()); + + commit(); + + } + + /** Find ports and auctions in a given district */ + public List<TerrestrialLocation> getAllPortsAndAuctions(TerrestrialLocation district) { + + Preconditions.checkArgument(district.isDistrict(), "terrestrial location " + district + " is not district"); + + TerrestrialLocationTopiaDao dao = getPersistenceContext().getTerrestrialLocationDao(); + + TopiaQueryBuilderAddCriteriaOrRunQueryStep<TerrestrialLocation> query = dao.newQueryBuilder(); + + query.addIn(TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, ImmutableSet.of(LocationType.PORT.ordinal(), LocationType.AUCTION.ordinal())); + + query.addEquals(TerrestrialLocation.PROPERTY_DISTRICT_CODE, district.getDistrictCode()); + + List<TerrestrialLocation> result = query.findAll(); + + return result; + + } + + public List<TerrestrialLocation> executeGetAllRegionIfremers() { + + TerrestrialLocationTopiaDao dao = getPersistenceContext().getTerrestrialLocationDao(); + + List<TerrestrialLocation> allRegionIfremers = dao.forLocationTypeOrdinalEquals(LocationType.REGION.ordinal()).findAll(); + + return allRegionIfremers; + + } + + public TerrestrialLocation getTerrestrialDistrict(String districtCode) { + + Preconditions.checkArgument(StringUtils.isNotBlank(districtCode)); + + TerrestrialLocationTopiaDao dao = getPersistenceContext().getTerrestrialLocationDao(); + + TerrestrialLocation terrestrialDistrict = dao.forProperties( + TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, LocationType.DISTRICT.ordinal(), + TerrestrialLocation.PROPERTY_DISTRICT_CODE, districtCode).findUnique(); + + return terrestrialDistrict; + + } + + /** + * @param contactState if null, return motifs for all contact states + */ + public List<ContactStateMotif> getAllContactStateMotifs(ContactState contactState) throws Exception { + + ContactStateMotifTopiaDao dao = getPersistenceContext().getContactStateMotifDao(); + + List<ContactStateMotif> result; + if (contactState == null) { + result = dao.findAll(); + } else { + ContactState substituteState = ContactState.getSubstituteForMotif(contactState); + result = dao.forContactStateOrdinalEquals(substituteState.ordinal()).findAll(); + } + + if (log.isDebugEnabled()) { + log.debug(result.size() + " motifs found for state " + contactState); + } + + return result; + + } + + public void importContactStateMotives(InputStream input) throws ImportErrorException { + + ImportModel<ContactStateMotif> model = new ContactStateMotivesImportModel(); + Import<ContactStateMotif> motivesImport = Import.newImport(model, input); + + ContactStateMotifTopiaDao dao = getPersistenceContext().getContactStateMotifDao(); + + try { + for (ContactStateMotif motif : motivesImport) { + ContactStateMotif existingMotif = dao.forCodeEquals(motif.getCode()).findUniqueOrNull(); + if (existingMotif == null) { + dao.create(motif); + } else { + existingMotif.setName(motif.getName()); + existingMotif.setContactState(motif.getContactState()); + existingMotif.setColor(motif.getColor()); + dao.update(existingMotif); + } + } + } catch (ImportRuntimeException e) { + throw new ImportErrorException(e); + } + + updateReferentialMeta(ContactStateMotif.class.getName()); + + commit(); + + } + + public void importTerrestrialDivisions(InputStream input) throws ImportErrorException { + + TerrestrialLocationTopiaDao terrestrialLocationDao = getPersistenceContext().getTerrestrialLocationDao(); + + // let's find all ports in terrestrial location reference + List<TerrestrialLocation> ports = terrestrialLocationDao.forLocationTypeEquals(LocationType.PORT).findAll(); + List<TerrestrialLocation> regions = terrestrialLocationDao.forLocationTypeEquals(LocationType.REGION).findAll(); + + if (log.isDebugEnabled()) { + log.debug(ports.size() + " ports, " + regions.size() + " regions"); + } + + // the import itself + ImportModel<TerrestrialDivision> importModel = new TerrestrialDivisionImportModel(ports, regions); + Import<TerrestrialDivision> terrestrialDivisionImport = Import.newImport(importModel, input); + + TerrestrialDivisionTopiaDao dao = getPersistenceContext().getTerrestrialDivisionDao(); + + Binder<TerrestrialDivision, TerrestrialDivision> terrestrialDivisionBinder = BinderFactory.newBinder(TerrestrialDivision.class); + + try { + for (TerrestrialDivision terrestrialDivision : terrestrialDivisionImport) { + + TerrestrialDivision existingTerrestrialDivision = dao.forCodeEquals(terrestrialDivision.getCode()).findUniqueOrNull(); + if (existingTerrestrialDivision == null) { + // add as new + dao.create(terrestrialDivision); + } else { + // update the old one + terrestrialDivisionBinder.copyExcluding(terrestrialDivision, existingTerrestrialDivision, + TopiaEntity.PROPERTY_TOPIA_ID, TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION); + dao.update(existingTerrestrialDivision); + } + + TerrestrialDivision observationUnit = new TerrestrialDivisionImpl(); + terrestrialDivisionBinder.copyExcluding( + terrestrialDivision, observationUnit, + TopiaEntity.PROPERTY_TOPIA_ID, TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, + TopiaEntity.PROPERTY_TOPIA_VERSION, + TerrestrialDivision.PROPERTY_CODE, + TerrestrialDivision.PROPERTY_PORT); + + TerrestrialDivision existingObservationUnit = dao.forProperties( + TerrestrialDivision.PROPERTY_CODE, observationUnit.getCode(), + TerrestrialDivision.PROPERTY_PORT, observationUnit.getPort(), + TerrestrialDivision.PROPERTY_REGION_IFREMER, observationUnit.getRegionIfremer(), + TerrestrialDivision.PROPERTY_OBSERVATION_UNIT_CODE, observationUnit.getObservationUnitCode()).findUniqueOrNull(); + + if (existingObservationUnit == null) { + dao.create(observationUnit); + } else { + terrestrialDivisionBinder.copyExcluding( + observationUnit, existingObservationUnit, TopiaEntity.PROPERTY_TOPIA_ID, + TopiaEntity.PROPERTY_TOPIA_CREATE_DATE, TopiaEntity.PROPERTY_TOPIA_VERSION); + dao.update(existingObservationUnit); + } + + } + } catch (ImportRuntimeException e) { + throw new ImportErrorException(e); + } + + if (log.isDebugEnabled()) { + log.debug(dao.count() + " terrestrial divisions in database"); + } + + updateReferentialMeta(TerrestrialDivision.class.getName()); + + commit(); + + } + + public List<TerrestrialDivision> getAllObservationUnits() { + + TerrestrialDivisionTopiaDao dao = getPersistenceContext().getTerrestrialDivisionDao(); + + // having code null make TerrestrialDivision.isObservationUnit + List<TerrestrialDivision> observationUnits = dao.forCodeEquals(null).findAll(); + + if (log.isDebugEnabled()) { + log.debug("will return " + observationUnits.size() + " observation units"); + } + + return observationUnits; + + } + + /** + * @param region may be null, and all ports will be returned + * @returns all the ports that are in a region + */ + public List<TerrestrialLocation> getAllPorts(TerrestrialLocation region) { + + Preconditions.checkArgument(region == null || region.isRegion(), region + " is not a region"); + + TerrestrialLocationTopiaDao dao = getPersistenceContext().getTerrestrialLocationDao(); + + Map<String, Object> properties = new HashMap<>(); + + // we are looking for ports only + properties.put(TerrestrialLocation.PROPERTY_LOCATION_TYPE_ORDINAL, LocationType.PORT.ordinal()); + + // ports in a specific region + properties.put(TerrestrialLocation.PROPERTY_REGION_IFREMER_CODE, region.getRegionIfremerCode()); + + // run query + List<TerrestrialLocation> ports = dao.forProperties(properties).findAll(); + + return ports; + + } + + public void importObsDebCodes(InputStream input) throws ImportErrorException { + + TerrestrialLocationTopiaDao terrestrialLocationDao = + getPersistenceContext().getTerrestrialLocationDao(); + + List<TerrestrialLocation> allRegions = + terrestrialLocationDao.forLocationTypeEquals(LocationType.REGION).findAll(); + + ObsDebCodeTopiaDao dao = getPersistenceContext().getObsDebCodeDao(); + ObsDebCodeDetailsTopiaDao obsDebCodeDetailsDAO = getPersistenceContext().getObsDebCodeDetailsDao(); + + ImportModel<RawObsDebCode> model = new RawObsDebCodesImportModel(allRegions); + Import<RawObsDebCode> rawObsDebCodeImport = Import.newImport(model, input); + + // start reading the CSV file line by line + try { + for (RawObsDebCode rawObsDebCode : rawObsDebCodeImport) { + + // try to find an already existing entity to update + // or create one + ObsDebCode existingCode = dao.forCodeEquals(rawObsDebCode.getCode()).findUniqueOrNull(); + if (existingCode == null) { + existingCode = new ObsDebCodeImpl(); + existingCode.setCode(rawObsDebCode.getCode()); + existingCode = dao.create(existingCode); + } + ObsDebCodeDetails existingDetails = null; + if (existingCode.getObsDebCodeDetails() != null) { + for (ObsDebCodeDetails obsDebCodeDetails : existingCode.getObsDebCodeDetails()) { + if (rawObsDebCode.getRegion().getRegionIfremerCode().equals(obsDebCodeDetails.getRegion().getRegionIfremerCode())) { + existingDetails = obsDebCodeDetails; + } + } + } + + if (existingDetails == null) { + existingDetails = new ObsDebCodeDetailsImpl(); + existingDetails.setLabel(rawObsDebCode.getLabel()); + existingDetails.setRegion(rawObsDebCode.getRegion()); + existingCode.addObsDebCodeDetails(existingDetails); + obsDebCodeDetailsDAO.create(existingDetails); + } else { + existingDetails.setLabel(rawObsDebCode.getLabel()); + obsDebCodeDetailsDAO.update(existingDetails); + } + + dao.update(existingCode); + + } + } catch (ImportRuntimeException e) { + throw new ImportErrorException(e); + } + + updateReferentialMeta(ObsDebCode.class.getName()); + + commit(); + + } + + protected void initialDCF5CodesImport() { + + FishingGearDCFTopiaDao fishingGearDCFDao = getPersistenceContext().getFishingGearDCFDao(); + TargetSpeciesDCFTopiaDao targetSpeciesDCFDao = getPersistenceContext().getTargetSpeciesDCFDao(); + + final String[] gearCodesBase = {"DRB", "DRH", + "FPN", "FPO", "FSN", "FWR", "FYK", "GES", "GNC", + "GND", "GNF", "GNS", "GTN", "GTR", "HAR", "HMD", "HMP", + "LA", "LHM", "LHP", "LLD", "LLS", "LNB", "LNP", "LNS", + "LTL", "LX", "OTB", "OTM", "OTT", "PS", + "PTB", "PTM", "RG", "SB", "SDN", "SPR", "SSC", "SV", + "TBB", "TBN", "TBS", "TMS"}; + + final String[] speciesCodesBase = {"ALG", "ANA", "CAT", "CRU", + "DEF", "DWS", "LPF", "MOL", "SPF", "FIF"}; + + long nbCodes = fishingGearDCFDao.count() + targetSpeciesDCFDao.count(); + + if (nbCodes == 0) { + + if (log.isInfoEnabled()) { + log.info("no DCF in database, mass import"); + } + + for (String code : gearCodesBase) { + fishingGearDCFDao.create(FishingGearDCF.PROPERTY_CODE, code); + } + + for (String code : speciesCodesBase) { + targetSpeciesDCFDao.create(TargetSpeciesDCF.PROPERTY_CODE, code); + } + + } else { + + if (log.isInfoEnabled()) { + log.info("some DCF in database, import only missing ones"); + } + + for (String code : gearCodesBase) { + FishingGearDCF fishingGearDCF = fishingGearDCFDao.forCodeEquals(code).findUniqueOrNull(); + if (fishingGearDCF == null) { + log.info("add missing fishing gear DCF: '" + code + "'"); + fishingGearDCFDao.create(FishingGearDCF.PROPERTY_CODE, code); + } + } + + for (String code : speciesCodesBase) { + TargetSpeciesDCF targetSpeciesDCF = targetSpeciesDCFDao.forCodeEquals(code).findUniqueOrNull(); + if (targetSpeciesDCF == null) { + log.info("add missing target species DCF: '" + code + "'"); + targetSpeciesDCFDao.create(TargetSpeciesDCF.PROPERTY_CODE, code); + } + } + + // on supprime ce qu'il y a en trop + for (FishingGearDCF fishingGearDCF : fishingGearDCFDao.findAll()) { + if ( ! ArrayUtils.contains(gearCodesBase, fishingGearDCF.getCode())) { + List<DCF5Code> usages = fishingGearDCFDao.findUsages(DCF5Code.class, fishingGearDCF); + if (usages.isEmpty()) { + log.info("will delete code " + fishingGearDCF); + fishingGearDCFDao.delete(fishingGearDCF); + } else { + log.warn("will not delete " + fishingGearDCF); + SampleRowTopiaDao sampleRowDao = getPersistenceContext().getSampleRowDao(); + for (DCF5Code usage : usages) { + List<SampleRow> sampleRows = sampleRowDao.fordCF5CodeContains(usage).findAll(); + for (SampleRow sampleRow : sampleRows) { + log.warn("sampleRow " + sampleRow.getCode() + " use " + usage); + } + } + } + } + } + + for (TargetSpeciesDCF targetSpeciesDCF : targetSpeciesDCFDao.findAll()) { + if ( ! ArrayUtils.contains(speciesCodesBase, targetSpeciesDCF.getCode())) { + List<DCF5Code> usages = targetSpeciesDCFDao.findUsages(DCF5Code.class, targetSpeciesDCF); + if (usages.isEmpty()) { + log.info("will delete code " + targetSpeciesDCF); + targetSpeciesDCFDao.delete(targetSpeciesDCF); + } else { + log.warn("will not delete " + targetSpeciesDCF); + } + } + } + } + + if (log.isInfoEnabled()) { + nbCodes = fishingGearDCFDao.count() + targetSpeciesDCFDao.count(); + log.info(nbCodes + " dcf codes in database"); + } + + commit(); + + } + + public void initialImport() { + + initialDCF5CodesImport(); + + InputStream input = null; + + TerrestrialLocationTopiaDao terrestrialLocationDao = getPersistenceContext().getTerrestrialLocationDao(); + ObsDebCodeTopiaDao obsDebCodeDao = getPersistenceContext().getObsDebCodeDao(); + ContactStateMotifTopiaDao contactStateMotifDao = getPersistenceContext().getContactStateMotifDao(); + + if (terrestrialLocationDao.count() == 0) { + try { + input = getClass().getResourceAsStream("/terrestrialLocations.csv"); + importTerrestrialLocations(input); + } catch (ImportErrorException e) { + throw new WaoTechnicalException(e); + } finally { + IOUtils.closeQuietly(input); + } + } + + if (obsDebCodeDao.count() == 0) { + try { + input = getClass().getResourceAsStream("/obsDebCodes.csv"); + importObsDebCodes(input); + } catch (ImportErrorException e) { + throw new WaoTechnicalException(e); + } finally { + IOUtils.closeQuietly(input); + } + } + + if (contactStateMotifDao.count() == 0) { + try { + input = getClass().getResourceAsStream("/motifs.csv"); + importContactStateMotives(input); + } catch (ImportErrorException e) { + throw new WaoTechnicalException(e); + } finally { + IOUtils.closeQuietly(input); + } + } + + } + + /** + * Pour un programme donné, permet d'obtenir des informations sur tous les + * référentiels utilisés par ce programme. Notamment la date de dernière + * mise à jour ainsi que le nombre d'entités en base. + */ + public List<ReferentialState> getReferentialStates(ObsProgram obsProgram) { + + List<ReferentialState> referentialStates = new LinkedList<>(); + + for (String entityClassFqn : PER_PROGRAM_REFERENTIAL.get(obsProgram)) { + + Class<?> entityClass; + try { + entityClass = getClass().getClassLoader().loadClass(entityClassFqn); + } catch (ClassNotFoundException e) { + throw new WaoTechnicalException("cannot load class " + entityClassFqn, e); + } + + if ( ! TopiaEntity.class.isAssignableFrom(entityClass)) { + throw new IllegalArgumentException("il faut passer le FQN d'une classe d'entité"); + } + + long count; + + if (TerrestrialDivision.class.equals(entityClass)) { + // Pour les stratification géographique, on compte le nombre de strate + // (on ne compte pas les unités d'observations, etc qui prennent + // des lignes en base) + TerrestrialDivisionTopiaDao dao = getPersistenceContext().getTerrestrialDivisionDao(); + count = dao.countDistinctTerrestrialDivision(); + } else { + TopiaDao<? extends TopiaEntity> dao = getPersistenceContext().getDao((Class<? extends TopiaEntity>) entityClass); + count = dao.count(); + } + + ReferentialMetaTopiaDao referentialMetaDao = getPersistenceContext().getReferentialMetaDao(); + ReferentialMeta referentialMeta = referentialMetaDao.forEntityClassFqnEquals(entityClassFqn).findUniqueOrNull(); + if (referentialMeta == null) { + referentialMeta = new ReferentialMetaImpl(); + } + + ReferentialState referentialState = new ReferentialState(); + referentialState.setReferentialName(I18n.t(entityClassFqn)); + referentialState.setLastUpdate(referentialMeta.getLastUpdate()); + referentialState.setSize(count); + + referentialStates.add(referentialState); + } + + return referentialStates; + } + + public List<FishingGearDCF> getAllFishingGearDCF() { + FishingGearDCFTopiaDao dao = getPersistenceContext().getFishingGearDCFDao(); + List<FishingGearDCF> all = dao.findAll(); + return all; + } + + public List<TargetSpeciesDCF> getAllTargetSpeciesDCF() { + TargetSpeciesDCFTopiaDao dao = getPersistenceContext().getTargetSpeciesDCFDao(); + List<TargetSpeciesDCF> all = dao.findAll(); + return all; + } + +} Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialService.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:mergeinfo + /branches/wao-1.5.x/wao-business/src/main/java/fr/ifremer/wao/service/ServiceReferentialImpl.java:679-733 Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialState.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialState.java (rev 0) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ReferentialState.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,41 @@ +package fr.ifremer.wao.services.service; + +import java.util.Date; + +/** + * Répresente l'état d'une référential à un instant donné. (Date de dernière + * mise à jour par exemple). + */ +public class ReferentialState { + + protected String referentialName; + + protected long size; + + protected Date lastUpdate; + + public String getReferentialName() { + return referentialName; + } + + public void setReferentialName(String referentialName) { + this.referentialName = referentialName; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + +} Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/WaoServiceSupport.java =================================================================== --- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/WaoServiceSupport.java 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/WaoServiceSupport.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -45,4 +45,7 @@ getPersistenceContext().commit(); } + protected ReferentialService getReferentialService() { + return newService(ReferentialService.class); + } } Modified: trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-services/src/main/resources/i18n/wao-services_en_GB.properties 2014-02-28 14:23:50 UTC (rev 1696) @@ -32,6 +32,7 @@ wao.import.contact.failure.wrongDistrict='%s' is not a valid boat district code wao.import.contact.failure.wrongSampleRowCode=The is no sample row with code '%s' wao.import.contact.failure.wrongTerrestrialLocation=There is no location of type '%s' with code '%s' +wao.import.failure=Import fail. wao.import.failure.wrongLocationType='%s' is not a valid location type, allowed values are %s wao.import.failure.wrongObsDebCode=There is no profession code having code '%s' wao.import.failure.wrongUser=There is no user with login '%s' Modified: trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties =================================================================== --- trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-services/src/main/resources/i18n/wao-services_fr_FR.properties 2014-02-28 14:23:50 UTC (rev 1696) @@ -32,6 +32,7 @@ wao.import.contact.failure.wrongDistrict='%s' n'est pas un code quartier maritime valide wao.import.contact.failure.wrongSampleRowCode=Il n'y a pas de ligne du plan avec le code '%s' wao.import.contact.failure.wrongTerrestrialLocation=Il n'y a pas de lieu de type '%s' ayant pour code '%s' +wao.import.failure=Une erreur est survenue lors de l'import. wao.import.failure.wrongLocationType='%s' n'est pas un type de lieu valide, les valeurs admises sont %s wao.import.failure.wrongObsDebCode=Il n'y a pas de code métier ayant pour code '%s' wao.import.failure.wrongUser=Il n'y a pas d'utilisateur ayant pour identifiant '%s' Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoJspActionSupport.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoJspActionSupport.java 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoJspActionSupport.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -1,5 +1,7 @@ package fr.ifremer.wao.web; +import fr.ifremer.wao.entity.ObsProgram; + public class WaoJspActionSupport extends WaoActionSupport { protected WaoSession getSession() { @@ -10,4 +12,24 @@ return applicationConfig.getInstanceDisclaimer(); } + public ObsProgram getObsProgram() { + return ObsProgram.OBSMER; + } + + public boolean isObsMer() { + return getObsProgram().isObsMer(); + } + + public boolean isObsVente() { + return getObsProgram().isObsVente(); + } + + public boolean isObsDeb() { + return getObsProgram().isObsDeb(); + } + + public String getText(Enum<?> enumeration) { + return getText(enumeration.getClass().getSimpleName() + "." + enumeration.name()); + } + } Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/AbstractImportReferentialAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/AbstractImportReferentialAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/AbstractImportReferentialAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,108 @@ +package fr.ifremer.wao.web.action.administration; + +import com.google.common.collect.ImmutableSet; +import fr.ifremer.wao.WaoTechnicalException; +import fr.ifremer.wao.services.service.ImportErrorException; +import fr.ifremer.wao.services.service.ReferentialService; +import fr.ifremer.wao.web.WaoJspActionSupport; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts2.convention.annotation.Result; +import org.apache.struts2.convention.annotation.Results; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +@Results({ + @Result(name="error", type="redirectAction", params = { "actionName", "referential-management" }), + @Result(name="success", type="redirectAction", params = { "actionName", "referential-management" }) +}) +public abstract class AbstractImportReferentialAction extends WaoJspActionSupport { + + private static final Log log = LogFactory.getLog(AbstractImportReferentialAction.class); + + protected static final ImmutableSet<String> CSV_CONTENT_TYPES = + ImmutableSet.of("text/csv", "text/comma-separated-values", "application/vnd.ms-excel"); + + protected ReferentialService service; + + protected File csvFile; + + protected String csvFileContentType; + + public void setCsvFile(File csvFile) { + this.csvFile = csvFile; + } + + public void setCsvFileContentType(String csvFileContentType) { + this.csvFileContentType = csvFileContentType; + } + + public void setService(ReferentialService service) { + this.service = service; + } + + protected abstract void importCsv(InputStream csvInputStream) throws ImportErrorException; + + protected abstract String getSuccessMessage(); + + @Override + public String execute() { + + String result = SUCCESS; + + if (CSV_CONTENT_TYPES.contains(csvFileContentType)) { + + InputStream csvInputStream = null; + + try { + + csvInputStream = new FileInputStream(csvFile); + + importCsv(csvInputStream); + + session.addMessage(getSuccessMessage()); + + } catch (FileNotFoundException e) { + + if (log.isErrorEnabled()) { + log.error("should never occur", e); + } + + throw new WaoTechnicalException(e); + + } catch (ImportErrorException e) { + + session.addErrorMessages(e.getMessage()); + + result = ERROR; + + } finally { + + IOUtils.closeQuietly(csvInputStream); + + } + + } else { + + if (log.isWarnEnabled()) { + log.warn("content type " + csvFileContentType + " is not CSV compatible"); + } + + // TODO brendan 28/02/14 i18n + session.addErrorMessages( + "il faut fournir un fichier de type CSV (type détecté : " + + csvFileContentType + ")"); + + result = ERROR; + + } + + return result; + + } + +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportContactStateMotivesAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportContactStateMotivesAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportContactStateMotivesAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,19 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ImportErrorException; +import org.nuiton.i18n.I18n; + +import java.io.InputStream; + +public class ImportContactStateMotivesAction extends AbstractImportReferentialAction { + + @Override + protected String getSuccessMessage() { + return I18n.t("wao.import.contactStateMotives.success"); + } + + @Override + public void importCsv(InputStream csvInputStream) throws ImportErrorException { + service.importContactStateMotives(csvInputStream); + } +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportFishingZonesAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportFishingZonesAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportFishingZonesAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,20 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ImportErrorException; +import org.nuiton.i18n.I18n; + +import java.io.InputStream; + +public class ImportFishingZonesAction extends AbstractImportReferentialAction { + + @Override + protected String getSuccessMessage() { + return I18n.t("wao.import.fishingZones.success"); + } + + @Override + public void importCsv(InputStream csvInputStream) throws ImportErrorException { + service.importFishingZones(csvInputStream); + } + +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportObsdebCodesAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportObsdebCodesAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportObsdebCodesAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,20 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ImportErrorException; +import org.nuiton.i18n.I18n; + +import java.io.InputStream; + +public class ImportObsdebCodesAction extends AbstractImportReferentialAction { + + @Override + protected String getSuccessMessage() { + return I18n.t("wao.import.obsDebCodes.success"); + } + + @Override + protected void importCsv(InputStream csvInputStream) throws ImportErrorException { + service.importObsDebCodes(csvInputStream); + } + +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialDivisionsAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialDivisionsAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialDivisionsAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,19 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ImportErrorException; +import org.nuiton.i18n.I18n; + +import java.io.InputStream; + +public class ImportTerrestrialDivisionsAction extends AbstractImportReferentialAction { + + @Override + protected String getSuccessMessage() { + return I18n.t("wao.import.terrestrialDivisions.success"); + } + + @Override + public void importCsv(InputStream csvInputStream) throws ImportErrorException { + service.importTerrestrialDivisions(csvInputStream); + } +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialLocationsAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialLocationsAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ImportTerrestrialLocationsAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,20 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ImportErrorException; +import org.nuiton.i18n.I18n; + +import java.io.InputStream; + +public class ImportTerrestrialLocationsAction extends AbstractImportReferentialAction { + + @Override + protected String getSuccessMessage() { + return I18n.t("wao.import.terrestrialLocations.success"); + } + + @Override + public void importCsv(InputStream csvInputStream) throws ImportErrorException { + service.importTerrestrialLocations(csvInputStream); + } + +} Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ReferentialManagementAction.java =================================================================== --- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ReferentialManagementAction.java (rev 0) +++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/administration/ReferentialManagementAction.java 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,32 @@ +package fr.ifremer.wao.web.action.administration; + +import fr.ifremer.wao.services.service.ReferentialService; +import fr.ifremer.wao.services.service.ReferentialState; +import fr.ifremer.wao.web.WaoJspActionSupport; + +import java.util.List; + +public class ReferentialManagementAction extends WaoJspActionSupport { + + protected ReferentialService referentialService; + + protected List<ReferentialState> referentialStates; + + public void setReferentialService(ReferentialService referentialService) { + this.referentialService = referentialService; + } + + @Override + public String execute() { + + referentialStates = referentialService.getReferentialStates(getObsProgram()); + + return SUCCESS; + + } + + public List<ReferentialState> getReferentialStates() { + return referentialStates; + } + +} Modified: trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties =================================================================== --- trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-02-28 14:23:50 UTC (rev 1696) @@ -1,3 +1,16 @@ +fr.ifremer.wao.services.service.ReferentialState.lastUpdate=Last update +fr.ifremer.wao.services.service.ReferentialState.referentialName=Referential +fr.ifremer.wao.services.service.ReferentialState.size=Lines count +wao.import.contactStateMotives.prompt=Import contact state motives +wao.import.contactStateMotives.success=Import contact state motives successful +wao.import.fishingZones.prompt=Import fishing zones +wao.import.fishingZones.success=Import fishing zones successful +wao.import.obsDebCodes.prompt=Import ObsDeb codes +wao.import.obsDebCodes.success=Import ObsDeb codes successful +wao.import.terrestrialDivisions.prompt=Import ObsDeb terrestrial divisions +wao.import.terrestrialDivisions.success=Import ObsDeb terrestrial divisions successful +wao.import.terrestrialLocations.prompt=Import terrestrial locations +wao.import.terrestrialLocations.success=Import terrestrial locations successful wao.ui.acceptCgu=I've read and accept the terms of use wao.ui.action.acceptContact=Validate contact wao.ui.action.add=Add @@ -71,7 +84,7 @@ wao.ui.entity.Contact=Contact wao.ui.entity.FishingZone=Fishing zones wao.ui.entity.SampleRow=Sample row -wao.ui.entity.SampleRow.day= +wao.ui.entity.SampleRow.day=Day wao.ui.entity.TerrestrialLocation=Place wao.ui.entity.fishingGearDCF=Gear DCF code wao.ui.entity.targetSpeciesDCF=Target species DCF code @@ -268,6 +281,7 @@ wao.ui.page.ContactForm.title=Contact edition wao.ui.page.Contacts.title=Contacts wao.ui.page.Index.title=Home +wao.ui.page.ReferentialManagement.title=Referentials management wao.ui.page.SamplingPlan.title=Sampling plan wao.ui.page.Synthesis.title=Synthesis wao.ui.page.UserProfileForm.title=Profile management @@ -335,3 +349,4 @@ wao.ui.userList=Users list wao.ui.userMustAcceptCgu=You must accept the terms of use wao.ui.validLogin=Valid identifier +wao.ui.import.disclaimer=You must upload CSV files using ";" as seperator and UTF-8 as character encoding Modified: trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties =================================================================== --- trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-02-28 14:23:50 UTC (rev 1696) @@ -1,3 +1,17 @@ +fr.ifremer.wao.services.service.ReferentialState.lastUpdate=Date de dernière mise à jour +fr.ifremer.wao.services.service.ReferentialState.referentialName=Référentiel +fr.ifremer.wao.services.service.ReferentialState.size=Nombre de lignes en base +wao.import.contactStateMotives.prompt=Import des motifs de refus +wao.import.contactStateMotives.success=Import des motifs de refus réalisé avec succès +wao.import.fishingZones.prompt=Import des zones de pêches +wao.import.fishingZones.success=Import des zones de pêches réalisé avec succès +wao.import.obsDebCodes.prompt=Import des codes ObsDeb +wao.import.obsDebCodes.success=Import des codes ObsDeb réalisé avec succès +wao.import.terrestrialDivisions.prompt=Import des unités d'observation +wao.import.terrestrialDivisions.success=Import des unités d'observation réalisé avec succès +wao.import.terrestrialLocations.prompt=Import des lieux terrestres +wao.import.terrestrialLocations.success=Import des lieux terrestres réalisé avec succès +wao.ui.import.disclaimer=Veuillez utiliser des fichiers CSV utilisant « ; » comme séparateur et UTF-8 comme encodage de caractères. wao.ui.acceptCgu=J'ai lu et j'accepte les conditions d'utilisation wao.ui.action.acceptContact=Valider le contact wao.ui.action.add=Ajouter @@ -71,6 +85,7 @@ wao.ui.entity.Contact=Contact wao.ui.entity.FishingZone=Zones de pêche wao.ui.entity.SampleRow=Ligne du plan d'échantillonnage +wao.ui.entity.SampleRow.day=Jour wao.ui.entity.TerrestrialLocation=Lieu wao.ui.entity.fishingGearDCF=Engin code DCF wao.ui.entity.targetSpeciesDCF=Ensembles d'espèces-cible code DCF @@ -84,6 +99,7 @@ wao.ui.field.Boat.name=Nom wao.ui.field.Boat.portOfRegistry=Port d'attache wao.ui.field.Boat.shipOwner=Armateur +wao.ui.field.BoatDistrict.code=Code du quartier maritime wao.ui.field.BoatInfos.dup=Capacité d'accueil du navire en personnels spécialisés wao.ui.field.Company.active=Active wao.ui.field.Company.name=Nom Added: trunk/wao-web/src/main/webapp/WEB-INF/content/administration/referential-management.jsp =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/content/administration/referential-management.jsp (rev 0) +++ trunk/wao-web/src/main/webapp/WEB-INF/content/administration/referential-management.jsp 2014-02-28 14:23:50 UTC (rev 1696) @@ -0,0 +1,125 @@ +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> +<%@taglib uri="/struts-tags" prefix="s" %> + +<html> + + <head> + + </head> + + <div class="alert alert-info"> + <s:property value="getText('wao.ui.import.disclaimer')" /> + </div> + + <s:form action="import-fishing-zones" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:property value="getText('wao.import.fishingZones.prompt')" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> Importer + </s:submit> + </fieldset> + + </s:form> + + <s:form action="import-terrestrial-locations" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:property value="getText('wao.import.terrestrialLocations.prompt')" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> Importer + </s:submit> + </fieldset> + + </s:form> + + <s:if test="obsMer"> + <s:form action="import-contact-state-motives" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:property value="getText('wao.import.contactStateMotives.prompt')" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> Importer + </s:submit> + </fieldset> + + </s:form> + </s:if> + + <s:if test="obsDeb"> + <s:form action="import-obsdeb-codes" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:property value="getText('wao.import.obsDebCodes.prompt')" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> Importer + </s:submit> + </fieldset> + + </s:form> + + <s:form action="import-terrestrial-divisions" method="POST" enctype="multipart/form-data"> + + <fieldset> + <legend> + <s:property value="getText('wao.import.terrestrialDivisions.prompt')" /> + </legend> + + <s:file name="csvFile" /> + + <s:submit type="button"> + <i class="icon-upload"></i> Importer + </s:submit> + </fieldset> + + </s:form> + </s:if> + + <table class="table table-bordered"> + <tr> + <th> + <s:property value="getText('fr.ifremer.wao.services.service.ReferentialState.referentialName')" /> + </th> + <th> + <s:property value="getText('fr.ifremer.wao.services.service.ReferentialState.size')" /> + </th> + <th> + <s:property value="getText('fr.ifremer.wao.services.service.ReferentialState.lastUpdate')" /> + </th> + </tr> + <s:iterator value="referentialStates"> + <tr> + <td> + <s:property value="referentialName" /> + </td> + <td> + <s:property value="size" /> + </td> + <td> + <s:property value="lastUpdate" /> + </td> + </tr> + </s:iterator> + </table> + +</html> Modified: trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-02-28 14:23:50 UTC (rev 1696) @@ -24,7 +24,7 @@ <div class="navbar"> <div class="navbar-inner"> - <a class="brand" href="#">Wao Obs???</a> + <a class="brand" href="#">Wao <s:property value="getText(obsProgram)" /></a> <ul class="nav"> <li class="active"> <s:url action="news" id="newsUrl" /> @@ -58,11 +58,19 @@ </li> </ul> <ul class="nav pull-right"> - <li> - <s:url action="administration" id="administrationUrl" /> - <s:a href="%{administrationUrl}" title="Accèder à la partie administration"> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown"> <s:property value="getText('wao.ui.page.Administration.title')" /> - </s:a> + <b class="caret"></b> + </a> + <ul class="dropdown-menu"> + <li> + <s:url namespace="/administration" action="referential-management" id="referentialManagementUrl" /> + <s:a href="%{referentialManagementUrl}"> + <i class="icon-upload"></i> <s:property value="getText('wao.ui.page.ReferentialManagement.title')" /> + </s:a> + </li> + </ul> </li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> @@ -104,7 +112,7 @@ <%@include file="version.jsp" %> </a> </li> - <t:if test="connectedUser.obsMer"> + <t:if test="obsMer"> <li> <a href="mailto:harmonie@ifremer.fr" title="Contacter un responsable Obsmer"> Obsmer Modified: trunk/wao-web/src/main/webapp/WEB-INF/web.xml =================================================================== --- trunk/wao-web/src/main/webapp/WEB-INF/web.xml 2014-02-28 11:25:17 UTC (rev 1695) +++ trunk/wao-web/src/main/webapp/WEB-INF/web.xml 2014-02-28 14:23:50 UTC (rev 1696) @@ -55,14 +55,15 @@ </filter-mapping> <!-- Le filtre Shiro doit être executer après le fltre struts prepare: Pour gérer l'encodage de la requête --> - <filter-mapping> - <filter-name>shiro</filter-name> - <url-pattern>/*</url-pattern> - <dispatcher>REQUEST</dispatcher> - <dispatcher>FORWARD</dispatcher> - <dispatcher>INCLUDE</dispatcher> - <dispatcher>ERROR</dispatcher> - </filter-mapping> + <!-- XXX bleny 28/02/2014 attention à le réactivation, on peut avoir le problème d'upload de fichier --> + <!--<filter-mapping>--> + <!--<filter-name>shiro</filter-name>--> + <!--<url-pattern>/*</url-pattern>--> + <!--<dispatcher>REQUEST</dispatcher>--> + <!--<dispatcher>FORWARD</dispatcher>--> + <!--<dispatcher>INCLUDE</dispatcher>--> + <!--<dispatcher>ERROR</dispatcher>--> + <!--</filter-mapping>--> <filter-mapping> <filter-name>sitemesh</filter-name>
participants (1)
-
bleny@users.forge.codelutin.com