Skip to content

Commit 078c19a

Browse files
authored
Merge pull request #2306 from digma-ai/support-timeout-in-login-handler
Support timeout in login handler
2 parents 20716ed + 5857cb0 commit 078c19a

File tree

76 files changed

+3721
-1908
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+3721
-1908
lines changed

analytics-provider/src/main/java/org/digma/intellij/plugin/analytics/AnalyticsProviderException.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ public AnalyticsProviderException(Throwable cause) {
1717
super(cause);
1818
}
1919

20+
public AnalyticsProviderException(String message) {
21+
super(message);
22+
}
23+
2024
public int getResponseCode() {
2125
return responseCode;
2226
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.digma.intellij.plugin.analytics;
2+
3+
import javax.annotation.Nonnull;
4+
5+
//provides dynamically changing url
6+
public interface BaseUrlProvider {
7+
8+
@Nonnull
9+
String baseUrl();
10+
11+
void addUrlChangedListener(UrlChangedListener urlChangedListener, int order);
12+
13+
void removeUrlChangedListener(UrlChangedListener urlChangedListener);
14+
15+
16+
interface UrlChangedListener {
17+
void urlChanged(UrlChangedEvent urlChangedEvent);
18+
}
19+
20+
class UrlChangedEvent {
21+
String oldUrl;
22+
String newUrl;
23+
24+
public UrlChangedEvent(String oldUrl, String newUrl) {
25+
this.oldUrl = oldUrl;
26+
this.newUrl = newUrl;
27+
}
28+
}
29+
30+
}
31+
32+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.digma.intellij.plugin.analytics;
2+
3+
public class CantConstructClientException extends AnalyticsProviderException {
4+
5+
public CantConstructClientException(Throwable e) {
6+
super(e);
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.digma.intellij.plugin.analytics;
2+
3+
public class ReplacingClientException extends RuntimeException {
4+
5+
public ReplacingClientException(String message) {
6+
super(message);
7+
}
8+
}

analytics-provider/src/main/java/org/digma/intellij/plugin/analytics/RestAnalyticsProvider.java

Lines changed: 95 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,95 @@
3535
import retrofit2.http.Headers;
3636
import retrofit2.http.*;
3737

38-
import javax.annotation.CheckForNull;
38+
import javax.annotation.*;
3939
import javax.net.ssl.*;
4040
import java.io.*;
4141
import java.security.*;
4242
import java.security.cert.X509Certificate;
4343
import java.util.*;
4444
import java.util.concurrent.TimeUnit;
45+
import java.util.concurrent.atomic.AtomicBoolean;
4546
import java.util.function.*;
4647

47-
public class RestAnalyticsProvider implements AnalyticsProvider, Closeable {
48+
public class RestAnalyticsProvider implements AnalyticsProvider, Closeable, BaseUrlProvider.UrlChangedListener {
4849

4950
public static final ThreadLocal<Long> PERFORMANCE = new ThreadLocal<>();
51+
private final List<AuthenticationProvider> authenticationProviders;
52+
private final Consumer<String> logger;
5053

51-
private final Client client;
52-
private final String apiUrl;
54+
private Client client;
55+
private final BaseUrlProvider baseUrlProvider;
56+
private final AtomicBoolean replacingClient = new AtomicBoolean(false);
57+
private final Object replacingClientLock = new Object();
5358

5459
//this constructor is used only in tests
5560
RestAnalyticsProvider(String baseUrl) {
5661

57-
this(baseUrl, Collections.singletonList(new AuthenticationProvider() {
62+
this(Collections.singletonList(new AuthenticationProvider() {
5863
@CheckForNull
5964
@Override
6065
public String getHeaderName() {
6166
return null;
6267
}
68+
6369
@CheckForNull
6470
@Override
6571
public String getHeaderValue() {
6672
return null;
6773
}
68-
}), System.out::println);
74+
}), System.out::println, new BaseUrlProvider() {
75+
@Nonnull
76+
@Override
77+
public String baseUrl() {
78+
return baseUrl;
79+
}
80+
81+
@Override
82+
public void addUrlChangedListener(UrlChangedListener urlChangedListener, int order) {
83+
84+
}
85+
86+
@Override
87+
public void removeUrlChangedListener(UrlChangedListener urlChangedListener) {
88+
89+
}
90+
}, 1);
91+
}
92+
93+
public RestAnalyticsProvider(List<AuthenticationProvider> authenticationProviders, Consumer<String> logger, BaseUrlProvider baseUrlProvider, int urlChangeOrder) {
94+
this.authenticationProviders = authenticationProviders;
95+
this.logger = logger;
96+
this.baseUrlProvider = baseUrlProvider;
97+
this.client = constructClient(authenticationProviders, logger, baseUrlProvider);
98+
baseUrlProvider.addUrlChangedListener(this, urlChangeOrder);
99+
}
100+
101+
102+
private Client constructClient(List<AuthenticationProvider> authenticationProviders, Consumer<String> logger, BaseUrlProvider baseUrlProvider) {
103+
try {
104+
return createClient(authenticationProviders, logger, baseUrlProvider);
105+
} catch (Throwable e) {
106+
throw new CantConstructClientException(e);
107+
}
69108
}
70109

71-
public RestAnalyticsProvider(String baseUrl, List<AuthenticationProvider> authenticationProviders, Consumer<String> logger) {
72-
this.client = createClient(baseUrl, authenticationProviders, logger);
73-
this.apiUrl = baseUrl;
110+
111+
@Override
112+
public void urlChanged(BaseUrlProvider.UrlChangedEvent urlChangedEvent) {
113+
synchronized (replacingClientLock) {
114+
try {
115+
replacingClient.set(true);
116+
client.close();
117+
client = constructClient(authenticationProviders, logger, baseUrlProvider);
118+
} finally {
119+
replacingClient.set(false);
120+
}
121+
}
74122
}
75123

124+
76125
public String getApiUrl() {
77-
return apiUrl;
126+
return baseUrlProvider.baseUrl();
78127
}
79128

80129
@Override
@@ -360,7 +409,7 @@ public String getSpanInfo(String spanCodeObjectId) {
360409

361410
@Override
362411
public void resetThrottlingStatus() {
363-
execute(() -> client.analyticsProvider.resetThrottlingStatus());
412+
execute(client.analyticsProvider::resetThrottlingStatus);
364413
}
365414

366415
@Override
@@ -400,9 +449,10 @@ private HttpResponse toHttpResponse(okhttp3.Response response) {
400449
var body = response.body();
401450
var headers = response.headers().toMultimap().entrySet().stream()
402451
.filter(i -> !i.getValue().isEmpty())
403-
.collect(HashMap<String, String>::new, (m,i) -> m.put(i.getKey(), i.getValue().get(0)), Map::putAll);
452+
.collect(HashMap<String, String>::new, (m, i) -> m.put(i.getKey(), i.getValue().get(0)), Map::putAll);
404453
var contentLength = body != null ? body.contentLength() : null;
405-
var contentType = body != null && body.contentType() != null ? body.contentType().toString() : null;
454+
MediaType mediaType = body != null ? body.contentType() : null;
455+
var contentType = mediaType != null ? mediaType.toString() : null;
406456
var contentStream = body != null ? body.byteStream() : null;
407457

408458
return new HttpResponse(
@@ -428,6 +478,12 @@ protected static String readEntire(ResponseBody responseBody) {
428478

429479
public <T> T execute(Supplier<Call<T>> supplier) {
430480

481+
//don't want to use locks, just throw calling threads if currently replacing the client as a result of url changed.
482+
//caller should always catch and handle AnalyticsProviderException
483+
if (replacingClient.get()) {
484+
throw new ReplacingClientException("can't serve requests, currently replacing clients");
485+
}
486+
431487
Response<T> response;
432488
try {
433489
Call<T> call = supplier.get();
@@ -450,7 +506,7 @@ public <T> T execute(Supplier<Call<T>> supplier) {
450506
private AnalyticsProviderException createUnsuccessfulResponseException(int code, ResponseBody errorBody) throws IOException {
451507
var errorMessage = errorBody == null ? null : errorBody.string();
452508
if (code == HTTPConstants.UNAUTHORIZED) {
453-
var message = errorMessage != null && !errorMessage.isEmpty() ? errorMessage: "Unauthorized " + code;
509+
var message = errorMessage != null && !errorMessage.isEmpty() ? errorMessage : "Unauthorized " + code;
454510
return new AuthenticationException(code, message);
455511
}
456512

@@ -459,14 +515,15 @@ private AnalyticsProviderException createUnsuccessfulResponseException(int code,
459515
}
460516

461517

462-
private Client createClient(String baseUrl, List<AuthenticationProvider> authenticationProviders, Consumer<String> logger) {
463-
return new Client(baseUrl, authenticationProviders, logger);
518+
private Client createClient(List<AuthenticationProvider> authenticationProviders, Consumer<String> logger, BaseUrlProvider baseUrlProvider) {
519+
return new Client(authenticationProviders, logger, baseUrlProvider);
464520
}
465521

466522

467523
@Override
468524
public void close() throws IOException {
469525
client.close();
526+
baseUrlProvider.removeUrlChangedListener(this);
470527
}
471528

472529

@@ -478,15 +535,17 @@ private static class Client implements Closeable {
478535
private final OkHttpClient okHttpClient;
479536

480537
@SuppressWarnings("MoveFieldAssignmentToInitializer")
481-
public Client(String baseUrl, List<AuthenticationProvider> authenticationProviders, Consumer<String> logger) {
538+
public Client(List<AuthenticationProvider> authenticationProviders, Consumer<String> logger, BaseUrlProvider baseUrlProvider) {
482539

483540
//configure okHttp here if necessary
484541
OkHttpClient.Builder builder = new OkHttpClient.Builder();
485542

486-
if (baseUrl.startsWith("https:")) {
487-
// SSL
488-
applyInsecureSsl(builder);
489-
}
543+
544+
//if (baseUrlProvider.baseUrl().startsWith("https:")) {
545+
// SSL
546+
//we can always applyInsecureSsl even if the schema is http
547+
applyInsecureSsl(builder);
548+
//}
490549

491550

492551
authenticationProviders.forEach(authenticationProvider -> builder.addInterceptor(chain -> {
@@ -506,18 +565,16 @@ public Client(String baseUrl, List<AuthenticationProvider> authenticationProvide
506565
//always add the logging interceptor last, so it will log info from all other interceptors
507566
addLoggingInterceptor(builder, logger);
508567

509-
builder.callTimeout(10, TimeUnit.SECONDS)
510-
.connectTimeout(5, TimeUnit.SECONDS)
511-
.readTimeout(5, TimeUnit.SECONDS);
568+
builder.callTimeout(20, TimeUnit.SECONDS)
569+
.connectTimeout(10, TimeUnit.SECONDS)
570+
.readTimeout(10, TimeUnit.SECONDS);
512571

513572
okHttpClient = builder.build();
514573

515574
var jacksonFactory = JacksonConverterFactory.create(createObjectMapper());
516575

517-
baseUrl = ensureEndsWithSlash(baseUrl);
518-
519576
Retrofit retrofit = new Retrofit.Builder()
520-
.baseUrl(baseUrl)
577+
.baseUrl(ensureEndsWithSlash(baseUrlProvider.baseUrl()))
521578
.client(okHttpClient)
522579
//ScalarsConverterFactory must be the first, it supports serializing to plain String, see getAssets
523580
.addConverterFactory(ScalarsConverterFactory.create())
@@ -528,17 +585,19 @@ public Client(String baseUrl, List<AuthenticationProvider> authenticationProvide
528585
analyticsProvider = retrofit.create(AnalyticsProviderRetrofit.class);
529586
}
530587

588+
531589
private String ensureEndsWithSlash(String baseUrl) {
532590
//if url contains path it must end with slash.
533591
//retrofit will check that in retrofit2.Retrofit.Builder.baseUrl(okhttp3.HttpUrl)
534592
var url = HttpUrl.get(baseUrl);
535593
List<String> pathSegments = url.pathSegments();
536-
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
594+
if (!pathSegments.isEmpty() && !"".equals(pathSegments.get(pathSegments.size() - 1))) {
537595
return baseUrl + "/";
538596
}
539597
return baseUrl;
540598
}
541599

600+
542601
private void addPerformanceInterceptor(OkHttpClient.Builder builder) {
543602
builder.addInterceptor(chain -> {
544603
PERFORMANCE.remove();
@@ -727,7 +786,7 @@ private interface AnalyticsProviderRetrofit {
727786
"Content-Type:application/json"
728787
})
729788
@PUT("CodeAnalytics/insights/start-time")
730-
Call<ResponseBody> setInsightCustomStartTime(
789+
Call<Void> setInsightCustomStartTime(
731790
@Body CustomStartTimeInsightRequest customStartTimeInsightRequest
732791
);
733792

@@ -803,7 +862,7 @@ Call<ResponseBody> setInsightCustomStartTime(
803862
"Content-Type:application/json"
804863
})
805864
@POST("Notifications/read")
806-
Call<ResponseBody> setReadNotificationsTime(@Body SetReadNotificationsRequest setReadNotificationsRequest);
865+
Call<Void> setReadNotificationsTime(@Body SetReadNotificationsRequest setReadNotificationsRequest);
807866

808867
@Headers({
809868
"Accept: application/+json",
@@ -930,28 +989,28 @@ Call<ResponseBody> setInsightCustomStartTime(
930989
"Content-Type:application/json"
931990
})
932991
@POST("Insights/markRead")
933-
Call<ResponseBody> markInsightsAsRead(@Body MarkInsightsAsReadRequest request);
992+
Call<Void> markInsightsAsRead(@Body MarkInsightsAsReadRequest request);
934993

935994
@Headers({
936995
"Accept: application/+json",
937996
"Content-Type:application/json"
938997
})
939998
@POST("Insights/markAllRead")
940-
Call<ResponseBody> markAllInsightsAsRead(@Body MarkAllInsightsAsReadRequest request);
999+
Call<Void> markAllInsightsAsRead(@Body MarkAllInsightsAsReadRequest request);
9411000

9421001
@Headers({
9431002
"Accept: application/+json",
9441003
"Content-Type:application/json"
9451004
})
9461005
@PUT("InsightsActions/dismiss")
947-
Call<ResponseBody> dismissInsight(@Body DismissRequest insightId);
1006+
Call<Void> dismissInsight(@Body DismissRequest insightId);
9481007

9491008
@Headers({
9501009
"Accept: application/+json",
9511010
"Content-Type:application/json"
9521011
})
9531012
@PUT("InsightsActions/unDismiss")
954-
Call<ResponseBody> undismissInsight(@Body UnDismissRequest insightId);
1013+
Call<Void> undismissInsight(@Body UnDismissRequest insightId);
9551014

9561015
@Headers({
9571016
"Accept: application/+json",
@@ -1041,11 +1100,12 @@ Call<ResponseBody> setInsightCustomStartTime(
10411100

10421101
@GET("spans/info")
10431102
Call<String> getSpanInfo(@Query("SpanCodeObjectId") String spanCodeObjectId);
1103+
10441104
@Headers({
10451105
"Accept: application/+json",
10461106
"Content-Type:application/json"
10471107
})
10481108
@POST("PerformanceMetrics/reset-throttling")
1049-
Call<ResponseBody> resetThrottlingStatus();
1109+
Call<Void> resetThrottlingStatus();
10501110
}
10511111
}

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ tasks {
281281

282282
// jvmArgs("-XX:ReservedCodeCacheSize=512M")
283283

284-
maxHeapSize = "2g"
284+
maxHeapSize = "6g"
285285

286286
systemProperties(
287287
"idea.log.trace.categories" to "#org.digma",

0 commit comments

Comments
 (0)