add format version to stepic format
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / stepic / EduStepicClient.java
1 package com.jetbrains.edu.learning.stepic;
2
3 import com.google.gson.FieldNamingPolicy;
4 import com.google.gson.Gson;
5 import com.google.gson.GsonBuilder;
6 import com.intellij.openapi.diagnostic.Logger;
7 import com.intellij.util.net.HttpConfigurable;
8 import com.intellij.util.net.ssl.CertificateManager;
9 import com.jetbrains.edu.learning.StudySerializationUtils;
10 import org.apache.http.HttpEntity;
11 import org.apache.http.HttpHost;
12 import org.apache.http.HttpStatus;
13 import org.apache.http.StatusLine;
14 import org.apache.http.client.methods.CloseableHttpResponse;
15 import org.apache.http.client.methods.HttpGet;
16 import org.apache.http.impl.DefaultConnectionReuseStrategy;
17 import org.apache.http.impl.client.CloseableHttpClient;
18 import org.apache.http.impl.client.HttpClientBuilder;
19 import org.apache.http.impl.client.HttpClients;
20 import org.apache.http.util.EntityUtils;
21 import org.jetbrains.annotations.NotNull;
22
23 import javax.net.ssl.SSLContext;
24 import javax.net.ssl.TrustManager;
25 import javax.net.ssl.X509TrustManager;
26 import java.io.IOException;
27 import java.net.InetSocketAddress;
28 import java.net.Proxy;
29 import java.net.URI;
30 import java.security.KeyManagementException;
31 import java.security.NoSuchAlgorithmException;
32 import java.security.SecureRandom;
33 import java.security.cert.X509Certificate;
34 import java.util.List;
35
36 public class EduStepicClient {
37   private static final Logger LOG = Logger.getInstance(EduStepicClient.class.getName());
38   private static CloseableHttpClient ourClient;
39
40   private EduStepicClient() {
41   }
42
43   @NotNull
44   public static CloseableHttpClient getHttpClient() {
45     if (ourClient == null) {
46       initializeClient();
47     }
48     return ourClient;
49   }
50
51   public static <T> T getFromStepic(String link, final Class<T> container) throws IOException {
52     return getFromStepic(link, container, getHttpClient());
53   }
54
55   static <T> T getFromStepic(String link, final Class<T> container, @NotNull final CloseableHttpClient client) throws IOException {
56     if (!link.startsWith("/")) link = "/" + link;
57     final HttpGet request = new HttpGet(EduStepicNames.STEPIC_API_URL + link);
58     if (ourClient == null) {
59       initializeClient();
60     }
61
62     final CloseableHttpResponse response = client.execute(request);
63     final StatusLine statusLine = response.getStatusLine();
64     final HttpEntity responseEntity = response.getEntity();
65     final String responseString = responseEntity != null ? EntityUtils.toString(responseEntity) : "";
66     EntityUtils.consume(responseEntity);
67     if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
68       throw new IOException("Stepic returned non 200 status code " + responseString);
69     }
70     return deserializeStepicResponse(container, responseString);
71   }
72
73   static <T> T deserializeStepicResponse(Class<T> container, String responseString) {
74     Gson gson = new GsonBuilder().registerTypeAdapter(StepicWrappers.StepOptions.class, new StudySerializationUtils.Json.StepicStepOptionsAdapter()).
75       setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").
76       setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
77     return gson.fromJson(responseString, container);
78   }
79
80   private static void initializeClient() {
81     if (ourClient == null) {
82       final HttpClientBuilder builder = getBuilder();
83       ourClient = builder.build();
84     }
85   }
86
87   @NotNull
88   private static TrustManager[] trustAllCerts() {
89     // Create a trust manager that does not validate certificate for this connection
90     return new TrustManager[]{new X509TrustManager() {
91       public X509Certificate[] getAcceptedIssuers() {
92         return null;
93       }
94
95       public void checkClientTrusted(X509Certificate[] certs, String authType) {
96       }
97
98       public void checkServerTrusted(X509Certificate[] certs, String authType) {
99       }
100     }};
101   }
102
103   @NotNull
104   private static HttpClientBuilder getBuilder() {
105     final HttpClientBuilder builder = HttpClients.custom().setSslcontext(CertificateManager.getInstance().getSslContext()).
106       setMaxConnPerRoute(100000).setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE);
107
108     final HttpConfigurable proxyConfigurable = HttpConfigurable.getInstance();
109     final List<Proxy> proxies = proxyConfigurable.getOnlyBySettingsSelector().select(URI.create(EduStepicNames.STEPIC_URL));
110     final InetSocketAddress address = proxies.size() > 0 ? (InetSocketAddress)proxies.get(0).address() : null;
111     if (address != null) {
112       builder.setProxy(new HttpHost(address.getHostName(), address.getPort()));
113     }
114     final TrustManager[] trustAllCerts = trustAllCerts();
115     try {
116       SSLContext sslContext = SSLContext.getInstance("TLS");
117       sslContext.init(null, trustAllCerts, new SecureRandom());
118       builder.setSslcontext(sslContext);
119     }
120     catch (NoSuchAlgorithmException | KeyManagementException e) {
121       LOG.error(e.getMessage());
122     }
123     return builder;
124   }
125 }