diff --git a/rd-api-client/src/main/java/org/rundeck/client/RundeckClient.java b/rd-api-client/src/main/java/org/rundeck/client/RundeckClient.java index 8048f900..a5c9b28b 100644 --- a/rd-api-client/src/main/java/org/rundeck/client/RundeckClient.java +++ b/rd-api-client/src/main/java/org/rundeck/client/RundeckClient.java @@ -16,6 +16,7 @@ package org.rundeck.client; +import okhttp3.Cache; import okhttp3.HttpUrl; import okhttp3.JavaNetCookieJar; import okhttp3.OkHttpClient; @@ -294,10 +295,11 @@ private Client buildRundeckClient() { okhttp.addInterceptor(new StaticHeaderInterceptor("User-Agent", userAgent)); + OkHttpClient okhttp = this.okhttp.build(); - Retrofit build = new Retrofit.Builder() + Retrofit retrofit = new Retrofit.Builder() .baseUrl(apiBaseUrl) - .client(okhttp.build()) + .client(okhttp) .addConverterFactory(new QualifiedTypeConverterFactory( JacksonConverterFactory.create(), JaxbConverterFactory.create(), @@ -306,8 +308,16 @@ private Client buildRundeckClient() { .build(); return new Client<>( - build.create(api), - build, + retrofit.create(api), + retrofit, + () -> { + okhttp.dispatcher().executorService().shutdown(); + okhttp.connectionPool().evictAll(); + Cache cache = okhttp.cache(); + if (null != cache && !cache.isClosed()) { + cache.close(); + } + }, appBaseUrl, apiBaseUrl, usedApiVers, diff --git a/rd-api-client/src/main/java/org/rundeck/client/util/Client.java b/rd-api-client/src/main/java/org/rundeck/client/util/Client.java index 780b75fa..9bafaafb 100644 --- a/rd-api-client/src/main/java/org/rundeck/client/util/Client.java +++ b/rd-api-client/src/main/java/org/rundeck/client/util/Client.java @@ -60,6 +60,7 @@ public class Client implements ServiceClient { private final String apiBaseUrl; private final boolean allowVersionDowngrade; private final Logger logger; + private final Closeable closer; public interface Logger { void output(String out); @@ -86,6 +87,33 @@ public Client( this.apiVersion = apiVersion; this.allowVersionDowngrade = allowVersionDowngrade; this.logger = logger; + this.closer = () -> { + }; + } + public Client( + final T service, + final Retrofit retrofit, + final Closeable closer, + final String appBaseUrl, + final String apiBaseUrl, + final int apiVersion, + final boolean allowVersionDowngrade, + final Logger logger + ) + { + this.service = service; + this.retrofit = retrofit; + this.appBaseUrl = appBaseUrl; + this.apiBaseUrl = apiBaseUrl; + this.apiVersion = apiVersion; + this.allowVersionDowngrade = allowVersionDowngrade; + this.logger = logger; + this.closer = closer; + } + + @Override + public void close() throws IOException { + closer.close(); } /** diff --git a/rd-api-client/src/main/java/org/rundeck/client/util/ServiceClient.java b/rd-api-client/src/main/java/org/rundeck/client/util/ServiceClient.java index f5ab288a..64e86901 100644 --- a/rd-api-client/src/main/java/org/rundeck/client/util/ServiceClient.java +++ b/rd-api-client/src/main/java/org/rundeck/client/util/ServiceClient.java @@ -7,6 +7,7 @@ import retrofit2.Response; import retrofit2.Retrofit; +import java.io.Closeable; import java.io.IOException; import java.util.function.Function; @@ -14,7 +15,7 @@ * @author greg * @since 10/19/17 */ -public interface ServiceClient { +public interface ServiceClient extends Closeable { /** * @param mediaType1 test type * @param types list of media types diff --git a/rd-cli-tool/src/main/java/org/rundeck/client/tool/Main.java b/rd-cli-tool/src/main/java/org/rundeck/client/tool/Main.java index d1637fe0..2571929f 100644 --- a/rd-cli-tool/src/main/java/org/rundeck/client/tool/Main.java +++ b/rd-cli-tool/src/main/java/org/rundeck/client/tool/Main.java @@ -27,6 +27,7 @@ import org.rundeck.client.tool.extension.RdCommandExtension; import org.rundeck.client.tool.util.AdaptedToolbeltOutput; import org.rundeck.client.tool.util.ExtensionLoaderUtil; +import org.rundeck.client.tool.util.Resources; import org.rundeck.client.util.*; import org.rundeck.toolbelt.*; import org.rundeck.toolbelt.format.json.jackson.JsonFormatter; @@ -37,6 +38,8 @@ import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; +import java.io.Closeable; +import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.*; @@ -64,18 +67,21 @@ public class Main { RundeckClient.Builder.getUserAgent("rd-cli-tool/" + org.rundeck.client.Version.VERSION); public static void main(String[] args) throws CommandRunFailure { - Rd rd = new Rd(new Env()); - Tool tool = tool(rd); boolean success = false; - try { - success = tool.runMain(args, false); - } catch (RequestFailed failure) { - rd.getOutput().error(failure.getMessage()); - if (rd.getDebugLevel() > 0) { - StringWriter sb = new StringWriter(); - failure.printStackTrace(new PrintWriter(sb)); - rd.getOutput().error(sb.toString()); + try (Rd rd = new Rd(new Env())) { + Tool tool = tool(rd); + try { + success = tool.runMain(args, false); + } catch (RequestFailed failure) { + rd.getOutput().error(failure.getMessage()); + if (rd.getDebugLevel() > 0) { + StringWriter sb = new StringWriter(); + failure.printStackTrace(new PrintWriter(sb)); + rd.getOutput().error(sb.toString()); + } } + } catch (IOException e) { + e.printStackTrace(); } if (!success) { System.exit(2); @@ -232,7 +238,8 @@ public static Tool tool(final Rd rd) { return belt.buckle(); } - static class Rd extends ExtConfigSource implements RdApp, RdClientConfig { + static class Rd extends ExtConfigSource implements RdApp, RdClientConfig, Closeable { + private final Resources resources = new Resources(); Client client; private CommandOutput output; @@ -264,7 +271,7 @@ public String getDateFormat() { public Client getClient() throws InputError { if (null == client) { try { - client = Main.createClient(this); + client = resources.add(Main.createClient(this)); } catch (ConfigSourceError configSourceError) { throw new InputError(configSourceError.getMessage()); } @@ -275,7 +282,7 @@ public Client getClient() throws InputError { @Override public Client getClient(final int version) throws InputError { try { - client = Main.createClient(this, version); + client = resources.add(Main.createClient(this, version)); } catch (ConfigSourceError configSourceError) { throw new InputError(configSourceError.getMessage()); } @@ -285,7 +292,7 @@ public Client getClient(final int version) throws InputError { @Override public ServiceClient getClient(final Class api, final int version) throws InputError { try { - return Main.createClient(this, api, version); + return resources.add(Main.createClient(this, api, version)); } catch (ConfigSourceError configSourceError) { throw new InputError(configSourceError.getMessage()); } @@ -294,7 +301,7 @@ public ServiceClient getClient(final Class api, final int version) thr @Override public ServiceClient getClient(final Class api) throws InputError { try { - return Main.createClient(this, api, null); + return resources.add(Main.createClient(this, api, null)); } catch (ConfigSourceError configSourceError) { throw new InputError(configSourceError.getMessage()); } @@ -328,6 +335,11 @@ public CommandOutput getOutput() { public void setOutput(CommandOutput output) { this.output = output; } + + @Override + public void close() throws IOException { + resources.close(); + } } private static void setupColor(final ToolBelt belt, RdClientConfig config) { diff --git a/rd-cli-tool/src/main/java/org/rundeck/client/tool/util/Resources.java b/rd-cli-tool/src/main/java/org/rundeck/client/tool/util/Resources.java new file mode 100644 index 00000000..d8938a66 --- /dev/null +++ b/rd-cli-tool/src/main/java/org/rundeck/client/tool/util/Resources.java @@ -0,0 +1,34 @@ +package org.rundeck.client.tool.util; + +import java.io.Closeable; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +/** + * Holds collection of closeable resources + */ +public class Resources + implements Closeable +{ + private final Collection closeableResources = new ArrayList<>(); + + public T add(T closeable) { + closeableResources.add(closeable); + return closeable; + } + + @Override + public void close() throws IOException { + closeableResources.forEach( + closeable -> { + try { + closeable.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + ); + closeableResources.clear(); + } +}