View Javadoc
1   /*
2    * Copyright (c) 2002-2023, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  
35  package fr.paris.lutece.plugins.appointment.modules.ants.service;
36  
37  import java.io.IOException;
38  import java.util.Collections;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Map;
42  
43  import com.fasterxml.jackson.core.type.TypeReference;
44  import com.fasterxml.jackson.databind.ObjectMapper;
45  
46  import fr.paris.lutece.plugins.appointment.modules.ants.utils.HttpCallsUtils;
47  import fr.paris.lutece.plugins.appointment.modules.ants.web.PreDemandeStatusEnum;
48  import fr.paris.lutece.plugins.appointment.modules.ants.web.PredemandeResponse;
49  import fr.paris.lutece.portal.service.util.AppLogService;
50  import fr.paris.lutece.portal.service.util.AppPropertiesService;
51  import fr.paris.lutece.util.httpaccess.HttpAccess;
52  import fr.paris.lutece.util.httpaccess.HttpAccessException;
53  import fr.paris.lutece.util.url.UrlItem;
54  import fr.paris.lutece.portal.service.datastore.DatastoreService;
55  import fr.paris.lutece.portal.service.html.EncodingService;
56  
57  /**
58   * This class provides methods for processing and validating predemande codes.
59   */
60  public class PreDemandeValidationService
61  {
62  
63      private static final String PROPERTY_ENDPOINT_STATUS = AppPropertiesService.getProperty( "ants.api.opt.get.status" );
64      private static final String PROPERTY_API_OPT_AUTH_TOKEN_KEY = AppPropertiesService.getProperty( "ants.auth.token" );
65      private static final String PROPERTY_API_OPT_AUTH_TOKEN_VALUE = String.valueOf( DatastoreService.getDataValue( "module.appointment.ants.site_property.token" ,"") );
66      private static final String PROPERTY_ID_APPLICATION_PARAMETER = AppPropertiesService.getProperty( "ants.ids_application.parameters" );
67      private static final String PROPERTY_MEETING_POINT_ID_PARAMETER = AppPropertiesService.getProperty( "ants.meeting_point_id.parameters" );
68      private static final String PROPERTY_MEETING_POINT_ID_DEFAULT_VALUE = AppPropertiesService.getProperty( "ants.meeting_point_id.defaultValue" );
69  
70      // Timeout properties specific to the ANTS HTTP calls
71      private static final String PROPERTY_SOCKET_TIMEOUT = "ants.api.socketTimeout";
72      private static final String PROPERTY_CONNECTION_TIMEOUT = "ants.api.connectionTimeout";
73  
74      private PreDemandeValidationService( )
75      {
76      }
77  
78      /**
79       * Processes a list of predemande codes to check their status and appointments.
80       *
81       * @param codes
82       *            The list of predemande codes to process.
83       * @return True if all predemande codes are validated and have appointments; otherwise, false.
84       * @throws IOException
85       *             If there is an error while processing the predemande codes.
86       */
87      public static boolean checkPredemandeCodesValidationAndAppointments( List<String> codes ) throws IOException
88      {
89          Map<String, PredemandeResponse> responseMap = getPreDemandeStatusAndAppointments( codes );
90  
91          if ( responseMap.isEmpty( ) )
92          {
93              return false;
94          }
95  
96          for ( PredemandeResponse predemande : responseMap.values( ) )
97          {
98              List<PredemandeResponse.Appointment> appointments = predemande.getAppointments( );
99  
100             if ( !appointments.isEmpty( ) || !PreDemandeStatusEnum.VALIDATED.name( ).equalsIgnoreCase( predemande.getStatus( ) ) )
101             {
102                 return false;
103             }
104         }
105 
106         return true;
107     }
108 
109     /**
110      * Retrieves the pre-demande status and appointments from the API.
111      *
112      * @param codes
113      *            The list of predemande codes to retrieve.
114      * @return The JSON response from the API.
115      * @throws IOException
116      *             If there is an error while processing the predemande codes.
117      */
118     private static Map<String, PredemandeResponse> getPreDemandeStatusAndAppointments( List<String> codes ) throws IOException
119     {
120         UrlItem urlItem;
121         String apiUrl = null;
122 
123         if ( !codes.isEmpty( ) )
124         {
125             urlItem = new UrlItem( PROPERTY_ENDPOINT_STATUS + PROPERTY_ID_APPLICATION_PARAMETER + "=" + codes.get( 0 ) );
126             for ( int i = 1; i < codes.size( ); i++ )
127             {
128                 urlItem.addParameter( PROPERTY_ID_APPLICATION_PARAMETER, codes.get( i ) );
129             }
130             // Add the "meeting_point_id" parameter and its value in the URL
131             String strMeetingPointId = EncodingService.encodeUrl( PROPERTY_MEETING_POINT_ID_DEFAULT_VALUE ).replace( "+", "%20" );
132             urlItem.addParameter( PROPERTY_MEETING_POINT_ID_PARAMETER, strMeetingPointId );
133 
134             apiUrl = urlItem.toString( );
135         }
136 
137         // Create a new HttpAccess object with specific timeout values, if any was set,
138         // otherwise the default configuration will be used
139         HttpAccess httpAccess = HttpCallsUtils.getHttpAccessTimeoutFromProperties( PROPERTY_SOCKET_TIMEOUT, PROPERTY_CONNECTION_TIMEOUT );
140 
141         Map<String, String> headers = new HashMap<>( );
142         headers.put( PROPERTY_API_OPT_AUTH_TOKEN_KEY, PROPERTY_API_OPT_AUTH_TOKEN_VALUE );
143 
144         try
145         {
146             String jsonResponse = httpAccess.doGet( apiUrl, null, null, headers );
147             ObjectMapper mapper = new ObjectMapper( );
148             TypeReference<HashMap<String, PredemandeResponse>> typeRef = new TypeReference<HashMap<String, PredemandeResponse>>( )
149             {
150             };
151             return mapper.readValue( jsonResponse, typeRef );
152         }
153         catch( HttpAccessException | IOException ex )
154         {
155             AppLogService.error( "Error calling API {}", apiUrl, ex );
156             return Collections.emptyMap( );
157         }
158     }
159 }