aboutsummaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/onap/cps/temporal/domain/SearchCriteria.java98
-rw-r--r--src/main/java/org/onap/cps/temporal/repository/NetworkDataQueryRepository.java31
-rw-r--r--src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java5
-rw-r--r--src/main/java/org/onap/cps/temporal/repository/NetworkDataRepositoryImpl.java162
-rw-r--r--src/main/java/org/onap/cps/temporal/service/NetworkDataService.java6
-rw-r--r--src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java15
6 files changed, 313 insertions, 4 deletions
diff --git a/src/main/java/org/onap/cps/temporal/domain/SearchCriteria.java b/src/main/java/org/onap/cps/temporal/domain/SearchCriteria.java
new file mode 100644
index 0000000..8188d84
--- /dev/null
+++ b/src/main/java/org/onap/cps/temporal/domain/SearchCriteria.java
@@ -0,0 +1,98 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://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
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.temporal.domain;
+
+import java.time.OffsetDateTime;
+import javax.validation.constraints.NotNull;
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@Builder(builderClassName = "Builder")
+public class SearchCriteria {
+
+ private OffsetDateTime createdBefore;
+ private OffsetDateTime observedAfter;
+ private String dataspaceName;
+ private String anchorName;
+ private String schemaSetName;
+ private Pageable pageable;
+ private String simplePayloadFilter;
+
+ public static class Builder {
+
+ private Sort sort = Sort.by(Direction.DESC, "observed_timestamp");
+ private OffsetDateTime createdBefore = OffsetDateTime.now();
+
+ public Builder pagination(final int pageNumber, final int pageSize) {
+ pageable = PageRequest.of(pageNumber, pageSize);
+ return this;
+ }
+
+ public Builder sort(final @NotNull Sort sort) {
+ this.sort = sort;
+ return this;
+ }
+
+ /**
+ * Validates the state before building search criteria.
+ *
+ * @return SearchCriteria searchCriteria
+ */
+ public SearchCriteria build() {
+
+ if (StringUtils.isEmpty(anchorName) && StringUtils.isEmpty(schemaSetName)) {
+ throw new IllegalStateException(
+ "Either anchorName or schemaSetName must be provided");
+ }
+
+ if (StringUtils.isEmpty(dataspaceName)) {
+ throw new IllegalStateException("Dataspace is mandatory");
+ }
+
+ if (pageable == null) {
+ throw new IllegalStateException("Pageable is mandatory");
+ }
+
+ final var searchCriteria = new SearchCriteria();
+ searchCriteria.createdBefore = createdBefore;
+ searchCriteria.observedAfter = observedAfter;
+ searchCriteria.dataspaceName = dataspaceName;
+ searchCriteria.anchorName = anchorName;
+ searchCriteria.schemaSetName = schemaSetName;
+ searchCriteria.pageable = ((PageRequest) pageable).withSort(sort);
+ searchCriteria.simplePayloadFilter = simplePayloadFilter;
+ return searchCriteria;
+ }
+
+ }
+
+}
+
+
diff --git a/src/main/java/org/onap/cps/temporal/repository/NetworkDataQueryRepository.java b/src/main/java/org/onap/cps/temporal/repository/NetworkDataQueryRepository.java
new file mode 100644
index 0000000..12d3d68
--- /dev/null
+++ b/src/main/java/org/onap/cps/temporal/repository/NetworkDataQueryRepository.java
@@ -0,0 +1,31 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://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
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.temporal.repository;
+
+import org.onap.cps.temporal.domain.NetworkData;
+import org.onap.cps.temporal.domain.SearchCriteria;
+import org.springframework.data.domain.Slice;
+
+public interface NetworkDataQueryRepository {
+
+ Slice<NetworkData> findBySearchCriteria(SearchCriteria searchCriteria);
+
+}
diff --git a/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java b/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java
index 2e9f34b..c0f4fc9 100644
--- a/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java
+++ b/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepository.java
@@ -13,6 +13,8 @@
* 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
* ============LICENSE_END=========================================================
*/
@@ -24,5 +26,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
-public interface NetworkDataRepository extends JpaRepository<NetworkData, NetworkDataId> {
+public interface NetworkDataRepository extends JpaRepository<NetworkData, NetworkDataId>,
+ NetworkDataQueryRepository {
}
diff --git a/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepositoryImpl.java b/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepositoryImpl.java
new file mode 100644
index 0000000..548f973
--- /dev/null
+++ b/src/main/java/org/onap/cps/temporal/repository/NetworkDataRepositoryImpl.java
@@ -0,0 +1,162 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (c) 2021 Bell Canada.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://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
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.temporal.repository;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.onap.cps.temporal.domain.NetworkData;
+import org.onap.cps.temporal.domain.SearchCriteria;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.domain.SliceImpl;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@Slf4j
+public class NetworkDataRepositoryImpl implements NetworkDataQueryRepository {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ /*
+ Slice is the response type instead of List<NetworkData> to provide the information if next set of data is available.
+ To identify if next slice is available, the getDatNetworkDataList fetches one record extra ( n+1).
+ If ( n +1) records are fetched, it means that the next slice exist, otherwise it does not.
+ */
+ @Override
+ public Slice<NetworkData> findBySearchCriteria(final SearchCriteria searchCriteria) {
+
+ final var searchCriteriaQueryBuilder = new SearchCriteriaQueryBuilder(searchCriteria);
+ searchCriteriaQueryBuilder.buildQuery();
+
+ final List<NetworkData> data = getNetworkDataList(searchCriteriaQueryBuilder.getDataNativeQuery(),
+ searchCriteriaQueryBuilder.getQueryParameters(), searchCriteria.getPageable());
+
+ final boolean hasNextSlice = data.size() > searchCriteria.getPageable().getPageSize();
+ final List<NetworkData> sliceData = new ArrayList<>(data);
+ if (hasNextSlice) {
+ sliceData.remove(searchCriteria.getPageable().getPageSize());
+ }
+
+ return new SliceImpl<>(sliceData, searchCriteria.getPageable(), hasNextSlice);
+ }
+
+ private List<NetworkData> getNetworkDataList(final String nativeDataQuery,
+ final Map<String, Object> queryParameters, final Pageable pageable) {
+ final var dataQuery = entityManager.createNativeQuery(nativeDataQuery, NetworkData.class);
+ queryParameters.forEach(dataQuery::setParameter);
+ dataQuery.setFirstResult(Math.toIntExact(pageable.getOffset()));
+ dataQuery.setMaxResults(pageable.getPageSize() + 1);
+ return dataQuery.getResultList();
+ }
+
+ private static class SearchCriteriaQueryBuilder {
+
+ @Getter
+ private Map<String, Object> queryParameters = new HashMap<>();
+ private StringBuilder queryBuilder = new StringBuilder();
+
+ private String dataQuery;
+
+ private final SearchCriteria searchCriteria;
+
+ SearchCriteriaQueryBuilder(final SearchCriteria searchCriteria) {
+ this.searchCriteria = searchCriteria;
+ }
+
+ private void buildQuery() {
+
+ queryBuilder.append("SELECT * FROM network_data nd WHERE dataspace = :dataspace ");
+ queryParameters.put("dataspace", searchCriteria.getDataspaceName());
+
+ addAnchorCondition();
+ addSchemaSetCondition();
+ addObservedAfterCondition();
+ addSimplePayloadCondition();
+ addCreatedBeforeCondition();
+ addOrderBy();
+ dataQuery = queryBuilder.toString();
+
+ }
+
+
+ private void addSchemaSetCondition() {
+ if (!StringUtils.isEmpty(searchCriteria.getSchemaSetName())) {
+ queryBuilder.append(" AND schema_set = :schemaSetName ");
+ queryParameters.put("schemaSetName", searchCriteria.getSchemaSetName());
+ }
+ }
+
+ private void addAnchorCondition() {
+ if (!StringUtils.isEmpty(searchCriteria.getAnchorName())) {
+ queryBuilder.append(" AND anchor = :anchorName");
+ queryParameters.put("anchorName", searchCriteria.getAnchorName());
+ }
+ }
+
+ private void addSimplePayloadCondition() {
+ if (!StringUtils.isEmpty(searchCriteria.getSimplePayloadFilter())) {
+ queryBuilder.append(" AND payload @> :simplePayloadFilter\\:\\:jsonb ");
+ queryParameters.put("simplePayloadFilter", searchCriteria.getSimplePayloadFilter());
+ }
+ }
+
+ private void addCreatedBeforeCondition() {
+ if (searchCriteria.getCreatedBefore() != null) {
+ queryBuilder.append(" AND created_timestamp <= :createdBefore");
+ queryParameters.put("createdBefore", searchCriteria.getCreatedBefore());
+ }
+ }
+
+ private void addObservedAfterCondition() {
+ if (searchCriteria.getObservedAfter() != null) {
+ queryBuilder.append(" AND observed_timestamp >= :observedAfter");
+ queryParameters.put("observedAfter", searchCriteria.getObservedAfter());
+ }
+ }
+
+ private void addOrderBy() {
+ final var sortBy = searchCriteria.getPageable().getSort();
+ queryBuilder.append(" ORDER BY ");
+ final String orderByQuery = sortBy.stream().map(order -> {
+ final var direction = order.isAscending() ? "asc" : "desc";
+ return order.getProperty() + " " + direction;
+ }).collect(Collectors.joining(","));
+ queryBuilder.append(orderByQuery);
+ }
+
+ String getDataNativeQuery() {
+ return dataQuery;
+ }
+
+ }
+
+
+}
+
diff --git a/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java b/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java
index 509e470..261f05e 100644
--- a/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java
+++ b/src/main/java/org/onap/cps/temporal/service/NetworkDataService.java
@@ -13,12 +13,16 @@
* 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
* ============LICENSE_END=========================================================
*/
package org.onap.cps.temporal.service;
import org.onap.cps.temporal.domain.NetworkData;
+import org.onap.cps.temporal.domain.SearchCriteria;
+import org.springframework.data.domain.Slice;
public interface NetworkDataService {
@@ -28,4 +32,6 @@ public interface NetworkDataService {
* @param networkData the network data to be stored
*/
NetworkData addNetworkData(NetworkData networkData);
+
+ Slice<NetworkData> searchNetworkData(SearchCriteria searchCriteria);
}
diff --git a/src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java b/src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java
index 687ba85..7c2f999 100644
--- a/src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java
+++ b/src/main/java/org/onap/cps/temporal/service/NetworkDataServiceImpl.java
@@ -13,6 +13,8 @@
* 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
* ============LICENSE_END=========================================================
*/
@@ -22,7 +24,9 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.temporal.domain.NetworkData;
import org.onap.cps.temporal.domain.NetworkDataId;
+import org.onap.cps.temporal.domain.SearchCriteria;
import org.onap.cps.temporal.repository.NetworkDataRepository;
+import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
/**
@@ -44,13 +48,18 @@ public class NetworkDataServiceImpl implements NetworkDataService {
if (savedNetworkData.getCreatedTimestamp() == null) {
// Data already exists and can not be inserted
final var id =
- new NetworkDataId(
- networkData.getObservedTimestamp(), networkData.getDataspace(), networkData.getAnchor());
+ new NetworkDataId(
+ networkData.getObservedTimestamp(), networkData.getDataspace(), networkData.getAnchor());
final Optional<NetworkData> existingNetworkData = networkDataRepository.findById(id);
throw new ServiceException(
- "Failed to create network data. It already exists: " + (existingNetworkData.orElse(null)));
+ "Failed to create network data. It already exists: " + (existingNetworkData.orElse(null)));
}
return savedNetworkData;
}
+ @Override
+ public Slice<NetworkData> searchNetworkData(final SearchCriteria searchCriteria) {
+ return networkDataRepository.findBySearchCriteria(searchCriteria);
+ }
+
}