From dd5d0232524db013d8d2d00284008b086d873fcf Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Mon, 23 Mar 2020 18:01:24 -0500 Subject: [PATCH 01/23] Allow type coercion when determining APi types When we read objects from the API, we want to ensure the type matches either the type class that the client is aware of, or whatever the complexType property on the object tells us. In some cases, the API returns a type for a property that is not the same or a subtype of the type defined by the API. The API should not do this, however the previous behavior was to throw an exception in these cases, which is quite annoying. Instead, we will now coerce the object we get into the type that the definition says. If properties are missing, they will remain unset, and any extra properties will be added to the unknown properties. --- .../api/json/GsonJsonMarshallerFactory.java | 14 +-- .../json/GsonJsonMarshallerFactoryTest.java | 95 ++++++++++++++++--- .../com/softlayer/api/service/TestEntity.java | 1 - .../com/softlayer/api/service/TestThing.java | 2 + 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/softlayer/api/json/GsonJsonMarshallerFactory.java b/src/main/java/com/softlayer/api/json/GsonJsonMarshallerFactory.java index f77eb2b..e47d558 100644 --- a/src/main/java/com/softlayer/api/json/GsonJsonMarshallerFactory.java +++ b/src/main/java/com/softlayer/api/json/GsonJsonMarshallerFactory.java @@ -14,12 +14,8 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Base64; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.function.Supplier; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -191,12 +187,12 @@ public Entity read(JsonReader in) throws IOException { // we're an adapter for. So if we have SoftLayer_Something and a newer release of the // API has a type extending it but we don't have a generated class for it, it will get // properly serialized to a SoftLayer_Something. + // If the API returns a type that isn't the same or a subtype of the type class, + // try as best we can to fit the data within the type class. Class clazz = typeClasses.get(apiTypeName); Entity result; - if (clazz == null) { + if (clazz == null || !typeClass.isAssignableFrom(clazz)) { result = readForThisType(in); - } else if (!typeClass.isAssignableFrom(clazz)) { - throw new RuntimeException("Expecting " + typeClass + " to be super type of " + clazz); } else { result = ((EntityTypeAdapter) gson.getAdapter(clazz)).readForThisType(in); } diff --git a/src/test/java/com/softlayer/api/json/GsonJsonMarshallerFactoryTest.java b/src/test/java/com/softlayer/api/json/GsonJsonMarshallerFactoryTest.java index 06ea291..5233db7 100644 --- a/src/test/java/com/softlayer/api/json/GsonJsonMarshallerFactoryTest.java +++ b/src/test/java/com/softlayer/api/json/GsonJsonMarshallerFactoryTest.java @@ -21,6 +21,7 @@ import com.google.gson.reflect.TypeToken; import com.softlayer.api.service.Entity; import com.softlayer.api.service.TestEntity; +import com.softlayer.api.service.TestThing; public class GsonJsonMarshallerFactoryTest { @@ -51,21 +52,22 @@ private String toJson(Object obj) throws Exception { public void testRead() throws Exception { Entity entity = fromJson(Entity.class, "{" - + "\"complexType\": \"SoftLayer_TestEntity\"," - + "\"bar\": \"some string\"," - + "\"foo\": \"another string\"," - + "\"baz\": null," - + "\"date\": \"1984-02-25T20:15:25-06:00\"," - + "\"notApiProperty\": \"bad value\"," - + "\"child\": {" - + " \"complexType\": \"SoftLayer_TestEntity\"," - + " \"bar\": \"child string\"" - + "}," - + "\"moreChildren\": [" - + " { \"complexType\": \"SoftLayer_TestEntity\", \"bar\": \"child 1\" }," - + " { \"complexType\": \"SoftLayer_TestEntity\", \"bar\": \"child 2\" }" - + "]" - + "}"); + + "\"complexType\": \"SoftLayer_TestEntity\"," + + "\"bar\": \"some string\"," + + "\"foo\": \"another string\"," + + "\"baz\": null," + + "\"date\": \"1984-02-25T20:15:25-06:00\"," + + "\"notApiProperty\": \"bad value\"," + + "\"child\": {" + + " \"complexType\": \"SoftLayer_TestEntity\"," + + " \"bar\": \"child string\"" + + "}," + + "\"moreChildren\": [" + + " { \"complexType\": \"SoftLayer_TestEntity\", \"bar\": \"child 1\" }," + + " { \"complexType\": \"SoftLayer_TestEntity\", \"bar\": \"child 2\" }" + + "]," + + "\"testThing\": {\"complexType\": \"SoftLayer_TestThing\", \"id\": 123}" + + "}"); assertEquals(TestEntity.class, entity.getClass()); TestEntity obj = (TestEntity) entity; assertEquals("some string", obj.getFoo()); @@ -85,6 +87,69 @@ public void testRead() throws Exception { assertEquals(2, obj.getMoreChildren().size()); assertEquals("child 1", obj.getMoreChildren().get(0).getFoo()); assertEquals("child 2", obj.getMoreChildren().get(1).getFoo()); + assertEquals(TestThing.class, obj.getTestThing().getClass()); + assertEquals(123, obj.getTestThing().getId().intValue()); + } + + @Test + public void testReadPropertyWithIncorrectComplexTypeCoercesTheType() throws Exception { + Entity entity = fromJson(Entity.class, + "{" + + "\"complexType\": \"SoftLayer_TestEntity\"," + + "\"testThing\": {\"complexType\": \"SoftLayer_TestEntity\", \"id\": 123, \"foo\": \"unknown!\"}" + + "}"); + assertEquals(TestEntity.class, entity.getClass()); + TestEntity obj = (TestEntity) entity; + assertEquals(0, obj.getUnknownProperties().size()); + assertEquals(TestThing.class, obj.getTestThing().getClass()); + assertEquals(123, obj.getTestThing().getId().intValue()); + assertEquals(1, obj.getTestThing().getUnknownProperties().size()); + assertEquals("unknown!", obj.getTestThing().getUnknownProperties().get("foo")); + } + + + @Test + public void testReadPropertyWithUnknownComplexTypeCoercesTheType() throws Exception { + Entity entity = fromJson(Entity.class, + "{" + + "\"complexType\": \"SoftLayer_TestEntity\"," + + "\"testThing\": {\"complexType\": \"WhoKnows\", \"id\": 123, \"foo\": \"unknown!\"}" + + "}"); + assertEquals(TestEntity.class, entity.getClass()); + TestEntity obj = (TestEntity) entity; + assertEquals(0, obj.getUnknownProperties().size()); + assertEquals(TestThing.class, obj.getTestThing().getClass()); + assertEquals(123, obj.getTestThing().getId().intValue()); + assertEquals(1, obj.getTestThing().getUnknownProperties().size()); + assertEquals("unknown!", obj.getTestThing().getUnknownProperties().get("foo")); + } + + @Test + public void testReadPropertyThrowsExceptionWithoutComplexType() { + + Exception e = assertThrows(RuntimeException.class, () -> { + Entity entity = fromJson(Entity.class, + "{" + + "\"complexType\": \"SoftLayer_TestEntity\"," + + "\"testThing\": {\"id\": 123}" + + "}"); + }); + + assertEquals("Expected 'complexType' as first property", e.getMessage()); + } + + @Test + public void testReadPropertyThrowsExceptioWithComplexTypeNotFirst() { + + Exception e = assertThrows(RuntimeException.class, () -> { + Entity entity = fromJson(Entity.class, + "{" + + "\"testThing\": {\"id\": 123}," + + "\"complexType\": \"SoftLayer_TestEntity\"" + + "}"); + }); + + assertEquals("Expected 'complexType' as first property", e.getMessage()); } @Test diff --git a/src/test/java/com/softlayer/api/service/TestEntity.java b/src/test/java/com/softlayer/api/service/TestEntity.java index ce85bf6..df3f7d8 100644 --- a/src/test/java/com/softlayer/api/service/TestEntity.java +++ b/src/test/java/com/softlayer/api/service/TestEntity.java @@ -11,7 +11,6 @@ import com.softlayer.api.annotation.ApiType; import com.softlayer.api.ApiClient; import com.softlayer.api.ResponseHandler; -import com.softlayer.api.ResultLimit; @ApiType("SoftLayer_TestEntity") public class TestEntity extends Entity { diff --git a/src/test/java/com/softlayer/api/service/TestThing.java b/src/test/java/com/softlayer/api/service/TestThing.java index 2eac363..548b87c 100644 --- a/src/test/java/com/softlayer/api/service/TestThing.java +++ b/src/test/java/com/softlayer/api/service/TestThing.java @@ -10,7 +10,9 @@ import com.softlayer.api.annotation.ApiMethod; import com.softlayer.api.annotation.ApiProperty; import com.softlayer.api.annotation.ApiService; +import com.softlayer.api.annotation.ApiType; +@ApiType("SoftLayer_TestThing") public class TestThing extends Entity { @ApiProperty(canBeNullOrNotSet = true) From 5c1a5a1b112af06530ca94cd9bb6ed01704ad0dc Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 25 Mar 2020 10:06:23 -0500 Subject: [PATCH 02/23] Update RestApiClient docs and add a BASE_SERVICE_URL constant. --- src/main/java/com/softlayer/api/RestApiClient.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/softlayer/api/RestApiClient.java b/src/main/java/com/softlayer/api/RestApiClient.java index 5c11e2e..f587b33 100644 --- a/src/main/java/com/softlayer/api/RestApiClient.java +++ b/src/main/java/com/softlayer/api/RestApiClient.java @@ -30,7 +30,15 @@ */ public class RestApiClient implements ApiClient { + /** + * The publically available API URL. + */ public static final String BASE_URL = "https://api.softlayer.com/rest/v3.1/"; + + /** + * The API URL that should be used when connecting via the softlayer/classic infrastructure private network. + */ + public static final String BASE_SERVICE_URL = "https://api.service.softlayer.com/rest/v3.1/"; static final String BASE_PKG = Entity.class.getPackage().getName(); @@ -58,6 +66,9 @@ public class RestApiClient implements ApiClient { private boolean loggingEnabled = false; private HttpBasicAuthCredentials credentials; + /** + * Create a Rest client that uses the publically available API. + */ public RestApiClient() { this(BASE_URL); } From 4b6df6f494464437374d0bc2c3f9906de3005086 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 25 Mar 2020 10:13:02 -0500 Subject: [PATCH 03/23] Update README with service API information. --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c79ee7..e963476 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,14 @@ ApiClient client = new RestApiClient().withCredentials("my user", "my api key"); ``` If the end point isn't at the normal SoftLayer API, you can provide the prefix to the constructor of the -`RestApiClient`. By default it is set to `https://api.softlayer.com/rest/v3.1/`. +`RestApiClient`. By default it is set to the public API endpoint, `https://api.softlayer.com/rest/v3.1/`. + +If you are using the classic infrastructure private network, you can communicate with the API over that network by using the service URL instead: + +```java +ApiClient client = new RestApiClient(RestApiClient.BASE_SERVICE_URL) + .withCredentials("my user", "my api key"); +``` ### Making API Calls From 5eace401e1a1954760d32ddafc33cf77bfb5059f Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 25 Mar 2020 12:15:00 -0500 Subject: [PATCH 04/23] Release version 0.3.0 --- README.md | 6 +++--- examples/pom.xml | 2 +- gen/pom.xml | 2 +- pom.xml | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e963476..95261b2 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,20 @@ additions to the SoftLayer API. com.softlayer.api softlayer-api-client - 0.2.9 + 0.3.0 ``` ### Gradle ```groovy -implementation 'com.softlayer.api:softlayer-api-client:0.2.9' +implementation 'com.softlayer.api:softlayer-api-client:0.3.0' ``` ### Kotlin ```kotlin -compile("com.softlayer.api:softlayer-api-client:0.2.9") +compile("com.softlayer.api:softlayer-api-client:0.3.0") ``` ### Creating a Client diff --git a/examples/pom.xml b/examples/pom.xml index b9d43ba..9cf4371 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-examples jar - 0.2.9 + 0.3.0 softlayer-api-client-examples http://sldn.softlayer.com diff --git a/gen/pom.xml b/gen/pom.xml index 005927a..58a5eb2 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-gen jar - 0.2.9 + 0.3.0 softlayer-api-client-gen http://sldn.softlayer.com diff --git a/pom.xml b/pom.xml index b1854bf..f003f80 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ softlayer-api-client jar - 0.2.9 + 0.3.0 SoftLayer API Client for Java API client for accessing the SoftLayer API http://sldn.softlayer.com @@ -41,7 +41,7 @@ scm:git:git@github.com:softlayer/softlayer-java.git scm:git:git@github.com:softlayer/softlayer-java.git git@github.com:softlayer/softlayer-java.git - 0.2.9 + 0.3.0 UTF-8 @@ -78,7 +78,7 @@ org.mockito mockito-core - 2.28.2 + 3.3.3 test From 8a0e0d36ee7c7c7563c572e18f7866612c90f2a7 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 25 Mar 2020 14:59:41 -0500 Subject: [PATCH 05/23] Use shields.io for maven badge. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95261b2..6612f93 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # SoftLayer API Client for Java [![Build Status](https://travis-ci.org/softlayer/softlayer-java.svg)](https://travis-ci.org/softlayer/softlayer-java) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.softlayer.api/softlayer-api-client/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.softlayer.api/softlayer-api-client) +[![Maven Central](https://img.shields.io/maven-central/v/com.softlayer.api/softlayer-api-client)](https://search.maven.org/artifact/com.softlayer.api/softlayer-api-client) [![Javadocs](https://www.javadoc.io/badge/com.softlayer.api/softlayer-api-client.svg)](https://www.javadoc.io/doc/com.softlayer.api/softlayer-api-client) ## Introduction From 961e406f2f51394681e674e35fa52b57e7c587e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 02:47:46 +0000 Subject: [PATCH 06/23] Bump junit from 4.13 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f003f80..8bb7ed9 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ junit junit - 4.13 + 4.13.1 test From 280931d170b2ff1a8c34ebc990cd9094270259e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 02:51:11 +0000 Subject: [PATCH 07/23] Bump junit from 4.13 to 4.13.1 in /gen Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1) Signed-off-by: dependabot[bot] --- gen/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/pom.xml b/gen/pom.xml index 58a5eb2..c646e34 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -34,7 +34,7 @@ junit junit - 4.13 + 4.13.1 test From b70f9535dc1dea23a084a360aea0ae0ffb1e1dea Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Mon, 9 Nov 2020 15:34:30 -0600 Subject: [PATCH 08/23] Release 0.3.1 --- README.md | 6 +++--- examples/pom.xml | 2 +- gen/pom.xml | 4 ++-- pom.xml | 15 +++++++-------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6612f93..2563f68 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,20 @@ additions to the SoftLayer API. com.softlayer.api softlayer-api-client - 0.3.0 + 0.3.1 ``` ### Gradle ```groovy -implementation 'com.softlayer.api:softlayer-api-client:0.3.0' +implementation 'com.softlayer.api:softlayer-api-client:0.3.1' ``` ### Kotlin ```kotlin -compile("com.softlayer.api:softlayer-api-client:0.3.0") +compile("com.softlayer.api:softlayer-api-client:0.3.1") ``` ### Creating a Client diff --git a/examples/pom.xml b/examples/pom.xml index 9cf4371..21d766c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-examples jar - 0.3.0 + 0.3.1 softlayer-api-client-examples http://sldn.softlayer.com diff --git a/gen/pom.xml b/gen/pom.xml index c646e34..f1becb3 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-gen jar - 0.3.0 + 0.3.1 softlayer-api-client-gen http://sldn.softlayer.com @@ -29,7 +29,7 @@ com.google.code.gson gson - 2.8.5 + 2.8.6 junit diff --git a/pom.xml b/pom.xml index 8bb7ed9..ac69f4e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ softlayer-api-client jar - 0.3.0 + 0.3.1 SoftLayer API Client for Java API client for accessing the SoftLayer API http://sldn.softlayer.com @@ -27,9 +27,8 @@ camporter Cameron Porter - cmporter@softlayer.com - SoftLayer - http://softlayer.com + IBM + http://ibm.com/cloud owner developer @@ -41,7 +40,7 @@ scm:git:git@github.com:softlayer/softlayer-java.git scm:git:git@github.com:softlayer/softlayer-java.git git@github.com:softlayer/softlayer-java.git - 0.3.0 + 0.3.1 UTF-8 @@ -50,7 +49,7 @@ jcenter - http://jcenter.bintray.com/ + https://jcenter.bintray.com/ @@ -67,7 +66,7 @@ com.google.code.gson gson - 2.8.5 + 2.8.6 junit @@ -78,7 +77,7 @@ org.mockito mockito-core - 3.3.3 + 3.6.0 test From 94db1a6eeaf4fca2ec44263b25f66d93d086d460 Mon Sep 17 00:00:00 2001 From: cmp Date: Thu, 19 Nov 2020 19:22:52 -0600 Subject: [PATCH 09/23] Add maven workflow action --- .github/workflows/maven.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..6f18e58 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,20 @@ +name: Java CI + +on: + push: + branches: [ master ] + pull_request: +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + java: [8, 11, 15] + steps: + - uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: ${{matrix.java}} + - name: Build with Maven + run: mvn -B package --file pom.xml From d51f8a17a2e63690ce6bf1328634877b75e34315 Mon Sep 17 00:00:00 2001 From: cmp Date: Tue, 8 Dec 2020 17:28:11 -0600 Subject: [PATCH 10/23] Replace travisci badge with github actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2563f68..34b8046 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SoftLayer API Client for Java -[![Build Status](https://travis-ci.org/softlayer/softlayer-java.svg)](https://travis-ci.org/softlayer/softlayer-java) +![Java CI](https://github.com/softlayer/softlayer-java/workflows/Java%20CI/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/com.softlayer.api/softlayer-api-client)](https://search.maven.org/artifact/com.softlayer.api/softlayer-api-client) [![Javadocs](https://www.javadoc.io/badge/com.softlayer.api/softlayer-api-client.svg)](https://www.javadoc.io/doc/com.softlayer.api/softlayer-api-client) From c0cf8e9107fa521f45c9b7da37639990992e4fbc Mon Sep 17 00:00:00 2001 From: Christopher Gallo Date: Mon, 4 Jan 2021 16:41:23 -0600 Subject: [PATCH 11/23] #70 examples for Bearer Authentication --- .../com/softlayer/api/example/Example.java | 9 +++++- .../com/softlayer/api/example/QuickTest.java | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 examples/src/main/java/com/softlayer/api/example/QuickTest.java diff --git a/examples/src/main/java/com/softlayer/api/example/Example.java b/examples/src/main/java/com/softlayer/api/example/Example.java index db2d386..32566fc 100644 --- a/examples/src/main/java/com/softlayer/api/example/Example.java +++ b/examples/src/main/java/com/softlayer/api/example/Example.java @@ -17,7 +17,14 @@ public void start(String[] args) throws Exception { baseUrl += '/'; } - run(new RestApiClient(baseUrl).withCredentials(args[0], args[1])); + RestApiClient client; + // mvn -e -q compile exec:java -Dexec.args="QuickTest Bearer eyJraWQ..... + if (args[0].trim().equals("Bearer")) { + client = new RestApiClient(baseUrl).withBearerToken(args[1]); + } else { + client = new RestApiClient(baseUrl).withCredentials(args[0], args[1]); + } + run(client); } /** Run the example with the given client */ diff --git a/examples/src/main/java/com/softlayer/api/example/QuickTest.java b/examples/src/main/java/com/softlayer/api/example/QuickTest.java new file mode 100644 index 0000000..24701da --- /dev/null +++ b/examples/src/main/java/com/softlayer/api/example/QuickTest.java @@ -0,0 +1,28 @@ +package com.softlayer.api.example; + +import com.softlayer.api.ApiClient; +import com.softlayer.api.RestApiClient; +import com.softlayer.api.service.Account; + + +/** A quick example for testing if authentication works. + +cd softlayer-java/examples +mvn -e -q compile exec:java -Dexec.args="QuickTest Bearer eyJraWQ..... +*/ +public class QuickTest extends Example { + + @Override + public void run(ApiClient client) throws Exception { + client.withLoggingEnabled(); + System.out.format("Authorization: %s\n", client.getCredentials()); + Account.Service service = Account.service(client); + + Account account = service.getObject(); + System.out.format("Account Name: %s\n", account.getCompanyName()); + } + + public static void main(String[] args) throws Exception { + new QuickTest().start(args); + } +} From 0cdfb8d1c3845ad77569df8e66977595c5f8dacb Mon Sep 17 00:00:00 2001 From: Christopher Gallo Date: Mon, 4 Jan 2021 16:42:50 -0600 Subject: [PATCH 12/23] #70 support for Bearer HTTP authorization --- .../java/com/softlayer/api/ApiClient.java | 25 ++++++++++++++++++- .../java/com/softlayer/api/RestApiClient.java | 14 +++++++++-- .../api/http/BuiltInHttpClientFactory.java | 8 ++---- .../api/http/HttpBearerCredentials.java | 20 +++++++++++++++ .../softlayer/api/http/HttpCredentials.java | 1 + .../http/BuiltInHttpClientFactoryTest.java | 15 ----------- .../api/http/HttpBearerCredentialsTest.java | 22 ++++++++++++++++ 7 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/softlayer/api/http/HttpBearerCredentials.java create mode 100644 src/test/java/com/softlayer/api/http/HttpBearerCredentialsTest.java diff --git a/src/main/java/com/softlayer/api/ApiClient.java b/src/main/java/com/softlayer/api/ApiClient.java index 092d686..a637995 100644 --- a/src/main/java/com/softlayer/api/ApiClient.java +++ b/src/main/java/com/softlayer/api/ApiClient.java @@ -1,5 +1,7 @@ package com.softlayer.api; +import com.softlayer.api.http.HttpCredentials; + /** Common interface for all API clients. {@link RestApiClient} is the preferred implementation */ public interface ApiClient { @@ -9,7 +11,28 @@ public interface ApiClient { * @return This instance */ ApiClient withCredentials(String username, String apiKey); - + + /** + * Uses a HTTP Bearer token for authentication instead of API key. + * + * @return This instance + */ + ApiClient withBearerToken(String token); + + /** + * Enables logging for client API calls + * + * @return This instance + */ + ApiClient withLoggingEnabled(); + + /** + * Returns the HTTP Authorization header + * + * @return This instance + */ + HttpCredentials getCredentials(); + /** * Get a service for the given sets of classes and optional ID. It is not recommended to call this * directly, but rather invoke the service method on the type class. diff --git a/src/main/java/com/softlayer/api/RestApiClient.java b/src/main/java/com/softlayer/api/RestApiClient.java index f587b33..43450c8 100644 --- a/src/main/java/com/softlayer/api/RestApiClient.java +++ b/src/main/java/com/softlayer/api/RestApiClient.java @@ -18,7 +18,9 @@ import com.softlayer.api.annotation.ApiMethod; import com.softlayer.api.annotation.ApiService; +import com.softlayer.api.http.HttpCredentials; import com.softlayer.api.http.HttpBasicAuthCredentials; +import com.softlayer.api.http.HttpBearerCredentials; import com.softlayer.api.http.HttpClient; import com.softlayer.api.http.HttpClientFactory; import com.softlayer.api.http.HttpResponse; @@ -64,7 +66,7 @@ public class RestApiClient implements ApiClient { private HttpClientFactory httpClientFactory; private JsonMarshallerFactory jsonMarshallerFactory; private boolean loggingEnabled = false; - private HttpBasicAuthCredentials credentials; + private HttpCredentials credentials; /** * Create a Rest client that uses the publically available API. @@ -114,6 +116,7 @@ public void setLoggingEnabled(boolean loggingEnabled) { this.loggingEnabled = loggingEnabled; } + @Override public RestApiClient withLoggingEnabled() { this.loggingEnabled = true; return this; @@ -141,7 +144,14 @@ public RestApiClient withCredentials(String username, String apiKey) { return this; } - public HttpBasicAuthCredentials getCredentials() { + @Override + public RestApiClient withBearerToken(String token) { + credentials = new HttpBearerCredentials(token); + return this; + } + + @Override + public HttpCredentials getCredentials() { return credentials; } diff --git a/src/main/java/com/softlayer/api/http/BuiltInHttpClientFactory.java b/src/main/java/com/softlayer/api/http/BuiltInHttpClientFactory.java index 5cf49f0..2d96b32 100644 --- a/src/main/java/com/softlayer/api/http/BuiltInHttpClientFactory.java +++ b/src/main/java/com/softlayer/api/http/BuiltInHttpClientFactory.java @@ -89,7 +89,7 @@ public void setThreadPool(ExecutorService threadPool) { class BuiltInHttpClient implements HttpClient, HttpResponse { - final HttpBasicAuthCredentials credentials; + final HttpCredentials credentials; final String method; final String fullUrl; final Map> headers; @@ -101,11 +101,7 @@ public BuiltInHttpClient( String fullUrl, Map> headers ) { - // We only support basic auth - if (credentials != null && !(credentials instanceof HttpBasicAuthCredentials)) { - throw new UnsupportedOperationException("Only basic auth is supported, not " + credentials.getClass()); - } - this.credentials = (HttpBasicAuthCredentials) credentials; + this.credentials = credentials; this.method = method; this.fullUrl = fullUrl; this.headers = headers; diff --git a/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java b/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java new file mode 100644 index 0000000..fd80aa1 --- /dev/null +++ b/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java @@ -0,0 +1,20 @@ +package com.softlayer.api.http; + +/** HTTP bearer authorization support for bearer token fromhttps://iam.cloud.ibm.com/identity/token */ +public class HttpBearerCredentials implements HttpCredentials { + + public final String token; + + public HttpBearerCredentials(String token) { + this.token = token; + } + + /** + * Formats the token into a HTTP Authorization header. + * + * @return String + */ + public String getHeader() { + return "Bearer " + token; + } +} diff --git a/src/main/java/com/softlayer/api/http/HttpCredentials.java b/src/main/java/com/softlayer/api/http/HttpCredentials.java index a0ae093..a588f83 100644 --- a/src/main/java/com/softlayer/api/http/HttpCredentials.java +++ b/src/main/java/com/softlayer/api/http/HttpCredentials.java @@ -2,4 +2,5 @@ /** Base interface for all accepted HTTP credentials */ public interface HttpCredentials { + public String getHeader(); } diff --git a/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java b/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java index ee40c56..75ff90f 100644 --- a/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java +++ b/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java @@ -15,21 +15,6 @@ public class BuiltInHttpClientFactoryTest { - @Test - public void testGetHttpClientWithoutBasicAuth() { - try { - new BuiltInHttpClientFactory().getHttpClient( - new HttpCredentials() { }, - "GET", - "http://example.com", - Collections.emptyMap() - ); - fail(); - } catch (UnsupportedOperationException e) { - assertTrue(e.getMessage().contains("basic auth")); - } - } - @Test public void testGetThreadPoolDefaultsToDaemonThreads() throws Exception { boolean daemon = new BuiltInHttpClientFactory().getThreadPool().submit( diff --git a/src/test/java/com/softlayer/api/http/HttpBearerCredentialsTest.java b/src/test/java/com/softlayer/api/http/HttpBearerCredentialsTest.java new file mode 100644 index 0000000..0a1d67d --- /dev/null +++ b/src/test/java/com/softlayer/api/http/HttpBearerCredentialsTest.java @@ -0,0 +1,22 @@ +package com.softlayer.api.http; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class HttpBearerCredentialsTest { + + public final String bearerToken = "qqqqwwwweeerrttyyuuiiooppasddfgfgjghjkjklZXxcvcvbvbnnbm"; + @Test + public void testConstructor() { + HttpBearerCredentials authCredentials = new HttpBearerCredentials(bearerToken); + assertEquals(bearerToken, authCredentials.token); + } + + @Test + public void testGetHeader() { + HttpBearerCredentials authCredentials = new HttpBearerCredentials(bearerToken); + String header = "Bearer " + bearerToken; + assertEquals(header, authCredentials.getHeader()); + } +} From 194e7166f667622fa858f208f404b92eb5e45ce5 Mon Sep 17 00:00:00 2001 From: Christopher Gallo Date: Tue, 5 Jan 2021 16:37:02 -0600 Subject: [PATCH 13/23] #70 added code coverage tool to pom.xml, and a BuiltinHttpClientFactoryTest test --- README.md | 20 ++++++++++--- pom.xml | 28 +++++++++++++++++-- .../http/BuiltInHttpClientFactoryTest.java | 8 ++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 34b8046..ca73258 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,20 @@ additions to the SoftLayer API. com.softlayer.api softlayer-api-client - 0.3.1 + 0.3.2 ``` ### Gradle ```groovy -implementation 'com.softlayer.api:softlayer-api-client:0.3.1' +implementation 'com.softlayer.api:softlayer-api-client:0.3.2' ``` ### Kotlin ```kotlin -compile("com.softlayer.api:softlayer-api-client:0.3.1") +compile("com.softlayer.api:softlayer-api-client:0.3.2") ``` ### Creating a Client @@ -61,12 +61,24 @@ compile("com.softlayer.api:softlayer-api-client:0.3.1") All clients are instances of `ApiClient`. Currently there is only one implementation, the `RestApiClient`. Simply instantiate it and provide your credentials: + +#### Username and API Key +For using a Classic Infrastructure or IBM Cloud API key. When using the IBM Cloud Api key, your username is litterally `apikey`, more information about that can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#cloud-api) article. + ```java import com.softlayer.api.*; ApiClient client = new RestApiClient().withCredentials("my user", "my api key"); ``` +#### Acesses Token +Information on how to get a temoprary api token can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) article. + +```java +import com.softlayer.api.*; +ApiClient client = new RestApiClient().withBearerToken("qqqqwwwweeeaaassddd...."); +``` + If the end point isn't at the normal SoftLayer API, you can provide the prefix to the constructor of the `RestApiClient`. By default it is set to the public API endpoint, `https://api.softlayer.com/rest/v3.1/`. @@ -296,4 +308,4 @@ fully qualified class name of your implementation on a single line in a file in ## Copyright -This software is Copyright (c) 2020 The SoftLayer Developer Network. See the bundled LICENSE file for more information. +This software is Copyright (c) 2021 The SoftLayer Developer Network. See the bundled LICENSE file for more information. diff --git a/pom.xml b/pom.xml index ac69f4e..32ae219 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ softlayer-api-client jar - 0.3.1 + 0.3.2 SoftLayer API Client for Java API client for accessing the SoftLayer API http://sldn.softlayer.com @@ -40,7 +40,7 @@ scm:git:git@github.com:softlayer/softlayer-java.git scm:git:git@github.com:softlayer/softlayer-java.git git@github.com:softlayer/softlayer-java.git - 0.3.1 + 0.3.2 UTF-8 @@ -161,6 +161,30 @@ + + org.jacoco + jacoco-maven-plugin + 0.8.6 + + + **/*com/softlayer/api/service/**/* + + + + + + prepare-agent + + + + report + prepare-package + + report + + + + diff --git a/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java b/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java index 75ff90f..15a355c 100644 --- a/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java +++ b/src/test/java/com/softlayer/api/http/BuiltInHttpClientFactoryTest.java @@ -23,6 +23,14 @@ public void testGetThreadPoolDefaultsToDaemonThreads() throws Exception { assertTrue(daemon); } + @Test + public void testGetThreadPoolLazyLoading() { + BuiltInHttpClientFactory factory = new BuiltInHttpClientFactory(); + ExecutorService threadPool = factory.getThreadPool(); + assertNotNull(threadPool); + assertEquals(threadPool, factory.getThreadPool()); + } + @Test public void testSetThreadPoolShutsDownNonUserDefined() { BuiltInHttpClientFactory factory = new BuiltInHttpClientFactory(); From 80ed0e74cb3286d4b530934ed7f43dbf0b80aa66 Mon Sep 17 00:00:00 2001 From: Christopher Gallo Date: Thu, 7 Jan 2021 13:03:32 -0600 Subject: [PATCH 14/23] cleared up some documentation for BearerAuthorization --- README.md | 2 +- .../com/softlayer/api/http/HttpBearerCredentials.java | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ca73258..1944b81 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ instantiate it and provide your credentials: #### Username and API Key -For using a Classic Infrastructure or IBM Cloud API key. When using the IBM Cloud Api key, your username is litterally `apikey`, more information about that can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#cloud-api) article. +For using a Classic Infrastructure or IBM Cloud API key. When using the IBM Cloud Api key, your username is the literal string `apikey`, more information about that can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#cloud-api) article. ```java import com.softlayer.api.*; diff --git a/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java b/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java index fd80aa1..951f4f2 100644 --- a/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java +++ b/src/main/java/com/softlayer/api/http/HttpBearerCredentials.java @@ -1,9 +1,13 @@ package com.softlayer.api.http; -/** HTTP bearer authorization support for bearer token fromhttps://iam.cloud.ibm.com/identity/token */ +/** HTTP Bearer authorization support for IBM IAM Tokens. + * + * @see IAM Tokens + * @see Authenticating SoftLayer API + */ public class HttpBearerCredentials implements HttpCredentials { - public final String token; + protected final String token; public HttpBearerCredentials(String token) { this.token = token; From 1e82fa35d5cca13b11ff2be045fde93ac9ef098a Mon Sep 17 00:00:00 2001 From: Christopher Gallo Date: Thu, 14 Jan 2021 14:45:18 -0600 Subject: [PATCH 15/23] fixed pull request feedback --- LICENSE | 2 +- README.md | 2 +- examples/pom.xml | 2 +- gen/pom.xml | 2 +- src/main/java/com/softlayer/api/http/HttpCredentials.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index d8f5d64..213959f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2020 The SoftLayer Developer Network +Copyright (c) 2021 The SoftLayer Developer Network Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1944b81..c99f64f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ import com.softlayer.api.*; ApiClient client = new RestApiClient().withCredentials("my user", "my api key"); ``` -#### Acesses Token +#### Access Token Information on how to get a temoprary api token can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) article. ```java diff --git a/examples/pom.xml b/examples/pom.xml index 21d766c..7a988fc 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-examples jar - 0.3.1 + 0.3.2 softlayer-api-client-examples http://sldn.softlayer.com diff --git a/gen/pom.xml b/gen/pom.xml index f1becb3..c62354f 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-gen jar - 0.3.1 + 0.3.2 softlayer-api-client-gen http://sldn.softlayer.com diff --git a/src/main/java/com/softlayer/api/http/HttpCredentials.java b/src/main/java/com/softlayer/api/http/HttpCredentials.java index a588f83..a751a46 100644 --- a/src/main/java/com/softlayer/api/http/HttpCredentials.java +++ b/src/main/java/com/softlayer/api/http/HttpCredentials.java @@ -2,5 +2,5 @@ /** Base interface for all accepted HTTP credentials */ public interface HttpCredentials { - public String getHeader(); + String getHeader(); } From 7492c132e5930c0964af1f7ab952fca896e4e26a Mon Sep 17 00:00:00 2001 From: cmp Date: Thu, 21 Jan 2021 10:49:02 -0600 Subject: [PATCH 16/23] Add credential usage warning --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c99f64f..363c06f 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,12 @@ instantiate it and provide your credentials: #### Username and API Key For using a Classic Infrastructure or IBM Cloud API key. When using the IBM Cloud Api key, your username is the literal string `apikey`, more information about that can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#cloud-api) article. +:warning: Make sure to avoid hard coding your username and API key when using the client! Always pull credentials from the environment, secure config, or other source. + ```java import com.softlayer.api.*; -ApiClient client = new RestApiClient().withCredentials("my user", "my api key"); +ApiClient client = new RestApiClient().withCredentials(myUser, myApiKey); ``` #### Access Token From 76029c8040c709cc98b95fd1806047bae259a2f8 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Tue, 14 Sep 2021 21:41:04 -0500 Subject: [PATCH 17/23] Remove Travis CI config. Prep version 0.3.3. * Update maven workflow and add github pages workflow. * Update dependencies. * Fix links in README and credential misuse examples. --- .github/workflows/maven.yml | 18 ++++++++++-------- .github/workflows/pages.yml | 23 +++++++++++++++++++++++ .travis.yml | 31 ------------------------------- README.md | 26 ++++++++++++++------------ examples/pom.xml | 4 ++-- gen/pom.xml | 10 +++++----- ghpages_secret.enc | Bin 1680 -> 0 bytes pom.xml | 22 +++++++++++----------- 8 files changed, 65 insertions(+), 69 deletions(-) create mode 100644 .github/workflows/pages.yml delete mode 100644 .travis.yml delete mode 100644 ghpages_secret.enc diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6f18e58..67b51dc 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -9,12 +9,14 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [8, 11, 15] + java: [8, 11, 16] steps: - - uses: actions/checkout@v2 - - name: Set up JDK - uses: actions/setup-java@v1 - with: - java-version: ${{matrix.java}} - - name: Build with Maven - run: mvn -B package --file pom.xml + - name: Checkout + uses: actions/checkout@v2 + - name: Set up JDK + uses: actions/setup-java@v2.3.0 + with: + distribution: 'temurin' + java-version: ${{matrix.java}} + - name: Build with Maven + run: mvn verify -B -e -V --file pom.xml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..3e50206 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,23 @@ +name: Publish Pages +on: + push: + branches: + - master +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Build + run: | + apt-get update && apt-get install -y pandoc + mkdir ghpages + pandoc -o ghpages/index.html README.md + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@4.1.5 + with: + branch: gh-pages + folder: ghpages diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6a06ba8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: java - -addons: - apt: - update: true - packages: - - pandoc - -jdk: - - oraclejdk11 - - openjdk8 - - openjdk9 - - openjdk10 - - openjdk11 - - openjdk12 - -install: - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dgpg.skip=true - - mkdir ghpages - - pandoc -o ghpages/index.html README.md - - openssl aes-256-cbc -K $encrypted_60afd10366bc_key -iv $encrypted_60afd10366bc_iv -in ghpages_secret.enc -out ghpages_secret -d - -deploy: - provider: pages:git - edge: true - skip_cleanup: true - local_dir: ghpages - deploy_key: ghpages_secret - keep_history: true - on: - branch: master diff --git a/README.md b/README.md index 363c06f..2baff25 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # SoftLayer API Client for Java -![Java CI](https://github.com/softlayer/softlayer-java/workflows/Java%20CI/badge.svg) +[![Java CI](https://github.com/softlayer/softlayer-java/actions/workflows/maven.yml/badge.svg)](https://github.com/softlayer/softlayer-java/actions/workflows/maven.yml) [![Maven Central](https://img.shields.io/maven-central/v/com.softlayer.api/softlayer-api-client)](https://search.maven.org/artifact/com.softlayer.api/softlayer-api-client) [![Javadocs](https://www.javadoc.io/badge/com.softlayer.api/softlayer-api-client.svg)](https://www.javadoc.io/doc/com.softlayer.api/softlayer-api-client) ## Introduction -This library provides a JVM client for the [SoftLayer API](http://sldn.softlayer.com/article/SoftLayer-API-Overview). It +This library provides a JVM client for the [SoftLayer API](https://sldn.softlayer.com/article/getting-started/). It has code generated and compiled via Maven. The client can work with any Java 8+ runtime. It uses the code generation project in `gen/` to generate the service and type related code. Although likely to work in resource-constrained environments (i.e. Android, J2ME, etc), using this is not recommended; Use the -[REST](http://sldn.softlayer.com/article/REST) API instead. +[REST](https://sldn.softlayer.com/article/rest/) API instead. By default the HTTP client is the Java `HttpUrlConnection` and the JSON marshalling is done by -[Gson](https://code.google.com/p/google-gson/). Both of these pieces can be exchanged for alternative implementations +[Gson](https://github.com/google/gson). Both of these pieces can be exchanged for alternative implementations (see below). The `examples/` project has sample uses of the API. It can be executed from Maven while inside the `examples/` folder @@ -40,20 +40,20 @@ additions to the SoftLayer API. com.softlayer.api softlayer-api-client - 0.3.2 + 0.3.3 ``` ### Gradle ```groovy -implementation 'com.softlayer.api:softlayer-api-client:0.3.2' +implementation 'com.softlayer.api:softlayer-api-client:0.3.3' ``` ### Kotlin ```kotlin -compile("com.softlayer.api:softlayer-api-client:0.3.2") +compile("com.softlayer.api:softlayer-api-client:0.3.3") ``` ### Creating a Client @@ -74,21 +74,23 @@ ApiClient client = new RestApiClient().withCredentials(myUser, myApiKey); ``` #### Access Token -Information on how to get a temoprary api token can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) article. +Information on how to get a temoprary api token can be found on the SLDN +[Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) +article. ```java import com.softlayer.api.*; -ApiClient client = new RestApiClient().withBearerToken("qqqqwwwweeeaaassddd...."); +ApiClient client = new RestApiClient().withBearerToken(myBearerToken); ``` If the end point isn't at the normal SoftLayer API, you can provide the prefix to the constructor of the -`RestApiClient`. By default it is set to the public API endpoint, `https://api.softlayer.com/rest/v3.1/`. +`RestApiClient`. By default, it is set to the public API endpoint, `https://api.softlayer.com/rest/v3.1/`. If you are using the classic infrastructure private network, you can communicate with the API over that network by using the service URL instead: ```java ApiClient client = new RestApiClient(RestApiClient.BASE_SERVICE_URL) - .withCredentials("my user", "my api key"); + .withCredentials(myUser, myApiKey); ``` ### Making API Calls @@ -170,7 +172,7 @@ for (Vlan vlan : service.getObject().getNetworkVlans()) { All values of a type can be masked upon. If a value represents a primitive or collection of primitives, the same mask it is called on is returned. Otherwise the mask of the other type is given. These translate into SoftLayer's -[string-based object mask format](http://sldn.softlayer.com/article/Object-Masks). A string or an instance of a mask +[string-based object mask format](https://sldn.softlayer.com/article/object-masks/). A string or an instance of a mask can be given directly by calling `setMask` on the service. Note, when object masks are added on a service object, they will be sent with every service call unless removed via `clearMask` or overwritten via `withNewMask` or `setMask`. diff --git a/examples/pom.xml b/examples/pom.xml index 7a988fc..ca8db44 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-examples jar - 0.3.2 + 0.3.3 softlayer-api-client-examples http://sldn.softlayer.com @@ -36,7 +36,7 @@ org.codehaus.mojo exec-maven-plugin - 1.6.0 + 3.0.0 diff --git a/gen/pom.xml b/gen/pom.xml index c62354f..9a7961f 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -5,7 +5,7 @@ softlayer-api-client-gen jar - 0.3.2 + 0.3.3 softlayer-api-client-gen http://sldn.softlayer.com @@ -29,12 +29,12 @@ com.google.code.gson gson - 2.8.6 + 2.8.8 junit junit - 4.13.1 + 4.13.2 test @@ -43,7 +43,7 @@ org.codehaus.mojo exec-maven-plugin - 1.6.0 + 3.0.0 @@ -58,7 +58,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.1.1 + 3.3.1 ${java.version} diff --git a/ghpages_secret.enc b/ghpages_secret.enc deleted file mode 100644 index 00f2d2dd1621942d5fd86858ba6e2dd70a7e21cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1680 zcmV;B25a!HSY;t5VW`I zj6X`@zbB5p)CeOBuJ%$+ShwS zYkCh)e1&w4!u5TLrI)`IoV-ddzk~@oxTVIPO=2SiEh)#g{*5VoT9bspE*6U3&#NSs~*XnCBQLB-BlKgQl)F} z9wf4yghr3;d8z?_lxHUF^mAVTR7vDOCofyKqNd;*eY@#Rn7THUF1fV>jRHu}3_v zYoXRgB9(ybXVB=JpGRBaa%V4Ku>_+Sl?Ka@W8oyb42zf{=j~noMFdS0rT(0V`HeGd zje(1e2YL5liZ*X{iLoH;|2jrN{T+x?uWv$=xjB=k8?Y{m2P$FdBI_Yqc(8Bd3!+Mv zXW59n0NdrT90Oz>8i%7p+N>Xwq&=U+M5HKR(jL>Kr=MmU1$0_ujCIZFOo(*nTx7CC z7pTJY0;L0!X)m@gz{(xQJGM5@o*Q2cDx{LXl=if}O8QG=#!Xh$c(?_`!a<~)BvGgb z(c;hUsjZW^X%c1!4*k7Xgdqa*SO=;{I2u62%Vcd#PVPt%d=R{|S zzQ{7vbeXBSBQ!3?PVhk{OTQp~_p?bv*Fu{xtrN&bbc)oAlswcZv%Y4es8|tbP$w{A^KQov6K3@2E#yi%0L8KA>p)bk1G$>x zsWbvy8bA(HB`@5aM_(|`4nnU?T}W}Z{^WsbCi~J}t%zC$L5!Bz%bI^nO}AQI4m(l+ zP!G;NoquANSytz;aj*_u_`j@Pgzx;1u=*J2YWHEDFs<}a46lb$kB6)xO;eep!~Jo3 z&h*as7yA<%)c`%E%50MzBT=zRPIxZp5yo=7WV8>bh@uaQ^CxycvBpcVt3=q|&L49C zLNrPJ6%K8XDi_PW7d6!(>astWJ(Xd{b5wx9ywPhNJQRKhBm>y3Io?!gud)FEFBh#* zkRjQWyUL{QOS4?hOL=WkvOp=4A=PC(s{BEk(5|F z;8O)SDofHf|5J;5gAtXe4gzw+Ll!6DYfCpQY`DA=S z``}??k({vhbx?dBgXm^NoGy47nK$b-kyTkg8N}-j9Ct(lW1Br^Ds(wF)|oZ7W+-kF zW27J?o@IHuCK3!63(CDK1&qDk2o)ySEYka3v@softlayer-api-client jar - 0.3.2 + 0.3.3 SoftLayer API Client for Java API client for accessing the SoftLayer API - http://sldn.softlayer.com + https://sldn.softlayer.com The MIT License (MIT) - http://opensource.org/licenses/MIT + https://opensource.org/licenses/MIT repo @@ -28,7 +28,7 @@ camporter Cameron Porter IBM - http://ibm.com/cloud + https://ibm.com/cloud owner developer @@ -40,7 +40,7 @@ scm:git:git@github.com:softlayer/softlayer-java.git scm:git:git@github.com:softlayer/softlayer-java.git git@github.com:softlayer/softlayer-java.git - 0.3.2 + 0.3.3 UTF-8 @@ -66,12 +66,12 @@ com.google.code.gson gson - 2.8.6 + 2.8.8 junit junit - 4.13.1 + 4.13.2 test @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.1.1 + 3.3.1 @@ -128,7 +128,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.0.1 sign-artifacts @@ -142,7 +142,7 @@ maven-invoker-plugin - 3.2.1 + 3.2.2 generate-services @@ -164,7 +164,7 @@ org.jacoco jacoco-maven-plugin - 0.8.6 + 0.8.7 **/*com/softlayer/api/service/**/* From d2e3ddad640186f42c79a166a1bd87b59a75fe98 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 15 Sep 2021 12:41:26 -0500 Subject: [PATCH 18/23] Skip gpg signing for the maven workflow. --- .github/workflows/maven.yml | 2 +- pom.xml | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 67b51dc..5a48c50 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -19,4 +19,4 @@ jobs: distribution: 'temurin' java-version: ${{matrix.java}} - name: Build with Maven - run: mvn verify -B -e -V --file pom.xml + run: mvn verify -B -e -V --file pom.xml -Dgpg.skip=true diff --git a/pom.xml b/pom.xml index 7612382..32b563f 100644 --- a/pom.xml +++ b/pom.xml @@ -46,12 +46,6 @@ UTF-8 8 - - - jcenter - https://jcenter.bintray.com/ - - ossrh From a1e38e9fa97b771797a9546ae751f7f4635ed6f1 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 15 Sep 2021 12:50:01 -0500 Subject: [PATCH 19/23] Use maven cache for java setup. --- .github/workflows/maven.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 5a48c50..36a45c6 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -18,5 +18,6 @@ jobs: with: distribution: 'temurin' java-version: ${{matrix.java}} + cache: 'maven' - name: Build with Maven run: mvn verify -B -e -V --file pom.xml -Dgpg.skip=true From 7a337d9d8a72a6bb517105ce9c4e986e84ce9502 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Wed, 15 Sep 2021 13:46:35 -0500 Subject: [PATCH 20/23] Publishing requires using passwordless sudo to install pandoc. --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 3e50206..fb9fbe9 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -12,7 +12,7 @@ jobs: - name: Build run: | - apt-get update && apt-get install -y pandoc + sudo apt-get update && sudo apt-get install -y pandoc mkdir ghpages pandoc -o ghpages/index.html README.md From 7b1a5a0bec48d2753e8445ae53c6ee802c4e6839 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Thu, 16 Dec 2021 16:57:28 -0600 Subject: [PATCH 21/23] Process deprecations from the API metadata and annotate types, methods, and properties if they are deprecated. --- .github/workflows/maven.yml | 4 +- examples/pom.xml | 7 ++- gen/pom.xml | 7 ++- .../com/softlayer/api/gen/ClassWriter.java | 50 +++++++++++++++---- .../main/java/com/softlayer/api/gen/Meta.java | 3 ++ pom.xml | 25 +++++++++- 6 files changed, 78 insertions(+), 18 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 36a45c6..2581fba 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [8, 11, 16] + java: [8, 11, 16, 17] steps: - name: Checkout uses: actions/checkout@v2 - name: Set up JDK - uses: actions/setup-java@v2.3.0 + uses: actions/setup-java@v2.4.0 with: distribution: 'temurin' java-version: ${{matrix.java}} diff --git a/examples/pom.xml b/examples/pom.xml index ca8db44..09cd982 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,17 +1,20 @@ 4.0.0 + + 3.3.9 + com.softlayer.api softlayer-api-client-examples jar 0.3.3 softlayer-api-client-examples - http://sldn.softlayer.com + https://sldn.softlayer.com/ The MIT License (MIT) - http://opensource.org/licenses/MIT + https://opensource.org/licenses/MIT repo diff --git a/gen/pom.xml b/gen/pom.xml index 9a7961f..0181564 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -1,13 +1,16 @@ 4.0.0 + + 3.3.9 + com.softlayer.api softlayer-api-client-gen jar 0.3.3 softlayer-api-client-gen - http://sldn.softlayer.com + https://sldn.softlayer.com/ The MIT License (MIT) @@ -29,7 +32,7 @@ com.google.code.gson gson - 2.8.8 + 2.8.9 junit diff --git a/gen/src/main/java/com/softlayer/api/gen/ClassWriter.java b/gen/src/main/java/com/softlayer/api/gen/ClassWriter.java index 671c04f..2d4ef46 100644 --- a/gen/src/main/java/com/softlayer/api/gen/ClassWriter.java +++ b/gen/src/main/java/com/softlayer/api/gen/ClassWriter.java @@ -134,6 +134,10 @@ public ClassWriter emitProperty(TypeClass.Property property) throws IOException if (property.meta.doc != null) { emitJavadoc(property.meta.doc.replace("\n", "
\n")); } + + if (property.meta.deprecated) { + emitAnnotation("Deprecated"); + } Map params = new HashMap<>(2); if (!property.name.equals(property.meta.name)) { @@ -267,6 +271,10 @@ public ClassWriter emitServiceMethod(TypeClass.Method method, boolean async) thr javadoc += "@see " + type.meta.name + "::" + method.meta.name + ""; emitJavadoc(javadoc); + + if (method.meta.deprecated) { + emitAnnotation("Deprecated"); + } Map params = new HashMap<>(2); if (!method.name.equals(method.meta.name)) { @@ -279,6 +287,10 @@ public ClassWriter emitServiceMethod(TypeClass.Method method, boolean async) thr } else { // Otherwise, just a javadoc link emitJavadoc("Async version of {@link Service#" + method.name + "}"); + + if (method.meta.deprecated) { + emitAnnotation("Deprecated"); + } } String[] parameters = new String[method.parameters.size() * 2]; @@ -296,6 +308,9 @@ public ClassWriter emitServiceMethod(TypeClass.Method method, boolean async) thr // Async has an extra callback method if (async) { + if (method.meta.deprecated) { + emitAnnotation("Deprecated"); + } parameters = Arrays.copyOf(parameters, parameters.length + 2); parameters[parameters.length - 2] = TYPE_RESPONSE_HANDLER + '<' + method.javaType + '>'; parameters[parameters.length - 1] = "callback"; @@ -324,6 +339,10 @@ public ClassWriter emitServiceMethod(TypeClass.Property property, boolean async) javadoc += "@see " + type.meta.name + "::" + name + ""; emitJavadoc(javadoc); + + if (property.meta.deprecated) { + emitAnnotation("Deprecated"); + } // Instance is only required if it's not an account property if ("SoftLayer_Account".equals(type.meta.name)) { @@ -334,6 +353,10 @@ public ClassWriter emitServiceMethod(TypeClass.Property property, boolean async) } else { // Otherwise, just a javadoc link emitJavadoc("Async version of {@link Service#" + name + "}"); + + if (property.meta.deprecated) { + emitAnnotation("Deprecated"); + } } String returnType = property.javaType; @@ -355,17 +378,12 @@ public ClassWriter emitType() throws IOException { emitPackage(type.packageName); emitTypeImports(); - - // Javadoc - String javadoc = type.meta.typeDoc != null ? type.meta.typeDoc : type.meta.serviceDoc; - if (javadoc == null) { - javadoc = ""; - } else { - javadoc = javadoc.replace("\n", "
\n") + "\n\n"; + + emitJavadoc(getTypeJavadoc()); + + if (type.meta.deprecated) { + emitAnnotation("Deprecated"); } - javadoc += "@see " + type.meta.name + ""; - emitJavadoc(javadoc); // Each type has a type attribute emitAnnotation("ApiType", stringLiteral(type.meta.name)); @@ -432,6 +450,18 @@ public ClassWriter emitType() throws IOException { emitMask().endType(); return this; } + + protected String getTypeJavadoc() { + String javadoc = type.meta.typeDoc != null ? type.meta.typeDoc : type.meta.serviceDoc; + if (javadoc == null) { + javadoc = ""; + } else { + javadoc = javadoc.replace("\n", "
\n") + "\n\n"; + } + javadoc += "@see " + type.meta.name + ""; + return javadoc; + } public ClassWriter emitTypeImports() throws IOException { Map imports = new HashMap<>(type.imports); diff --git a/gen/src/main/java/com/softlayer/api/gen/Meta.java b/gen/src/main/java/com/softlayer/api/gen/Meta.java index 7a9ad8d..838af47 100644 --- a/gen/src/main/java/com/softlayer/api/gen/Meta.java +++ b/gen/src/main/java/com/softlayer/api/gen/Meta.java @@ -75,6 +75,7 @@ public static class Type { public String serviceDoc; public Map methods = Collections.emptyMap(); public boolean noservice; + public boolean deprecated; } /** @@ -86,6 +87,7 @@ public static class Property { public boolean typeArray; public PropertyForm form; public String doc; + public boolean deprecated; } public enum PropertyForm { @@ -109,6 +111,7 @@ public static class Method { public boolean filterable; public boolean maskable; public List parameters = Collections.emptyList(); + public boolean deprecated; } /** diff --git a/pom.xml b/pom.xml index 32b563f..314cd06 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,8 @@ 4.0.0 + + 3.3.9 + com.softlayer.api softlayer-api-client jar @@ -60,7 +63,7 @@ com.google.code.gson gson - 2.8.8 + 2.8.9 junit @@ -71,7 +74,7 @@ org.mockito mockito-core - 3.6.0 + 4.2.0 test @@ -181,4 +184,22 @@
+ + + + org.codehaus.mojo + versions-maven-plugin + 2.8.1 + + + + dependency-updates-report + plugin-updates-report + property-updates-report + + + + + + From ecc49545c1d487ae1261d3b4e6e30ce0817d1c28 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Fri, 17 Dec 2021 12:08:09 -0600 Subject: [PATCH 22/23] Release version 0.3.4 --- CHANGELOG.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 8 +++---- examples/pom.xml | 2 +- gen/pom.xml | 2 +- pom.xml | 4 ++-- 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e123418 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,56 @@ +# Changelog + +Note that new releases update the API types and services and may change or remove classes, methods, and types without +notice. + +## [Unreleased] + +## [0.3.4] - 2021-12-17 + +### Changed +* Add deprecation annotations to types, properties, and methods. Deprecations may be removed in future changes to the + API. + +### Changed +* New service definitions. + +## [0.3.3] - 2021-09-15 + +### Changed +* Updated services and types. +* Updated dependencies. + +## [0.3.2] - 2021-01-20 + +### Added +* Added support for Bearer Authentication Token Support. + +```java +import com.softlayer.api.*; +ApiClient client = new RestApiClient().withBearerToken("qqqqwwwweeeaaassddd...."); +``` + +### Changed +* Updated services and types. + +## [0.3.1] - 2021-11-09 + +### Changed +* Updated services and types. + +## [0.3.0] - 2021-03-25 + +### Added +* Added a new `RestApiClient.BASE_SERVICE_URL` constant to use the client with the classic infrastructure private + network. + +### Changed +* A breaking change has been made. Coerce return types to whatever the API metadata says should be returned, even if + the type returned by the API does not match (#64). + +* Updated services and types. + +## [0.2.9] - 2020-01-21 + +### Changed +* Updated generated services and types. diff --git a/README.md b/README.md index 2baff25..a771bf3 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,20 @@ additions to the SoftLayer API. com.softlayer.api softlayer-api-client - 0.3.3 + 0.3.4 ``` ### Gradle ```groovy -implementation 'com.softlayer.api:softlayer-api-client:0.3.3' +implementation 'com.softlayer.api:softlayer-api-client:0.3.4' ``` ### Kotlin ```kotlin -compile("com.softlayer.api:softlayer-api-client:0.3.3") +compile("com.softlayer.api:softlayer-api-client:0.3.4") ``` ### Creating a Client @@ -74,7 +74,7 @@ ApiClient client = new RestApiClient().withCredentials(myUser, myApiKey); ``` #### Access Token -Information on how to get a temoprary api token can be found on the SLDN +Information on how to get a temporary api token can be found on the SLDN [Authenticating to the SoftLayer API](https://sldn.softlayer.com/article/authenticating-softlayer-api/#temp-token) article. diff --git a/examples/pom.xml b/examples/pom.xml index 09cd982..f90f564 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -8,7 +8,7 @@ softlayer-api-client-examples jar - 0.3.3 + 0.3.4 softlayer-api-client-examples https://sldn.softlayer.com/ diff --git a/gen/pom.xml b/gen/pom.xml index 0181564..768a3a5 100644 --- a/gen/pom.xml +++ b/gen/pom.xml @@ -8,7 +8,7 @@ softlayer-api-client-gen jar - 0.3.3 + 0.3.4 softlayer-api-client-gen https://sldn.softlayer.com/ diff --git a/pom.xml b/pom.xml index 314cd06..23bd176 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ softlayer-api-client jar - 0.3.3 + 0.3.4 SoftLayer API Client for Java API client for accessing the SoftLayer API https://sldn.softlayer.com @@ -43,7 +43,7 @@ scm:git:git@github.com:softlayer/softlayer-java.git scm:git:git@github.com:softlayer/softlayer-java.git git@github.com:softlayer/softlayer-java.git - 0.3.3 + 0.3.4 UTF-8 From 6185d58b1d7c34146a66922c0bbe440df8ca6941 Mon Sep 17 00:00:00 2001 From: Cameron Porter Date: Fri, 17 Dec 2021 12:17:52 -0600 Subject: [PATCH 23/23] Correct some changelog release dates --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e123418..b8b5301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,12 +33,12 @@ ApiClient client = new RestApiClient().withBearerToken("qqqqwwwweeeaaassddd...." ### Changed * Updated services and types. -## [0.3.1] - 2021-11-09 +## [0.3.1] - 2020-11-09 ### Changed * Updated services and types. -## [0.3.0] - 2021-03-25 +## [0.3.0] - 2020-03-25 ### Added * Added a new `RestApiClient.BASE_SERVICE_URL` constant to use the client with the classic infrastructure private