1- /*
2- * Licensed to the Apache Software Foundation (ASF) under one
3- * or more contributor license agreements. See the NOTICE file
4- * distributed with this work for additional information
5- * regarding copyright ownership. The ASF licenses this file
6- * to you under the Apache License, Version 2.0 (the
7- * "License"); you may not use this file except in compliance
8- * with the License. You may obtain a copy of the License at
9- *
10- * http://www.apache.org/licenses/LICENSE-2.0
11- *
12- * Unless required by applicable law or agreed to in writing,
13- * software distributed under the License is distributed on an
14- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15- * KIND, either express or implied. See the License for the
16- * specific language governing permissions and limitations
17- * under the License.
18- */
19-
201package org .apache .cloudstack .storage .feign ;
212
22-
233import feign .RequestInterceptor ;
24- import feign .RequestTemplate ;
254import feign .Retryer ;
26- import org .springframework .cloud .commons .httpclient .ApacheHttpClientFactory ;
5+ import feign .Client ;
6+ import feign .httpclient .ApacheHttpClient ;
7+ import feign .codec .Decoder ;
8+ import feign .codec .Encoder ;
9+ import feign .Response ;
10+ import feign .codec .DecodeException ;
11+ import feign .codec .EncodeException ;
12+ import com .fasterxml .jackson .core .JsonProcessingException ;
13+ import com .fasterxml .jackson .databind .DeserializationFeature ;
14+ import com .fasterxml .jackson .databind .json .JsonMapper ;
2715import org .apache .http .conn .ConnectionKeepAliveStrategy ;
2816import org .apache .http .conn .ssl .NoopHostnameVerifier ;
2917import org .apache .http .conn .ssl .SSLConnectionSocketFactory ;
3018import org .apache .http .conn .ssl .TrustAllStrategy ;
3119import org .apache .http .impl .client .CloseableHttpClient ;
20+ import org .apache .http .impl .client .HttpClientBuilder ;
3221import org .apache .http .ssl .SSLContexts ;
3322import org .apache .logging .log4j .LogManager ;
3423import org .apache .logging .log4j .Logger ;
35- import org .springframework .context .annotation .Bean ;
36- import org .springframework .context .annotation .Configuration ;
37- import feign .Client ;
38- import feign .httpclient .ApacheHttpClient ;
24+
3925import javax .net .ssl .SSLContext ;
26+ import java .io .IOException ;
27+ import java .io .InputStream ;
28+ import java .lang .reflect .Type ;
29+ import java .nio .charset .StandardCharsets ;
4030import java .util .concurrent .TimeUnit ;
4131
42- @ Configuration
4332public class FeignConfiguration {
44- private static Logger logger = LogManager .getLogger (FeignConfiguration .class );
45-
46- private int retryMaxAttempt = 3 ;
47-
48- private int retryMaxInterval = 5 ;
33+ private static final Logger logger = LogManager .getLogger (FeignConfiguration .class );
4934
50- private String ontapFeignMaxConnection = "80" ;
35+ private final int retryMaxAttempt = 3 ;
36+ private final int retryMaxInterval = 5 ;
37+ private final String ontapFeignMaxConnection = "80" ;
38+ private final String ontapFeignMaxConnectionPerRoute = "20" ;
39+ private final JsonMapper jsonMapper ;
5140
52- private String ontapFeignMaxConnectionPerRoute = "20" ;
53-
54- @ Bean
55- public Client client (ApacheHttpClientFactory httpClientFactory ) {
41+ public FeignConfiguration () {
42+ this .jsonMapper = JsonMapper .builder ()
43+ .disable (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES )
44+ .findAndAddModules ()
45+ .build ();
46+ }
5647
48+ public Client createClient () {
5749 int maxConn ;
5850 int maxConnPerRoute ;
5951 try {
6052 maxConn = Integer .parseInt (this .ontapFeignMaxConnection );
6153 } catch (Exception e ) {
62- logger .error ("ontapFeignClient: encounter exception while parse the max connection from env. setting default value " );
54+ logger .error ("ontapFeignClient: parse max connection failed, using default" );
6355 maxConn = 20 ;
6456 }
6557 try {
6658 maxConnPerRoute = Integer .parseInt (this .ontapFeignMaxConnectionPerRoute );
6759 } catch (Exception e ) {
68- logger .error ("ontapFeignClient: encounter exception while parse the max connection per route from env. setting default value " );
60+ logger .error ("ontapFeignClient: parse max connection per route failed, using default" );
6961 maxConnPerRoute = 2 ;
7062 }
71- // Disable Keep Alive for Http Connection
72- logger .debug ("ontapFeignClient: Setting the feign client config values as max connection: {}, max connections per route: {}" , maxConn , maxConnPerRoute );
63+ logger .debug ("ontapFeignClient: maxConn={}, maxConnPerRoute={}" , maxConn , maxConnPerRoute );
7364 ConnectionKeepAliveStrategy keepAliveStrategy = (response , context ) -> 0 ;
74- CloseableHttpClient httpClient = httpClientFactory . createBuilder ()
65+ CloseableHttpClient httpClient = HttpClientBuilder . create ()
7566 .setMaxConnTotal (maxConn )
7667 .setMaxConnPerRoute (maxConnPerRoute )
7768 .setKeepAliveStrategy (keepAliveStrategy )
@@ -83,30 +74,64 @@ public Client client(ApacheHttpClientFactory httpClientFactory) {
8374
8475 private SSLConnectionSocketFactory getSSLSocketFactory () {
8576 try {
86- // The TrustAllStrategy is a strategy used in SSL context configuration that accepts any certificate
8777 SSLContext sslContext = SSLContexts .custom ().loadTrustMaterial (null , new TrustAllStrategy ()).build ();
8878 return new SSLConnectionSocketFactory (sslContext , new NoopHostnameVerifier ());
8979 } catch (Exception ex ) {
9080 throw new RuntimeException (ex );
9181 }
9282 }
9383
84+ public RequestInterceptor createRequestInterceptor () {
85+ return template -> {
86+ logger .info ("Feign Request URL: {}" , template .url ());
87+ logger .info ("HTTP Method: {}" , template .method ());
88+ logger .info ("Headers: {}" , template .headers ());
89+ if (template .body () != null ) {
90+ logger .info ("Body: {}" , new String (template .body (), StandardCharsets .UTF_8 ));
91+ }
92+ };
93+ }
9494
95- @ Bean
96- public RequestInterceptor requestInterceptor () {
97- return new RequestInterceptor () {
95+ public Retryer createRetryer () {
96+ return new Retryer .Default (1000L , retryMaxInterval * 1000L , retryMaxAttempt );
97+ }
98+
99+ public Encoder createEncoder () {
100+ return new Encoder () {
98101 @ Override
99- public void apply (RequestTemplate template ) {
100- logger .info ("Feign Request URL: {}" , template .url ());
101- logger .info ("HTTP Method: {}" , template .method ());
102- logger .info ("Headers: {}" , template .headers ());
103- logger .info ("Body: {}" , template .requestBody ().asString ());
102+ public void encode (Object object , Type bodyType , feign .RequestTemplate template ) throws EncodeException {
103+ if (object == null ) {
104+ template .body (null , StandardCharsets .UTF_8 );
105+ return ;
106+ }
107+ try {
108+ byte [] jsonBytes = jsonMapper .writeValueAsBytes (object );
109+ template .body (jsonBytes , StandardCharsets .UTF_8 );
110+ template .header ("Content-Type" , "application/json" );
111+ } catch (JsonProcessingException e ) {
112+ throw new EncodeException ("Error encoding object to JSON" , e );
113+ }
104114 }
105115 };
106116 }
107117
108- @ Bean
109- public Retryer feignRetryer () {
110- return new Retryer .Default (1000L , retryMaxInterval * 1000L , retryMaxAttempt );
118+ public Decoder createDecoder () {
119+ return new Decoder () {
120+ @ Override
121+ public Object decode (Response response , Type type ) throws IOException , DecodeException {
122+ if (response .body () == null ) {
123+ return null ;
124+ }
125+ String json = null ;
126+ try (InputStream bodyStream = response .body ().asInputStream ()) {
127+ json = new String (bodyStream .readAllBytes (), StandardCharsets .UTF_8 );
128+ logger .debug ("Decoding JSON response: {}" , json );
129+ return jsonMapper .readValue (json , jsonMapper .getTypeFactory ().constructType (type ));
130+ } catch (IOException e ) {
131+ logger .error ("Error decoding JSON response. Status: {}, Raw body: {}" , response .status (), json , e );
132+ throw new DecodeException (response .status (), "Error decoding JSON response" , response .request (), e );
133+ }
134+ }
135+ };
111136 }
112137}
0 commit comments