diff --git a/build.gradle.kts b/build.gradle.kts
index 5d4e059..9f0b07e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,34 +1,47 @@
plugins {
id("java")
- id("org.jetbrains.intellij") version "1.11.0"
+ id("org.jetbrains.intellij.platform") version "2.0.1"
}
group = "com.codealike.client.intellij"
-
-
-version = "1.7.3.0"
-
-
-
+version = "1.8.0.1"
repositories {
mavenCentral()
+ intellijPlatform{
+ defaultRepositories()
+ }
}
-val libs: Configuration by configurations.creating
-
// Configure Gradle IntelliJ Plugin
-// Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
-intellij {
-
-
- version.set("2023.3.3")
+// Read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html
+intellijPlatform {
+
+ pluginConfiguration{
+ ideaVersion {
+ sinceBuild = "233"
+ untilBuild = "241.*"
+ }
+ }
+ publishing{
+ token = System.getenv("PUBLISH_TOKEN")
+ }
- type.set("IC") // Target IDE Platform
+ signing{
+ certificateChain = System.getenv("CERTIFICATE_CHAIN")
+ privateKey = System.getenv("PRIVATE_KEY")
+ password = System.getenv("PRIVATE_KEY_PASSWORD")
+ }
+}
- plugins.set(listOf("com.intellij.java"))
+dependencies {
+ intellijPlatform {
+ create("IC", "2023.3.3")
+ bundledPlugin("com.intellij.java")
+ instrumentationTools()
+ }
}
tasks {
@@ -38,49 +51,7 @@ tasks {
targetCompatibility = "17"
}
- patchPluginXml {
- sinceBuild.set("222")
- untilBuild.set("233.*")
- }
-
- signPlugin {
- certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
- privateKey.set(System.getenv("PRIVATE_KEY"))
- password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
- }
-
- publishPlugin {
- token.set(System.getenv("PUBLISH_TOKEN"))
- }
-
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
- from(libs.map { if (it.isDirectory) it else zipTree(it) })
}
}
-
-dependencies {
- libs("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0")
- implementation("jakarta.activation:jakarta.activation-api:2.1.0")
- implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
- implementation("jakarta.inject:jakarta.inject-api:2.0.1.MR")
- libs("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2")
- implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
- implementation("com.fasterxml.jackson.core:jackson-annotations:2.14.0")
- implementation("com.fasterxml.jackson.core:jackson-core:2.14.0")
- implementation("org.apache.httpcomponents:httpclient:4.5.14")
- implementation("org.apache.httpcomponents:httpcore:4.4.16")
- implementation("cglib:cglib:3.3.0")
- implementation("com.google.guava:guava:31.1-jre")
- implementation("org.glassfish.hk2:hk2:3.1.0")
- implementation("org.glassfish.hk2:hk2-utils:3.1.0")
- implementation("org.glassfish.hk2:hk2-locator:3.1.0")
- libs("org.glassfish.jersey.core:jersey-client:3.1.5")
- implementation("org.glassfish.jersey.core:jersey-common:3.1.5")
- implementation("org.glassfish.jersey.inject:jersey-hk2:3.1.5")
- libs("org.osgi:osgi.core:8.0.0")
- implementation("log4j:log4j:1.2.17")
- libs("joda-time:joda-time:2.12.2")
- implementation("nekohtml:nekohtml:1.9.6.2")
- configurations.implementation.get().extendsFrom(libs)
-}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ae04661..15de902 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/java/com/codealike/client/core/api/ApiClient.java b/src/main/java/com/codealike/client/core/api/ApiClient.java
index ffd0c25..681c730 100644
--- a/src/main/java/com/codealike/client/core/api/ApiClient.java
+++ b/src/main/java/com/codealike/client/core/api/ApiClient.java
@@ -3,26 +3,32 @@
*/
package com.codealike.client.core.api;
-import com.codealike.client.core.internal.dto.*;
+import com.codealike.client.core.internal.dto.ActivityInfo;
+import com.codealike.client.core.internal.dto.HealthInfo;
+import com.codealike.client.core.internal.dto.PluginSettingsInfo;
+import com.codealike.client.core.internal.dto.ProfileInfo;
+import com.codealike.client.core.internal.dto.SolutionContextInfo;
+import com.codealike.client.core.internal.dto.UserConfigurationInfo;
+import com.codealike.client.core.internal.dto.Version;
import com.codealike.client.core.internal.startup.PluginContext;
+import com.codealike.client.core.internal.utils.LogManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
-import jakarta.ws.rs.ProcessingException;
-import jakarta.ws.rs.client.*;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import org.glassfish.jersey.client.ClientProperties;
+import org.jetbrains.annotations.NotNull;
-import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
-import java.net.ConnectException;
+import javax.net.ssl.X509TrustManager;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.time.Duration;
import java.util.UUID;
/**
@@ -32,16 +38,20 @@
* @version 1.6.0.0
*/
public class ApiClient {
+ private static final LogManager LOG = LogManager.INSTANCE;
- // Headers for API authentication
private static final String X_EAUTH_CLIENT_HEADER = "X-Eauth-Client";
private static final String X_EAUTH_TOKEN_HEADER = "X-Api-Token";
- public static final String X_EAUTH_IDENTITY_HEADER = "X-Api-Identity";
- // Number of API retries
- public static final int MAX_RETRIES = 5;
- private final WebTarget apiTarget;
- private String identity;
- private String token;
+ private static final String X_EAUTH_IDENTITY_HEADER = "X-Api-Identity";
+
+ private static final int CONNECT_TIMEOUT = 30000;
+ private static final int READ_TIMEOUT = 5000;
+
+ private final HttpClient httpClient;
+ private final String apiUrl;
+
+ private final String identity;
+ private final String token;
/**
* Create a new API client. Used to communicate with the Codealike remote server.
@@ -62,64 +72,80 @@ public static ApiClient tryCreateNew(String identity, String token) throws KeyMa
* @throws KeyManagementException if any error with token occurs
*/
public static ApiClient tryCreateNew() throws KeyManagementException {
- return new ApiClient();
+ return new ApiClient("", "");
}
/**
- * API Client constructor. Used to communicate with the Codealike remote server.
+ * Constructor for `ApiClient` class.
+ *
+ * It initializes the HttpClient, apiUrl, identity, and token fields.
*
- * @throws KeyManagementException if any error with token occurs
+ * @param identity A String representing the identity, if it's null it will be assigned an empty string
+ * @param token A String representing the token, if it's null it will be assigned an empty string
+ * @throws KeyManagementException if a failure occurred during the SSL context configuration in the HttpClient
*/
- protected ApiClient() throws KeyManagementException {
- ClientBuilder builder = ClientBuilder.newBuilder();
- TrustManager[] certs = new TrustManager[]{new javax.net.ssl.X509TrustManager() {
+ private ApiClient(String identity, String token) throws KeyManagementException {
+ this.httpClient = createHttpClient();
+ this.apiUrl = PluginContext.getInstance().getConfiguration().getApiUrl();
+ this.identity = identity != null ? identity : "";
+ this.token = token != null ? token : "";
+ }
+
+ /**
+ * Factory method that creates and returns an HttpClient object with specified settings.
+ *
+ * @return HttpClient which is configured for SSL context, HTTP version, connection timeout, and follow redirects
+ * @throws KeyManagementException if a failure occurred during retrieving or setting SSL Context or SSL context initialization
+ */
+ private HttpClient createHttpClient() throws KeyManagementException {
+ TrustManager[] trustManagers = createTrustManagers();
+ SSLContext sslContext = createSslContext(trustManagers);
+
+ return HttpClient.newBuilder()
+ .sslContext(sslContext)
+ .version(HttpClient.Version.HTTP_2)
+ .connectTimeout(Duration.ofMillis(CONNECT_TIMEOUT))
+ .followRedirects(HttpClient.Redirect.NORMAL)
+ .build();
+ }
+
+ /**
+ * Factory method that creates and returns an array of TrustManager objects with custom settings.
+ *
+ * @return Array of TrustManager objects
+ */
+ private TrustManager[] createTrustManagers() {
+ return new TrustManager[]{new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[]{};
+ return new X509Certificate[0];
}
@Override
- public void checkServerTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
- public void checkClientTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
}};
-
- SSLContext sslContext = null;
- try {
- sslContext = SSLContext.getInstance("SSL");
- sslContext.init(null, certs, new SecureRandom());
- } catch (NoSuchAlgorithmException e1) {
- e1.printStackTrace();
- }
-
- builder.sslContext(sslContext).hostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier());
-
- Client client = builder.build();
- client.property(ClientProperties.CONNECT_TIMEOUT, 30000);
- client.property(ClientProperties.READ_TIMEOUT, 5000);
-
- apiTarget = client.target(PluginContext.getInstance().getConfiguration().getApiUrl());
- this.identity = "";
- this.token = "";
}
/**
- * API Client constructor.
+ * Factory method that creates and returns an SSLContext object with specified TrustManagers.
*
- * @param identity the user identity
- * @param token the user token
- * @throws KeyManagementException if any error with token occurs
+ * @param trustManagers an array of trust managers to use for initializing the SSL context
+ * @return SSLContext which is configured with the given trust managers
+ * @throws KeyManagementException if a failure occurred during initializing the SSL context
*/
- protected ApiClient(String identity, String token) throws KeyManagementException {
- this();
- if (identity != null && token != null) {
- this.identity = identity;
- this.token = token;
+ private SSLContext createSslContext(TrustManager[] trustManagers) throws KeyManagementException {
+ try {
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustManagers, new SecureRandom());
+ return sslContext;
+ } catch (NoSuchAlgorithmException | KeyManagementException exception) {
+ LOG.logWarn("Error initializing SSL context: " + exception.getMessage());
+ throw new KeyManagementException("Failed to initialize SSL context", exception);
}
}
@@ -130,105 +156,103 @@ protected ApiClient(String identity, String token) throws KeyManagementException
*/
public static ApiResponse getPluginSettings() {
ObjectMapper mapper = new ObjectMapper();
- ClientBuilder builder = ClientBuilder.newBuilder();
- Client client = builder.build();
- client.property(ClientProperties.CONNECT_TIMEOUT, 30000);
- client.property(ClientProperties.READ_TIMEOUT, 5000);
+ HttpClient client = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofMillis(CONNECT_TIMEOUT))
+ .build();
- WebTarget pluginSettingsTarget = client.target("https://codealike.com/api/v2/public/PluginsConfiguration");
-
- Invocation.Builder invocationBuilder = pluginSettingsTarget.request(
- MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("https://codealike.com/api/v2/public/PluginsConfiguration"))
+ .header("Accept", "application/json")
+ .timeout(Duration.ofMillis(READ_TIMEOUT))
+ .GET()
+ .build();
try {
- Response response;
- try {
- response = invocationBuilder.get();
- } catch (Exception e) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- }
-
- if (response.getStatusInfo().getStatusCode() == Response.Status.OK.getStatusCode()) {
- // process response to get a valid json string representation
- String serializedObject = response.readEntity(String.class);
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
+ if (response.statusCode() == 200) {
+ String serializedObject = response.body();
String normalizedObject = serializedObject.substring(1, serializedObject.length() - 1).replace("\\", "");
- // parse the json object to get a valid plugin settings object
PluginSettingsInfo pluginSettingsInfo = mapper.readValue(normalizedObject, PluginSettingsInfo.class);
-
if (pluginSettingsInfo != null) {
- return new ApiResponse<>(
- response.getStatus(), response.getStatusInfo()
- .getReasonPhrase(), pluginSettingsInfo);
+ return new ApiResponse<>(response.statusCode(), response.headers()
+ .firstValue("reason").orElse("OK"), pluginSettingsInfo);
} else {
return new ApiResponse<>(ApiResponse.Status.ClientError,
"Problem parsing data from the server.");
}
} else {
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
+ return new ApiResponse<>(response.statusCode(), response.headers()
+ .firstValue("reason").orElse("Error"));
}
- } catch (Exception e) {
+ } catch (Exception exception) {
return new ApiResponse<>(ApiResponse.Status.ClientError,
- String.format("Problem parsing data from the server. %s",
- e.getMessage()));
+ String.format("Problem parsing data from the server: %s", exception.getMessage()));
}
}
/**
- * Check API health.
+ * Log the plugin health information to the remote server.
*
- * @return the {@link ApiResponse} instance
+ * @param healthInfo the health information object to update
*/
- public ApiResponse health() {
+ public void logHealth(HealthInfo healthInfo) {
try {
- WebTarget target = apiTarget.path("health");
-
- Invocation.Builder invocationBuilder = target
- .request(MediaType.APPLICATION_JSON);
- Response response = invocationBuilder.get();
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
- } catch (ProcessingException e) {
- if (e.getCause() != null
- && e.getCause() instanceof ConnectException) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- } else {
- return new ApiResponse<>(ApiResponse.Status.ClientError);
- }
+ URI uri = URI.create(apiUrl + "/health");
+
+ String healthInfoLog = serializeDataToJson(healthInfo);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(uri)
+ .header("Accept", "application/json")
+ .header("Content-Type", "application/json")
+ .header(X_EAUTH_IDENTITY_HEADER, this.identity)
+ .header(X_EAUTH_TOKEN_HEADER, this.token)
+ .header(X_EAUTH_CLIENT_HEADER, "intellij")
+ .timeout(Duration.ofMillis(READ_TIMEOUT))
+ .PUT(HttpRequest.BodyPublishers.ofString(healthInfoLog))
+ .build();
+
+ HttpClient client = HttpClient.newHttpClient();
+ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.discarding());
+
+ int statusCode = response.statusCode();
+ String reasonPhrase = response.headers().firstValue("reason").orElse("No reason provided");
+
+ LOG.logInfo("Health log response: " + statusCode + " - " + reasonPhrase);
+
+ } catch (JsonProcessingException exception) {
+ LOG.logWarn("Error processing JSON for health log: " + exception.getMessage());
+ } catch (Exception exception) {
+ LOG.logWarn("Error sending health log request: " + exception.getMessage());
}
}
/**
- * Log the plugin health information to the remote server.
+ * Do an account authentication using the Codealike token.
*
- * @param healthInfo the health information object to update
* @return the {@link ApiResponse} instance
*/
- public ApiResponse logHealth(HealthInfo healthInfo) {
+ public ApiResponse tokenAuthenticate() {
try {
- WebTarget target = apiTarget.path("health");
-
- ObjectWriter writer = PluginContext.getInstance().getJsonWriter();
- String healthInfoLog = writer.writeValueAsString(healthInfo);
-
- Invocation.Builder invocationBuilder = target.request().accept(
- MediaType.APPLICATION_JSON);
- addHeaders(invocationBuilder);
-
- Response response;
- try {
- response = invocationBuilder.put(Entity.entity(healthInfoLog,
- MediaType.APPLICATION_JSON));
- } catch (Exception e) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- }
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
- } catch (JsonProcessingException e) {
- return new ApiResponse<>(ApiResponse.Status.ClientError,
- String.format("Problem parsing data from the server. %s",
- e.getMessage()));
+ URI uri = URI.create(apiUrl + "/account/" + this.identity + "/authorized");
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(uri)
+ .header("Accept", "application/json")
+ .header(X_EAUTH_IDENTITY_HEADER, this.identity)
+ .header(X_EAUTH_TOKEN_HEADER, this.token)
+ .header(X_EAUTH_CLIENT_HEADER, "intellij")
+ .timeout(Duration.ofMillis(READ_TIMEOUT))
+ .GET()
+ .build();
+
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.discarding());
+
+ return new ApiResponse<>(response.statusCode(), response.headers().firstValue("reason").orElse("OK"));
+ } catch (Exception exception) {
+ LOG.logWarn("Error during token authentication " + exception.getMessage());
+ return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
}
}
@@ -238,8 +262,8 @@ public ApiResponse logHealth(HealthInfo healthInfo) {
* @return the {@link ApiResponse} instance with {@link Version} information
*/
public ApiResponse version() {
- WebTarget target = apiTarget.path("version").queryParam("client", "intellij");
- return doGet(target, Version.class);
+ String path = "/version?client=intellij";
+ return get(path, Version.class);
}
/**
@@ -249,8 +273,8 @@ public ApiResponse version() {
* @return the {@link ApiResponse} instance with {@link SolutionContextInfo} information
*/
public ApiResponse getSolutionContext(UUID projectId) {
- WebTarget target = apiTarget.path("solution").path(projectId.toString());
- return doGet(target, SolutionContextInfo.class);
+ String path = "/solution/" + projectId.toString();
+ return get(path, SolutionContextInfo.class);
}
/**
@@ -260,8 +284,8 @@ public ApiResponse getSolutionContext(UUID projectId) {
* @return the {@link ApiResponse} instance with {@link ProfileInfo} information
*/
public ApiResponse getProfile(String username) {
- WebTarget target = apiTarget.path("account").path(username).path("profile");
- return doGet(target, ProfileInfo.class);
+ String path = "/account/" + username + "/profile";
+ return get(path, ProfileInfo.class);
}
/**
@@ -271,8 +295,8 @@ public ApiResponse getProfile(String username) {
* @return the {@link ApiResponse} instance with {@link UserConfigurationInfo} information
*/
public ApiResponse getUserConfiguration(String username) {
- WebTarget target = apiTarget.path("account").path(username).path("config");
- return doGet(target, UserConfigurationInfo.class);
+ String path = "/account/" + username + "/config";
+ return get(path, UserConfigurationInfo.class);
}
/**
@@ -283,31 +307,8 @@ public ApiResponse getUserConfiguration(String username)
* @return the {@link ApiResponse} instance
*/
public ApiResponse registerProjectContext(UUID projectId, String name) {
- try {
- SolutionContextInfo solutionContext = new SolutionContextInfo(
- projectId, name);
- WebTarget target = apiTarget.path("solution");
-
- ObjectWriter writer = PluginContext.getInstance().getJsonWriter();
- String solutionAsJson = writer.writeValueAsString(solutionContext);
- Invocation.Builder invocationBuilder = target.request().accept(
- MediaType.APPLICATION_JSON);
- addHeaders(invocationBuilder);
-
- Response response;
- try {
- response = invocationBuilder.post(Entity.entity(solutionAsJson,
- MediaType.APPLICATION_JSON));
- } catch (Exception e) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- }
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
- } catch (JsonProcessingException e) {
- return new ApiResponse<>(ApiResponse.Status.ClientError,
- String.format("Problem parsing data from the server. %s",
- e.getMessage()));
- }
+ String path = "/solution";
+ return post(path, new SolutionContextInfo(projectId, name));
}
/**
@@ -317,104 +318,90 @@ public ApiResponse registerProjectContext(UUID projectId, String name) {
* @return the {@link ApiResponse} instance
*/
public ApiResponse postActivityInfo(ActivityInfo info) {
- try {
- WebTarget target = apiTarget.path("activity");
-
- ObjectWriter writer = PluginContext.getInstance().getJsonWriter();
- String activityInfoAsJson = writer.writeValueAsString(info);
- Invocation.Builder invocationBuilder = target.request().accept(
- MediaType.APPLICATION_JSON);
- addHeaders(invocationBuilder);
-
- Response response;
- try {
- response = invocationBuilder.post(Entity.entity(
- activityInfoAsJson, MediaType.APPLICATION_JSON));
- } catch (Exception e) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- }
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
- } catch (JsonProcessingException e) {
- return new ApiResponse<>(ApiResponse.Status.ClientError,
- String.format("Problem parsing data from the server. %s",
- e.getMessage()));
- }
+ String path = "/activity";
+ return post(path, info);
}
/**
- * Do an account authentication using the Codealike token.
- *
- * @return the {@link ApiResponse} instance
+ * Private method to do an API POST.
*/
- public ApiResponse tokenAuthenticate() {
- WebTarget target = apiTarget.path("account").path(this.identity)
- .path("authorized");
- Invocation.Builder invocationBuilder = target.request(
- MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
-
- addHeaders(invocationBuilder);
-
- Response response;
+ @NotNull
+ private ApiResponse post(String path, Object data) {
try {
- response = invocationBuilder.get();
+ URI uri = URI.create(apiUrl + path);
+ String jsonData = serializeDataToJson(data);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(uri)
+ .header("Accept", "application/json")
+ .header("Content-Type", "application/json")
+ .header(X_EAUTH_IDENTITY_HEADER, this.identity)
+ .header(X_EAUTH_TOKEN_HEADER, this.token)
+ .header(X_EAUTH_CLIENT_HEADER, "intellij")
+ .timeout(Duration.ofMillis(READ_TIMEOUT))
+ .POST(HttpRequest.BodyPublishers.ofString(jsonData))
+ .build();
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.discarding());
+
+ return new ApiResponse<>(response.statusCode(),
+ response.headers().firstValue("reason").orElse("OK"));
+ } catch (JsonProcessingException e) {
+ return new ApiResponse<>(ApiResponse.Status.ClientError,
+ String.format("Problem parsing data to JSON: %s", e.getMessage()));
} catch (Exception e) {
return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
}
- return new ApiResponse<>(response.getStatus(), response.getStatusInfo()
- .getReasonPhrase());
- }
-
- /**
- * Private method to add headers to request.
- */
- private void addHeaders(Invocation.Builder invocationBuilder) {
- invocationBuilder.header(X_EAUTH_IDENTITY_HEADER, this.identity);
- invocationBuilder.header(X_EAUTH_TOKEN_HEADER, this.token);
- invocationBuilder.header(X_EAUTH_CLIENT_HEADER, "intellij");
}
/**
* Private method to do an API GET.
*/
- private ApiResponse doGet(WebTarget target, Class type) {
- Invocation.Builder invocationBuilder = target.request(
- MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
- addHeaders(invocationBuilder);
-
+ private ApiResponse get(String path, Class type) {
try {
- Response response;
- try {
- response = invocationBuilder.get();
- } catch (Exception e) {
- return new ApiResponse<>(ApiResponse.Status.ConnectionProblems);
- }
-
- if (response.getStatusInfo().getStatusCode() == Response.Status.OK
- .getStatusCode()) {
- String solutionContextInfoSerialized = response
- .readEntity(String.class);
- ObjectMapper mapper = PluginContext.getInstance()
- .getJsonMapper();
- T contextInfo = mapper.readValue(
- solutionContextInfoSerialized,
- type);
+ URI uri = URI.create(apiUrl + path);
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(uri)
+ .header("Accept", "application/json")
+ .header("Content-Type", "application/json")
+ .header(X_EAUTH_IDENTITY_HEADER, this.identity)
+ .header(X_EAUTH_TOKEN_HEADER, this.token)
+ .header(X_EAUTH_CLIENT_HEADER, "intellij")
+ .timeout(Duration.ofMillis(READ_TIMEOUT))
+ .GET()
+ .build();
+
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+ if (response.statusCode() == 200) {
+ ObjectMapper mapper = PluginContext.getInstance().getJsonMapper();
+ T contextInfo = mapper.readValue(response.body(), type);
if (contextInfo != null) {
- return new ApiResponse<>(
- response.getStatus(), response.getStatusInfo()
- .getReasonPhrase(), contextInfo);
+ return new ApiResponse<>(response.statusCode(),
+ response.headers().firstValue("reason").orElse("OK"), contextInfo);
} else {
return new ApiResponse<>(ApiResponse.Status.ClientError,
"Problem parsing data from the server.");
}
} else {
- return new ApiResponse<>(response.getStatus(), response
- .getStatusInfo().getReasonPhrase());
+ return new ApiResponse<>(response.statusCode(),
+ response.headers().firstValue("reason").orElse("Error"));
}
- } catch (Exception e) {
+ } catch (Exception exception) {
return new ApiResponse<>(ApiResponse.Status.ClientError,
- String.format("Problem parsing data from the server. %s",
- e.getMessage()));
+ String.format("Problem parsing data from the server: %s", exception.getMessage()));
}
}
+
+ /**
+ * Converts a given object to its JSON representation.
+ *
+ * @param data the object that needs to be converted to JSON.
+ * @return a String containing the JSON representation of the input object.
+ * @throws JsonProcessingException if the input object could not be converted to JSON.
+ */
+ private String serializeDataToJson(Object data) throws JsonProcessingException {
+ ObjectWriter writer = PluginContext.getInstance().getJsonWriter();
+ return writer.writeValueAsString(data);
+ }
}
diff --git a/src/main/java/com/codealike/client/core/internal/dto/ActivityEntryInfo.java b/src/main/java/com/codealike/client/core/internal/dto/ActivityEntryInfo.java
index 2c64048..4225ff8 100644
--- a/src/main/java/com/codealike/client/core/internal/dto/ActivityEntryInfo.java
+++ b/src/main/java/com/codealike/client/core/internal/dto/ActivityEntryInfo.java
@@ -1,22 +1,18 @@
package com.codealike.client.core.internal.dto;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
-
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.UUID;
public class ActivityEntryInfo {
private UUID parentId;
- private DateTime start;
- private DateTime end;
+ private OffsetDateTime start;
+ private OffsetDateTime end;
private ActivityType type;
- private Period duration;
+ private Duration duration;
private CodeContextInfo context;
- public ActivityEntryInfo() {
- }
-
public ActivityEntryInfo(UUID parentId) {
this.parentId = parentId;
}
@@ -45,27 +41,27 @@ public void setType(ActivityType type) {
this.type = type;
}
- public DateTime getStart() {
+ public OffsetDateTime getStart() {
return start;
}
- public void setStart(DateTime start) {
+ public void setStart(OffsetDateTime start) {
this.start = start;
}
- public DateTime getEnd() {
+ public OffsetDateTime getEnd() {
return end;
}
- public void setEnd(DateTime end) {
+ public void setEnd(OffsetDateTime end) {
this.end = end;
}
- public Period getDuration() {
+ public Duration getDuration() {
return duration;
}
- public void setDuration(Period duration) {
+ public void setDuration(Duration duration) {
this.duration = duration;
}
diff --git a/src/main/java/com/codealike/client/core/internal/dto/ActivityInfo.java b/src/main/java/com/codealike/client/core/internal/dto/ActivityInfo.java
index b927f6c..47dfeee 100644
--- a/src/main/java/com/codealike/client/core/internal/dto/ActivityInfo.java
+++ b/src/main/java/com/codealike/client/core/internal/dto/ActivityInfo.java
@@ -1,8 +1,8 @@
package com.codealike.client.core.internal.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
@@ -17,13 +17,10 @@ public class ActivityInfo {
private String instance;
private UUID solutionId;
private UUID batchId;
- private DateTime batchStart;
- private DateTime batchEnd;
+ private OffsetDateTime batchStart;
+ private OffsetDateTime batchEnd;
- public ActivityInfo() {
- }
-
- public ActivityInfo(String instance, UUID solutionId, UUID batchId, DateTime batchStart, DateTime batchEnd) {
+ public ActivityInfo(String instance, UUID solutionId, UUID batchId, OffsetDateTime batchStart, OffsetDateTime batchEnd) {
this.instance = instance;
this.solutionId = solutionId;
this.batchId = batchId;
@@ -109,25 +106,22 @@ public boolean isValid() {
// if (this.projects == null || this.projects.isEmpty()) {
// return false;
// }
- if (this.states == null || this.states.isEmpty()) {
- return false;
- }
- return true;
+ return this.states != null && !this.states.isEmpty();
}
- public DateTime getBatchStart() {
+ public OffsetDateTime getBatchStart() {
return batchStart;
}
- public void setBatchStart(DateTime batchStart) {
+ public void setBatchStart(OffsetDateTime batchStart) {
this.batchStart = batchStart;
}
- public DateTime getBatchEnd() {
+ public OffsetDateTime getBatchEnd() {
return batchEnd;
}
- public void setBatchEnd(DateTime batchEnd) {
+ public void setBatchEnd(OffsetDateTime batchEnd) {
this.batchEnd = batchEnd;
}
}
diff --git a/src/main/java/com/codealike/client/core/internal/dto/HealthInfo.java b/src/main/java/com/codealike/client/core/internal/dto/HealthInfo.java
index 0dc90af..55b14d5 100644
--- a/src/main/java/com/codealike/client/core/internal/dto/HealthInfo.java
+++ b/src/main/java/com/codealike/client/core/internal/dto/HealthInfo.java
@@ -4,10 +4,10 @@
public class HealthInfo {
- private String identity;
- private String source;
- private String message;
- private HealthInfoType type;
+ private final String identity;
+ private final String source;
+ private final String message;
+ private final HealthInfoType type;
public HealthInfo(Exception ex, String message, String source, HealthInfoType type, String identity) {
this.identity = identity;
@@ -16,13 +16,6 @@ public HealthInfo(Exception ex, String message, String source, HealthInfoType ty
this.source = source;
}
- public HealthInfo(String message, String source, HealthInfoType type, String identity) {
- this.identity = identity;
- this.message = message;
- this.type = type;
- this.source = source;
- }
-
public String getIdentity() {
return identity;
}
diff --git a/src/main/java/com/codealike/client/core/internal/dto/SolutionContextInfo.java b/src/main/java/com/codealike/client/core/internal/dto/SolutionContextInfo.java
index 08e328c..9bf8139 100644
--- a/src/main/java/com/codealike/client/core/internal/dto/SolutionContextInfo.java
+++ b/src/main/java/com/codealike/client/core/internal/dto/SolutionContextInfo.java
@@ -1,8 +1,8 @@
package com.codealike.client.core.internal.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.UUID;
public class SolutionContextInfo {
@@ -12,16 +12,12 @@ public class SolutionContextInfo {
@JsonProperty("Name")
private String name;
@JsonProperty("CreationTime")
- private DateTime creationTime;
-
- public SolutionContextInfo() {
- this.creationTime = new DateTime(0);
- }
+ private OffsetDateTime creationTime;
public SolutionContextInfo(UUID solutionID, String name) {
this.solutionId = solutionID;
this.name = name;
- this.creationTime = DateTime.now();
+ this.creationTime = OffsetDateTime.now();
}
public UUID getSolutionId() {
@@ -42,12 +38,12 @@ public void setName(String name) {
this.name = name;
}
- public DateTime getCreationTime() {
+ public OffsetDateTime getCreationTime() {
return creationTime;
}
@JsonProperty("CreationTime")
- public void setCreationTime(DateTime creationTime) {
+ public void setCreationTime(OffsetDateTime creationTime) {
this.creationTime = creationTime;
}
}
diff --git a/src/main/java/com/codealike/client/core/internal/model/ActivityEvent.java b/src/main/java/com/codealike/client/core/internal/model/ActivityEvent.java
index fa70ada..1b6b235 100644
--- a/src/main/java/com/codealike/client/core/internal/model/ActivityEvent.java
+++ b/src/main/java/com/codealike/client/core/internal/model/ActivityEvent.java
@@ -4,9 +4,9 @@
package com.codealike.client.core.internal.model;
import com.codealike.client.core.internal.dto.ActivityType;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.UUID;
/**
@@ -19,14 +19,14 @@ public class ActivityEvent implements IEndable {
protected ActivityType type;
protected CodeContext context;
- protected DateTime creationTime;
- protected Period duration;
+ protected OffsetDateTime creationTime;
+ protected Duration duration;
protected UUID projectId;
public ActivityEvent(UUID projectId, ActivityType type, CodeContext context) {
- creationTime = DateTime.now();
- duration = Period.ZERO;
+ creationTime = OffsetDateTime.now();
+ duration = Duration.ZERO;
this.type = type;
this.context = context;
this.projectId = projectId;
@@ -44,19 +44,19 @@ public void setContext(CodeContext context) {
this.context = context;
}
- public DateTime getCreationTime() {
+ public OffsetDateTime getCreationTime() {
return creationTime;
}
- public void setCreationTime(DateTime creationTime) {
+ public void setCreationTime(OffsetDateTime creationTime) {
this.creationTime = creationTime;
}
- public Period getDuration() {
+ public Duration getDuration() {
return duration;
}
- public void setDuration(Period duration) {
+ public void setDuration(Duration duration) {
this.duration = duration;
}
@@ -81,8 +81,8 @@ public ActivityEvent recreate() {
return new ActivityEvent(this.projectId, this.type, this.getContext());
}
- public void closeDuration(DateTime closeTo) {
- this.duration = new Period(this.getCreationTime(), closeTo);
+ public void closeDuration(OffsetDateTime closeTo) {
+ this.duration = Duration.between(this.getCreationTime(), closeTo);
}
public boolean isEquivalent(ActivityEvent event) {
@@ -95,8 +95,7 @@ public boolean isEquivalent(ActivityEvent event) {
public boolean equals(Object event) {
if (event == null) return false;
if (event == this) return true;
- if (!(event instanceof ActivityEvent)) return false;
- ActivityEvent eventClass = (ActivityEvent) event;
+ if (!(event instanceof ActivityEvent eventClass)) return false;
return (this.getProjectId() == eventClass.getProjectId()
&& this.getType() == eventClass.getType()
diff --git a/src/main/java/com/codealike/client/core/internal/model/ActivityState.java b/src/main/java/com/codealike/client/core/internal/model/ActivityState.java
index 175a50d..fd5dc51 100644
--- a/src/main/java/com/codealike/client/core/internal/model/ActivityState.java
+++ b/src/main/java/com/codealike/client/core/internal/model/ActivityState.java
@@ -5,9 +5,9 @@
import com.codealike.client.core.internal.dto.ActivityType;
import com.codealike.client.core.internal.startup.PluginContext;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -22,37 +22,37 @@ public class ActivityState implements IEndable {
public static final ActivityState NONE = new ActivityState();
- protected Period duration;
+ protected Duration duration;
protected ActivityType type;
- protected DateTime creationTime;
+ protected OffsetDateTime creationTime;
protected UUID projectId;
protected ActivityState() {
this.type = ActivityType.None;
- this.duration = Period.ZERO;
+ this.duration = Duration.ZERO;
}
- protected ActivityState(UUID projectId, ActivityType type, DateTime creationTime) {
+ protected ActivityState(UUID projectId, ActivityType type, OffsetDateTime creationTime) {
this.projectId = projectId;
this.creationTime = creationTime;
this.type = type;
- this.duration = Period.ZERO;
+ this.duration = Duration.ZERO;
}
public static ActivityState createDebugState(UUID projectId) {
- return new ActivityState(projectId, ActivityType.Debugging, DateTime.now());
+ return new ActivityState(projectId, ActivityType.Debugging, OffsetDateTime.now());
}
public static ActivityState createDesignState(UUID projectId) {
- return new ActivityState(projectId, ActivityType.Coding, DateTime.now());
+ return new ActivityState(projectId, ActivityType.Coding, OffsetDateTime.now());
}
public static ActivityState createBuildState(UUID projectId) {
- return new ActivityState(projectId, ActivityType.Building, DateTime.now());
+ return new ActivityState(projectId, ActivityType.Building, OffsetDateTime.now());
}
public static ActivityState createSystemState(UUID projectId) {
- return new ActivityState(projectId, ActivityType.System, DateTime.now());
+ return new ActivityState(projectId, ActivityType.System, OffsetDateTime.now());
}
public static IdleActivityState createIdleState(UUID projectId) {
@@ -71,11 +71,11 @@ public static ActivityState createNullState(UUID projectId) {
return NullActivityState.createNew(projectId);
}
- public Period getDuration() {
+ public Duration getDuration() {
return duration;
}
- public void setDuration(Period duration) {
+ public void setDuration(Duration duration) {
this.duration = duration;
}
@@ -83,20 +83,20 @@ public ActivityType getType() {
return type;
}
- public DateTime getCreationTime() {
+ public OffsetDateTime getCreationTime() {
return creationTime;
}
- public void setCreationTime(DateTime startWorkspaceDate) {
+ public void setCreationTime(OffsetDateTime startWorkspaceDate) {
this.creationTime = startWorkspaceDate;
}
public ActivityState recreate() {
- return new ActivityState(this.projectId, this.type, DateTime.now());
+ return new ActivityState(this.projectId, this.type, OffsetDateTime.now());
}
- public void closeDuration(DateTime closeTo) {
- this.duration = new Period(this.getCreationTime(), closeTo);
+ public void closeDuration(OffsetDateTime closeTo) {
+ this.duration = Duration.between(this.getCreationTime(), closeTo);
}
public UUID getProjectId() {
@@ -117,8 +117,7 @@ public boolean canShrink() {
public boolean equals(Object state) {
if (state == null) return false;
if (state == this) return true;
- if (!(state instanceof ActivityState)) return false;
- ActivityState stateClass = (ActivityState) state;
+ if (!(state instanceof ActivityState stateClass)) return false;
return (this.getProjectId() == stateClass.getProjectId()
&& this.getType() == stateClass.getType());
diff --git a/src/main/java/com/codealike/client/core/internal/model/IEndable.java b/src/main/java/com/codealike/client/core/internal/model/IEndable.java
index d0b11a6..5cf2d28 100644
--- a/src/main/java/com/codealike/client/core/internal/model/IEndable.java
+++ b/src/main/java/com/codealike/client/core/internal/model/IEndable.java
@@ -4,8 +4,9 @@
package com.codealike.client.core.internal.model;
import com.codealike.client.core.internal.dto.ActivityType;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
+
+import java.time.Duration;
+import java.time.OffsetDateTime;
/**
* Endable model interface.
@@ -14,11 +15,11 @@
* @version 1.6.0.0
*/
public interface IEndable {
- DateTime getCreationTime();
+ OffsetDateTime getCreationTime();
- Period getDuration();
+ Duration getDuration();
- void setDuration(Period duration);
+ void setDuration(Duration duration);
ActivityType getType();
}
diff --git a/src/main/java/com/codealike/client/core/internal/model/IdleActivityState.java b/src/main/java/com/codealike/client/core/internal/model/IdleActivityState.java
index 8e99fb0..0c3bd9b 100644
--- a/src/main/java/com/codealike/client/core/internal/model/IdleActivityState.java
+++ b/src/main/java/com/codealike/client/core/internal/model/IdleActivityState.java
@@ -4,8 +4,8 @@
package com.codealike.client.core.internal.model;
import com.codealike.client.core.internal.dto.ActivityType;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.UUID;
/**
@@ -16,30 +16,30 @@
*/
public class IdleActivityState extends ActivityState {
- private DateTime lastActivity;
+ private OffsetDateTime lastActivity;
- public IdleActivityState(UUID projectId, ActivityType type, DateTime creationTime) {
+ public IdleActivityState(UUID projectId, ActivityType type, OffsetDateTime creationTime) {
super(projectId, type, creationTime);
}
protected static IdleActivityState createNew(UUID projectId) {
- IdleActivityState state = new IdleActivityState(projectId, ActivityType.Idle, DateTime.now());
+ IdleActivityState state = new IdleActivityState(projectId, ActivityType.Idle, OffsetDateTime.now());
state.lastActivity = state.getCreationTime();
return state;
}
- public DateTime getLastActivity() {
+ public OffsetDateTime getLastActivity() {
return lastActivity;
}
- public void setLastActivity(DateTime lastActivity) {
+ public void setLastActivity(OffsetDateTime lastActivity) {
this.lastActivity = lastActivity;
}
@Override
public IdleActivityState recreate() {
- return new IdleActivityState(this.projectId, this.type, DateTime.now());
+ return new IdleActivityState(this.projectId, this.type, OffsetDateTime.now());
}
}
diff --git a/src/main/java/com/codealike/client/core/internal/model/NullActivityState.java b/src/main/java/com/codealike/client/core/internal/model/NullActivityState.java
index 6fb8dec..3e9d0a8 100644
--- a/src/main/java/com/codealike/client/core/internal/model/NullActivityState.java
+++ b/src/main/java/com/codealike/client/core/internal/model/NullActivityState.java
@@ -5,8 +5,8 @@
import com.codealike.client.core.internal.dto.ActivityType;
import com.codealike.client.core.internal.startup.PluginContext;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.UUID;
/**
@@ -17,25 +17,21 @@
*/
public class NullActivityState extends ActivityState {
- public NullActivityState(ActivityType type, DateTime creationTime, UUID projectId) {
+ public NullActivityState(ActivityType type, OffsetDateTime creationTime, UUID projectId) {
super(projectId, type, creationTime);
}
protected static NullActivityState createNew() {
- NullActivityState state = new NullActivityState(ActivityType.Idle, DateTime.now(), PluginContext.UNASSIGNED_PROJECT);
-
- return state;
+ return new NullActivityState(ActivityType.Idle, OffsetDateTime.now(), PluginContext.UNASSIGNED_PROJECT);
}
protected static NullActivityState createNew(UUID projectId) {
- NullActivityState state = new NullActivityState(ActivityType.Idle, DateTime.now(), projectId);
-
- return state;
+ return new NullActivityState(ActivityType.Idle, OffsetDateTime.now(), projectId);
}
@Override
public NullActivityState recreate() {
- return new NullActivityState(this.type, DateTime.now(), this.projectId);
+ return new NullActivityState(this.type, OffsetDateTime.now(), this.projectId);
}
}
diff --git a/src/main/java/com/codealike/client/core/internal/model/exception/IncompatibleVersionException.java b/src/main/java/com/codealike/client/core/internal/model/exception/IncompatibleVersionException.java
new file mode 100644
index 0000000..b72cc6e
--- /dev/null
+++ b/src/main/java/com/codealike/client/core/internal/model/exception/IncompatibleVersionException.java
@@ -0,0 +1,7 @@
+package com.codealike.client.core.internal.model.exception;
+
+public class IncompatibleVersionException extends Exception {
+ public IncompatibleVersionException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/codealike/client/core/internal/processing/ActivityInfoProcessor.java b/src/main/java/com/codealike/client/core/internal/processing/ActivityInfoProcessor.java
index 04c10a1..61b60cf 100644
--- a/src/main/java/com/codealike/client/core/internal/processing/ActivityInfoProcessor.java
+++ b/src/main/java/com/codealike/client/core/internal/processing/ActivityInfoProcessor.java
@@ -10,8 +10,8 @@
import com.codealike.client.core.internal.model.ActivityEvent;
import com.codealike.client.core.internal.model.ActivityState;
import com.codealike.client.core.internal.startup.PluginContext;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@@ -27,8 +27,8 @@ public class ActivityInfoProcessor {
private final List processedStates;
// list of processed events
private final List processedEvents;
- private DateTime batchStart;
- private DateTime batchEnd;
+ private final OffsetDateTime batchStart;
+ private final OffsetDateTime batchEnd;
/**
* Activity information processor constructor
@@ -36,7 +36,7 @@ public class ActivityInfoProcessor {
* @param states the states to process
* @param events the events to process
*/
- public ActivityInfoProcessor(List states, List events, DateTime batchStart, DateTime batchEnd) {
+ public ActivityInfoProcessor(List states, List events, OffsetDateTime batchStart, OffsetDateTime batchEnd) {
this.processedStates = states;
this.processedEvents = events;
this.batchStart = batchStart;
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeDeserializer.java b/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeDeserializer.java
index 7bc8748..7b97ccd 100644
--- a/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeDeserializer.java
+++ b/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeDeserializer.java
@@ -5,7 +5,6 @@
import com.codealike.client.core.internal.dto.ActivityType;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
@@ -16,11 +15,10 @@ public class ActivityTypeDeserializer extends JsonDeserializer {
@Override
public ActivityType deserialize(JsonParser jsonParser, DeserializationContext context)
- throws IOException, JsonProcessingException {
+ throws IOException {
if (jsonParser.getCurrentToken() == JsonToken.VALUE_NUMBER_INT) {
return ActivityType.fromId(jsonParser.getNumberValue().intValue());
}
throw context.instantiationException(ActivityType.class, "Expected int value to parse an ActivityType");
}
-
}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeSerializer.java b/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeSerializer.java
index ec9a91f..dd10902 100644
--- a/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeSerializer.java
+++ b/src/main/java/com/codealike/client/core/internal/serialization/ActivityTypeSerializer.java
@@ -5,7 +5,6 @@
import com.codealike.client.core.internal.dto.ActivityType;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
@@ -14,9 +13,7 @@
public class ActivityTypeSerializer extends JsonSerializer {
@Override
- public void serialize(ActivityType type, JsonGenerator jgen, SerializerProvider arg2) throws IOException,
- JsonProcessingException {
+ public void serialize(ActivityType type, JsonGenerator jgen, SerializerProvider arg2) throws IOException {
jgen.writeNumber(type.getId());
}
-
}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/DateTimeDeserializer.java b/src/main/java/com/codealike/client/core/internal/serialization/DateTimeDeserializer.java
index 0381452..7f68354 100644
--- a/src/main/java/com/codealike/client/core/internal/serialization/DateTimeDeserializer.java
+++ b/src/main/java/com/codealike/client/core/internal/serialization/DateTimeDeserializer.java
@@ -3,37 +3,36 @@
*/
package com.codealike.client.core.internal.serialization;
-import com.codealike.client.core.internal.startup.PluginContext;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormatter;
import java.io.IOException;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
-public class DateTimeDeserializer extends JsonDeserializer {
+public class DateTimeDeserializer extends JsonDeserializer {
@Override
- public DateTime deserialize(JsonParser jsonParser, DeserializationContext context)
- throws IOException, JsonProcessingException {
+ public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext context)
+ throws IOException {
- DateTimeFormatter formatter = PluginContext.getInstance().getDateTimeParser();
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
if (jsonParser.getCurrentToken() == JsonToken.VALUE_STRING) {
String date = jsonParser.getValueAsString();
String[] tokens = date.split("\\.");
if (tokens.length > 1 && tokens[1].length() > 3) {
+ // Handling fractional seconds
String fractionalSecsAsString = tokens[1].replace("Z", "");
int fractionalSecs = Integer.parseInt(fractionalSecsAsString) / 10000;
- return formatter.parseDateTime(String.format("%s.%03d", tokens[0], fractionalSecs));
+ String formattedDate = String.format("%s.%03dZ", tokens[0], fractionalSecs);
+ return OffsetDateTime.parse(formattedDate, formatter);
}
- return formatter.parseDateTime(date);
+ return OffsetDateTime.parse(date, formatter);
}
- throw context.instantiationException(DateTime.class, "Expected string value to parse a DateTime");
+ throw context.instantiationException(OffsetDateTime.class, "Expected string value to parse an OffsetDateTime");
}
-
}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/DateTimeSerializer.java b/src/main/java/com/codealike/client/core/internal/serialization/DateTimeSerializer.java
index 90e480e..854353a 100644
--- a/src/main/java/com/codealike/client/core/internal/serialization/DateTimeSerializer.java
+++ b/src/main/java/com/codealike/client/core/internal/serialization/DateTimeSerializer.java
@@ -5,22 +5,19 @@
import com.codealike.client.core.internal.startup.PluginContext;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
-import org.joda.time.DateTime;
import java.io.IOException;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
-public class DateTimeSerializer extends JsonSerializer {
-
+public class DateTimeSerializer extends JsonSerializer {
@Override
- public void serialize(DateTime dateTime, JsonGenerator jgen, SerializerProvider provider) throws IOException,
- JsonProcessingException {
-// jgen.writeString(String.format("/Date(%d)/", dateTime.getMillis()));
- String formattedDate = PluginContext.getInstance().getDateTimeFormatter().print(dateTime);
+ public void serialize(OffsetDateTime dateTime, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+ DateTimeFormatter formatter = PluginContext.getInstance().getDateTimeFormatter();
+ String formattedDate = dateTime.format(formatter);
jgen.writeString(formattedDate);
}
-
}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/DurationDeserializer.java b/src/main/java/com/codealike/client/core/internal/serialization/DurationDeserializer.java
new file mode 100644
index 0000000..5476d48
--- /dev/null
+++ b/src/main/java/com/codealike/client/core/internal/serialization/DurationDeserializer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023. All rights reserved to Torc LLC.
+ */
+package com.codealike.client.core.internal.serialization;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+import java.io.IOException;
+import java.time.Duration;
+
+public class DurationDeserializer extends JsonDeserializer {
+
+ @Override
+ public Duration deserialize(JsonParser jsonParser, DeserializationContext context)
+ throws IOException {
+ if (jsonParser.getCurrentToken() == JsonToken.VALUE_STRING) {
+ try {
+ return Duration.parse(jsonParser.getValueAsString());
+ } catch (Exception exception) {
+ throw context.instantiationException(Duration.class, "Failed to parse Duration: " + exception.getMessage());
+ }
+ }
+
+ throw context.instantiationException(Duration.class, "Expected string to parse a Duration");
+ }
+}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/DurationSerializer.java b/src/main/java/com/codealike/client/core/internal/serialization/DurationSerializer.java
new file mode 100644
index 0000000..ed13fd4
--- /dev/null
+++ b/src/main/java/com/codealike/client/core/internal/serialization/DurationSerializer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023. All rights reserved to Torc LLC.
+ */
+package com.codealike.client.core.internal.serialization;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+public class DurationSerializer extends JsonSerializer {
+
+
+ @Override
+ public void serialize(Duration period, JsonGenerator jgen, SerializerProvider provider) throws IOException {
+ long millis = period.toMillis();
+ long hours = TimeUnit.MILLISECONDS.toHours(millis);
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
+ long milliseconds = millis % 1000;
+
+ // Format the duration as "HH:mm:ss.SSS"
+ String formattedDuration = String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds);
+
+ jgen.writeString(formattedDuration);
+ }
+}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/JavaTimeModule.java b/src/main/java/com/codealike/client/core/internal/serialization/JavaTimeModule.java
new file mode 100644
index 0000000..0cc9161
--- /dev/null
+++ b/src/main/java/com/codealike/client/core/internal/serialization/JavaTimeModule.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2023. All rights reserved to Torc LLC.
+ */
+package com.codealike.client.core.internal.serialization;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+import java.io.Serial;
+import java.time.Duration;
+import java.time.OffsetDateTime;
+
+public class JavaTimeModule extends SimpleModule {
+
+ @Serial
+ private static final long serialVersionUID = -8783171321786654936L;
+
+ public JavaTimeModule() {
+ addSerializer(Duration.class, new DurationSerializer());
+ addDeserializer(Duration.class, new DurationDeserializer());
+
+ addSerializer(OffsetDateTime.class, new DateTimeSerializer());
+ addDeserializer(OffsetDateTime.class, new DateTimeDeserializer());
+ }
+}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/JodaPeriodModule.java b/src/main/java/com/codealike/client/core/internal/serialization/JodaPeriodModule.java
deleted file mode 100644
index cf735a6..0000000
--- a/src/main/java/com/codealike/client/core/internal/serialization/JodaPeriodModule.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2023. All rights reserved to Torc LLC.
- */
-package com.codealike.client.core.internal.serialization;
-
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
-
-public class JodaPeriodModule extends SimpleModule {
-
- private static final long serialVersionUID = -8783171321786654936L;
-
- public JodaPeriodModule() {
- addSerializer(Period.class, new PeriodSerializer());
- addDeserializer(Period.class, new PeriodDeserializer());
-
- addSerializer(DateTime.class, new DateTimeSerializer());
- addDeserializer(DateTime.class, new DateTimeDeserializer());
- }
-}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/PeriodDeserializer.java b/src/main/java/com/codealike/client/core/internal/serialization/PeriodDeserializer.java
deleted file mode 100644
index d6ed8e9..0000000
--- a/src/main/java/com/codealike/client/core/internal/serialization/PeriodDeserializer.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2023. All rights reserved to Torc LLC.
- */
-package com.codealike.client.core.internal.serialization;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.JsonToken;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import org.joda.time.Period;
-
-import java.io.IOException;
-
-public class PeriodDeserializer extends JsonDeserializer {
-
-
- public PeriodDeserializer() {
- }
-
- @Override
- public Period deserialize(JsonParser jsonParser, DeserializationContext context)
- throws IOException, JsonProcessingException {
- if (jsonParser.getCurrentToken() == JsonToken.VALUE_STRING) {
- Period period = Period.parse(jsonParser.getValueAsString(), PeriodSerializer.FORMATER);
- if (period != null) {
- return period;
- }
- }
-
- throw context.instantiationException(Period.class, "Expected string");
- }
-
-}
diff --git a/src/main/java/com/codealike/client/core/internal/serialization/PeriodSerializer.java b/src/main/java/com/codealike/client/core/internal/serialization/PeriodSerializer.java
deleted file mode 100644
index b756704..0000000
--- a/src/main/java/com/codealike/client/core/internal/serialization/PeriodSerializer.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2023. All rights reserved to Torc LLC.
- */
-package com.codealike.client.core.internal.serialization;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import org.joda.time.Period;
-import org.joda.time.format.PeriodFormatter;
-import org.joda.time.format.PeriodFormatterBuilder;
-
-import java.io.IOException;
-
-public class PeriodSerializer extends JsonSerializer {
-
- public static final PeriodFormatter FORMATER = new PeriodFormatterBuilder().printZeroAlways().minimumPrintedDigits(2).appendHours().appendLiteral(":").
- appendMinutes().appendLiteral(":").appendSeconds().appendLiteral(".").appendMillis().toFormatter();
-
- public PeriodSerializer() {
- }
-
- @Override
- public void serialize(Period period, JsonGenerator jgen, SerializerProvider provider) throws IOException,
- JsonProcessingException {
- jgen.writeString(FORMATER.print(period.toPeriod()));
- }
-
-
-}
diff --git a/src/main/java/com/codealike/client/core/internal/services/IdentityService.java b/src/main/java/com/codealike/client/core/internal/services/IdentityService.java
index 6e205c7..4def63d 100644
--- a/src/main/java/com/codealike/client/core/internal/services/IdentityService.java
+++ b/src/main/java/com/codealike/client/core/internal/services/IdentityService.java
@@ -55,7 +55,7 @@ public boolean isAuthenticated() {
}
public boolean login(String identity, String token, boolean storeCredentials, boolean rememberMe) {
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is connecting...",
NotificationType.INFORMATION);
@@ -190,7 +190,7 @@ public boolean isCredentialsStored() {
}
public void logOff() {
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is disconnecting...",
NotificationType.INFORMATION);
diff --git a/src/main/java/com/codealike/client/core/internal/services/TrackingService.java b/src/main/java/com/codealike/client/core/internal/services/TrackingService.java
index 4fe8a55..f2f8e9e 100644
--- a/src/main/java/com/codealike/client/core/internal/services/TrackingService.java
+++ b/src/main/java/com/codealike/client/core/internal/services/TrackingService.java
@@ -15,8 +15,8 @@
import com.intellij.notification.Notifications;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -31,9 +31,10 @@
public class TrackingService extends BaseService {
private static TrackingService _instance;
- private TrackedProjectManager trackedProjectManager;
+ private final TrackedProjectManager trackedProjectManager;
+ private final StateTracker tracker;
+
private ScheduledExecutorService flushExecutor = null;
- private StateTracker tracker;
private boolean isTracking;
private PluginContext context;
@@ -97,11 +98,11 @@ public void run() {
}
private void flushTrackingInformation() {
- Boolean verboseMode = Boolean.parseBoolean(context.getProperty("activity-verbose-notifications"));
+ boolean verboseMode = Boolean.parseBoolean(context.getProperty("activity-verbose-notifications"));
Notification resultNote = null;
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is sending activities...",
NotificationType.INFORMATION);
@@ -112,7 +113,7 @@ private void flushTrackingInformation() {
FlushResult result = tracker.flush(context.getIdentityService().getIdentity(), context.getIdentityService().getToken());
switch (result) {
case Succeded:
- resultNote = new Notification("CodealikeApplicationComponent.Notifications",
+ resultNote = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike sent activities",
NotificationType.INFORMATION);
@@ -121,7 +122,7 @@ private void flushTrackingInformation() {
break;
case Skip:
- resultNote = new Notification("CodealikeApplicationComponent.Notifications",
+ resultNote = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"No data to be sent",
NotificationType.INFORMATION);
@@ -132,7 +133,7 @@ private void flushTrackingInformation() {
break;
case Offline:
- resultNote = new Notification("CodealikeApplicationComponent.Notifications",
+ resultNote = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is working in offline mode",
NotificationType.INFORMATION);
@@ -141,7 +142,7 @@ private void flushTrackingInformation() {
break;
case Report:
- resultNote = new Notification("CodealikeApplicationComponent.Notifications",
+ resultNote = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is storing corrupted entries for further inspection",
NotificationType.INFORMATION);
@@ -171,7 +172,7 @@ public void enableTracking() {
if (context.isAuthenticated()) {
startTracking();
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is connected and tracking your projects.",
NotificationType.INFORMATION);
@@ -186,7 +187,7 @@ public void disableTracking() {
// flush last information before leaving
flushTrackingInformation();
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is not tracking your projects",
NotificationType.INFORMATION);
@@ -194,7 +195,7 @@ public void disableTracking() {
}
}
- public synchronized void startTracking(Project project, DateTime workspaceInitDate) {
+ public synchronized void startTracking(Project project, OffsetDateTime workspaceInitDate) {
if (!project.isOpen()) {
return;
}
diff --git a/src/main/java/com/codealike/client/core/internal/startup/PluginContext.java b/src/main/java/com/codealike/client/core/internal/startup/PluginContext.java
index 3a9a98c..42f6076 100644
--- a/src/main/java/com/codealike/client/core/internal/startup/PluginContext.java
+++ b/src/main/java/com/codealike/client/core/internal/startup/PluginContext.java
@@ -9,7 +9,7 @@
import com.codealike.client.core.internal.dto.SolutionContextInfo;
import com.codealike.client.core.internal.dto.Version;
import com.codealike.client.core.internal.model.ProjectSettings;
-import com.codealike.client.core.internal.serialization.JodaPeriodModule;
+import com.codealike.client.core.internal.serialization.JavaTimeModule;
import com.codealike.client.core.internal.services.IdentityService;
import com.codealike.client.core.internal.services.TrackingService;
import com.codealike.client.core.internal.tracking.code.ContextCreator;
@@ -24,17 +24,16 @@
import com.intellij.openapi.components.impl.stores.IProjectStore;
import com.intellij.openapi.project.Project;
import com.intellij.project.ProjectKt;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.DateTimeFormatterBuilder;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.security.KeyManagementException;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
import java.util.Properties;
import java.util.Random;
import java.util.UUID;
@@ -47,41 +46,51 @@
*/
@SuppressWarnings("restriction")
public class PluginContext {
- public static final String VERSION = "1.6.0.0";
public static final UUID UNASSIGNED_PROJECT = UUID.fromString("00000000-0000-0000-0000-0000000001");
- private static final String PLUGIN_PREFERENCES_QUALIFIER = "com.codealike.client.intellij";
+ private static final String VERSION = "1.6.0.0";
+
private static PluginContext _instance;
- private String ideName;
- private Version protocolVersion;
- private Properties properties;
- private ObjectWriter jsonWriter;
- private ObjectMapper jsonMapper;
- private ContextCreator contextCreator;
- private DateTimeFormatter dateTimeFormatter;
- private DateTimeFormatter dateTimeParser;
- private IdentityService identityService;
+
+ private final String ideName;
+ private final Version protocolVersion;
+ private final Properties properties;
+ private final ObjectWriter jsonWriter;
+ private final ObjectMapper jsonMapper;
+ private final ContextCreator contextCreator;
+ private final DateTimeFormatter dateTimeFormatter;
+ private final IdentityService identityService;
+ private final String instanceValue;
+ private final String machineName;
+ private final Configuration configuration;
+
private TrackingService trackingService;
- private String instanceValue;
- private String machineName;
- private Configuration configuration;
public PluginContext(Properties properties) {
- DateTimeZone.setDefault(DateTimeZone.UTC);
ObjectMapper mapper = new ObjectMapper();
- mapper.registerModule(new JodaPeriodModule());
+ mapper.registerModule(new JavaTimeModule());
mapper.setSerializationInclusion(Include.NON_NULL);
this.jsonWriter = mapper.writer().withDefaultPrettyPrinter();
this.jsonMapper = mapper;
this.contextCreator = new ContextCreator();
- this.dateTimeParser = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
- this.dateTimeFormatter = new DateTimeFormatterBuilder().appendYear(4, 4).appendLiteral("-").
- appendMonthOfYear(2).appendLiteral("-").appendDayOfMonth(2).
- appendLiteral("T").appendHourOfDay(2).appendLiteral(":").
- appendMinuteOfHour(2).appendLiteral(":").appendSecondOfMinute(2).
- appendLiteral(".").appendMillisOfSecond(3).appendLiteral("Z").toFormatter();
+ this.dateTimeFormatter = new DateTimeFormatterBuilder()
+ .appendValue(ChronoField.YEAR, 4)
+ .appendLiteral("-")
+ .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+ .appendLiteral("-")
+ .appendValue(ChronoField.DAY_OF_MONTH, 2)
+ .appendLiteral("T")
+ .appendValue(ChronoField.HOUR_OF_DAY, 2)
+ .appendLiteral(":")
+ .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+ .appendLiteral(":")
+ .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+ .appendLiteral(".")
+ .appendValue(ChronoField.MILLI_OF_SECOND, 3)
+ .appendLiteral("Z")
+ .toFormatter();
this.identityService = IdentityService.getInstance();
- this.instanceValue = String.valueOf(new Random(DateTime.now().getMillis()).nextInt(Integer.MAX_VALUE) + 1);
+ this.instanceValue = String.valueOf(new Random(OffsetDateTime.now().toInstant().toEpochMilli()).nextInt(Integer.MAX_VALUE) + 1);
this.protocolVersion = new Version(0, 9);
this.properties = properties;
this.ideName = ApplicationNamesInfo.getInstance().getLowercaseProductName();
@@ -245,8 +254,7 @@ private UUID tryCreateUniqueId() {
LogManager.INSTANCE.logInfo("Communication problems running in offline mode.");
return solutionId;
}
- int numberOfRetries = 0;
- while (response.conflict() || (response.error() && numberOfRetries < ApiClient.MAX_RETRIES)) {
+ while (response.conflict() || response.error()) {
solutionId = UUID.randomUUID();
response = client.getSolutionContext(solutionId);
}
@@ -318,7 +326,7 @@ public boolean checkVersion() {
private void showIcompatibleVersionDialog() {
String title = "This version is not updated";
- String text = "Click below to be on the bleeding edge and enjoy an improved version of CodealikeApplicationComponent.";
+ String text = "Click below to be on the bleeding edge and enjoy an improved version of Codealike.";
/*ErrorDialogView dialog = new ErrorDialogView(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, text, "Download the latest.", "images/bigCodealike.jpg",
new Runnable() {
@@ -354,10 +362,6 @@ public DateTimeFormatter getDateTimeFormatter() {
return this.dateTimeFormatter;
}
- public DateTimeFormatter getDateTimeParser() {
- return this.dateTimeParser;
- }
-
public IdentityService getIdentityService() {
return identityService;
}
diff --git a/src/main/java/com/codealike/client/core/internal/tracking/ActivitiesRecorder.java b/src/main/java/com/codealike/client/core/internal/tracking/ActivitiesRecorder.java
index 36132c5..83c67e0 100644
--- a/src/main/java/com/codealike/client/core/internal/tracking/ActivitiesRecorder.java
+++ b/src/main/java/com/codealike/client/core/internal/tracking/ActivitiesRecorder.java
@@ -16,8 +16,6 @@
import com.codealike.client.core.internal.utils.LogManager;
import com.codealike.client.core.internal.utils.TrackingConsole;
import com.fasterxml.jackson.databind.ObjectWriter;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
import java.io.File;
import java.io.FileInputStream;
@@ -26,6 +24,8 @@
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.LinkedList;
import java.util.List;
@@ -36,19 +36,19 @@ public class ActivitiesRecorder {
private ActivityEvent lastEvent;
private ActivityState lastState;
- private PluginContext context;
+ private final PluginContext context;
- private DateTime currentBatchStart;
- private DateTime lastEventTime;
+ private OffsetDateTime currentBatchStart;
+ private OffsetDateTime lastEventTime;
public ActivitiesRecorder(PluginContext context) {
this.states = new LinkedList<>();
this.events = new LinkedList<>();
this.context = context;
- this.currentBatchStart = DateTime.now();
+ this.currentBatchStart = OffsetDateTime.now();
}
- public DateTime getLastEventTime() {
+ public OffsetDateTime getLastEventTime() {
return lastEventTime;
}
@@ -97,25 +97,25 @@ public void updateEndableEntityAsOfNowIfRequired(IEndable endableEntity) {
// get idle max interval in seconds
int idleMinIntervalInSeconds = PluginContext.getInstance().getConfiguration().getIdleCheckInterval() / 1000;
- DateTime currentTime = DateTime.now();
- DateTime entityBaseEnd = endableEntity.getCreationTime().plus(endableEntity.getDuration());
- int elapsedPeriodBetweenLastEventAndNow = new Period(entityBaseEnd, currentTime).toStandardSeconds().getSeconds();
+ OffsetDateTime currentTime = OffsetDateTime.now();
+ OffsetDateTime entityBaseEnd = endableEntity.getCreationTime().plus(endableEntity.getDuration());
+ long elapsedPeriodBetweenLastEventAndNow = Duration.between(entityBaseEnd, currentTime).getSeconds();
// if time elapsed between last event activity and now is less than
// the time it takes to infer user was idle, we track the time as it is
// else, something happened and idle check was not doing it work, so
- // we consider the duration to be as much as a complete idle period
+ // we consider the duration to be as much as a complete idle Duration
if (elapsedPeriodBetweenLastEventAndNow <= idleMinIntervalInSeconds) {
- endableEntity.setDuration(new Period(endableEntity.getCreationTime(), currentTime));
+ endableEntity.setDuration(Duration.between(endableEntity.getCreationTime(), currentTime));
} else {
// if event/state type is system related we track
// whatever it is (no exceptions or checks about duration)
if (endableEntity.getType() == ActivityType.System
|| endableEntity.getType() == ActivityType.OpenSolution) {
- endableEntity.setDuration(new Period(endableEntity.getCreationTime(), currentTime));
+ endableEntity.setDuration(Duration.between(endableEntity.getCreationTime(), currentTime));
} else {
// else, we ensure it does not have inconsistent time
- endableEntity.setDuration(new Period(endableEntity.getCreationTime(), entityBaseEnd.plusSeconds(idleMinIntervalInSeconds).toDateTime()));
+ endableEntity.setDuration(Duration.between(endableEntity.getCreationTime(), entityBaseEnd.plusSeconds(idleMinIntervalInSeconds)));
}
}
@@ -181,7 +181,7 @@ public synchronized ActivityEvent recordEvent(ActivityEvent event) {
}
// saves time from last event
- this.lastEventTime = DateTime.now();
+ this.lastEventTime = OffsetDateTime.now();
TrackingConsole.getInstance().trackEvent(this.lastEvent);
@@ -200,8 +200,8 @@ private Boolean HasOnlyIdleState() {
public FlushResult flush(String username, String token) throws UnknownHostException {
List statesToSend = null;
List eventsToSend = null;
- DateTime batchStart = currentBatchStart;
- DateTime batchEnd = DateTime.now();
+ OffsetDateTime batchStart = currentBatchStart;
+ OffsetDateTime batchEnd = OffsetDateTime.now();
// if lastState or lastEvent are null then there is no info to flush
// so lets skip this attempt
@@ -229,7 +229,7 @@ public FlushResult flush(String username, String token) throws UnknownHostExcept
this.events = new LinkedList<>();
this.recordEvent(lastEvent.recreate());
- currentBatchStart = DateTime.now();
+ currentBatchStart = OffsetDateTime.now();
}
// creates an info procesor
diff --git a/src/main/java/com/codealike/client/core/internal/tracking/StateTracker.java b/src/main/java/com/codealike/client/core/internal/tracking/StateTracker.java
index 1e4c05a..dc4a8d3 100644
--- a/src/main/java/com/codealike/client/core/internal/tracking/StateTracker.java
+++ b/src/main/java/com/codealike/client/core/internal/tracking/StateTracker.java
@@ -27,11 +27,16 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.*;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.PsiMember;
import com.intellij.psi.util.PsiTreeUtil;
-import org.joda.time.DateTime;
-import org.joda.time.Period;
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -45,11 +50,12 @@
*/
public class StateTracker {
- private ActivitiesRecorder recorder;
+ private final ActivitiesRecorder recorder;
+ private final ContextCreator contextCreator;
+
private ActivityState lastState;
private ActivityEvent lastEvent;
- private ContextCreator contextCreator;
private ScheduledExecutorService idleDetectionExecutor;
private DocumentListener documentListener;
@@ -110,7 +116,7 @@ private synchronized StructuralCodeContext gatherEventContextInformation(UUID pr
VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument());
// if no file was obtained or file is special ide file 'fragment.java' skip process
- if (file == null || file.getName() == "fragment.java")
+ if (file == null || file.getName().equals("fragment.java"))
return null;
// create code context and populate with event information
@@ -192,7 +198,7 @@ public synchronized void trackCodingEvent(Editor editor, int offset, int line) {
}
}
- public void startTrackingProject(Project project, UUID projectId, DateTime startWorkspaceDate) {
+ public void startTrackingProject(Project project, UUID projectId, OffsetDateTime startWorkspaceDate) {
ActivityEvent openSolutionEvent = new ActivityEvent(projectId, ActivityType.OpenSolution, contextCreator.createCodeContext(project));
openSolutionEvent.setCreationTime(startWorkspaceDate);
@@ -294,9 +300,9 @@ private void checkIdleStatus() {
if (recorder.getLastState().getType() == ActivityType.Idle) {
recorder.updateLastState();
} else {
- DateTime currentTime = DateTime.now();
+ OffsetDateTime currentTime = OffsetDateTime.now();
long idleMaxPeriodInSeconds = PluginContext.getInstance().getConfiguration().getIdleMinInterval() / 1000;
- long elapsedFromLastEventInSeconds = new Period(recorder.getLastEventTime(), currentTime).toStandardSeconds().getSeconds();
+ long elapsedFromLastEventInSeconds = Duration.between(recorder.getLastEventTime(), currentTime).getSeconds();
if (elapsedFromLastEventInSeconds >= idleMaxPeriodInSeconds) {
// not needed because idea cannot track another type than coding
// save last state type before going iddle
diff --git a/src/main/java/com/codealike/client/core/internal/utils/LogManager.java b/src/main/java/com/codealike/client/core/internal/utils/LogManager.java
index 7ad6ef3..fdcf534 100644
--- a/src/main/java/com/codealike/client/core/internal/utils/LogManager.java
+++ b/src/main/java/com/codealike/client/core/internal/utils/LogManager.java
@@ -20,22 +20,22 @@ public LogManager() {
}
public void logError(String msg) {
- logger.error("CodealikeApplicationComponent: " + msg);
+ logger.error("CodealikeLifecycleListener: " + msg);
}
public void logError(Throwable t, String msg) {
- logger.error("CodealikeApplicationComponent: " + msg, t);
+ logger.error("CodealikeLifecycleListener: " + msg, t);
}
public void logWarn(String msg) {
- logger.warn("CodealikeApplicationComponent: " + msg);
+ logger.warn("CodealikeLifecycleListener: " + msg);
}
public void logWarn(Throwable t, String msg) {
- logger.warn("CodealikeApplicationComponent: " + msg, t);
+ logger.warn("CodealikeLifecycleListener: " + msg, t);
}
public void logInfo(String msg) {
- logger.info("CodealikeApplicationComponent: " + msg);
+ logger.info("CodealikeLifecycleListener: " + msg);
}
}
diff --git a/src/main/java/com/codealike/client/core/internal/utils/TrackingConsole.java b/src/main/java/com/codealike/client/core/internal/utils/TrackingConsole.java
index 1e40730..2659ec0 100644
--- a/src/main/java/com/codealike/client/core/internal/utils/TrackingConsole.java
+++ b/src/main/java/com/codealike/client/core/internal/utils/TrackingConsole.java
@@ -3,15 +3,14 @@
*/
package com.codealike.client.core.internal.utils;
-import java.util.UUID;
-
-import org.joda.time.format.PeriodFormatter;
-
import com.codealike.client.core.internal.model.ActivityEvent;
import com.codealike.client.core.internal.model.ActivityState;
-import com.codealike.client.core.internal.serialization.PeriodSerializer;
import com.codealike.client.core.internal.startup.PluginContext;
+import java.time.Duration;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
/**
* Tracking console class. Used to print track events messages to console.
*
@@ -22,9 +21,9 @@ public class TrackingConsole {
// Singleton instance
private static TrackingConsole _instance;
// The plugin context instance
- private PluginContext context;
+ private final PluginContext context;
// Flag to enable messages to the console
- private boolean enabled;
+ private final boolean enabled;
// private constructor
private TrackingConsole(PluginContext context) {
@@ -66,8 +65,8 @@ public void trackMessage(String message) {
public void trackEvent(ActivityEvent event) {
if (enabled) {
System.out.println("---------------------------------------------------------------------");
- String formattedDate = context.getDateTimeFormatter().print(event.getCreationTime());
- System.out.println(String.format("Event: type:%s, time:%s", event.getType().toString(), formattedDate));
+ String formattedDate = context.getDateTimeFormatter().format(event.getCreationTime());
+ System.out.printf("Event: type:%s, time:%s%n", event.getType().toString(), formattedDate);
System.out.println(event.getContext().toString());
System.out.println("---------------------------------------------------------------------");
}
@@ -80,8 +79,22 @@ public void trackEvent(ActivityEvent event) {
*/
public void trackState(ActivityState state) {
if (enabled) {
- PeriodFormatter formatter = PeriodSerializer.FORMATER;
- System.out.println(String.format("Last recorded state: type:%s, duration:%s\n", state.getType().toString(), state.getDuration().toString(formatter)));
+ Duration duration = state.getDuration();
+
+ long millis = duration.toMillis();
+ long absMillis = Math.abs(millis);
+
+ long hours = TimeUnit.MILLISECONDS.toHours(absMillis);
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(absMillis) % 60;
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(absMillis) % 60;
+ long milliseconds = absMillis % 1000;
+
+ String formattedDuration = String.format("%s%02d:%02d:%02d.%03d",
+ (millis < 0 ? "-" : ""), hours, minutes, seconds, milliseconds);
+
+ System.out.printf("Last recorded state: type:%s, duration:%s\n%n",
+ state.getType().toString(),
+ formattedDuration);
}
}
@@ -93,7 +106,7 @@ public void trackState(ActivityState state) {
*/
public void trackProjectEnd(String name, UUID id) {
if (enabled) {
- System.out.println(String.format("Stopped tracking project \"%s\" with id %s", name, id));
+ System.out.printf("Stopped tracking project \"%s\" with id %s%n", name, id);
}
}
@@ -105,7 +118,7 @@ public void trackProjectEnd(String name, UUID id) {
*/
public void trackProjectStart(String name, UUID id) {
if (enabled) {
- System.out.println(String.format("Started tracking project \"%s\" with id %s", name, id));
+ System.out.printf("Started tracking project \"%s\" with id %s%n", name, id);
}
}
diff --git a/src/main/java/com/codealike/client/intellij/CodealikeApplicationComponent.java b/src/main/java/com/codealike/client/intellij/CodealikeApplicationComponent.java
deleted file mode 100644
index 8a9fd51..0000000
--- a/src/main/java/com/codealike/client/intellij/CodealikeApplicationComponent.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2022-2023. All rights reserved to Torc LLC.
- */
-package com.codealike.client.intellij;
-
-import com.codealike.client.core.api.ApiClient;
-import com.codealike.client.core.internal.dto.HealthInfo;
-import com.codealike.client.core.internal.services.ServiceListener;
-import com.codealike.client.core.internal.startup.PluginContext;
-import com.codealike.client.core.internal.utils.LogManager;
-import com.codealike.client.intellij.ui.AuthenticationDialog;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ApplicationComponent;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyManagementException;
-import java.util.Properties;
-
-/**
- * Plugin application component class.
- *
- * @author Daniel, pvmagacho
- * @version 1.6.0.0
- */
-public class CodealikeApplicationComponent implements ApplicationComponent {
- private static final String CODEALIKE_PROPERTIES_FILE = "/codealike.properties";
- ServiceListener loginObserver = () -> reloadOpenedProjects();
- private PluginContext pluginContext;
-
- public CodealikeApplicationComponent() {
- }
-
- @Override
- public void initComponent() {
- // TODO: insert component initialization logic here
- LogManager.INSTANCE.logInfo("CodealikeApplicationComponent plugin initialized.");
-
- start();
- }
-
- @Override
- public void disposeComponent() {
- // TODO: insert component disposal logic here
- }
-
- @Override
- @NotNull
- public String getComponentName() {
- return "CodealikeApplicationComponent";
- }
-
- protected void start() {
-
- // load plugin properties
- Properties properties = new Properties();
- try {
- properties = loadPluginProperties();
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- // initialize plugin context with properties
- this.pluginContext = PluginContext.getInstance(properties);
-
- try {
- pluginContext.initializeContext();
-
- if (!pluginContext.checkVersion()) {
- throw new Exception();
- }
-
- pluginContext.getIdentityService().addListener(loginObserver);
- if (!pluginContext.getIdentityService().tryLoginWithStoredCredentials()) {
- authenticate();
- }
- } catch (Exception e) {
- try {
- ApiClient client = ApiClient.tryCreateNew();
- client.logHealth(new HealthInfo(e, "Plugin could not start.", "intellij", HealthInfo.HealthInfoType.Error, pluginContext.getIdentityService().getIdentity()));
- } catch (KeyManagementException e1) {
- e1.printStackTrace();
- LogManager.INSTANCE.logError(e, "Couldn't send HealtInfo.");
- }
- LogManager.INSTANCE.logError(e, "Couldn't start plugin.");
- }
- }
-
- protected Properties loadPluginProperties() throws IOException {
- Properties properties = new Properties();
- InputStream in = CodealikeApplicationComponent.class.getResourceAsStream(CODEALIKE_PROPERTIES_FILE);
- properties.load(in);
- in.close();
-
- return properties;
- }
-
- protected void authenticate() {
- ApplicationManager.getApplication().invokeLater(() -> {
- // prompt for apiKey if it does not already exist
- Project project = null;
- try {
- project = ProjectManager.getInstance().getDefaultProject();
- } catch (NullPointerException e) {
- }
-
- // lets ask for a api key
- AuthenticationDialog dialog = new AuthenticationDialog(project);
- dialog.show();
- });
- }
-
- private void reloadOpenedProjects() {
- Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
- if (openProjects.length > 0) {
- for (Project p : openProjects) {
- ProjectManager.getInstance().reloadProject(p);
- }
- }
- }
-}
diff --git a/src/main/java/com/codealike/client/intellij/CodealikeLifecycleListener.java b/src/main/java/com/codealike/client/intellij/CodealikeLifecycleListener.java
new file mode 100644
index 0000000..54cafed
--- /dev/null
+++ b/src/main/java/com/codealike/client/intellij/CodealikeLifecycleListener.java
@@ -0,0 +1,100 @@
+package com.codealike.client.intellij;
+
+import com.codealike.client.core.api.ApiClient;
+import com.codealike.client.core.internal.dto.HealthInfo;
+import com.codealike.client.core.internal.model.exception.IncompatibleVersionException;
+import com.codealike.client.core.internal.startup.PluginContext;
+import com.codealike.client.core.internal.utils.LogManager;
+import com.codealike.client.intellij.ui.AuthenticationDialog;
+import com.intellij.ide.AppLifecycleListener;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyManagementException;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Plugin initialization on startup
+ *
+ * @author afomkina
+ */
+public class CodealikeLifecycleListener implements AppLifecycleListener {
+ private static final LogManager LOG = LogManager.INSTANCE;
+ private static final String PROPERTIES_PATH = "/codealike.properties";
+
+ @Override
+ public void appFrameCreated(@NotNull List commandLineArgs) {
+ start();
+ LOG.logInfo("Codealike plugin is initialized.");
+ }
+
+ private void start() {
+ Properties properties = loadPluginProperties();
+ PluginContext pluginContext = PluginContext.getInstance(properties);
+
+ try {
+ pluginContext.initializeContext();
+ if (!pluginContext.checkVersion()) {
+ throw new IncompatibleVersionException("Incompatible version detected. The application failed to start.");
+ }
+
+ pluginContext.getIdentityService().addListener(this::reloadOpenedProjects);
+ if (!pluginContext.getIdentityService().tryLoginWithStoredCredentials()) {
+ authenticate();
+ }
+ } catch (Exception exception) {
+ try {
+ ApiClient client = ApiClient.tryCreateNew();
+ client.logHealth(
+ new HealthInfo(
+ exception,
+ "Plugin could not start.",
+ "intellij",
+ HealthInfo.HealthInfoType.Error,
+ pluginContext.getIdentityService().getIdentity()
+ )
+ );
+ } catch (KeyManagementException keyManagementException) {
+ LOG.logError(exception, "Couldn't send HealthInfo.");
+ }
+ LOG.logError(exception, "Couldn't start plugin.");
+ }
+ }
+
+ private Properties loadPluginProperties() {
+ Properties properties = new Properties();
+ InputStream stream = CodealikeLifecycleListener.class.getResourceAsStream(PROPERTIES_PATH);
+ try {
+ properties.load(stream);
+ if (stream != null) {
+ stream.close();
+ } else {
+ LOG.logWarn("Properties is null");
+ }
+ } catch (IOException exception) {
+ LOG.logError("Couldn't get properties: " + exception.getMessage());
+ }
+
+ return properties;
+ }
+
+ private void authenticate() {
+ ApplicationManager.getApplication().invokeLater(() -> {
+ Project project = ProjectManager.getInstance().getDefaultProject();
+ AuthenticationDialog dialog = new AuthenticationDialog(project);
+ dialog.show();
+ });
+ }
+
+ private void reloadOpenedProjects() {
+ Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
+ for (Project project : openProjects) {
+ ProjectManager.getInstance().reloadProject(project);
+ }
+ }
+}
diff --git a/src/main/java/com/codealike/client/intellij/CodealikeProjectService.java b/src/main/java/com/codealike/client/intellij/CodealikeProjectService.java
index 998fcfe..f748911 100644
--- a/src/main/java/com/codealike/client/intellij/CodealikeProjectService.java
+++ b/src/main/java/com/codealike/client/intellij/CodealikeProjectService.java
@@ -13,7 +13,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import org.jetbrains.annotations.NotNull;
-import org.joda.time.DateTime;
+import java.time.OffsetDateTime;
/**
* Plugin project service.
@@ -46,12 +46,12 @@ void onProjectOpened() {
switch (identityService.getTrackActivity()) {
case Always: {
trackingService.enableTracking();
- trackingService.startTracking(project, DateTime.now());
+ trackingService.startTracking(project, OffsetDateTime.now());
break;
}
case AskEveryTime:
case Never:
- Notification note = new Notification("CodealikeApplicationComponent.Notifications",
+ Notification note = new Notification("CodealikeLifecycleListener.Notifications",
"Codealike",
"Codealike is not tracking your projects",
NotificationType.INFORMATION);
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index c8cf7a7..f81b202 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -35,16 +35,14 @@
-
-
-
- com.codealike.client.intellij.CodealikeApplicationComponent
-
-
+
+
+
\ No newline at end of file