Fix sonar findings on 21 style (#3020)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -39,7 +39,7 @@ public class AmqpDeadletterProperties {
|
||||
* @return map which holds the properties
|
||||
*/
|
||||
public Map<String, Object> getDeadLetterExchangeArgs(final String exchange) {
|
||||
final Map<String, Object> args = new HashMap<>(1);
|
||||
final Map<String, Object> args = HashMap.newHashMap(1);
|
||||
args.put("x-dead-letter-exchange", exchange);
|
||||
return args;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class AmqpDeadletterProperties {
|
||||
}
|
||||
|
||||
private Map<String, Object> getTTLArgs() {
|
||||
final Map<String, Object> args = new HashMap<>(1);
|
||||
final Map<String, Object> args = HashMap.newHashMap(1);
|
||||
args.put("x-message-ttl", getTtl());
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ public class DmfAmqpDeclarationConfiguration {
|
||||
}
|
||||
|
||||
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {
|
||||
final Map<String, Object> args = new HashMap<>(2);
|
||||
final Map<String, Object> args = HashMap.newHashMap(2);
|
||||
args.put("x-message-ttl", Duration.ofSeconds(30).toMillis());
|
||||
args.put("x-max-length", 1_000);
|
||||
return args;
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.mcp.server.tools;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.mcp.server.config.HawkbitMcpProperties;
|
||||
@@ -24,10 +27,18 @@ import org.eclipse.hawkbit.mcp.server.dto.TargetRequest;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.PagedList;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
|
||||
@@ -39,9 +50,6 @@ import org.eclipse.hawkbit.sdk.Tenant;
|
||||
import org.springaicommunity.mcp.annotation.McpTool;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* MCP tools for hawkBit using the SDK.
|
||||
* <p>
|
||||
@@ -94,8 +102,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_targets",
|
||||
description = "Retrieves a paged list of targets (devices) with optional RSQL filtering. " +
|
||||
"Targets represent devices that can receive software updates.")
|
||||
description = "Retrieves a paged list of targets (devices) with optional RSQL filtering. " +
|
||||
"Targets represent devices that can receive software updates.")
|
||||
public PagedResponse<MgmtTarget> listTargets(final ListRequest request) {
|
||||
log.debug("Listing targets with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -111,8 +119,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_rollouts",
|
||||
description = "Retrieves a paged list of rollouts with optional RSQL filtering. " +
|
||||
"Rollouts are used to deploy software to groups of targets.")
|
||||
description = "Retrieves a paged list of rollouts with optional RSQL filtering. " +
|
||||
"Rollouts are used to deploy software to groups of targets.")
|
||||
public PagedResponse<MgmtRolloutResponseBody> listRollouts(final ListRequest request) {
|
||||
log.debug("Listing rollouts with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -129,8 +137,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_distribution_sets",
|
||||
description = "Retrieves a paged list of distribution sets with optional RSQL filtering. " +
|
||||
"Distribution sets are software packages that can be deployed to targets.")
|
||||
description = "Retrieves a paged list of distribution sets with optional RSQL filtering. " +
|
||||
"Distribution sets are software packages that can be deployed to targets.")
|
||||
public PagedResponse<MgmtDistributionSet> listDistributionSets(final ListRequest request) {
|
||||
log.debug("Listing distribution sets with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -146,8 +154,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_actions",
|
||||
description = "Retrieves a paged list of actions with optional RSQL filtering. " +
|
||||
"Actions represent deployment operations assigned to targets.")
|
||||
description = "Retrieves a paged list of actions with optional RSQL filtering. " +
|
||||
"Actions represent deployment operations assigned to targets.")
|
||||
public PagedResponse<MgmtAction> listActions(final ListRequest request) {
|
||||
log.debug("Listing actions with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -164,8 +172,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_software_modules",
|
||||
description = "Retrieves a paged list of software modules with optional RSQL filtering. " +
|
||||
"Software modules are individual software components within distribution sets.")
|
||||
description = "Retrieves a paged list of software modules with optional RSQL filtering. " +
|
||||
"Software modules are individual software components within distribution sets.")
|
||||
public PagedResponse<MgmtSoftwareModule> listSoftwareModules(final ListRequest request) {
|
||||
log.debug("Listing software modules with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -181,8 +189,8 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "list_target_filters",
|
||||
description = "Retrieves a paged list of target filter queries with optional RSQL filtering. " +
|
||||
"Target filters define RSQL queries to group targets for rollouts or auto-assignment.")
|
||||
description = "Retrieves a paged list of target filter queries with optional RSQL filtering. " +
|
||||
"Target filters define RSQL queries to group targets for rollouts or auto-assignment.")
|
||||
public PagedResponse<MgmtTargetFilterQuery> listTargetFilters(final ListRequest request) {
|
||||
log.debug("Listing target filters with rsql={}, offset={}, limit={}",
|
||||
request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
|
||||
@@ -199,305 +207,304 @@ public class HawkbitMcpToolProvider {
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_target",
|
||||
description = "Create, update, or delete targets (devices). " +
|
||||
"Operations: CREATE (new target with controllerId, name, description. When creating a target without a specific target type, set \"targetType\": null), " +
|
||||
"UPDATE (modify existing target by controllerId), " +
|
||||
"DELETE (remove target by controllerId). " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"controllerId\":\"id\",\"name\":\"name\"}}, " +
|
||||
"{\"type\":\"Update\",\"controllerId\":\"id\",\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"controllerId\":\"id\"}")
|
||||
description = "Create, update, or delete targets (devices). " +
|
||||
"Operations: CREATE (new target with controllerId, name, description. When creating a target without a specific target type, set \"targetType\": null), " +
|
||||
"UPDATE (modify existing target by controllerId), " +
|
||||
"DELETE (remove target by controllerId). " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"controllerId\":\"id\",\"name\":\"name\"}}, " +
|
||||
"{\"type\":\"Update\",\"controllerId\":\"id\",\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"controllerId\":\"id\"}")
|
||||
@SuppressWarnings("java:S3776") // not too complex
|
||||
public OperationResponse<Object> manageTarget(final TargetRequest request) {
|
||||
log.debug("Managing target: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtTargetRestApi api = hawkbitClient.mgmtService(MgmtTargetRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof TargetRequest.Create r) {
|
||||
if (request instanceof TargetRequest.Create(MgmtTargetRequestBody body)) {
|
||||
validateOperation(OP_CREATE, TARGETS);
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_CREATE, "Request body is required for CREATE operation");
|
||||
}
|
||||
final ResponseEntity<List<MgmtTarget>> response = api.createTargets(List.of(r.body()));
|
||||
final ResponseEntity<List<MgmtTarget>> response = api.createTargets(List.of(body));
|
||||
final List<MgmtTarget> created = response.getBody();
|
||||
return OperationResponse.success(OP_CREATE, "Target created successfully",
|
||||
created != null && !created.isEmpty() ? created.get(0) : null);
|
||||
} else if (request instanceof TargetRequest.Update r) {
|
||||
} else if (request instanceof TargetRequest.Update(String controllerId, MgmtTargetRequestBody body)) {
|
||||
validateOperation(OP_UPDATE, TARGETS);
|
||||
if (r.controllerId() == null || r.controllerId().isBlank()) {
|
||||
if (controllerId == null || controllerId.isBlank()) {
|
||||
return OperationResponse.failure(OP_UPDATE, "controllerId is required for UPDATE operation");
|
||||
}
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, "Request body is required for UPDATE operation");
|
||||
}
|
||||
final ResponseEntity<MgmtTarget> response = api.updateTarget(r.controllerId(), r.body());
|
||||
final ResponseEntity<MgmtTarget> response = api.updateTarget(controllerId, body);
|
||||
return OperationResponse.success(OP_UPDATE, "Target updated successfully", response.getBody());
|
||||
} else if (request instanceof TargetRequest.Delete r) {
|
||||
} else if (request instanceof TargetRequest.Delete(String controllerId)) {
|
||||
validateOperation(OP_DELETE, TARGETS);
|
||||
if (r.controllerId() == null || r.controllerId().isBlank()) {
|
||||
if (controllerId == null || controllerId.isBlank()) {
|
||||
return OperationResponse.failure(OP_DELETE, "controllerId is required for DELETE operation");
|
||||
}
|
||||
api.deleteTarget(r.controllerId());
|
||||
api.deleteTarget(controllerId);
|
||||
return OperationResponse.success(OP_DELETE, "Target deleted successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_rollout",
|
||||
description = "Create, update, delete, and control rollouts for software deployment. " +
|
||||
"Use 'type' field to select operation. " +
|
||||
"Types: Create, Update, Delete, Start, Pause, Stop, Resume, Approve, Deny, Retry, TriggerNextGroup. " +
|
||||
"For Create: use rollout 'type' values: 'soft', 'forced', 'timeforced', 'downloadonly' (lowercase). " +
|
||||
"If 'groups' list is provided, omit 'amountGroups' (they are mutually exclusive). " +
|
||||
"Examples: {\"type\":\"Create\",\"body\":{...}}, " +
|
||||
"{\"type\":\"Start\",\"rolloutId\":123}, " +
|
||||
"{\"type\":\"Approve\",\"rolloutId\":123,\"remark\":\"approved\"}")
|
||||
description = "Create, update, delete, and control rollouts for software deployment. " +
|
||||
"Use 'type' field to select operation. " +
|
||||
"Types: Create, Update, Delete, Start, Pause, Stop, Resume, Approve, Deny, Retry, TriggerNextGroup. " +
|
||||
"For Create: use rollout 'type' values: 'soft', 'forced', 'timeforced', 'downloadonly' (lowercase). " +
|
||||
"If 'groups' list is provided, omit 'amountGroups' (they are mutually exclusive). " +
|
||||
"Examples: {\"type\":\"Create\",\"body\":{...}}, " +
|
||||
"{\"type\":\"Start\",\"rolloutId\":123}, " +
|
||||
"{\"type\":\"Approve\",\"rolloutId\":123,\"remark\":\"approved\"}")
|
||||
@SuppressWarnings("java:S3776") // not too complex, iterative logic
|
||||
public OperationResponse<Object> manageRollout(final RolloutRequest request) {
|
||||
log.debug("Managing rollout: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtRolloutRestApi api = hawkbitClient.mgmtService(MgmtRolloutRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof RolloutRequest.Create r) {
|
||||
if (request instanceof RolloutRequest.Create(MgmtRolloutRestRequestBodyPost body)) {
|
||||
validateRolloutOperation(OP_CREATE);
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_CREATE, BODY_IS_REQUIRED_FOR_CREATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.create(r.body());
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.create(body);
|
||||
return OperationResponse.success(OP_CREATE, "Rollout created successfully", response.getBody());
|
||||
} else if (request instanceof RolloutRequest.Update r) {
|
||||
} else if (request instanceof RolloutRequest.Update(Long rolloutId, MgmtRolloutRestRequestBodyPut body)) {
|
||||
validateRolloutOperation("update");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, "rolloutId is required for UPDATE operation");
|
||||
}
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, BODY_IS_REQUIRED_FOR_UPDATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.update(r.rolloutId(), r.body());
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.update(rolloutId, body);
|
||||
return OperationResponse.success(OP_UPDATE, "Rollout updated successfully", response.getBody());
|
||||
} else if (request instanceof RolloutRequest.Delete r) {
|
||||
} else if (request instanceof RolloutRequest.Delete(Long rolloutId)) {
|
||||
validateRolloutOperation(OP_DELETE);
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_DELETE, "rolloutId is required for DELETE operation");
|
||||
}
|
||||
api.delete(r.rolloutId());
|
||||
api.delete(rolloutId);
|
||||
return OperationResponse.success(OP_DELETE, "Rollout deleted successfully");
|
||||
} else if (request instanceof RolloutRequest.Start r) {
|
||||
} else if (request instanceof RolloutRequest.Start(Long rolloutId)) {
|
||||
validateRolloutOperation("start");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_START, "rolloutId is required for START operation");
|
||||
}
|
||||
api.start(r.rolloutId());
|
||||
api.start(rolloutId);
|
||||
return OperationResponse.success(OP_START, "Rollout started successfully");
|
||||
} else if (request instanceof RolloutRequest.Pause r) {
|
||||
} else if (request instanceof RolloutRequest.Pause(Long rolloutId)) {
|
||||
validateRolloutOperation("pause");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_PAUSE, "rolloutId is required for PAUSE operation");
|
||||
}
|
||||
api.pause(r.rolloutId());
|
||||
api.pause(rolloutId);
|
||||
return OperationResponse.success(OP_PAUSE, "Rollout paused successfully");
|
||||
} else if (request instanceof RolloutRequest.Stop r) {
|
||||
} else if (request instanceof RolloutRequest.Stop(Long rolloutId)) {
|
||||
validateRolloutOperation("stop");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_STOP, "rolloutId is required for STOP operation");
|
||||
}
|
||||
api.stop(r.rolloutId());
|
||||
api.stop(rolloutId);
|
||||
return OperationResponse.success(OP_STOP, "Rollout stopped successfully");
|
||||
} else if (request instanceof RolloutRequest.Resume r) {
|
||||
} else if (request instanceof RolloutRequest.Resume(Long rolloutId)) {
|
||||
validateRolloutOperation("resume");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_RESUME, "rolloutId is required for RESUME operation");
|
||||
}
|
||||
api.resume(r.rolloutId());
|
||||
api.resume(rolloutId);
|
||||
return OperationResponse.success(OP_RESUME, "Rollout resumed successfully");
|
||||
} else if (request instanceof RolloutRequest.Approve r) {
|
||||
} else if (request instanceof RolloutRequest.Approve(Long rolloutId, String remark)) {
|
||||
validateRolloutOperation("approve");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_APPROVE, "rolloutId is required for APPROVE operation");
|
||||
}
|
||||
api.approve(r.rolloutId(), r.remark());
|
||||
api.approve(rolloutId, remark);
|
||||
return OperationResponse.success(OP_APPROVE, "Rollout approved successfully");
|
||||
} else if (request instanceof RolloutRequest.Deny r) {
|
||||
} else if (request instanceof RolloutRequest.Deny(Long rolloutId, String remark)) {
|
||||
validateRolloutOperation("deny");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_DENY, "rolloutId is required for DENY operation");
|
||||
}
|
||||
api.deny(r.rolloutId(), r.remark());
|
||||
api.deny(rolloutId, remark);
|
||||
return OperationResponse.success(OP_DENY, "Rollout denied successfully");
|
||||
} else if (request instanceof RolloutRequest.Retry r) {
|
||||
} else if (request instanceof RolloutRequest.Retry(Long rolloutId)) {
|
||||
validateRolloutOperation("retry");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_RETRY, "rolloutId is required for RETRY operation");
|
||||
}
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.retryRollout(r.rolloutId());
|
||||
final ResponseEntity<MgmtRolloutResponseBody> response = api.retryRollout(rolloutId);
|
||||
return OperationResponse.success(OP_RETRY, "Rollout retry created successfully", response.getBody());
|
||||
} else if (request instanceof RolloutRequest.TriggerNextGroup r) {
|
||||
} else if (request instanceof RolloutRequest.TriggerNextGroup(Long rolloutId)) {
|
||||
validateRolloutOperation("trigger-next-group");
|
||||
if (r.rolloutId() == null) {
|
||||
if (rolloutId == null) {
|
||||
return OperationResponse.failure(OP_TRIGGER_NEXT_GROUP, "rolloutId is required for TRIGGER_NEXT_GROUP operation");
|
||||
}
|
||||
api.triggerNextGroup(r.rolloutId());
|
||||
api.triggerNextGroup(rolloutId);
|
||||
return OperationResponse.success(OP_TRIGGER_NEXT_GROUP, "Next rollout group triggered successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_distribution_set",
|
||||
description = "Create, update, or delete distribution sets (software packages). " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"version\":\"v\",\"type\":\"t\"}}, " +
|
||||
"{\"type\":\"Update\",\"distributionSetId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"distributionSetId\":123}")
|
||||
description = "Create, update, or delete distribution sets (software packages). " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"version\":\"v\",\"type\":\"t\"}}, " +
|
||||
"{\"type\":\"Update\",\"distributionSetId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"distributionSetId\":123}")
|
||||
public OperationResponse<Object> manageDistributionSet(final DistributionSetRequest request) {
|
||||
log.debug("Managing distribution set: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtDistributionSetRestApi api = hawkbitClient.mgmtService(MgmtDistributionSetRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof DistributionSetRequest.Create r) {
|
||||
if (request instanceof DistributionSetRequest.Create(MgmtDistributionSetRequestBodyPost body)) {
|
||||
validateOperation(OP_CREATE, DISTRIBUTION_SETS);
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_CREATE, BODY_IS_REQUIRED_FOR_CREATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<List<MgmtDistributionSet>> response = api.createDistributionSets(List.of(r.body()));
|
||||
final ResponseEntity<List<MgmtDistributionSet>> response = api.createDistributionSets(List.of(body));
|
||||
final List<MgmtDistributionSet> created = response.getBody();
|
||||
return OperationResponse.success(OP_CREATE, "Distribution set created successfully",
|
||||
created != null && !created.isEmpty() ? created.get(0) : null);
|
||||
} else if (request instanceof DistributionSetRequest.Update r) {
|
||||
} else if (request instanceof DistributionSetRequest.Update(Long distributionSetId, MgmtDistributionSetRequestBodyPut body)) {
|
||||
validateOperation(OP_UPDATE, DISTRIBUTION_SETS);
|
||||
if (r.distributionSetId() == null) {
|
||||
if (distributionSetId == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, "distributionSetId is required for UPDATE operation");
|
||||
}
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, BODY_IS_REQUIRED_FOR_UPDATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtDistributionSet> response = api.updateDistributionSet(r.distributionSetId(), r.body());
|
||||
final ResponseEntity<MgmtDistributionSet> response = api.updateDistributionSet(distributionSetId, body);
|
||||
return OperationResponse.success(OP_UPDATE, "Distribution set updated successfully", response.getBody());
|
||||
} else if (request instanceof DistributionSetRequest.Delete r) {
|
||||
} else if (request instanceof DistributionSetRequest.Delete(Long distributionSetId)) {
|
||||
validateOperation(OP_DELETE, DISTRIBUTION_SETS);
|
||||
if (r.distributionSetId() == null) {
|
||||
if (distributionSetId == null) {
|
||||
return OperationResponse.failure(OP_DELETE, "distributionSetId is required for DELETE operation");
|
||||
}
|
||||
api.deleteDistributionSet(r.distributionSetId());
|
||||
api.deleteDistributionSet(distributionSetId);
|
||||
return OperationResponse.success(OP_DELETE, "Distribution set deleted successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_action",
|
||||
description = "Delete deployment actions. Actions are created indirectly via distribution set assignment. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Delete\",\"actionIds\":[123]}, " +
|
||||
"{\"type\":\"DeleteBatch\",\"actionIds\":[1,2,3],\"rsql\":\"\"}")
|
||||
description = "Delete deployment actions. Actions are created indirectly via distribution set assignment. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Delete\",\"actionIds\":[123]}, " +
|
||||
"{\"type\":\"DeleteBatch\",\"actionIds\":[1,2,3],\"rsql\":\"\"}")
|
||||
public OperationResponse<Object> manageAction(final ActionRequest request) {
|
||||
log.debug("Managing action: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtActionRestApi api = hawkbitClient.mgmtService(MgmtActionRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof ActionRequest.Delete r) {
|
||||
if (request instanceof ActionRequest.Delete(Long actionId)) {
|
||||
validateActionOperation(OP_DELETE);
|
||||
if (r.actionId() == null) {
|
||||
if (actionId == null) {
|
||||
return OperationResponse.failure(OP_DELETE, "actionId is required for DELETE operation");
|
||||
}
|
||||
api.deleteAction(r.actionId());
|
||||
api.deleteAction(actionId);
|
||||
return OperationResponse.success(OP_DELETE, "Action deleted successfully");
|
||||
} else if (request instanceof ActionRequest.DeleteBatch r) {
|
||||
} else if (request instanceof ActionRequest.DeleteBatch(List<Long> actionIds, String rsql)) {
|
||||
validateActionOperation("delete-batch");
|
||||
if ((r.actionIds() == null || r.actionIds().isEmpty()) &&
|
||||
(r.rsql() == null || r.rsql().isBlank())) {
|
||||
if ((actionIds == null || actionIds.isEmpty()) &&
|
||||
(rsql == null || rsql.isBlank())) {
|
||||
return OperationResponse.failure(OP_DELETE_BATCH, "Either actionIds or rsql is required for DELETE_BATCH operation");
|
||||
}
|
||||
api.deleteActions(r.rsql(), r.actionIds());
|
||||
api.deleteActions(rsql, actionIds);
|
||||
return OperationResponse.success(OP_DELETE_BATCH, "Actions deleted successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_software_module",
|
||||
description = "Create, update, or delete software modules. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"version\":\"v\",\"type\":\"t\"}}, " +
|
||||
"{\"type\":\"Update\",\"softwareModuleId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"softwareModuleId\":123}")
|
||||
description = "Create, update, or delete software modules. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"version\":\"v\",\"type\":\"t\"}}, " +
|
||||
"{\"type\":\"Update\",\"softwareModuleId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"softwareModuleId\":123}")
|
||||
public OperationResponse<Object> manageSoftwareModule(final SoftwareModuleRequest request) {
|
||||
log.debug("Managing software module: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtSoftwareModuleRestApi api = hawkbitClient.mgmtService(MgmtSoftwareModuleRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof SoftwareModuleRequest.Create r) {
|
||||
if (request instanceof SoftwareModuleRequest.Create(MgmtSoftwareModuleRequestBodyPost body)) {
|
||||
validateOperation(OP_CREATE, SOFTWARE_MODULES);
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_CREATE, BODY_IS_REQUIRED_FOR_CREATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<List<MgmtSoftwareModule>> response = api.createSoftwareModules(List.of(r.body()));
|
||||
final ResponseEntity<List<MgmtSoftwareModule>> response = api.createSoftwareModules(List.of(body));
|
||||
final List<MgmtSoftwareModule> created = response.getBody();
|
||||
return OperationResponse.success(OP_CREATE, "Software module created successfully",
|
||||
created != null && !created.isEmpty() ? created.get(0) : null);
|
||||
} else if (request instanceof SoftwareModuleRequest.Update r) {
|
||||
} else if (request instanceof SoftwareModuleRequest.Update(Long softwareModuleId, MgmtSoftwareModuleRequestBodyPut body)) {
|
||||
validateOperation(OP_UPDATE, SOFTWARE_MODULES);
|
||||
if (r.softwareModuleId() == null) {
|
||||
if (softwareModuleId == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, "softwareModuleId is required for UPDATE operation");
|
||||
}
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, BODY_IS_REQUIRED_FOR_UPDATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtSoftwareModule> response = api.updateSoftwareModule(r.softwareModuleId(), r.body());
|
||||
final ResponseEntity<MgmtSoftwareModule> response = api.updateSoftwareModule(softwareModuleId, body);
|
||||
return OperationResponse.success(OP_UPDATE, "Software module updated successfully", response.getBody());
|
||||
} else if (request instanceof SoftwareModuleRequest.Delete r) {
|
||||
} else if (request instanceof SoftwareModuleRequest.Delete(Long softwareModuleId)) {
|
||||
validateOperation(OP_DELETE, SOFTWARE_MODULES);
|
||||
if (r.softwareModuleId() == null) {
|
||||
if (softwareModuleId == null) {
|
||||
return OperationResponse.failure(OP_DELETE, "softwareModuleId is required for DELETE operation");
|
||||
}
|
||||
api.deleteSoftwareModule(r.softwareModuleId());
|
||||
api.deleteSoftwareModule(softwareModuleId);
|
||||
return OperationResponse.success(OP_DELETE, "Software module deleted successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@McpTool(name = "manage_target_filter",
|
||||
description = "Create, update, or delete target filter queries. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"query\":\"name==*\"}}, " +
|
||||
"{\"type\":\"Update\",\"filterId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"filterId\":123}")
|
||||
description = "Create, update, or delete target filter queries. " +
|
||||
"Use 'type' field to select operation: " +
|
||||
"{\"type\":\"Create\",\"body\":{\"name\":\"n\",\"query\":\"name==*\"}}, " +
|
||||
"{\"type\":\"Update\",\"filterId\":123,\"body\":{...}}, " +
|
||||
"{\"type\":\"Delete\",\"filterId\":123}")
|
||||
public OperationResponse<Object> manageTargetFilter(final TargetFilterRequest request) {
|
||||
log.debug("Managing target filter: request={}", request.getClass().getSimpleName());
|
||||
|
||||
final MgmtTargetFilterQueryRestApi api = hawkbitClient.mgmtService(MgmtTargetFilterQueryRestApi.class, dummyTenant);
|
||||
|
||||
if (request instanceof TargetFilterRequest.Create r) {
|
||||
if (request instanceof TargetFilterRequest.Create(MgmtTargetFilterQueryRequestBody body)) {
|
||||
validateOperation(OP_CREATE, TARGET_FILTERS);
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_CREATE, BODY_IS_REQUIRED_FOR_CREATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtTargetFilterQuery> response = api.createFilter(r.body());
|
||||
final ResponseEntity<MgmtTargetFilterQuery> response = api.createFilter(body);
|
||||
return OperationResponse.success(OP_CREATE, "Target filter created successfully", response.getBody());
|
||||
} else if (request instanceof TargetFilterRequest.Update r) {
|
||||
} else if (request instanceof TargetFilterRequest.Update(Long filterId, MgmtTargetFilterQueryRequestBody body)) {
|
||||
validateOperation(OP_UPDATE, TARGET_FILTERS);
|
||||
if (r.filterId() == null) {
|
||||
if (filterId == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, "filterId is required for UPDATE operation");
|
||||
}
|
||||
if (r.body() == null) {
|
||||
if (body == null) {
|
||||
return OperationResponse.failure(OP_UPDATE, BODY_IS_REQUIRED_FOR_UPDATE_OPERATION);
|
||||
}
|
||||
final ResponseEntity<MgmtTargetFilterQuery> response = api.updateFilter(r.filterId(), r.body());
|
||||
final ResponseEntity<MgmtTargetFilterQuery> response = api.updateFilter(filterId, body);
|
||||
return OperationResponse.success(OP_UPDATE, "Target filter updated successfully", response.getBody());
|
||||
} else if (request instanceof TargetFilterRequest.Delete r) {
|
||||
} else if (request instanceof TargetFilterRequest.Delete(Long filterId)) {
|
||||
validateOperation(OP_DELETE, TARGET_FILTERS);
|
||||
if (r.filterId() == null) {
|
||||
if (filterId == null) {
|
||||
return OperationResponse.failure(OP_DELETE, "filterId is required for DELETE operation");
|
||||
}
|
||||
api.deleteFilter(r.filterId());
|
||||
api.deleteFilter(filterId);
|
||||
return OperationResponse.success(OP_DELETE, "Target filter deleted successfully");
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown request type: " + request.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
|
||||
private void validateOperation(final String operation, final String entity) {
|
||||
if (!isOperationEnabled(operation, entity)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Operation " + operation.toUpperCase() + " is not enabled for " + entity +
|
||||
". Check hawkbit.mcp.operations configuration.");
|
||||
". Check hawkbit.mcp.operations configuration.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,7 +517,7 @@ public class HawkbitMcpToolProvider {
|
||||
if (!properties.getOperations().isGlobalOperationEnabled(operation)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Operation " + operation.toUpperCase() + " is not enabled for rollouts. " +
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -518,7 +525,7 @@ public class HawkbitMcpToolProvider {
|
||||
if (!entitySetting) {
|
||||
throw new IllegalArgumentException(
|
||||
"Operation " + operation.toUpperCase() + " is not enabled for rollouts. " +
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,7 +537,7 @@ public class HawkbitMcpToolProvider {
|
||||
if (operation.equals("delete") && !properties.getOperations().isGlobalOperationEnabled(OP_DELETE)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Operation " + operation.toUpperCase() + " is not enabled for actions. " +
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -538,7 +545,7 @@ public class HawkbitMcpToolProvider {
|
||||
if (!entitySetting) {
|
||||
throw new IllegalArgumentException(
|
||||
"Operation " + operation.toUpperCase() + " is not enabled for actions. " +
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
"Check hawkbit.mcp.operations configuration.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,85 +60,87 @@ public class EntityMatcher {
|
||||
|
||||
@SuppressWarnings({ "java:S3776", "java:S3358", "java:S1125", "java:S6541" }) // better readable this way
|
||||
private <T> boolean match(final T t, final Node node) {
|
||||
if (node instanceof Node.Comparison comparison) {
|
||||
final String[] split = comparison.getKey().split("\\.", 2);
|
||||
try {
|
||||
final Getter fieldGetter = getGetter(t.getClass(), split[0]);
|
||||
final Object fieldValue = fieldGetter.get(t);
|
||||
final Operator op = comparison.getOp();
|
||||
if (Map.class.isAssignableFrom(getReturnType(fieldGetter))) {
|
||||
if ((op == NE || op == NOT_IN || op == NOT_LIKE)
|
||||
&& (fieldValue == null || !((Map<?, ?>) fieldValue).containsKey(split[1]))) {
|
||||
// TODO / recheck - when missing entity shall it be included or not in != or =out=? - now it's not
|
||||
return false;
|
||||
}
|
||||
return compareIgnoreCaseAware(
|
||||
fieldValue == null ? null : ((Map<?, ?>) fieldValue).get(split[1]),
|
||||
op,
|
||||
map(
|
||||
comparison.getValue(),
|
||||
(Class<?>) ((ParameterizedType) fieldGetter.type()).getActualTypeArguments()[1]));
|
||||
} else if (Collection.class.isAssignableFrom(getReturnType(fieldGetter))) { // Set / List
|
||||
final Object value;
|
||||
final BiPredicate<Object, Operator> compare;
|
||||
if (split.length == 1) {
|
||||
value = map(comparison.getValue(), getReturnType(fieldGetter));
|
||||
compare = (e, operator) -> compareIgnoreCaseAware(e, operator, value);
|
||||
} else {
|
||||
final Getter valueGetter = getGetter(
|
||||
(Class<?>) ((ParameterizedType) fieldGetter.type()).getActualTypeArguments()[0], split[1]);
|
||||
value = map(comparison.getValue(), getReturnType(valueGetter));
|
||||
compare = (e, operator) -> {
|
||||
try {
|
||||
return compareIgnoreCaseAware(
|
||||
map(e == null ? null : valueGetter.get(e), getReturnType(valueGetter)), operator, value);
|
||||
} catch (final IllegalAccessException | InvocationTargetException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
final Collection<?> set = (Collection<?>) fieldValue;
|
||||
return switch (op) {
|
||||
case EQ, GT, GTE, LT, LTE, IN, LIKE -> set == null
|
||||
? false
|
||||
: set.stream().anyMatch(e -> compare.test(e, op));
|
||||
case NE, NOT_IN, NOT_LIKE -> set == null
|
||||
? true
|
||||
: set.stream().noneMatch(e -> compare.test(e, op == NE ? EQ : op == NOT_IN ? IN : LIKE));
|
||||
};
|
||||
} else {
|
||||
if (split.length == 1) {
|
||||
return compareIgnoreCaseAware(fieldValue, op, map(comparison.getValue(), getReturnType(fieldGetter)));
|
||||
} else {
|
||||
if (split[1].contains(".")) {
|
||||
// nested field access
|
||||
final String[] nestedSplit = split[1].split("\\.", 2);
|
||||
final Getter nestedFieldGetter = getGetter(getReturnType(fieldGetter), nestedSplit[0]);
|
||||
final Getter valueGetter = getGetter(getReturnType(nestedFieldGetter), nestedSplit[1]);
|
||||
final Object nestedFieldValue = fieldValue == null ? null : nestedFieldGetter.get(fieldValue);
|
||||
return compareIgnoreCaseAware(
|
||||
nestedFieldValue == null ? null : valueGetter.get(nestedFieldValue),
|
||||
op,
|
||||
map(comparison.getValue(), getReturnType(valueGetter)));
|
||||
switch (node) {
|
||||
case Node.Comparison comparison -> {
|
||||
final String[] split = comparison.getKey().split("\\.", 2);
|
||||
try {
|
||||
final Getter fieldGetter = getGetter(t.getClass(), split[0]);
|
||||
final Object fieldValue = fieldGetter.get(t);
|
||||
final Operator op = comparison.getOp();
|
||||
if (Map.class.isAssignableFrom(getReturnType(fieldGetter))) {
|
||||
if ((op == NE || op == NOT_IN || op == NOT_LIKE)
|
||||
&& (fieldValue == null || !((Map<?, ?>) fieldValue).containsKey(split[1]))) {
|
||||
// TODO / recheck - when missing entity shall it be included or not in != or =out=? - now it's not
|
||||
return false;
|
||||
}
|
||||
return compareIgnoreCaseAware(
|
||||
fieldValue == null ? null : ((Map<?, ?>) fieldValue).get(split[1]),
|
||||
op,
|
||||
map(
|
||||
comparison.getValue(),
|
||||
(Class<?>) ((ParameterizedType) fieldGetter.type()).getActualTypeArguments()[1]));
|
||||
} else if (Collection.class.isAssignableFrom(getReturnType(fieldGetter))) { // Set / List
|
||||
final Object value;
|
||||
final BiPredicate<Object, Operator> compare;
|
||||
if (split.length == 1) {
|
||||
value = map(comparison.getValue(), getReturnType(fieldGetter));
|
||||
compare = (e, operator) -> compareIgnoreCaseAware(e, operator, value);
|
||||
} else {
|
||||
final Getter valueGetter = getGetter(getReturnType(fieldGetter), split[1]);
|
||||
return compareIgnoreCaseAware(
|
||||
fieldValue == null ? null : valueGetter.get(fieldValue),
|
||||
op,
|
||||
map(comparison.getValue(), getReturnType(valueGetter)));
|
||||
final Getter valueGetter = getGetter(
|
||||
(Class<?>) ((ParameterizedType) fieldGetter.type()).getActualTypeArguments()[0], split[1]);
|
||||
value = map(comparison.getValue(), getReturnType(valueGetter));
|
||||
compare = (e, operator) -> {
|
||||
try {
|
||||
return compareIgnoreCaseAware(
|
||||
map(e == null ? null : valueGetter.get(e), getReturnType(valueGetter)), operator, value);
|
||||
} catch (final IllegalAccessException | InvocationTargetException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
final Collection<?> set = (Collection<?>) fieldValue;
|
||||
return switch (op) {
|
||||
case EQ, GT, GTE, LT, LTE, IN, LIKE -> set == null
|
||||
? false
|
||||
: set.stream().anyMatch(e -> compare.test(e, op));
|
||||
case NE, NOT_IN, NOT_LIKE -> set == null
|
||||
? true
|
||||
: set.stream().noneMatch(e -> compare.test(e, op == NE ? EQ : op == NOT_IN ? IN : LIKE));
|
||||
};
|
||||
} else {
|
||||
if (split.length == 1) {
|
||||
return compareIgnoreCaseAware(fieldValue, op, map(comparison.getValue(), getReturnType(fieldGetter)));
|
||||
} else {
|
||||
if (split[1].contains(".")) {
|
||||
// nested field access
|
||||
final String[] nestedSplit = split[1].split("\\.", 2);
|
||||
final Getter nestedFieldGetter = getGetter(getReturnType(fieldGetter), nestedSplit[0]);
|
||||
final Getter valueGetter = getGetter(getReturnType(nestedFieldGetter), nestedSplit[1]);
|
||||
final Object nestedFieldValue = fieldValue == null ? null : nestedFieldGetter.get(fieldValue);
|
||||
return compareIgnoreCaseAware(
|
||||
nestedFieldValue == null ? null : valueGetter.get(nestedFieldValue),
|
||||
op,
|
||||
map(comparison.getValue(), getReturnType(valueGetter)));
|
||||
} else {
|
||||
final Getter valueGetter = getGetter(getReturnType(fieldGetter), split[1]);
|
||||
return compareIgnoreCaseAware(
|
||||
fieldValue == null ? null : valueGetter.get(fieldValue),
|
||||
op,
|
||||
map(comparison.getValue(), getReturnType(valueGetter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
} catch (final NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
} else if (node instanceof Node.Logical logical) {
|
||||
return switch (logical.getOp()) {
|
||||
case AND -> logical.getChildren().stream().allMatch(child -> match(t, child));
|
||||
case OR -> logical.getChildren().stream().anyMatch(child -> match(t, child));
|
||||
};
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported node type: " + node.getClass());
|
||||
case Node.Logical logical -> {
|
||||
return switch (logical.getOp()) {
|
||||
case AND -> logical.getChildren().stream().allMatch(child -> match(t, child));
|
||||
case OR -> logical.getChildren().stream().anyMatch(child -> match(t, child));
|
||||
};
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported node type: " + node.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,13 +153,11 @@ public class EntityMatcher {
|
||||
return o;
|
||||
}
|
||||
// if here - ignoreCase in true and we have non-null value
|
||||
if (o instanceof String str) {
|
||||
return str.toLowerCase();
|
||||
} else if (o instanceof Collection<?> collection) {
|
||||
return collection.stream().map(this::ignoreCase).toList();
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
return switch (o) {
|
||||
case String str -> str.toLowerCase();
|
||||
case Collection<?> collection -> collection.stream().map(this::ignoreCase).toList();
|
||||
default -> o;
|
||||
};
|
||||
}
|
||||
|
||||
// java:S3011 uses reflection to private members anyway
|
||||
|
||||
@@ -105,29 +105,33 @@ public class SpecificationBuilder<T> {
|
||||
}
|
||||
|
||||
public Predicate build(final Node node) {
|
||||
if (node instanceof Comparison comparison) {
|
||||
return predicate(comparison);
|
||||
} else if (node instanceof Logical logical) {
|
||||
final Logical.Operator op = Objects.requireNonNull(logical.getOp());
|
||||
if (op == Logical.Operator.AND) {
|
||||
return cb.and(logical.getChildren().stream()
|
||||
.map(this::build)
|
||||
.toList()
|
||||
.toArray(PREDICATES_ARRAY_0));
|
||||
} else if (op == Logical.Operator.OR) {
|
||||
final Map<String, Integer> state = pathResolver.getState();
|
||||
return cb.or(logical.getChildren().stream()
|
||||
.map(child -> {
|
||||
pathResolver.reset(state);
|
||||
return build(child); // for or path resolver joins could be reused
|
||||
})
|
||||
.toList()
|
||||
.toArray(PREDICATES_ARRAY_0));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported logical operator: " + op);
|
||||
switch (node) {
|
||||
case Comparison comparison -> {
|
||||
return predicate(comparison);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported node type: " + node.getClass());
|
||||
case Logical logical -> {
|
||||
final Logical.Operator op = Objects.requireNonNull(logical.getOp());
|
||||
switch (op) {
|
||||
case Logical.Operator.AND -> {
|
||||
return cb.and(logical.getChildren().stream()
|
||||
.map(this::build)
|
||||
.toList()
|
||||
.toArray(PREDICATES_ARRAY_0));
|
||||
}
|
||||
case Logical.Operator.OR -> {
|
||||
final Map<String, Integer> state = pathResolver.getState();
|
||||
return cb.or(logical.getChildren().stream()
|
||||
.map(child -> {
|
||||
pathResolver.reset(state);
|
||||
return build(child); // for or path resolver joins could be reused
|
||||
})
|
||||
.toList()
|
||||
.toArray(PREDICATES_ARRAY_0));
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported logical operator: " + op);
|
||||
}
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported node type: " + node.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.transaction.TransactionSystemException;
|
||||
@Slf4j
|
||||
public class ExceptionMapper {
|
||||
|
||||
private static final Map<String, String> EXCEPTION_MAPPING = new HashMap<>(4);
|
||||
private static final Map<String, String> EXCEPTION_MAPPING = HashMap.newHashMap(4);
|
||||
|
||||
// this is required to enable a certain order of exception and to select the most specific mappable exception according to the type
|
||||
// hierarchy of the exception
|
||||
|
||||
@@ -81,7 +81,7 @@ public class JpaConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getVendorProperties(final DataSource dataSource) {
|
||||
final Map<String, Object> properties = new HashMap<>(7);
|
||||
final Map<String, Object> properties = HashMap.newHashMap(7);
|
||||
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
|
||||
properties.put(PersistenceUnitProperties.WEAVING, "false");
|
||||
// needed for reports
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
@@ -154,13 +155,13 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||
return false;
|
||||
}
|
||||
final BaseEntity other = (BaseEntity) obj;
|
||||
final Long id = getId();
|
||||
final Long thisId = getId();
|
||||
final Long otherId = other.getId();
|
||||
if (id == null) {
|
||||
if (thisId == null) {
|
||||
if (otherId != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(otherId)) {
|
||||
} else if (!thisId.equals(otherId)) {
|
||||
return false;
|
||||
}
|
||||
return getOptLockRevision() == other.getOptLockRevision();
|
||||
@@ -198,9 +199,9 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||
}
|
||||
|
||||
protected boolean isController() {
|
||||
return SecurityContextHolder.getContext().getAuthentication() != null &&
|
||||
SecurityContextHolder.getContext().getAuthentication().getDetails()
|
||||
instanceof TenantAwareAuthenticationDetails tenantAwareDetails &&
|
||||
tenantAwareDetails.controller();
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
return authentication != null
|
||||
&& authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails
|
||||
&& tenantAwareDetails.controller();
|
||||
}
|
||||
}
|
||||
@@ -678,7 +678,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
log.debug("{} events in flushUpdateQueue.", size);
|
||||
|
||||
final Set<TargetPoll> events = new HashSet<>(queue.size());
|
||||
final Set<TargetPoll> events = HashSet.newHashSet(queue.size());
|
||||
final int drained = queue.drainTo(events);
|
||||
|
||||
if (drained <= 0) {
|
||||
|
||||
@@ -68,12 +68,12 @@ public class StatisticsUtils {
|
||||
final Meter.Id id = m.getId();
|
||||
if (id.getName().startsWith(Statistics.METER_PREFIX)) {
|
||||
final double value;
|
||||
if (m instanceof Counter counter) {
|
||||
value = counter.count();
|
||||
} else if (m instanceof FunctionCounter functionCounter) {
|
||||
value = functionCounter.count();
|
||||
} else {
|
||||
return;
|
||||
switch (m) {
|
||||
case Counter counter -> value = counter.count();
|
||||
case FunctionCounter functionCounter -> value = functionCounter.count();
|
||||
default -> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final StringBuilder key = new StringBuilder(id.getName());
|
||||
|
||||
@@ -255,9 +255,8 @@ public final class TargetView extends TableView<TargetView.TargetWithDs, String>
|
||||
}
|
||||
|
||||
private static List<MgmtTargetFilterQuery> listFilters(HawkbitMgmtClient hawkbitClient) {
|
||||
return Optional.ofNullable(hawkbitClient.getTargetFilterQueryRestApi()
|
||||
.getFilters(null, 0, 30, null, null).getBody())
|
||||
.map(PagedList<MgmtTargetFilterQuery>::getContent)
|
||||
return Optional.ofNullable(hawkbitClient.getTargetFilterQueryRestApi().getFilters(null, 0, 30, null, null).getBody())
|
||||
.map(PagedList::getContent)
|
||||
.orElseGet(List::of);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,18 +149,18 @@ public final class Filter extends Div {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value instanceof Collection<?> coll) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
coll.stream().forEach(next -> sb.append(key).append("==").append(next).append(','));
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
} else if (value instanceof Optional<?> opt) {
|
||||
if (opt.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return key + "==" + opt.get();
|
||||
switch (value) {
|
||||
case Collection<?> coll -> {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
coll.stream().forEach(next -> sb.append(key).append("==").append(next).append(','));
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
case Optional<?> opt -> {
|
||||
return opt.map(o -> key + "==" + o).orElse(null);
|
||||
}
|
||||
default -> {
|
||||
return key + "==" + value;
|
||||
}
|
||||
} else {
|
||||
return key + "==" + value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user