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  package fr.paris.lutece.plugins.geocode.v1.web.rs.service;
35  
36  import com.fasterxml.jackson.core.JsonProcessingException;
37  import com.fasterxml.jackson.databind.JavaType;
38  import com.fasterxml.jackson.databind.JsonNode;
39  import com.fasterxml.jackson.databind.ObjectMapper;
40  
41  import fr.paris.lutece.plugins.geocode.v1.web.rs.util.Constants;
42  import fr.paris.lutece.plugins.geocode.v1.web.service.CustomResponseStatusValidator;
43  import fr.paris.lutece.plugins.geocode.v1.web.service.IHttpTransportProvider;
44  import fr.paris.lutece.util.httpaccess.HttpAccess;
45  import fr.paris.lutece.util.httpaccess.InvalidResponseStatus;
46  import org.apache.hc.core5.http.HttpStatus;
47  import org.apache.hc.core5.net.URIBuilder;
48  import org.apache.log4j.Logger;
49  
50  import java.util.ArrayList;
51  import java.util.List;
52  import java.util.Map;
53  
54  /**
55   * IHttpTransportProvider which use library-httpaccess
56   */
57  public class HttpAccessTransport implements IHttpTransportProvider
58  {
59      private static Logger _logger = Logger.getLogger( HttpAccessTransport.class );
60  
61      protected HttpAccess _httpClient;
62      protected String _strEndPoint;
63  
64      public HttpAccessTransport( )
65      {
66          this._httpClient = new HttpAccess( CustomResponseStatusValidator.getInstance( ) );
67      }
68      
69      @Override
70      public <T> T doGet(String strEndPointUrl, Map<String, String> mapParams, Map<String, String> mapHeadersRequest,
71      		Class<T> responseJsonClass, ObjectMapper mapper) throws Exception
72      {
73          String strResponseJSON = "";
74          T oResponse = null;
75          
76          try
77          {
78              URIBuilder uriBuilder = new URIBuilder( strEndPointUrl );
79  
80              if ( ( mapParams != null ) && !mapParams.isEmpty( ) )
81              {
82                  for ( String strParamKey : mapParams.keySet( ) )
83                  {
84                      uriBuilder.addParameter( strParamKey, mapParams.get( strParamKey ) );
85                  }
86              }
87  
88              addAuthentication( mapHeadersRequest );
89              strResponseJSON = this._httpClient.doGet( uriBuilder.toString( ), null, null, mapHeadersRequest );
90              oResponse = mapJson( mapper, strResponseJSON, responseJsonClass );
91          }
92          catch( Exception e )
93          {
94          	handleExceptionGeocode( e );
95          }
96  
97          return oResponse;
98      }
99      
100     @Override
101     public <T> List<T> doGetList(String strEndPointUrl, Map<String, String> mapParams, Map<String, String> mapHeadersRequest,
102     		Class<T> responseJsonClass, ObjectMapper mapper) throws Exception
103     {
104         String strResponseJSON = "";
105         List<T> oResponse = null;
106         
107         try
108         {
109             URIBuilder uriBuilder = new URIBuilder( strEndPointUrl );
110 
111             if ( ( mapParams != null ) && !mapParams.isEmpty( ) )
112             {
113                 for ( String strParamKey : mapParams.keySet( ) )
114                 {
115                     uriBuilder.addParameter( strParamKey, mapParams.get( strParamKey ) );
116                 }
117             }
118 
119             addAuthentication( mapHeadersRequest );
120             strResponseJSON = this._httpClient.doGet( uriBuilder.toString( ), null, null, mapHeadersRequest );
121             oResponse = mapJsonList( mapper, strResponseJSON, responseJsonClass );
122         }
123         catch( Exception e )
124         {
125         	handleExceptionGeocode( e );
126         }
127 
128         return oResponse;
129     }
130     
131     /**
132      * add error log and throw correct Exception depending on the specified Exception
133      * 
134      * @param e
135      *            root exception
136      * @throws IdentityNotFoundException
137      *             if the specified Exception is an HttpAccessException with HTTP code 404
138      * @throws IdentityStoreException
139      *             otherwise
140      */
141     protected void handleExceptionGeocode( Exception e ) throws Exception
142     {
143         String strError = "LibraryIdentityStore - Error HttpAccessTransport :";
144         _logger.error( strError + e.getMessage( ), e );
145 
146         if ( e instanceof InvalidResponseStatus && HttpStatus.SC_NOT_FOUND == ( (InvalidResponseStatus) e ).getResponseStatus( )
147                 || e instanceof Exception )
148         {
149             // throw new IdentityNotFoundException( strError, e );
150             throw new Exception( strError, e );
151         }
152         else
153         {
154             throw new Exception( strError, e );
155         }
156     }
157 
158     /**
159      * add specific authentication to request
160      * 
161      * @param mapHeadersRequest
162      *            map of headers to add
163      * @throws IdentityStoreException
164      */
165     protected void addAuthentication( Map<String, String> mapHeadersRequest ) throws Exception
166     {
167         // default : no authentication
168     }
169 
170     /**
171      * set end point
172      * 
173      * @param strApiEndPointUrl
174      */
175     public void setApiEndPointUrl( String strApiEndPointUrl )
176     {
177 
178         _strEndPoint = strApiEndPointUrl;
179     }
180 
181     /**
182      * get end point
183      * 
184      * @return strEndPointUrl
185      */
186     public String getApiEndPointUrl( )
187     {
188 
189         return _strEndPoint;
190     }
191 
192     /**
193      * Converts json String response to the desired {@link ResponseDto} subclass instance.
194      *
195      * @param mapper
196      *            the mapper
197      * @param jsonStr
198      *            the json string value
199      * @param responseClass
200      *            the desired {@link ResponseDto} subclass
201      * @return the desired {@link ResponseDto} subclass instance
202      */
203     private <T> T mapJson( final ObjectMapper mapper, final String jsonStr, final Class<T> responseClass )
204             throws JsonProcessingException, InstantiationException, IllegalAccessException
205     {
206         T response = null;
207         try
208         {
209         	JsonNode root = mapper.readTree( jsonStr );
210         	JsonNode rootResult = root.get( Constants.PARAM_RESULT );
211         	String strResult = rootResult.toPrettyString( );
212             response = mapper.readValue( strResult, responseClass );
213         }
214         catch( final Exception e )
215         {
216         	String strError = "API GEOCODE - Error converting to Object from JSON '" + jsonStr + "' : ";
217             _logger.error( strError + e.getMessage( ), e );
218         }
219         return response;
220     }
221 
222     /**
223      * Converts json String response to a {@link List} of the desired {@link ResponseDto} subclass instances.
224      *
225      * @param mapper
226      *            the mapper
227      * @param jsonStr
228      *            the json string value
229      * @param responseClass
230      *            the desired {@link ResponseDto} subclass
231      * @return a {@link List} of the desired {@link ResponseDto} subclass instances
232      */
233     private <T> List<T> mapJsonList( final ObjectMapper mapper, final String jsonStr, final Class<T> responseClass )
234             throws JsonProcessingException, InstantiationException, IllegalAccessException
235     {
236         List<T> responseList = new ArrayList<>( );
237         JavaType responseListClassType = mapper.getTypeFactory( ).constructCollectionType( List.class, responseClass );
238         try
239         {
240         	JsonNode root = mapper.readTree( jsonStr );
241         	JsonNode rootResult = root.get( Constants.PARAM_RESULT );
242         	String strResult = rootResult.toPrettyString( );
243             responseList = mapper.readValue( strResult, responseListClassType );
244         }
245         catch( final Exception e1 )
246         {
247             try
248             {
249                 // If mapper didn't manage to map the json with the desired class, we try to map it as a list of error response
250                 //responseListClassType = mapper.getTypeFactory( ).constructCollectionType( List.class, ErrorResponse.class );
251                 String strError = "API GEOCODE - Error converting to Object from JSON '" + jsonStr + "' : ";
252                 _logger.error( strError + e1.getMessage( ), e1 );
253             }
254             catch( final Exception e2 )
255             {
256             	String strError = "API GEOCODE - Error converting to Object from JSON '" + jsonStr + "' : ";
257                 _logger.error( strError + e2.getMessage( ), e2 );
258             }
259         }
260         return responseList;
261     }
262 
263 }