blob: 850cb2fe412cb1593d781c394fdce0727ecc3dfe [file] [log] [blame]
/*
* Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// gonural - initial implementation
// 2014-09-01-2.6.0 Dmitry Kornilov
// - JPARS 2.0 related changes
package org.eclipse.persistence.jpa.rs.features.paging;
import java.util.List;
import java.util.Map;
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo;
import jakarta.xml.bind.JAXBElement;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.ItemLinks;
import org.eclipse.persistence.internal.jpa.rs.weaving.PersistenceWeavedRest;
import org.eclipse.persistence.internal.queries.ReportItem;
import org.eclipse.persistence.jpa.rs.PersistenceContext;
import org.eclipse.persistence.jpa.rs.QueryParameters;
import org.eclipse.persistence.jpa.rs.features.FeatureResponseBuilderImpl;
import org.eclipse.persistence.jpa.rs.features.ItemLinksBuilder;
import org.eclipse.persistence.jpa.rs.util.HrefHelper;
import org.eclipse.persistence.jpa.rs.util.IdHelper;
import org.eclipse.persistence.jpa.rs.util.list.PageableCollection;
import org.eclipse.persistence.jpa.rs.util.list.ReadAllQueryResultCollection;
import org.eclipse.persistence.jpa.rs.util.list.ReportQueryResultCollection;
import org.eclipse.persistence.jpa.rs.util.list.ReportQueryResultListItem;
/**
* FeatureResponseBuilder implementation used for pageable collections. Used in JPARS 2.0.
*
* @author gonural
* @since EclipseLink 2.6.0.
*/
public class PagingResponseBuilder extends FeatureResponseBuilderImpl {
@Override
public Object buildReadAllQueryResponse(PersistenceContext context, Map<String, Object> queryParams, List<Object> items, UriInfo uriInfo) {
ReadAllQueryResultCollection response = new ReadAllQueryResultCollection();
for (Object item : items) {
response.addItem(populatePagedReadAllQueryItemLinks(context, item));
}
return populatePagedCollectionLinks(queryParams, uriInfo, response);
}
@Override
public Object buildReportQueryResponse(PersistenceContext context, Map<String, Object> queryParams, List<Object[]> results, List<ReportItem> items, UriInfo uriInfo) {
return populatePagedReportQueryCollectionLinks(queryParams, results, items, uriInfo);
}
@Override
public Object buildAttributeResponse(PersistenceContext context, Map<String, Object> queryParams, String attribute, Object results, UriInfo uriInfo) {
if (results instanceof List) {
ReadAllQueryResultCollection response = new ReadAllQueryResultCollection();
response.setItems((List<Object>) results);
return populatePagedCollectionLinks(queryParams, uriInfo, response);
}
return results;
}
private Object populatePagedReadAllQueryItemLinks(PersistenceContext context, Object result) {
// populate links for the entity
ClassDescriptor descriptor = context.getJAXBDescriptorForClass(result.getClass());
if ((result instanceof PersistenceWeavedRest) && (descriptor != null)) {
final PersistenceWeavedRest entity = (PersistenceWeavedRest) result;
final String href = HrefHelper.buildEntityHref(context, descriptor.getAlias(), IdHelper.stringifyId(result, descriptor.getAlias(), context));
final ItemLinks itemLinks = (new ItemLinksBuilder())
.addSelf(href)
.addCanonical(href)
.build();
entity._persistence_setLinks(itemLinks);
return entity;
}
return result;
}
private PageableCollection<?> populatePagedCollectionLinks(Map<String, Object> queryParams, UriInfo uriInfo, PageableCollection<?> resultCollection) {
// populate links for entire response
final ItemLinksBuilder itemLinksBuilder = new ItemLinksBuilder();
final int limit = Integer.parseInt((String) queryParams.get(QueryParameters.JPARS_PAGING_LIMIT));
final int offset = Integer.parseInt((String) queryParams.get(QueryParameters.JPARS_PAGING_OFFSET));
final UriBuilder uriBuilder = UriBuilder.fromUri(uriInfo.getRequestUri());
if (resultCollection.getItems() != null) {
final int actualCount = resultCollection.getItems().size();
if (actualCount > limit) {
// Remove the last item from collection. It was artificially added to indicate there are more records or not.
resultCollection.getItems().remove(actualCount - 1);
resultCollection.setCount(actualCount - 1);
// next link
// The uri might have other query/matrix parameters, just replace the limit and offset
// for next and prev links and leave the rest untouched
uriBuilder.replaceQueryParam(QueryParameters.JPARS_PAGING_OFFSET, String.valueOf(limit + offset));
itemLinksBuilder.addNext(uriBuilder.build().toString());
resultCollection.setHasMore(true);
} else {
resultCollection.setHasMore(false);
resultCollection.setCount(actualCount);
}
} else {
resultCollection.setCount(0);
}
if (offset != 0) {
if (offset > limit) {
uriBuilder.replaceQueryParam(QueryParameters.JPARS_PAGING_OFFSET, String.valueOf(offset - limit));
} else {
uriBuilder.replaceQueryParam(QueryParameters.JPARS_PAGING_OFFSET, "0");
}
if (resultCollection.getItems() != null && !resultCollection.getItems().isEmpty()) {
itemLinksBuilder.addPrev(uriBuilder.build().toString());
}
}
itemLinksBuilder.addSelf(uriInfo.getRequestUri().toString());
resultCollection.setLinks(itemLinksBuilder.build().getLinks());
resultCollection.setOffset(offset);
resultCollection.setLimit(limit);
return resultCollection;
}
/**
* Populate paged report query collection links.
*
* @param queryParams the query params
* @param results the results
* @param reportItems the report items
* @param uriInfo the uri info
* @return the pageable collection
*/
@SuppressWarnings({ "rawtypes" })
private PageableCollection populatePagedReportQueryCollectionLinks(Map<String, Object> queryParams, List<Object[]> results, List<ReportItem> reportItems, UriInfo uriInfo) {
ReportQueryResultCollection response = new ReportQueryResultCollection();
for (Object result : results) {
ReportQueryResultListItem queryResultListItem = new ReportQueryResultListItem();
List<JAXBElement<?>> jaxbFields = createShellJAXBElementList(reportItems, result);
// We don't have a way of determining self links for the report query responses
// so, no links array will be inserted into individual items in the response
queryResultListItem.setFields(jaxbFields);
response.addItem(queryResultListItem);
}
response.setCount(results.size());
return populatePagedCollectionLinks(queryParams, uriInfo, response);
}
}