Skip to content

Commit 73d3ac3

Browse files
authored
Merge pull request #18 from makeOurCity/feature/add-get-entity
updateEntity updated using POST
2 parents 538b3d5 + cf33b9b commit 73d3ac3

4 files changed

Lines changed: 167 additions & 0 deletions

File tree

src/main/java/city/makeour/moc/MocClient.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import java.security.InvalidKeyException;
44
import java.security.NoSuchAlgorithmException;
5+
import java.util.Map;
56

7+
import org.springframework.web.client.RestClient;
68
import org.springframework.web.client.RestClient.ResponseSpec;
79

810
import city.makeour.moc.ngsiv2.Ngsiv2Client;
911
import city.makeour.ngsi.v2.api.EntitiesApi;
1012
import city.makeour.ngsi.v2.invoker.ApiClient;
13+
import city.makeour.ngsi.v2.model.UpdateExistingEntityAttributesRequest;
1114

1215
public class MocClient {
1316
protected Ngsiv2Client client;
@@ -146,4 +149,36 @@ public ResponseSpec getEntity(String entityId, String type) {
146149
return this.entities().retrieveEntityWithResponseSpec(entityId, type, null, null, "keyValues");
147150
}
148151

152+
public ResponseSpec updateEntity(String id, String type, Map<String, Object> attributesToUpdate) {
153+
if (id == null || id.isBlank()) throw new IllegalArgumentException("id is required");
154+
if (type == null || type.isBlank()) throw new IllegalArgumentException("type is required");
155+
if (attributesToUpdate == null) attributesToUpdate = java.util.Collections.emptyMap();
156+
157+
try {
158+
// Existence check
159+
this.entities()
160+
.retrieveEntityWithResponseSpec(id, type, null, null, "keyValues")
161+
.toEntity(Object.class);
162+
163+
// Exists -> POST (keyValues 形式でそのまま送る)
164+
return this.client.updateEntityAttributes(
165+
id,
166+
"application/json",
167+
attributesToUpdate, // Object(Map) をそのまま PATCH
168+
type,
169+
"keyValues"
170+
);
171+
172+
} catch (org.springframework.web.client.RestClientResponseException e) {
173+
if (e.getStatusCode().value() != 404) throw e;
174+
175+
// Not found -> create (従来通り)
176+
java.util.Map<String, Object> body = new java.util.HashMap<>();
177+
body.put("id", id);
178+
body.put("type", type);
179+
body.putAll(attributesToUpdate);
180+
return this.createEntity("application/json", body);
181+
}
182+
}
183+
149184
}

src/main/java/city/makeour/moc/auth/srp/Helper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ public static byte[] padHex(BigInteger bigInt) {
3636
}
3737

3838
public static byte[] hexStringToByteArray(String s) {
39+
40+
// 奇数桁なら先頭に 0 を追加
41+
if (s.length() % 2 != 0) {
42+
s = "0" + s;
43+
}
44+
3945
int len = s.length();
4046
byte[] data = new byte[len / 2];
4147
for (int i = 0; i < len; i += 2) {

src/main/java/city/makeour/moc/ngsiv2/Ngsiv2Client.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,71 @@ public RestClient.ResponseSpec createEntity(String contentType, Object body) {
7171
localVarReturnType);
7272
}
7373
}
74+
75+
public RestClient.ResponseSpec updateEntityAttributes(
76+
String entityId,
77+
String contentType,
78+
Object body,
79+
String type,
80+
String options
81+
) {
82+
if (entityId == null) {
83+
throw new RestClientResponseException(
84+
"Missing the required parameter 'entityId' when calling updateEntityAttributes",
85+
HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(),
86+
(HttpHeaders) null, (byte[]) null, (Charset) null
87+
);
88+
}
89+
if (contentType == null) {
90+
throw new RestClientResponseException(
91+
"Missing the required parameter 'contentType' when calling updateEntityAttributes",
92+
HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(),
93+
(HttpHeaders) null, (byte[]) null, (Charset) null
94+
);
95+
}
96+
if (body == null) {
97+
throw new RestClientResponseException(
98+
"Missing the required parameter 'body' when calling updateEntityAttributes",
99+
HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(),
100+
(HttpHeaders) null, (byte[]) null, (Charset) null
101+
);
102+
}
103+
104+
Map<String, Object> pathParams = new HashMap();
105+
pathParams.put("entityId", entityId);
106+
107+
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap();
108+
HttpHeaders headerParams = new HttpHeaders();
109+
MultiValueMap<String, String> cookieParams = new LinkedMultiValueMap();
110+
MultiValueMap<String, Object> formParams = new LinkedMultiValueMap();
111+
112+
// ?type=... と ?options=...
113+
queryParams.putAll(this.apiClient.parameterToMultiValueMap(null, "type", type));
114+
queryParams.putAll(this.apiClient.parameterToMultiValueMap(null, "options", options));
115+
116+
headerParams.add("Content-Type", this.apiClient.parameterToString(contentType));
117+
118+
String[] localVarAccepts = new String[] { }; // 204 No Content 想定
119+
List<MediaType> localVarAccept = this.apiClient.selectHeaderAccept(localVarAccepts);
120+
String[] localVarContentTypes = new String[] { "application/json" };
121+
MediaType localVarContentType = this.apiClient.selectHeaderContentType(localVarContentTypes);
122+
String[] localVarAuthNames = new String[] { };
123+
124+
ParameterizedTypeReference<Void> localVarReturnType = new ParameterizedTypeReference<>() {};
125+
return this.apiClient.invokeAPI(
126+
"/v2/entities/{entityId}/attrs",
127+
HttpMethod.POST,
128+
pathParams,
129+
queryParams,
130+
body, // ← Map<String,Object> 等をそのまま渡す
131+
headerParams,
132+
cookieParams,
133+
formParams,
134+
localVarAccept,
135+
localVarContentType,
136+
localVarAuthNames,
137+
localVarReturnType
138+
);
139+
}
140+
74141
}

src/test/java/city/makeour/moc/MocClientTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
package city.makeour.moc;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
45
import static org.junit.jupiter.api.Assertions.assertNotNull;
56

67
import java.security.GeneralSecurityException;
78
import java.security.NoSuchAlgorithmException;
9+
import java.util.HashMap;
810
import java.util.List;
11+
import java.util.Map;
912
import java.util.UUID;
1013

1114
import org.junit.jupiter.api.DisplayName;
1215
import org.junit.jupiter.api.Test;
1316
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
1417
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariables;
18+
import org.springframework.core.ParameterizedTypeReference;
1519

1620
import city.makeour.ngsi.v2.api.EntitiesApi;
1721
import city.makeour.ngsi.v2.model.CreateEntityRequest;
@@ -145,5 +149,60 @@ void testCreateAndGetEntity_Minimal() throws GeneralSecurityException, NoSuchAlg
145149

146150
assertNotNull(retrievedEntity);
147151
assertEquals(entityId, retrievedEntity.getId());
152+
}
153+
154+
@Test
155+
@DisplayName("updateEntityのUpsert(作成・更新)ロジックをテストする")
156+
@EnabledIfEnvironmentVariables({
157+
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USER_POOL_ID", matches = ".*"),
158+
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_CLIENT_ID", matches = ".*"),
159+
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_USERNAME", matches = ".*"),
160+
@EnabledIfEnvironmentVariable(named = "TEST_COGNITO_PASSWORD", matches = ".*")
161+
})
162+
void testUpdateEntity_UpsertLogic() throws GeneralSecurityException, NoSuchAlgorithmException {
163+
MocClient client = new MocClient();
164+
client.setMocAuthInfo(System.getenv("TEST_COGNITO_USER_POOL_ID"), System.getenv("TEST_COGNITO_CLIENT_ID"));
165+
client.login(System.getenv("TEST_COGNITO_USERNAME"), System.getenv("TEST_COGNITO_PASSWORD"));
166+
167+
String entityId = "urn:ngsi-ld:TestUpsert:" + UUID.randomUUID().toString();
168+
String entityType = "TestUpsertType";
169+
170+
// 1. "作成" (Insert) pathのテスト
171+
// エンティティが存在しない --> catchブロックの this.createEntity
172+
Map<String, Object> initialAttrs = new HashMap<>();
173+
initialAttrs.put("temperature", 25);
174+
initialAttrs.put("humidity", 50); // "temperature" 以外の属性も指定
175+
176+
client.updateEntity(entityId, entityType, initialAttrs);
177+
178+
// 検証 (作成)
179+
ParameterizedTypeReference<Map<String, Object>> mapType = new ParameterizedTypeReference<>() {};
180+
Map<String, Object> createdEntity = client.getEntity(entityId, entityType).body(mapType);
181+
182+
assertNotNull(createdEntity);
183+
assertEquals(entityId, createdEntity.get("id"));
184+
assertEquals(25, createdEntity.get("temperature"));
185+
assertEquals(50, createdEntity.get("humidity"));
186+
187+
// 2. "更新" (Update/PATCH) pathのテスト
188+
// エンティティが既に存在する --> tryブロックの updateExistingEntityAttributesWithResponseSpec
189+
Map<String, Object> updateAttrs = new HashMap<>();
190+
updateAttrs.put("temperature", 30); // 更新
191+
updateAttrs.put("seatNumber", 10); // 追加
192+
updateAttrs.put("status", "active");
193+
194+
client.updateEntity(entityId, entityType, updateAttrs);
195+
196+
// 検証 (更新)
197+
Map<String, Object> updatedEntity = client.getEntity(entityId, entityType).body(mapType);
198+
199+
assertNotNull(updatedEntity);
200+
// 更新・追加されている
201+
assertEquals(30, updatedEntity.get("temperature"));
202+
assertEquals(10, updatedEntity.get("seatNumber"));
203+
// 最初の作成時から変更されず残っている
204+
assertEquals(50, updatedEntity.get("humidity"));
205+
206+
assertEquals("active", updatedEntity.get("status"));
148207
}
149208
}

0 commit comments

Comments
 (0)