Skip to content

Commit 382291a

Browse files
John TompkinsRJ Lohan
authored andcommitted
Stripping writeOnlyProperties when recording progress (#222)
* Stripping writeOnlyProperties when recording progress * Remove ambiguous constructor & small template changes
1 parent 7460c2a commit 382291a

File tree

5 files changed

+38
-14
lines changed

5 files changed

+38
-14
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>software.amazon.cloudformation</groupId>
55
<artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
6-
<version>1.0.1</version>
6+
<version>1.0.4</version>
77
<name>AWS CloudFormation RPDK Java Plugin</name>
88
<description>The CloudFormation Resource Provider Development Kit (RPDK) allows you to author your own resource providers that can be used by CloudFormation. This plugin library helps to provide runtime bindings for the execution of your providers by CloudFormation.
99
</description>
@@ -65,7 +65,7 @@
6565
<dependency>
6666
<groupId>software.amazon.cloudformation</groupId>
6767
<artifactId>aws-cloudformation-resource-schema</artifactId>
68-
<version>2.0.0</version>
68+
<version>2.0.2</version>
6969
</dependency>
7070
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-databind -->
7171
<dependency>

python/rpdk/java/templates/HandlerWrapper.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
public final class HandlerWrapper extends LambdaWrapper<{{ pojo_name }}, CallbackContext> {
3838

3939
private final Configuration configuration = new Configuration();
40+
private JSONObject resourceSchema;
4041
private final Map<Action, BaseHandler<CallbackContext>> handlers = new HashMap<>();
4142
private final static TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext>> REQUEST_REFERENCE =
4243
new TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext>>() {};
@@ -111,7 +112,10 @@ public void testEntrypoint(
111112

112113
@Override
113114
public JSONObject provideResourceSchemaJSONObject() {
114-
return this.configuration.resourceSchemaJSONObject();
115+
if (resourceSchema == null) {
116+
resourceSchema = this.configuration.resourceSchemaJSONObject();
117+
}
118+
return resourceSchema;
115119
}
116120

117121
@Override

src/main/java/software/amazon/cloudformation/LambdaWrapper.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import software.amazon.cloudformation.proxy.ProgressEvent;
7575
import software.amazon.cloudformation.proxy.RequestContext;
7676
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;
77+
import software.amazon.cloudformation.resource.ResourceTypeSchema;
7778
import software.amazon.cloudformation.resource.SchemaValidator;
7879
import software.amazon.cloudformation.resource.Serializer;
7980
import software.amazon.cloudformation.resource.Validator;
@@ -226,7 +227,8 @@ private void initialiseRuntime(final String resourceType,
226227

227228
if (this.callbackAdapter == null) {
228229
this.callbackAdapter = new CloudFormationCallbackAdapter<>(this.cloudFormationProvider, this.loggerProxy,
229-
this.serializer);
230+
this.serializer, ResourceTypeSchema
231+
.load(provideResourceSchemaJSONObject()));
230232
}
231233
this.callbackAdapter.refreshClient();
232234

@@ -495,7 +497,7 @@ private void writeResponse(final OutputStream outputStream, final Response<Resou
495497
private void validateModel(final JSONObject modelObject) throws ValidationException, IOException {
496498
JSONObject resourceSchemaJSONObject = provideResourceSchemaJSONObject();
497499
if (resourceSchemaJSONObject == null) {
498-
throw new ValidationException("Unable to validate incoming model as no schema was provided.", null, null);
500+
throw new TerminalException("Unable to validate incoming model as no schema was provided.");
499501
}
500502

501503
TypeReference<ResourceT> modelTypeReference = getModelTypeReference();
@@ -507,7 +509,6 @@ private void validateModel(final JSONObject modelObject) throws ValidationExcept
507509
} catch (UnrecognizedPropertyException e) {
508510
throw new ValidationException(String.format("#: extraneous key [%s] is not permitted", e.getPropertyName()),
509511
"additionalProperties", "#");
510-
511512
}
512513

513514
JSONObject serializedModel = new JSONObject(this.serializer.serialize(deserializedModel));

src/main/java/software/amazon/cloudformation/proxy/CloudFormationCallbackAdapter.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818

1919
import java.util.UUID;
2020

21+
import org.json.JSONObject;
22+
2123
import software.amazon.awssdk.services.cloudformation.CloudFormationClient;
2224
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressRequest;
2325
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressResponse;
2426
import software.amazon.cloudformation.exceptions.TerminalException;
2527
import software.amazon.cloudformation.injection.CloudFormationProvider;
28+
import software.amazon.cloudformation.resource.ResourceTypeSchema;
2629
import software.amazon.cloudformation.resource.Serializer;
2730

2831
public class CloudFormationCallbackAdapter<T> implements CallbackAdapter<T> {
@@ -35,12 +38,16 @@ public class CloudFormationCallbackAdapter<T> implements CallbackAdapter<T> {
3538

3639
private Serializer serializer;
3740

41+
private ResourceTypeSchema resourceTypeSchema;
42+
3843
public CloudFormationCallbackAdapter(final CloudFormationProvider cloudFormationProvider,
3944
final LoggerProxy loggerProxy,
40-
final Serializer serializer) {
45+
final Serializer serializer,
46+
final ResourceTypeSchema resourceTypeSchema) {
4147
this.cloudFormationProvider = cloudFormationProvider;
4248
this.loggerProxy = loggerProxy;
4349
this.serializer = serializer;
50+
this.resourceTypeSchema = resourceTypeSchema;
4451
}
4552

4653
public void refreshClient() {
@@ -62,8 +69,10 @@ public void reportProgress(final String bearerToken,
6269

6370
if (resourceModel != null) {
6471
try {
72+
JSONObject jsonModel = new JSONObject(this.serializer.serialize(resourceModel));
73+
resourceTypeSchema.removeWriteOnlyProperties(jsonModel);
6574
// expect return type to be non-null
66-
requestBuilder.resourceModel(this.serializer.serialize(resourceModel));
75+
requestBuilder.resourceModel(jsonModel.toString());
6776
} catch (JsonProcessingException e) {
6877
throw new TerminalException("Unable to serialize resource model for reporting progress", e);
6978
}

src/test/java/software/amazon/cloudformation/proxy/CloudFormationCallbackAdapterTest.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import java.util.UUID;
3333

34+
import org.json.JSONObject;
3435
import org.junit.jupiter.api.Test;
3536
import org.junit.jupiter.api.extension.ExtendWith;
3637
import org.mockito.ArgumentCaptor;
@@ -43,6 +44,7 @@
4344
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressResponse;
4445
import software.amazon.cloudformation.TestModel;
4546
import software.amazon.cloudformation.injection.CloudFormationProvider;
47+
import software.amazon.cloudformation.resource.ResourceTypeSchema;
4648
import software.amazon.cloudformation.resource.Serializer;
4749

4850
@ExtendWith(MockitoExtension.class)
@@ -57,12 +59,15 @@ public class CloudFormationCallbackAdapterTest {
5759
@Mock
5860
private Serializer serializer;
5961

62+
@Mock
63+
private ResourceTypeSchema resourceTypeSchema;
64+
6065
@Test
6166
public void testReportProgress_withoutRefreshingClient() {
62-
final CloudFormationClient client = mock(CloudFormationClient.class);
6367

6468
final CloudFormationCallbackAdapter<
65-
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
69+
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
70+
resourceTypeSchema);
6671
final AssertionError expectedException = assertThrows(AssertionError.class, () -> adapter.reportProgress("bearer-token",
6772
HandlerErrorCode.InvalidRequest, OperationStatus.FAILED, OperationStatus.IN_PROGRESS, null, "some error"),
6873
"Expected assertion exception");
@@ -84,7 +89,8 @@ public void testReportProgress_Failed() {
8489
when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);
8590

8691
final CloudFormationCallbackAdapter<
87-
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
92+
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
93+
resourceTypeSchema);
8894
adapter.refreshClient();
8995

9096
adapter.reportProgress("bearer-token", HandlerErrorCode.InvalidRequest, OperationStatus.FAILED,
@@ -111,12 +117,13 @@ public void testReportProgress_IN_PROGRESS() throws JsonProcessingException {
111117
when(response.responseMetadata()).thenReturn(responseMetadata);
112118

113119
when(cloudFormationProvider.get()).thenReturn(client);
114-
when(serializer.serialize(any())).thenReturn("");
120+
when(serializer.serialize(any())).thenReturn("{}");
115121

116122
when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);
117123

118124
final CloudFormationCallbackAdapter<
119-
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
125+
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
126+
resourceTypeSchema);
120127

121128
adapter.refreshClient();
122129

@@ -131,6 +138,8 @@ public void testReportProgress_IN_PROGRESS() throws JsonProcessingException {
131138
assertThat(argument.getValue().operationStatus()).isEqualTo(IN_PROGRESS);
132139
assertThat(argument.getValue().currentOperationStatus()).isEqualTo(PENDING);
133140
assertThat(argument.getValue().statusMessage()).isEqualTo("doing it");
141+
142+
verify(resourceTypeSchema).removeWriteOnlyProperties(any(JSONObject.class));
134143
}
135144

136145
@Test
@@ -147,7 +156,8 @@ public void testReportProgress_SUCCESS() {
147156
when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);
148157

149158
final CloudFormationCallbackAdapter<
150-
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
159+
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
160+
resourceTypeSchema);
151161
adapter.refreshClient();
152162

153163
adapter.reportProgress("bearer-token", null, OperationStatus.SUCCESS, OperationStatus.IN_PROGRESS, null, "Succeeded");

0 commit comments

Comments
 (0)