Skip to content

Commit

Permalink
feat(policy-api):[#639] implement filtering and improvements
Browse files Browse the repository at this point in the history
still missing:
- filtering for validUntil and createdOn
- documentation, further / adjustment of tests, see TODOs with #639
  • Loading branch information
dsmf committed Jul 3, 2024
1 parent 9360ff0 commit 111885f
Show file tree
Hide file tree
Showing 9 changed files with 637 additions and 148 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ _**For better traceability add the corresponding GitHub issue number in each cha
- Documentation to describe the delegate process. #470
- Added file for CC BY 4.0 license for TRG 7. #681
- Paging for Policy Store API GET policies. #639

- New endpoint GET /irs/policies/paged.
- Supports sorting by multiple of the properties "bpn", "validUntil", "policyId", "createdOn", "action" with ascending / descending order.
- Supports filtering by multiple of properties "bpn", "validUntil", "policyId" (AND).
- note: filtering by "createdOn", "validUntil" has not been implemted yet

## [5.1.4] - 2024-05-27

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/********************************************************************************
* Copyright (c) 2022,2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.policystore.common;

public class CommonConstants {
public static final String PROPERTY_BPN = "bpn";
public static final String PROPERTY_POLICY_ID = "policyId";
public static final String PROPERTY_ACTION = "action";
public static final String PROPERTY_CREATED_ON = "createdOn";
public static final String PROPERTY_VALID_UNTIL = "validUntil";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/********************************************************************************
* Copyright (c) 2022,2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.policystore.common;

import java.util.ArrayList;
import java.util.List;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.tractusx.irs.policystore.models.SearchCriteria;

@Getter
public class SearchParameterParser {

public static final List<String> SUPPORTED_PROPERTIES = List.of(CommonConstants.PROPERTY_BPN,
CommonConstants.PROPERTY_VALID_UNTIL, CommonConstants.PROPERTY_POLICY_ID,
CommonConstants.PROPERTY_CREATED_ON, CommonConstants.PROPERTY_ACTION);
public static final List<String> DATE_PROPERTIES = List.of(CommonConstants.PROPERTY_VALID_UNTIL,
CommonConstants.PROPERTY_CREATED_ON);

public static final String CRITERIA_INNER_SEPARATOR = ",";

final List<SearchCriteria<?>> searchCriteria;

public SearchParameterParser(final List<String> searchParameters) {
searchCriteria = parseSearchParameters(searchParameters);
}

private List<SearchCriteria<?>> parseSearchParameters(final List<String> searchParameterList) {
final List<SearchCriteria<?>> searchCriteria = new ArrayList<>();
if (searchParameterList != null) {
for (int i = 0; i < searchParameterList.size(); i++) {

final String searchParameter = searchParameterList.get(i);
final String[] splittedSearchParam = StringUtils.split(searchParameter, CRITERIA_INNER_SEPARATOR);

if (splittedSearchParam.length < 3) {
throw new IllegalArgumentException(("Illegal search parameter at index %s. "
+ "Format should be <propertyName>,<operation>,<value>.").formatted(i));
}

final String property = getProperty(splittedSearchParam[0]);
final SearchCriteria.Operation operation = getOperation(splittedSearchParam[1], property);
final String value = getValue(splittedSearchParam[2]);

searchCriteria.add(new SearchCriteria<>(property, operation, value));
}
}

return searchCriteria;
}

private static String getValue(final String value) {
return StringUtils.trimToEmpty(value);
}

private static String getProperty(final String property) {
final String trimmedProperty = StringUtils.trimToEmpty(property);
if (SUPPORTED_PROPERTIES.stream().noneMatch(p -> p.equalsIgnoreCase(trimmedProperty))) {
throw new IllegalArgumentException("Only the following properties support filtering: %s".formatted(
String.join(", ", SUPPORTED_PROPERTIES)));
}
return trimmedProperty;
}

private SearchCriteria.Operation getOperation(final String operationStr, final String property) {
final SearchCriteria.Operation operation = SearchCriteria.Operation.valueOf(
StringUtils.trimToEmpty(operationStr));

if (operation == SearchCriteria.Operation.BETWEEN && DATE_PROPERTIES.stream()
.noneMatch(p -> p.equalsIgnoreCase(
property))) {
throw new IllegalArgumentException("Operation BETWEEN is only supported for date properties");
}
return operation;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -50,10 +51,13 @@
import org.eclipse.tractusx.irs.data.JsonParseException;
import org.eclipse.tractusx.irs.dtos.ErrorResponse;
import org.eclipse.tractusx.irs.edc.client.policy.Policy;
import org.eclipse.tractusx.irs.policystore.common.CommonConstants;
import org.eclipse.tractusx.irs.policystore.common.SearchParameterParser;
import org.eclipse.tractusx.irs.policystore.models.CreatePoliciesResponse;
import org.eclipse.tractusx.irs.policystore.models.CreatePolicyRequest;
import org.eclipse.tractusx.irs.policystore.models.PolicyResponse;
import org.eclipse.tractusx.irs.policystore.models.PolicyWithBpn;
import org.eclipse.tractusx.irs.policystore.models.SearchCriteria;
import org.eclipse.tractusx.irs.policystore.models.UpdatePolicyRequest;
import org.eclipse.tractusx.irs.policystore.services.PolicyPagingService;
import org.eclipse.tractusx.irs.policystore.services.PolicyStoreService;
Expand Down Expand Up @@ -204,23 +208,40 @@ public Map<String, List<PolicyResponse>> getPolicies(//
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
}

// TODO (mfischer): #639: add documentation
// TODO (mfischer): #639: add integration tests
// TODO (mfischer): #639: update insomnia
@GetMapping("/policies/paged")
@ResponseStatus(HttpStatus.OK)
@PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')")
public Page<PolicyResponse> getPoliciesPaged(//
@PageableDefault(size = DEFAULT_PAGE_SIZE, sort = "bpn", direction = Sort.Direction.ASC) //
@PageableDefault(size = DEFAULT_PAGE_SIZE, sort = CommonConstants.PROPERTY_BPN,
direction = Sort.Direction.ASC) //
final Pageable pageable, //
@RequestParam(required = false) //
@ValidListOfBusinessPartnerNumbers //
@Parameter(description = "List of business partner numbers.") //
final List<String> businessPartnerNumbers) {
final List<String> businessPartnerNumbers, //
// There seems to be a bug concerning interpretation of delimiters in Spring.
// If we pass only one search filter `?search=policyId,EQUALS,policy1`,
// the parts of this search filter are split up into several search filters even if we encode the comma.
// It only works if multiple search filters are passed `?search=policyId,EQUALS,policy1&search=...`.
// The solution described on stackoverflow
// (https://stackoverflow.com/questions/37058691/encoded-comma-in-url-is-read-as-list-in-spring)
// using the annotation Delimiter did not work either.
// Therefore, we read the search parameters from the request manually.
final HttpServletRequest request) {

if (pageable.getPageSize() > MAX_PAGE_SIZE) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Page size too large");
throw new IllegalArgumentException("Page size too large");
}

// TODO (mfischer): #639: add test coverage for this block
final List<String> searchParameters = Arrays.asList(request.getParameterMap().get("search"));
final List<SearchCriteria<?>> searchCriteria = new SearchParameterParser(searchParameters).getSearchCriteria();
final Map<String, List<Policy>> bpnToPoliciesMap = service.getPolicies(businessPartnerNumbers);
final Page<PolicyWithBpn> policies = policyPagingService.getPolicies(bpnToPoliciesMap, pageable);
final Page<PolicyWithBpn> policies = policyPagingService.getPolicies(bpnToPoliciesMap, pageable,
searchCriteria);
return policies.map(PolicyResponse::fromPolicyWithBpn);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/********************************************************************************
* Copyright (c) 2022,2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package org.eclipse.tractusx.irs.policystore.models;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class SearchCriteria<T> {
private String property;
private Operation operation;
private T value;

public enum Operation {
EQUALS,
STARTS_WITH,
BETWEEN
}
}
Loading

0 comments on commit 111885f

Please sign in to comment.