Skip to content

Commit da618ab

Browse files
authored
Merge pull request #600 from cap-java/RBSDMS-v1.10.3-SNAPSHOT-feature
Merge Snapshot 10.3 branch changes to develop
2 parents 1acf718 + c52b841 commit da618ab

7 files changed

Lines changed: 294 additions & 113 deletions

File tree

‎sdm/src/main/java/com/sap/cds/sdm/handler/TokenHandler.java‎

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,35 @@ public String toString(byte[] bytes) {
5656
}
5757

5858
public SDMCredentials getSDMCredentials() {
59+
logger.debug("START: getSDMCredentials - loading SDM credentials from service binding");
5960
Map<String, Object> uaaCredentials = getUaaCredentials();
6061
Map<String, Object> uaa = (Map<String, Object>) uaaCredentials.get("uaa");
6162
SDMCredentials sdmCredentials = new SDMCredentials();
6263
sdmCredentials.setBaseTokenUrl(uaa.get("url").toString());
6364
sdmCredentials.setUrl(uaaCredentials.get("uri").toString());
6465
sdmCredentials.setClientId(uaa.get("clientid").toString());
6566
sdmCredentials.setClientSecret(uaa.get("clientsecret").toString());
67+
logger.debug("END: getSDMCredentials - SDM URL: {}", sdmCredentials.getUrl());
6668
return sdmCredentials;
6769
}
6870

6971
public Map<String, Object> getUaaCredentials() {
72+
logger.debug("START: getUaaCredentials - scanning service bindings for 'sdm' tag");
7073
List<ServiceBinding> allServiceBindings =
7174
DefaultServiceBindingAccessor.getInstance().getServiceBindings();
75+
logger.debug("Total service bindings found: {}", allServiceBindings.size());
7276
ServiceBinding sdmBinding =
7377
allServiceBindings.stream()
7478
.filter(binding -> binding.getTags().contains("sdm"))
7579
.findFirst()
76-
.orElseThrow(() -> new IllegalStateException("SDM binding not found"));
80+
.orElseThrow(
81+
() -> {
82+
logger.error(
83+
"No service binding with 'sdm' tag found among {} bindings",
84+
allServiceBindings.size());
85+
return new IllegalStateException("SDM binding not found");
86+
});
87+
logger.debug("END: getUaaCredentials - SDM binding found");
7788
return sdmBinding.getCredentials();
7889
}
7990

@@ -83,37 +94,55 @@ public HttpClient getHttpClient(
8394
String subdomain,
8495
String type) {
8596

97+
logger.debug(
98+
"START: getHttpClient - type: {}, subdomain: {}, connectionPoolConfig: {}",
99+
type,
100+
subdomain,
101+
connectionPoolConfig != null ? "configured" : "null(using defaults)");
102+
86103
Map<String, Object> uaaCredentials;
87104
if (binding != null && !binding.getCredentials().isEmpty()) {
105+
logger.debug("getHttpClient - using credentials from provided ServiceBinding");
88106
uaaCredentials = binding.getCredentials();
89107
} else {
108+
logger.debug(
109+
"getHttpClient - binding not provided or empty, fetching from service binding registry");
90110
uaaCredentials = getUaaCredentials();
91111
}
92112

93113
Map<String, Object> uaa = (Map<String, Object>) uaaCredentials.get("uaa");
94114

95115
ClientCredentials clientCredentials =
96116
new ClientCredentials(uaa.get(CLIENT_ID).toString(), uaa.get(CLIENT_SECRET).toString());
117+
logger.debug("getHttpClient - clientId: {}", uaa.get(CLIENT_ID).toString());
97118

98119
String baseTokenUrl = uaa.get(SDM_TOKEN_ENDPOINT).toString();
120+
logger.debug("getHttpClient - base token URL: {}", baseTokenUrl);
99121
if (subdomain != null && !subdomain.isEmpty()) {
100122
String providerSubdomain =
101123
baseTokenUrl.substring(baseTokenUrl.indexOf("/") + 2, baseTokenUrl.indexOf("."));
102124
baseTokenUrl = baseTokenUrl.replace(providerSubdomain, subdomain);
125+
logger.debug(
126+
"getHttpClient - token URL adjusted for subdomain '{}': {}", subdomain, baseTokenUrl);
103127
}
104128

129+
String sdmTargetUrl = uaaCredentials.get(SDM_URL).toString();
130+
logger.debug("getHttpClient - SDM target URL: {}", sdmTargetUrl);
131+
105132
DefaultHttpDestination destination;
106133
if (NAMED_USER_FLOW.equals(type)) {
134+
logger.debug("getHttpClient - building NAMED_USER (token exchange) destination");
107135
destination =
108-
OAuth2DestinationBuilder.forTargetUrl(uaaCredentials.get(SDM_URL).toString())
136+
OAuth2DestinationBuilder.forTargetUrl(sdmTargetUrl)
109137
.withTokenEndpoint(baseTokenUrl)
110138
.withClient(clientCredentials, OnBehalfOf.NAMED_USER_CURRENT_TENANT)
111139
.property(
112140
SDMConstants.SDM_DESTINATION_KEY, SDMConstants.SDM_TOKEN_EXCHANGE_DESTINATION)
113141
.build();
114142
} else {
143+
logger.debug("getHttpClient - building TECHNICAL_USER (client credentials) destination");
115144
destination =
116-
OAuth2DestinationBuilder.forTargetUrl(uaaCredentials.get(SDM_URL).toString())
145+
OAuth2DestinationBuilder.forTargetUrl(sdmTargetUrl)
117146
.withTokenEndpoint(baseTokenUrl)
118147
.withClient(clientCredentials, OnBehalfOf.TECHNICAL_USER_CURRENT_TENANT)
119148
.property(
@@ -130,20 +159,36 @@ public HttpClient getHttpClient(
130159
builder.timeoutMilliseconds((int) timeout.toMillis());
131160
builder.maxConnectionsPerRoute(SDMConstants.MAX_CONNECTIONS);
132161
builder.maxConnectionsTotal(SDMConstants.MAX_CONNECTIONS);
162+
logger.debug(
163+
"getHttpClient - using default connection pool: timeout={}ms, maxConnPerRoute={},"
164+
+ " maxConnTotal={}",
165+
timeout.toMillis(),
166+
SDMConstants.MAX_CONNECTIONS,
167+
SDMConstants.MAX_CONNECTIONS);
133168
} else {
134169
builder.timeoutMilliseconds((int) connectionPoolConfig.getTimeout().toMillis());
135170
builder.maxConnectionsPerRoute(connectionPoolConfig.getMaxConnectionsPerRoute());
136171
builder.maxConnectionsTotal(connectionPoolConfig.getMaxConnections());
172+
logger.debug(
173+
"getHttpClient - using configured connection pool: timeout={}ms, maxConnPerRoute={},"
174+
+ " maxConnTotal={}",
175+
connectionPoolConfig.getTimeout().toMillis(),
176+
connectionPoolConfig.getMaxConnectionsPerRoute(),
177+
connectionPoolConfig.getMaxConnections());
137178
}
138179

139-
return builder.build().createHttpClient(destination);
180+
HttpClient httpClient = builder.build().createHttpClient(destination);
181+
logger.debug("END: getHttpClient - HttpClient created for type: {}", type);
182+
return httpClient;
140183
}
141184

142185
public HttpClient getHttpClientForAuthoritiesFlow(
143186
CdsProperties.ConnectionPool connectionPoolConfig, String user) {
144187

188+
logger.debug("START: getHttpClientForAuthoritiesFlow - user: {}", user);
145189
Optional<HttpDestination> destinations = getHttpDestination(user);
146190
if (destinations.isPresent()) {
191+
logger.debug("getHttpClientForAuthoritiesFlow - HttpDestination resolved for user: {}", user);
147192
DefaultHttpClientFactory.DefaultHttpClientFactoryBuilder builder =
148193
DefaultHttpClientFactory.builder();
149194

@@ -152,25 +197,40 @@ public HttpClient getHttpClientForAuthoritiesFlow(
152197
builder.timeoutMilliseconds((int) timeout.toMillis());
153198
builder.maxConnectionsPerRoute(SDMConstants.MAX_CONNECTIONS);
154199
builder.maxConnectionsTotal(SDMConstants.MAX_CONNECTIONS);
200+
logger.debug(
201+
"getHttpClientForAuthoritiesFlow - using default pool: timeout={}ms",
202+
timeout.toMillis());
155203
} else {
156204
builder.timeoutMilliseconds((int) connectionPoolConfig.getTimeout().toMillis());
157205
builder.maxConnectionsPerRoute(connectionPoolConfig.getMaxConnectionsPerRoute());
158206
builder.maxConnectionsTotal(connectionPoolConfig.getMaxConnections());
207+
logger.debug(
208+
"getHttpClientForAuthoritiesFlow - using configured pool: timeout={}ms",
209+
connectionPoolConfig.getTimeout().toMillis());
159210
}
160211

161-
return builder.build().createHttpClient(destinations.get());
212+
HttpClient httpClient = builder.build().createHttpClient(destinations.get());
213+
logger.debug("END: getHttpClientForAuthoritiesFlow - HttpClient created for user: {}", user);
214+
return httpClient;
162215
}
216+
logger.warn(
217+
"getHttpClientForAuthoritiesFlow - no HttpDestination found for user: {},"
218+
+ " returning null",
219+
user);
163220
return null;
164221
}
165222

166223
private Optional<HttpDestination> getHttpDestination(String userName) {
224+
logger.debug("START: getHttpDestination - resolving destination for user: {}", userName);
167225
HttpDestination httpDestination;
168226
try {
169227
httpDestination =
170228
ServiceBindingDestinationLoader.defaultLoaderChain()
171229
.getDestination(getSDMDestinationOptions(userName));
230+
logger.debug("END: getHttpDestination - destination resolved for user: {}", userName);
172231
} catch (Exception exception) {
173-
logger.error("Error with fetching httpdestination " + exception.getCause());
232+
logger.error(
233+
"Error with fetching httpdestination for user {}: {}", userName, exception.getCause());
174234
httpDestination = null;
175235
}
176236
return Optional.ofNullable(httpDestination);

‎sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMReadAttachmentsHandler.java‎

Lines changed: 95 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -133,95 +133,108 @@ public void processBefore(CdsReadEventContext context) throws IOException {
133133
return;
134134
}
135135
setErrorMessagesInCache(context);
136-
if (context.getTarget().getAnnotationValue(SDMConstants.ANNOTATION_IS_MEDIA_DATA, false)) {
137-
try {
138-
// update the uploadStatus of all blank attachments with success this is for existing
139-
// attachments
140-
logger.debug("Target is a media entity, processing attachment logic");
141-
RepoValue repoValue = checkRepositoryTypeWithFallback(repositoryId, context);
142-
143-
// Only process virus scan logic if repository info is available
144-
if (repoValue != null) {
145-
logger.debug(
146-
"Repository value found. Async virus scan enabled: {}",
147-
repoValue.getIsAsyncVirusScanEnabled());
148-
Optional<CdsEntity> attachmentDraftEntity =
149-
context.getModel().findEntity(context.getTarget().getQualifiedName() + "_drafts");
150-
String upIdKey = "", upID = "";
151-
if (attachmentDraftEntity.isPresent()) {
152-
upIdKey = SDMUtils.getUpIdKey(attachmentDraftEntity.get());
153-
CqnSelect select = (CqnSelect) context.get("cqn");
154-
upID = SDMUtils.fetchUPIDFromCQN(select, attachmentDraftEntity.get());
155-
logger.debug("Processing attachments for upID: {}", upID);
156-
157-
if (!repoValue.getIsAsyncVirusScanEnabled()) {
158-
logger.debug("Sync virus scan mode: updating in-progress upload status to success");
159-
dbQuery.updateInProgressUploadStatusToSuccess(
160-
attachmentDraftEntity.get(), persistenceService, upID, upIdKey);
161-
}
162-
if (repoValue.getIsAsyncVirusScanEnabled()) {
163-
logger.debug("Async virus scan mode: processing virus scan in-progress attachments");
164-
processVirusScanInProgressAttachments(context, upID, upIdKey);
165-
}
166-
}
167-
168-
// Get attachment associations to handle deep reads with expand
169-
CdsModel cdsModel = context.getModel();
170-
List<String> fieldNames =
171-
getAttachmentAssociations(cdsModel, context.getTarget(), "", new ArrayList<>());
172-
logger.debug("Found {} attachment associations", fieldNames.size());
173-
174-
// Create a combined modifier that handles both expand scenarios and repositoryId filter
175-
final SDMBeforeReadItemsModifier itemsModifier =
176-
new SDMBeforeReadItemsModifier(fieldNames);
177-
final Predicate repositoryFilter =
178-
CQL.or(CQL.get("repositoryId").eq(repositoryId), CQL.get("repositoryId").isNull());
179-
logger.debug(
180-
"Creating CQN modifier with {} field names and repository filter", fieldNames.size());
181-
182-
CqnSelect modifiedCqn =
183-
CQL.copy(
184-
context.getCqn(),
185-
new Modifier() {
186-
@SuppressWarnings({"rawtypes", "unchecked"})
187-
@Override
188-
public List items(List items) {
189-
// Always handle items for expand scenarios
190-
return itemsModifier.items(items);
191-
}
192-
193-
@Override
194-
public Predicate where(Predicate where) {
195-
// Always apply repositoryId filter for all reads
196-
if (where == null) {
197-
return repositoryFilter;
198-
}
199-
return CQL.and(where, repositoryFilter);
200-
}
201-
});
202-
context.setCqn(modifiedCqn);
203-
logger.debug("CQN query modified with repository filter and required fields");
204-
} else {
205-
logger.warn(
206-
"Repository value is null for repository ID: {}. Proceeding with limited functionality",
207-
repositoryId);
208-
context.setCqn(context.getCqn());
209-
}
210-
} catch (Exception e) {
211-
logger.error("Error in SDMReadAttachmentsHandler.processBefore: {}", e.getMessage(), e);
212-
// Re-throw to maintain error handling behavior
213-
throw e;
214-
}
215-
216-
} else {
136+
if (!SDMApplicationHandlerHelper.isMediaEntity(context.getTarget())) {
217137
logger.debug(
218138
"Target entity {} is not a media entity, skipping attachment processing",
219139
context.getTarget().getQualifiedName());
220-
context.setCqn(context.getCqn());
140+
return;
141+
}
142+
try {
143+
logger.debug("Target is a media entity, processing attachment logic");
144+
RepoValue repoValue = checkRepositoryTypeWithFallback(repositoryId, context);
145+
if (repoValue != null) {
146+
processMediaEntityRead(context, repositoryId, repoValue);
147+
} else {
148+
logger.warn(
149+
"Repository value is null for repository ID: {}. Proceeding with limited functionality",
150+
repositoryId);
151+
}
152+
} catch (Exception e) {
153+
logger.error("Error in SDMReadAttachmentsHandler.processBefore: {}", e.getMessage(), e);
154+
throw e;
221155
}
222156
logger.debug("END: Read attachments processing completed");
223157
}
224158

159+
private void processMediaEntityRead(
160+
CdsReadEventContext context, String repositoryId, RepoValue repoValue) {
161+
logger.debug(
162+
"Repository value found. Async virus scan enabled: {}",
163+
repoValue.getIsAsyncVirusScanEnabled());
164+
Optional<CdsEntity> attachmentActiveEntity =
165+
context.getModel().findEntity(context.getTarget().getQualifiedName());
166+
logger.debug(
167+
"Active entity: {}",
168+
attachmentActiveEntity.isPresent()
169+
? attachmentActiveEntity.get().getQualifiedName()
170+
: "No active entity");
171+
Optional<CdsEntity> attachmentDraftEntity =
172+
context
173+
.getModel()
174+
.findEntity(context.getTarget().getQualifiedName() + "_drafts")
175+
.or(() -> attachmentActiveEntity);
176+
logger.debug(
177+
"Draft entity: {}",
178+
attachmentDraftEntity.isPresent()
179+
? attachmentDraftEntity.get().getQualifiedName()
180+
: "No draft entity");
181+
182+
if (attachmentDraftEntity.isPresent()) {
183+
processUploadStatus(context, repoValue, attachmentDraftEntity.get());
184+
}
185+
186+
List<String> fieldNames =
187+
getAttachmentAssociations(context.getModel(), context.getTarget(), "", new ArrayList<>());
188+
logger.debug("Found {} attachment associations", fieldNames.size());
189+
190+
CqnSelect modifiedCqn = buildModifiedCqn(context, repositoryId, fieldNames);
191+
context.setCqn(modifiedCqn);
192+
logger.debug("CQN query modified with repository filter and required fields");
193+
}
194+
195+
private void processUploadStatus(
196+
CdsReadEventContext context, RepoValue repoValue, CdsEntity attachmentEntity) {
197+
String upIdKey = SDMUtils.getUpIdKey(attachmentEntity);
198+
CqnSelect select = (CqnSelect) context.get("cqn");
199+
String upID = SDMUtils.fetchUPIDFromCQN(select, attachmentEntity);
200+
logger.debug("Processing attachments for upID: {}", upID);
201+
202+
if (!repoValue.getIsAsyncVirusScanEnabled()) {
203+
logger.debug("Sync virus scan mode: updating in-progress upload status to success");
204+
dbQuery.updateInProgressUploadStatusToSuccess(
205+
attachmentEntity, persistenceService, upID, upIdKey);
206+
} else {
207+
logger.debug("Async virus scan mode: processing virus scan in-progress attachments");
208+
processVirusScanInProgressAttachments(context, upID, upIdKey);
209+
}
210+
}
211+
212+
private CqnSelect buildModifiedCqn(
213+
CdsReadEventContext context, String repositoryId, List<String> fieldNames) {
214+
final SDMBeforeReadItemsModifier itemsModifier = new SDMBeforeReadItemsModifier(fieldNames);
215+
final Predicate repositoryFilter =
216+
CQL.or(CQL.get("repositoryId").eq(repositoryId), CQL.get("repositoryId").isNull());
217+
logger.debug(
218+
"Creating CQN modifier with {} field names and repository filter", fieldNames.size());
219+
return CQL.copy(
220+
context.getCqn(),
221+
new Modifier() {
222+
@SuppressWarnings({"rawtypes", "unchecked"})
223+
@Override
224+
public List items(List items) {
225+
return itemsModifier.items(items);
226+
}
227+
228+
@Override
229+
public Predicate where(Predicate where) {
230+
if (where == null) {
231+
return repositoryFilter;
232+
}
233+
return CQL.and(where, repositoryFilter);
234+
}
235+
});
236+
}
237+
225238
/**
226239
* Recursively get all attachment associations in the entity tree. This is needed to properly
227240
* handle deep navigation like Books/covers with $expand=statusNav

0 commit comments

Comments
 (0)