Skip to content

Commit

Permalink
Merge pull request #107 from InseeFr/103-Service-identification-Iris
Browse files Browse the repository at this point in the history
Feat: WS for Iris
  • Loading branch information
Fabrice Bibonne authored Feb 15, 2024
2 parents b66c01d + 815b72f commit 2987ba5
Show file tree
Hide file tree
Showing 23 changed files with 1,159 additions and 93 deletions.
2 changes: 0 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@
<version>${jersey.version}</version>
</dependency>



<!-- LOGS -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import io.swagger.v3.oas.annotations.extensions.Extension;
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
import org.apache.commons.lang3.StringUtils;

import fr.insee.rmes.api.AbstractMetadataApi;
Expand All @@ -37,8 +39,7 @@
@Tag(name = "nomenclatures", description = "Nomenclatures API")
public class ClassificationApi extends AbstractMetadataApi {


@Hidden

@GET
@Path("/{code}/postes")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/fr/insee/rmes/api/geo/AbstractGeoApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class AbstractGeoApi extends AbstractMetadataApi {

Expand Down Expand Up @@ -135,7 +138,11 @@ else if (StringUtils.equalsAnyIgnoreCase(header, MediaType.APPLICATION_JSON)) {
}

protected Response generateBadRequestResponse() {
return Response.status(Status.BAD_REQUEST).entity("").build();
return generateBadRequestResponse("");
}

protected Response generateBadRequestResponse(String erreurMessage) {
return Response.status(Status.BAD_REQUEST).entity(erreurMessage).build();
}

// Method to find a list of projections
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/fr/insee/rmes/api/geo/ConstGeoApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class ConstGeoApi {

public static final String PATH_CIRCO_TER = PATH_SEPARATOR + "circonscriptionTerritoriale";
public static final String PATH_CANTON = PATH_SEPARATOR + "canton";
public static final String PATH_IRIS=PATH_SEPARATOR + "iris";
public static final String PATH_COMMUNE = PATH_SEPARATOR + "commune";
public static final String PATH_CANTON_OU_VILLE = PATH_SEPARATOR + "cantonOuVille";
public static final String PATH_PAYS = PATH_SEPARATOR + "pays";
Expand All @@ -28,7 +29,7 @@ public class ConstGeoApi {
public static final String PATH_LISTE_CANTON_OU_VILLE= PATH_SEPARATOR +"cantonsEtVilles";
public static final String PATH_INTERCO= PATH_SEPARATOR + "intercommunalite";
public static final String PATH_BASSINDEVIE= PATH_SEPARATOR + "bassinDeVie2022";

public static final String PATH_LISTE_IRIS = PATH_SEPARATOR + "iris";
public static final String PATH_LISTE_COMMUNE = PATH_SEPARATOR + "communes";
public static final String PATH_LISTE_PAYS = PATH_SEPARATOR + "pays";
public static final String PATH_LISTE_CANTON = PATH_SEPARATOR + "cantons";
Expand Down Expand Up @@ -59,6 +60,9 @@ public class ConstGeoApi {
public static final String PATTERN_DISTRICT ="9[78][1-9]{3}";
public static final String PATTERN_INTERCO ="2[0-4][0-9]{7}";
public static final String PATTERN_CANTON = "(([0-9]{2})|(2[0-9AB])|(97[1-6]))([0-9]{2})";

public static final String PATTERN_IRIS="[0-9][0-9AB][0-9]{7}";
public static final String PATTERN_IRIS_DESCRIPTION= "Code Insee de l’Iris (9 caractères)";
public static final String PATTERN_PAYS = "99[0-9]{3}";
public static final String PATTERN_REGION = "[0-9]{2}";
public static final String PATTERN_ZONE_EMPLOI = "[0-9]{4}";
Expand Down
210 changes: 210 additions & 0 deletions src/main/java/fr/insee/rmes/api/geo/territoire/IrisApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package fr.insee.rmes.api.geo.territoire;

import fr.insee.rmes.api.geo.AbstractGeoApi;
import fr.insee.rmes.api.geo.ConstGeoApi;
import fr.insee.rmes.modeles.geo.territoire.CodeIris;
import fr.insee.rmes.modeles.geo.territoire.Iris;
import fr.insee.rmes.modeles.geo.territoire.PseudoIris;
import fr.insee.rmes.modeles.geo.territoire.Territoire;
import fr.insee.rmes.modeles.geo.territoires.Territoires;
import fr.insee.rmes.queries.geo.GeoQueries;
import fr.insee.rmes.utils.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;

import javax.ws.rs.*;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;


@Path(ConstGeoApi.PATH_GEO)
@Tag(name = ConstGeoApi.TAG_NAME, description = ConstGeoApi.TAG_DESCRIPTION)
public class IrisApi extends AbstractGeoApi {
private static final String CODE_PATTERN = "/{code:}";
private static final String LITTERAL_PARAMETER_TYPE_DESCRIPTION = "Filtre sur le type de territoire renvoyé.";

private static final String LITTERAL_RESPONSE_DESCRIPTION = "Iris";
private static final String LITTERAL_ID_OPERATION = "getcogiris";
private static final String LITTERAL_CODE_EXAMPLE = "010040101";
private static final String LITTERAL_PARAMETER_DATE_DESCRIPTION =
"Filtre pour renvoyer l'Iris active à la date donnée. Par défaut, c’est la date courante. (Format : 'AAAA-MM-JJ')";
private static final String LITTERAL_OPERATION_SUMMARY =
"Informations sur un Iris identifié par son code (neuf chiffres pour la métropole ou 2A/2B plus 7 chiffres pour la Corse)";


private final IrisUtils irisUtils;

public IrisApi() {
// Constructeur par défaut
this.irisUtils = new IrisUtils();
}

protected IrisApi(SparqlUtils sparqlUtils, CSVUtils csvUtils, ResponseUtils responseUtils, IrisUtils irisUtils) {
super(sparqlUtils, csvUtils, responseUtils);
this.irisUtils = irisUtils;
}

@Path(ConstGeoApi.PATH_IRIS + CODE_PATTERN)
@GET
@Produces({
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML
})
@Operation(operationId = LITTERAL_ID_OPERATION, summary = LITTERAL_OPERATION_SUMMARY, responses = {
@ApiResponse(
content = @Content(schema = @Schema(implementation = Iris.class)),
description = LITTERAL_RESPONSE_DESCRIPTION)

})
public Response getByCode(
@Parameter(
description = ConstGeoApi.PATTERN_IRIS_DESCRIPTION,
required = true,
schema = @Schema(
pattern = ConstGeoApi.PATTERN_IRIS,
type = Constants.TYPE_STRING, example = LITTERAL_CODE_EXAMPLE)) @PathParam(Constants.CODE) String code,
@Parameter(hidden = true) @HeaderParam(HttpHeaders.ACCEPT) String header,
@Parameter(
description = LITTERAL_PARAMETER_DATE_DESCRIPTION,
schema = @Schema(type = Constants.TYPE_STRING, format = Constants.FORMAT_DATE)) @QueryParam(
value = Constants.PARAMETER_DATE) String date) {

var codeIris = CodeIris.of(code);
if (codeIris.isInvalid()) {
return generateBadRequestResponse(ConstGeoApi.ERREUR_PATTERN);
}
if (!this.verifyParameterDateIsRightWithoutHistory(date)) {
return this.generateBadRequestResponse();
}

return getResponseForIrisOrPseudoIris(codeIris, header, date);
}

private Response getResponseForIrisOrPseudoIris(CodeIris codeIris, String header, String date) {
if (irisUtils.hasIrisDescendant(codeIris.codeCommune())) {
return getResponseForIris(codeIris, header, date);
} else {
return getResponseForPseudoIris(codeIris, header, date);
}

}

private Response getResponseForPseudoIris(CodeIris codeIris, String header, String date) {
if (codeIris.isPseudoIrisCode()) {
return this.generateResponseATerritoireByCode(
sparqlUtils.executeSparqlQuery(
GeoQueries.getIrisByCodeAndDate(codeIris.code(), this.formatValidParameterDateIfIsNull(date))),
header,
new PseudoIris(codeIris.code()));
} else {
return Response.status(Response.Status.NOT_FOUND).entity("").build();
}
}

private Response getResponseForIris(CodeIris codeIris, String header, String date) {
if (codeIris.isPseudoIrisCode()) {
return Response.status(Response.Status.NOT_FOUND).entity("").build();
} else {
Territoire territoire = new Iris(codeIris.code());
return this.generateResponseATerritoireByCode(
sparqlUtils.executeSparqlQuery(
GeoQueries.getIrisByCodeAndDate(codeIris.code(), this.formatValidParameterDateIfIsNull(date))),
header,
territoire);
}
}


@Path(ConstGeoApi.PATH_LISTE_IRIS)
@GET
@Produces({
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML
})
@Operation(
operationId = LITTERAL_ID_OPERATION + ConstGeoApi.ID_OPERATION_LISTE,
summary = "Informations sur toutes les iris actifs à la date donnée. Par défaut, c’est la date courante.",
responses = {
@ApiResponse(
content = @Content(schema = @Schema(type = ARRAY, implementation = Territoire.class)),
description = LITTERAL_RESPONSE_DESCRIPTION)
})
public Response getListe(
@Parameter(hidden = true) @HeaderParam(HttpHeaders.ACCEPT) String header,
@Parameter(
description = "Filtre pour renvoyer les Iris ou faux-Iris à la date donnée. Par défaut, c’est la date courante. (Format : 'AAAA-MM-JJ')",
schema = @Schema(type = Constants.TYPE_STRING, format = Constants.FORMAT_DATE)) @QueryParam(
value = Constants.PARAMETER_DATE) String date,
@Parameter(description = "les Iris (et pseudo-iris) des collectivités d'outre-mer",
required = true,
schema = @Schema(type = Constants.TYPE_BOOLEAN, allowableValues = {"true", "false"}, example = "false", defaultValue = "false"))
@QueryParam(
value = Constants.PARAMETER_STRING) Boolean com
) {

if (!this.verifyParameterDateIsRightWithHistory(date)) {
return this.generateBadRequestResponse();
} else {
return this
.generateResponseListOfTerritoire(
sparqlUtils
.executeSparqlQuery(GeoQueries.getListIris(this.formatValidParameterDateIfIsNull(date), this.formatValidParameterBooleanIfIsNull(com))),
header,
Territoires.class,
Territoire.class);
}
}


@Path(ConstGeoApi.PATH_IRIS + CODE_PATTERN + ConstGeoApi.PATH_ASCENDANT)
@GET
@Produces({
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML
})
@Operation(
operationId = LITTERAL_ID_OPERATION + ConstGeoApi.ID_OPERATION_ASCENDANTS,
summary = "Informations concernant les territoires qui contiennent l'Iris",
responses = {
@ApiResponse(
content = @Content(schema = @Schema(type = ARRAY, implementation = Territoire.class)),
description = LITTERAL_RESPONSE_DESCRIPTION)
})
public Response getAscendants(
@Parameter(
description = ConstGeoApi.PATTERN_IRIS_DESCRIPTION,
required = true,
schema = @Schema(
pattern = ConstGeoApi.PATTERN_IRIS,
type = Constants.TYPE_STRING, example = LITTERAL_CODE_EXAMPLE)) @PathParam(Constants.CODE) String code,
@Parameter(hidden = true) @HeaderParam(HttpHeaders.ACCEPT) String header,
@Parameter(
description = "Filtre pour renvoyer les territoires contenant l'iris actif à la date donnée. Par défaut, c’est la date courante. (Format : 'AAAA-MM-JJ')",
schema = @Schema(type = Constants.TYPE_STRING, format = Constants.FORMAT_DATE)) @QueryParam(
value = Constants.PARAMETER_DATE) String date,
@Parameter(
description = LITTERAL_PARAMETER_TYPE_DESCRIPTION,
schema = @Schema(type = Constants.TYPE_STRING)) @QueryParam(
value = Constants.PARAMETER_TYPE) String typeTerritoire) {

if (!this.verifyParametersTypeAndDateAreValid(typeTerritoire, date)) {
return this.generateBadRequestResponse();
} else {
return this
.generateResponseListOfTerritoire(
sparqlUtils
.executeSparqlQuery(
GeoQueries
.getAscendantsIris(
code,
this.formatValidParameterDateIfIsNull(date),
this.formatValidParametertypeTerritoireIfIsNull(typeTerritoire))),
header,
Territoires.class,
Territoire.class);
}
}

}
10 changes: 5 additions & 5 deletions src/main/java/fr/insee/rmes/modeles/geo/EnumTypeGeographie.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package fr.insee.rmes.modeles.geo;

import java.util.Optional;
import java.util.stream.Stream;

import fr.insee.rmes.modeles.geo.territoire.*;
import fr.insee.rmes.modeles.geo.territoires.*;
import fr.insee.rmes.utils.Constants;

import java.util.Optional;
import java.util.stream.Stream;

public enum EnumTypeGeographie {

COMMUNE("Commune", Commune.class,Communes.class, Constants.NONE),
Expand All @@ -25,8 +25,8 @@ public enum EnumTypeGeographie {
DISTRICT("District",District.class,Districts.class,Constants.NONE),
CIRCONSCRIPTION_TERRITORIALE("CirconscriptionTerritoriale",CirconscriptionTerritoriale.class,CirconscriptionsTerritoriales.class,Constants.NONE),
INTERCOMMUNALITE("Intercommunalite",Intercommunalite.class,Intercommunalites.class,Constants.NONE),
BASSINDEVIE("BassinDeVie2022",BassinDeVie2022.class,BassinsDeVie2022.class,Constants.NONE);

BASSINDEVIE("BassinDeVie2022",BassinDeVie2022.class,BassinsDeVie2022.class,Constants.NONE),
IRIS("Iris", Iris.class,Iriss.class,Constants.NONE);

private String typeObjetGeo;
private Class<? extends Territoire> classNameOfGeoType;
Expand Down
21 changes: 9 additions & 12 deletions src/main/java/fr/insee/rmes/modeles/geo/IntituleSansArticle.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
package fr.insee.rmes.modeles.geo;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;

import io.swagger.v3.oas.annotations.media.Schema;

import javax.xml.bind.annotation.*;

@Schema(description="Intitulé sans son article et article associé")
@XmlAccessorType(XmlAccessType.PROPERTY)
@JsonPropertyOrder({"intituleSansArticle", "typeArticle"})
@XmlRootElement(name="IntituleSansArticle")
@XmlRootElement(name = "IntituleSansArticle")
@JacksonXmlRootElement(localName = "IntituleSansArticle")
public class IntituleSansArticle {

//@Schema(example = "Aigle")
@XmlValue
@Schema(example = "Aigle")
//@XmlValue
private String label = null;

@Schema(example = "5")
private String typeArticle = null;


@JacksonXmlText
// @JsonProperty("intituleSansArticle")
// @JacksonXmlProperty(localName="intituleSansArticle")
@JsonProperty("intituleSansArticle")
@JacksonXmlProperty(localName="IntituleSansArticle")
@Schema(example = "Aigle")
@XmlValue
public String getIntituleSansArticle() {
Expand Down
Loading

0 comments on commit 2987ba5

Please sign in to comment.