• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 24082290380

07 Apr 2026 12:51PM UTC coverage: 70.47% (-0.2%) from 70.643%
24082290380

Pull #1789

github

web-flow
Merge d94dcce6d into 420453a8c
Pull Request #1789: #1552: add certificates to truststore

4262 of 6688 branches covered (63.73%)

Branch coverage included in aggregate %.

11068 of 15066 relevant lines covered (73.46%)

3.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.04
cli/src/main/java/com/devonfw/tools/ide/network/NetworkStatusImpl.java
1
package com.devonfw.tools.ide.network;
2

3
import java.io.IOException;
4
import java.net.URL;
5
import java.net.URLConnection;
6
import java.util.Locale;
7
import java.util.concurrent.Callable;
8

9
import org.slf4j.Logger;
10
import org.slf4j.LoggerFactory;
11

12
import com.devonfw.tools.ide.cache.CachedValue;
13
import com.devonfw.tools.ide.cli.CliOfflineException;
14
import com.devonfw.tools.ide.context.AbstractIdeContext;
15
import com.devonfw.tools.ide.log.IdeLogLevel;
16

17
/**
18
 * Implementation of {@link NetworkStatus}.
19
 */
20
public class NetworkStatusImpl implements NetworkStatus {
21

22
  private static final Logger LOG = LoggerFactory.getLogger(NetworkStatusImpl.class);
4✔
23

24
  private final AbstractIdeContext context;
25

26
  private NetworkProxy networkProxy;
27

28
  private final String onlineCheckUrl;
29

30
  protected final CachedValue<Throwable> onlineCheck;
31

32
  private static final String ERROR_TEXT_PKIX = "pkix path building failed";
33

34
  /**
35
   * @param ideContext the {@link AbstractIdeContext}.
36
   */
37
  public NetworkStatusImpl(AbstractIdeContext ideContext) {
38
    this(ideContext, null, CachedValue.DEFAULT_RETENTION);
×
39
  }
×
40

41
  /**
42
   * @param context the {@link AbstractIdeContext}.
43
   * @param onlineCheckUrl the URL to test for the online-check.
44
   * @param retention the retention of the {@link CachedValue}.
45
   */
46
  protected NetworkStatusImpl(AbstractIdeContext context, String onlineCheckUrl, long retention) {
2✔
47
    this.context = context;
3✔
48
    if (onlineCheckUrl == null) {
2✔
49
      onlineCheckUrl = "https://www.github.com";
2✔
50
    }
51
    this.onlineCheckUrl = onlineCheckUrl;
3✔
52
    this.onlineCheck = new CachedValue<>(this::doOnlineCheck, retention);
8✔
53
  }
1✔
54

55
  @Override
56
  public boolean isOfflineMode() {
57

58
    return this.context.isOfflineMode();
4✔
59
  }
60

61
  @Override
62
  public boolean isOnline() {
63

64
    return getError() == null;
7✔
65
  }
66

67
  @Override
68
  public Throwable getError() {
69

70
    return this.onlineCheck.get();
5✔
71
  }
72

73
  private Throwable doOnlineCheck() {
74
    configureNetworkProxy();
×
75
    try {
76
      int timeout = 1000;
×
77
      //open a connection to URL and try to retrieve data
78
      //getContent fails if there is no connection
79
      URLConnection connection = new URL(this.onlineCheckUrl).openConnection();
×
80
      connection.setConnectTimeout(timeout);
×
81
      connection.getContent();
×
82
      return null;
×
83
    } catch (Exception e) {
×
84
      if (LOG.isDebugEnabled()) {
×
85
        LOG.debug("Error when trying to connect to {}", this.onlineCheckUrl, e);
×
86
      }
87
      return e;
×
88
    }
89
  }
90

91
  private void configureNetworkProxy() {
92

93
    if (this.networkProxy == null) {
3✔
94
      this.networkProxy = new NetworkProxy(this.context);
7✔
95
      this.networkProxy.configure();
3✔
96
    }
97
  }
1✔
98

99
  @Override
100
  public void logStatusMessage() {
101

102
    if (isOfflineMode()) {
3✔
103
      LOG.warn("You are offline because you have enabled offline mode via CLI option.");
3✔
104
      return;
1✔
105
    }
106
    Throwable error = getError();
3✔
107
    if (error == null) {
2✔
108
      IdeLogLevel.SUCCESS.log(LOG, "You are online.");
4✔
109
      return;
1✔
110
    }
111
    String message = "You are offline because of the following error:";
2✔
112
    if (LOG.isDebugEnabled()) {
3!
113
      LOG.error(message, error);
5✔
114
    } else {
115
      LOG.error(message);
×
116
      LOG.error(error.toString());
×
117
    }
118
    if (isTlsTrustIssue(error)) {
4✔
119
      logTruststoreFixHint();
3✔
120
    } else {
121
      IdeLogLevel.INTERACTION.log(LOG, "Please check potential proxy settings, ensure you are properly connected to the internet and retry this operation.");
4✔
122
    }
123
  }
1✔
124

125
  @Override
126
  public <T> T invokeNetworkTask(Callable<T> callable, String uri) {
127

128
    if (isOfflineMode()) {
3!
129
      throw CliOfflineException.ofDownloadViaUrl(uri);
×
130
    }
131
    configureNetworkProxy();
2✔
132
    try {
133
      return callable.call();
3✔
134
    } catch (IOException e) {
×
135
      this.onlineCheck.set(e);
×
136
      if (isTlsTrustIssue(e)) {
×
137
        logTruststoreFixHint();
×
138
      }
139
      throw new IllegalStateException("Network error whilst communicating to " + uri, e);
×
140
    } catch (Exception e) {
×
141
      throw new IllegalStateException("Unexpected checked exception whilst communicating to " + uri, e);
×
142
    }
143
  }
144

145
  private void logTruststoreFixHint() {
146

147
    LOG.warn(
3✔
148
        "You are having TLS trust issues (PKIX/certificate-path/SSL handshake). As a workaround you can create and configure a truststore via the following command (replace <url> with the failing endpoint):\nide fix-vpn-tls-problem <url>");
149
    IdeLogLevel.INTERACTION.log(LOG, "https://github.com/devonfw/IDEasy/blob/main/documentation/proxy-support.adoc#tls-certificate-issues");
4✔
150
  }
1✔
151

152
  boolean isTlsTrustIssue(Throwable throwable) {
153
    Throwable current = throwable;
2✔
154
    while (current != null) {
2✔
155
      String message = current.getMessage();
3✔
156
      if (containsTlsTrustIndicator(message)) {
4✔
157
        return true;
2✔
158
      }
159
      current = current.getCause();
3✔
160
    }
1✔
161
    return false;
2✔
162
  }
163

164
  boolean containsTlsTrustIndicator(String text) {
165
    if ((text == null) || text.isBlank()) {
5!
166
      return false;
×
167
    }
168
    String normalized = text.toLowerCase(Locale.ROOT);
4✔
169
    return normalized.contains(ERROR_TEXT_PKIX);
4✔
170
  }
171

172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc