Skip to content

Commit 1fb614f

Browse files
Merge pull request #320 from cap-java/errorHandlingFix
Error handling fix
2 parents 9c1a9cf + 43dfa3f commit 1fb614f

File tree

6 files changed

+228
-68
lines changed

6 files changed

+228
-68
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,13 @@ public void onSubscribe(SubscribeEventContext context) {
364364
repository.setDescription("Onboarding Repo Demo");
365365
repository.setDisplayName(" Test Onboarding repo");
366366
repository.setSubdomain(subdomain);
367+
repository.setHashAlgorithms("SHA-256");
367368

368369
// Using SDMAdminServiceImpl onboardRepository() to onboard repository
369370
SDMAdminService sdmAdminService = new SDMAdminServiceImpl();
370371
String response = sdmAdminService.onboardRepository(repository);
371372
}
372373
```
373-
374374
```java
375375
@After(event = DeploymentService.EVENT_UNSUBSCRIBE)
376376
public void afterUnsubscribe(UnsubscribeEventContext context) {
@@ -385,6 +385,11 @@ public void onSubscribe(SubscribeEventContext context) {
385385
String res = sdmAdminService.offboardRepository(subdomain);
386386
}
387387
```
388+
389+
> **Note**
390+
>
391+
> Unsubscription will fail if an error occurs while deleting the repository, except when the error indicates that the repository was not found — in that case, the unsubscription will succeed.
392+
388393
When the application is deployed as a SaaS application with above code, a repository is onboarded automatically when a tenant subscribes the SaaS application. The same repository is deleted when the tenant unsubscribes from the SaaS application.
389394
The necessary params for the Repository onboarding can be found in the [documentation](https://help.sap.com/docs/document-management-service/sap-document-management-service/internal-repository).
390395

sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -302,22 +302,29 @@ private void formResponse(
302302
String error = "";
303303
try {
304304
String responseString = EntityUtils.toString(response.getEntity());
305-
JSONObject jsonResponse = new JSONObject(responseString);
306305
int responseCode = response.getStatusLine().getStatusCode();
307306
if (responseCode == 201 || responseCode == 200) {
307+
JSONObject jsonResponse = new JSONObject(responseString);
308308
JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties");
309309
status = "success";
310310
objectId = succinctProperties.getString("cmis:objectId");
311311
} else {
312-
String message = jsonResponse.getString("message");
313-
if (responseCode == 409
314-
&& "Malware Service Exception: Virus found in the file!".equals(message)) {
315-
status = "virus";
316-
} else if (responseCode == 409) {
317-
status = "duplicate";
318-
} else if (responseCode == 403) {
312+
if (responseCode == 409) {
313+
JSONObject jsonResponse = new JSONObject(responseString);
314+
String message = jsonResponse.getString("message");
315+
JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties");
316+
objectId = succinctProperties.getString("cmis:objectId");
317+
if ("Malware Service Exception: Virus found in the file!".equals(message)) {
318+
status = "virus";
319+
} else {
320+
status = "duplicate";
321+
}
322+
} else if ((responseCode == 403)
323+
&& (responseString.equals("User does not have required scope"))) {
319324
status = "unauthorized";
320325
} else {
326+
JSONObject jsonResponse = new JSONObject(responseString);
327+
String message = jsonResponse.getString("message");
321328
status = "fail";
322329
error = message;
323330
}

sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java

Lines changed: 172 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import com.sap.cloud.security.config.ClientCredentials;
1818
import java.io.IOException;
1919
import java.io.UnsupportedEncodingException;
20+
import java.util.ArrayList;
21+
import java.util.List;
2022
import org.apache.http.client.HttpClient;
2123
import org.apache.http.client.methods.CloseableHttpResponse;
2224
import org.apache.http.client.methods.HttpDelete;
@@ -35,50 +37,147 @@ public class SDMAdminServiceImpl implements SDMAdminService {
3537
@java.lang.Override
3638
public String onboardRepository(Repository repository)
3739
throws JsonProcessingException, UnsupportedEncodingException {
38-
SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials();
39-
var httpClient =
40-
tokenHandler.getHttpClient(
41-
null, null, repository.getSubdomain(), "TECHNICAL_CREDENTIALS_FLOW");
40+
if (repository == null) {
41+
logger.error("Repository object is null. Cannot proceed with onboarding.");
42+
throw new IllegalArgumentException("Repository object cannot be null.");
43+
}
44+
45+
SDMCredentials sdmCredentials;
46+
try {
47+
sdmCredentials = tokenHandler.getSDMCredentials();
48+
if (sdmCredentials == null || sdmCredentials.getUrl() == null) {
49+
logger.error("SDM credentials are missing or invalid.");
50+
throw new ServiceException("SDM credentials are missing or invalid.");
51+
}
52+
} catch (Exception e) {
53+
logger.error("Failed to retrieve SDM credentials: " + e.getMessage());
54+
throw new ServiceException("Failed to retrieve SDM credentials.", e);
55+
}
56+
57+
HttpClient httpClient = null;
58+
try {
59+
httpClient =
60+
tokenHandler.getHttpClient(
61+
null, null, repository.getSubdomain(), "TECHNICAL_CREDENTIALS_FLOW");
62+
if (httpClient == null) {
63+
logger.error("Failed to create HTTP client.");
64+
throw new ServiceException("Failed to create HTTP client.");
65+
}
66+
} catch (Exception e) {
67+
logger.error("Error while creating HTTP client: " + e.getMessage());
68+
throw new ServiceException("Error while creating HTTP client.", e);
69+
}
70+
4271
String sdmUrl = sdmCredentials.getUrl() + SDMConstants.REST_V2_REPOSITORIES;
4372
HttpPost onboardingReq = new HttpPost(sdmUrl);
4473
ObjectMapper objectMapper = new ObjectMapper();
4574
RepositoryBody onboardRepository = new RepositoryBody();
46-
repository.setExternalId(REPOSITORY_ID);
47-
onboardRepository.setRepository(repository);
48-
String json = objectMapper.writeValueAsString(onboardRepository);
49-
StringEntity entity = new StringEntity(json);
75+
76+
try {
77+
repository.setExternalId(REPOSITORY_ID);
78+
onboardRepository.setRepository(repository);
79+
} catch (Exception e) {
80+
logger.error("Failed to set repository details: " + e.getMessage());
81+
throw new ServiceException("Failed to set repository details.", e);
82+
}
83+
84+
String json;
85+
try {
86+
json = objectMapper.writeValueAsString(onboardRepository);
87+
} catch (JsonProcessingException e) {
88+
logger.error("Failed to serialize repository object to JSON: " + e.getMessage());
89+
throw new ServiceException("Failed to serialize repository object to JSON.", e);
90+
}
91+
92+
StringEntity entity;
93+
try {
94+
entity = new StringEntity(json);
95+
} catch (UnsupportedEncodingException e) {
96+
logger.error("Failed to create StringEntity: " + e.getMessage());
97+
throw new ServiceException("Failed to create StringEntity.", e);
98+
}
99+
50100
onboardingReq.setEntity(entity);
51-
// Set the content type of the request
52101
onboardingReq.setHeader("Content-Type", "application/json");
102+
53103
try (var response = (CloseableHttpResponse) httpClient.execute(onboardingReq)) {
54104
String responseString = EntityUtils.toString(response.getEntity());
105+
55106
if ((responseString.contains(REPOSITORY_ID + " already exists"))
56107
&& response.getStatusLine().getStatusCode() == 409) {
57108
return String.format(
58109
SDMConstants.REPOSITORY_ALREADY_EXIST, repository.getDisplayName(), REPOSITORY_ID);
59110
}
60-
JsonObject jsonObject = JsonParser.parseString(responseString).getAsJsonObject();
61-
String repositoryId = jsonObject.get("id").getAsString();
111+
112+
JsonObject jsonObject;
113+
jsonObject = JsonParser.parseString(responseString).getAsJsonObject();
114+
115+
String repositoryId;
116+
if (jsonObject.has("id") && !jsonObject.get("id").isJsonNull()) {
117+
repositoryId = jsonObject.get("id").getAsString();
118+
} else {
119+
logger.error(
120+
String.format(SDMConstants.ONBOARD_REPO_ERROR_MESSAGE, repository.getDisplayName())
121+
+ " : "
122+
+ responseString);
123+
throw new ServiceException(
124+
String.format(SDMConstants.ONBOARD_REPO_ERROR_MESSAGE, repository.getDisplayName()),
125+
responseString);
126+
}
127+
62128
return String.format(
63129
SDMConstants.ONBOARD_REPO_MESSAGE, repository.getDisplayName(), repositoryId);
64-
} catch (IOException e) {
130+
} catch (Exception e) {
131+
logger.error(
132+
String.format(SDMConstants.ONBOARD_REPO_ERROR_MESSAGE, repository.getDisplayName())
133+
+ " : "
134+
+ e.getMessage());
65135
throw new ServiceException(
66-
String.format(SDMConstants.ONBOARD_REPO_ERROR_MESSAGE, repository.getDisplayName()),
67-
e.getMessage());
136+
String.format(SDMConstants.ONBOARD_REPO_ERROR_MESSAGE, repository.getDisplayName()), e);
68137
}
69138
}
70139

71140
@java.lang.Override
72141
public String offboardRepository(String subdomain) {
73-
SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials();
74-
ClientCredentials clientCredentials =
75-
new ClientCredentials(sdmCredentials.getClientId(), sdmCredentials.getClientSecret());
142+
SDMCredentials sdmCredentials;
143+
try {
144+
sdmCredentials = tokenHandler.getSDMCredentials();
145+
if (sdmCredentials == null
146+
|| sdmCredentials.getUrl() == null
147+
|| sdmCredentials.getBaseTokenUrl() == null) {
148+
logger.error("SDM credentials are missing or invalid.");
149+
throw new ServiceException("SDM credentials are missing or invalid.");
150+
}
151+
} catch (Exception e) {
152+
logger.error("Failed to retrieve SDM credentials: " + e.getMessage());
153+
throw new ServiceException("Failed to retrieve SDM credentials.", e);
154+
}
155+
156+
ClientCredentials clientCredentials;
157+
try {
158+
clientCredentials =
159+
new ClientCredentials(sdmCredentials.getClientId(), sdmCredentials.getClientSecret());
160+
if (clientCredentials.getId() == null || clientCredentials.getSecret() == null) {
161+
logger.error("Client credentials are missing or invalid.");
162+
throw new ServiceException("Client credentials are missing or invalid.");
163+
}
164+
} catch (Exception e) {
165+
logger.error("Failed to create client credentials: " + e.getMessage());
166+
throw new ServiceException("Failed to create client credentials.", e);
167+
}
168+
76169
String baseTokenUrl = sdmCredentials.getBaseTokenUrl();
77-
if (subdomain != null && !subdomain.equals("")) {
78-
String providersubdomain =
79-
baseTokenUrl.substring(baseTokenUrl.indexOf("/") + 2, baseTokenUrl.indexOf("."));
80-
baseTokenUrl = baseTokenUrl.replace(providersubdomain, subdomain);
170+
if (subdomain != null && !subdomain.isEmpty()) {
171+
try {
172+
String providersubdomain =
173+
baseTokenUrl.substring(baseTokenUrl.indexOf("/") + 2, baseTokenUrl.indexOf("."));
174+
baseTokenUrl = baseTokenUrl.replace(providersubdomain, subdomain);
175+
} catch (Exception e) {
176+
logger.error("Failed to replace subdomain in base token URL: " + e.getMessage());
177+
throw new ServiceException("Failed to replace subdomain in base token URL.", e);
178+
}
81179
}
180+
82181
var destination =
83182
OAuth2DestinationBuilder.forTargetUrl(sdmCredentials.getUrl())
84183
.withTokenEndpoint(baseTokenUrl)
@@ -92,44 +191,84 @@ public String offboardRepository(String subdomain) {
92191
builder.maxConnectionsPerRoute(SDMConstants.MAX_CONNECTIONS_PER_ROUTE);
93192
builder.maxConnectionsTotal(SDMConstants.MAX_CONNECTIONS_TOTAL);
94193
DefaultHttpClientFactory factory = builder.build();
95-
HttpClient httpClient = factory.createHttpClient(destination);
194+
HttpClient httpClient;
195+
try {
196+
httpClient = factory.createHttpClient(destination);
197+
if (httpClient == null) {
198+
logger.error("Failed to create HTTP client.");
199+
throw new ServiceException("Failed to create HTTP client.");
200+
}
201+
} catch (Exception e) {
202+
logger.error("Error while creating HTTP client: " + e.getMessage());
203+
throw new ServiceException("Error while creating HTTP client.", e);
204+
}
205+
96206
String sdmUrl = sdmCredentials.getUrl() + SDMConstants.REST_V2_REPOSITORIES + "/";
97207
HttpGet getRepos = new HttpGet(sdmUrl);
98208
String repoId = "";
99209
try (var response = (CloseableHttpResponse) httpClient.execute(getRepos)) {
100-
repoId = getRepositoryId(EntityUtils.toString(response.getEntity()));
210+
String responseString = EntityUtils.toString(response.getEntity());
211+
repoId = getRepositoryId(responseString);
212+
if (repoId == null || repoId.isEmpty()) {
213+
logger.error("Repository ID not found");
214+
return "Repository with ID " + SDMConstants.REPOSITORY_ID + " not found.";
215+
}
101216
} catch (IOException e) {
102-
logger.error("Error in offboarding repository : " + e.getMessage());
103-
throw new ServiceException("Error in offboarding ", e.getMessage());
217+
logger.error("Error while fetching repository ID: " + e.getMessage());
218+
throw new ServiceException("Error while fetching repository ID.", e);
219+
} catch (Exception e) {
220+
logger.error("Unexpected error while fetching repository ID: " + e.getMessage());
221+
throw new ServiceException("Unexpected error while fetching repository ID.", e);
104222
}
223+
105224
sdmUrl = sdmCredentials.getUrl() + SDMConstants.REST_V2_REPOSITORIES + "/" + repoId;
106225
HttpDelete offboardingReq = new HttpDelete(sdmUrl);
107-
// Set the content type of the request
108226
offboardingReq.setHeader("Content-Type", "application/json");
109227
try (var response = (CloseableHttpResponse) httpClient.execute(offboardingReq)) {
110-
logger.info("Repository <" + REPOSITORY_ID + "> Offboarded");
111-
return "Repository <" + REPOSITORY_ID + "> Offboarded";
228+
int statusCode = response.getStatusLine().getStatusCode();
229+
String responseString = EntityUtils.toString(response.getEntity());
230+
231+
if (statusCode != 200) { // Failed to offboard
232+
if (statusCode == 404) { // Exception isn't thrown in case of missing repository
233+
logger.warn("Repository with ID " + SDMConstants.REPOSITORY_ID + " not found.");
234+
return "Repository with ID " + SDMConstants.REPOSITORY_ID + " not found.";
235+
}
236+
logger.error("Failed to offboard repository : " + responseString);
237+
throw new ServiceException("Failed to offboard repository.", responseString);
238+
}
239+
240+
logger.info("Repository " + repoId + " Offboarded");
241+
return "Repository " + repoId + " Offboarded";
112242
} catch (IOException e) {
113-
logger.error("Error in offboarding repository : " + e.getMessage());
114-
throw new ServiceException("Error in offboarding ", e.getMessage());
243+
logger.error("Error while offboarding repository: " + e.getMessage());
244+
throw new ServiceException("Error while offboarding repository.", e);
245+
} catch (Exception e) {
246+
logger.error("Unexpected error while offboarding repository: " + e.getMessage());
247+
throw new ServiceException("Unexpected error while offboarding repository.", e);
115248
}
116249
}
117250

118251
private String getRepositoryId(String jsonString) {
119252
ObjectMapper objectMapper = new ObjectMapper();
120253
try {
121254
JsonNode rootNode = objectMapper.readTree(jsonString);
122-
JsonNode repoInfos = rootNode.path("repoAndConnectionInfos");
255+
JsonNode repoInfosNode = rootNode.path("repoAndConnectionInfos");
256+
257+
List<JsonNode> repoInfos = new ArrayList<>();
258+
if (repoInfosNode.isArray()) {
259+
repoInfosNode.forEach(repoInfos::add);
260+
} else if (!repoInfosNode.isMissingNode() && !repoInfosNode.isNull()) {
261+
repoInfos.add(repoInfosNode); // wrap single object in a list
262+
}
123263

124-
// Iterate through the array to find the correct externalId and retrieve the id
125264
for (JsonNode repoInfo : repoInfos) {
126265
JsonNode repository = repoInfo.path("repository");
127266
if (repository.path("externalId").asText().equals(SDMConstants.REPOSITORY_ID)) {
128267
return repository.path("id").asText();
129268
}
130269
}
131270
} catch (Exception e) {
132-
throw new ServiceException(String.format(e.getMessage()));
271+
throw new ServiceException("Failed to parse repository response", e);
133272
}
134273
return null;
135274
}

sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,30 @@ private void formResponse(
145145
String error = "";
146146
try {
147147
String responseString = EntityUtils.toString(response.getEntity());
148-
JSONObject jsonResponse = new JSONObject(responseString);
149148
int responseCode = response.getStatusLine().getStatusCode();
149+
150150
if (responseCode == 201 || responseCode == 200) {
151-
JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties");
152151
status = "success";
152+
JSONObject jsonResponse = new JSONObject(responseString);
153+
JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties");
153154
objectId = succinctProperties.getString("cmis:objectId");
154155
} else {
155-
String message = jsonResponse.getString("message");
156-
if (responseCode == 409
157-
&& "Malware Service Exception: Virus found in the file!".equals(message)) {
158-
status = "virus";
159-
} else if (responseCode == 409) {
160-
status = "duplicate";
161-
} else if (responseCode == 403) {
156+
if (responseCode == 409) {
157+
JSONObject jsonResponse = new JSONObject(responseString);
158+
String message = jsonResponse.getString("message");
159+
JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties");
160+
objectId = succinctProperties.getString("cmis:objectId");
161+
if ("Malware Service Exception: Virus found in the file!".equals(message)) {
162+
status = "virus";
163+
} else {
164+
status = "duplicate";
165+
}
166+
} else if ((responseCode == 403)
167+
&& (responseString.equals("User does not have required scope"))) {
162168
status = "unauthorized";
163169
} else {
170+
JSONObject jsonResponse = new JSONObject(responseString);
171+
String message = jsonResponse.getString("message");
164172
status = "fail";
165173
error = message;
166174
}
@@ -173,8 +181,8 @@ private void formResponse(
173181
if (!objectId.isEmpty()) {
174182
finalResponse.put("objectId", objectId);
175183
}
176-
} catch (IOException e) {
177-
throw new ServiceException(SDMConstants.getGenericError("upload"));
184+
} catch (Exception e) {
185+
throw new ServiceException(e.getMessage());
178186
}
179187
}
180188

0 commit comments

Comments
 (0)