blob: 099f426e3423d7c311e012082b7b7d0db96f391d [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 fixes
package org.eclipse.persistence.jpa.rs.features.core.selflinks;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.ItemLinks;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.LinkV2;
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.ReservedWords;
import org.eclipse.persistence.jpa.rs.exceptions.JPARSException;
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.ReadAllQueryResultCollection;
import org.eclipse.persistence.jpa.rs.util.list.ReportQueryResultCollection;
import org.eclipse.persistence.jpa.rs.util.list.ReportQueryResultListItem;
import org.eclipse.persistence.jpa.rs.util.list.SingleResultQueryResult;
import jakarta.ws.rs.core.UriInfo;
import jakarta.xml.bind.JAXBElement;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
/**
* FeatureResponseBuilder implementation generating 'self' and 'canonical' links. Used in JPARS 2.0.
*
* @author gonural, Dmitry Kornilov
* @since EclipseList 2.6.0
*/
@SuppressWarnings({ "unchecked"})
public class SelfLinksResponseBuilder extends FeatureResponseBuilderImpl {
@Override
public Object buildReadAllQueryResponse(PersistenceContext context, Map<String, Object> queryParams, List<Object> items, UriInfo uriInfo) {
return collectionResponse(context, items, uriInfo);
}
@Override
public Object buildReportQueryResponse(PersistenceContext context, Map<String, Object> queryParams, List<Object[]> results, List<ReportItem> items, UriInfo uriInfo) {
ReportQueryResultCollection response = new ReportQueryResultCollection();
for (Object result : results) {
ReportQueryResultListItem queryResultListItem = new ReportQueryResultListItem();
List<JAXBElement<?>> jaxbFields = createShellJAXBElementList(items, result);
generateLinksInElementsList(context, jaxbFields);
queryResultListItem.setFields(jaxbFields);
response.addItem(queryResultListItem);
}
response.addLink(new LinkV2(ReservedWords.JPARS_REL_SELF, uriInfo.getRequestUri().toString()));
return response;
}
@Override
public Object buildSingleResultQueryResponse(PersistenceContext context, Map<String, Object> queryParams, Object result, List<ReportItem> items, UriInfo uriInfo) {
final SingleResultQueryResult response = new SingleResultQueryResult();
final List<JAXBElement<?>> fields = createShellJAXBElementList(items, result);
// If there are entities in fields insert links there
generateLinksInElementsList(context, fields);
response.setFields(fields);
response.addLink(new LinkV2(ReservedWords.JPARS_REL_SELF, uriInfo.getRequestUri().toString()));
return response;
}
@Override
public Object buildAttributeResponse(PersistenceContext context, Map<String, Object> queryParams, String attribute, Object item, UriInfo uriInfo) {
if (item instanceof List) {
return collectionResponse(context, (List<Object>) item, uriInfo);
}
return item;
}
@Override
public Object buildSingleEntityResponse(PersistenceContext context, Map<String, Object> queryParams, Object result, UriInfo uriInfo) {
if (result instanceof PersistenceWeavedRest) {
final PersistenceWeavedRest entity = (PersistenceWeavedRest)result;
final ClassDescriptor classDescriptor = context.getServerSession().getProject().getDescriptor(result.getClass());
final String entityClassName = classDescriptor.getAlias();
final String entityId = IdHelper.stringifyId(entity, entityClassName, context);
final ItemLinksBuilder itemLinksBuilder = (new ItemLinksBuilder())
.addSelf(uriInfo.getRequestUri().toString())
.addCanonical(HrefHelper.buildEntityHref(context, entityClassName, entityId));
generateLinksForRelationships(context, entity);
entity._persistence_setLinks(itemLinksBuilder.build());
return entity;
}
return result;
}
private Object collectionResponse(PersistenceContext context, List<Object> results, UriInfo uriInfo) {
if ((results != null) && (!results.isEmpty())) {
final ReadAllQueryResultCollection response = new ReadAllQueryResultCollection();
for (Object item : results) {
if (item instanceof PersistenceWeavedRest) {
final PersistenceWeavedRest entity = (PersistenceWeavedRest) item;
final ClassDescriptor classDescriptor = context.getServerSession().getProject().getDescriptor(item.getClass());
final String entityClassName = classDescriptor.getAlias();
final String entityId = IdHelper.stringifyId(entity, entityClassName, context);
final String href = HrefHelper.buildEntityHref(context, entityClassName, entityId);
final ItemLinksBuilder itemLinksBuilder = (new ItemLinksBuilder())
.addCanonical(href);
entity._persistence_setLinks(itemLinksBuilder.build());
generateLinksForRelationships(context, entity);
response.addItem(entity);
} else {
response.addItem(item);
}
}
response.addLink(new LinkV2(ReservedWords.JPARS_REL_SELF, uriInfo.getRequestUri().toString()));
return response;
}
return results;
}
private void generateLinksInElementsList(PersistenceContext context, List<JAXBElement<?>> fields) {
for (JAXBElement<?> field : fields) {
if (field.getValue() instanceof PersistenceWeavedRest) {
final PersistenceWeavedRest entity = (PersistenceWeavedRest) field.getValue();
final ClassDescriptor classDescriptor = context.getServerSession().getProject().getDescriptor(entity.getClass());
final String entityClassName = classDescriptor.getAlias();
final String entityId = IdHelper.stringifyId(entity, entityClassName, context);
// No links for embedded objects
if (!classDescriptor.isAggregateDescriptor()) {
final String href = HrefHelper.buildEntityHref(context, entityClassName, entityId);
final ItemLinksBuilder itemLinksBuilder = (new ItemLinksBuilder())
.addSelf(href)
.addCanonical(href);
entity._persistence_setLinks(itemLinksBuilder.build());
}
}
}
}
private void generateLinksForRelationships(PersistenceContext context, PersistenceWeavedRest entity) {
final ClassDescriptor classDescriptor = context.getServerSession().getProject().getDescriptor(entity.getClass());
final String entityClassName = classDescriptor.getAlias();
final String entityId = IdHelper.stringifyId(entity, entityClassName, context);
for (final Field field : entity.getClass().getDeclaredFields()) {
if (PersistenceWeavedRest.class.isAssignableFrom(field.getType())) {
final PersistenceWeavedRest obj = (PersistenceWeavedRest) callGetterForProperty(entity, field.getName());
if (obj != null) {
final String fieldClassName = context.getJAXBDescriptorForClass(field.getType()).getAlias();
final String fieldId = IdHelper.stringifyId(obj, fieldClassName, context);
final ItemLinks links = (new ItemLinksBuilder())
.addSelf(HrefHelper.buildEntityFieldHref(context, entityClassName, entityId, field.getName()))
.addCanonical(HrefHelper.buildEntityHref(context, fieldClassName, fieldId))
.build();
obj._persistence_setLinks(links);
}
}
}
}
private Object callGetterForProperty(Object bean, String propertyName) {
try {
final BeanInfo info = Introspector.getBeanInfo(bean.getClass(), Object.class);
final PropertyDescriptor[] props = info.getPropertyDescriptors();
for (PropertyDescriptor pd : props) {
if (propertyName.equals(pd.getName())) {
return pd.getReadMethod().invoke(bean);
}
}
} catch (InvocationTargetException| IntrospectionException | IllegalAccessException e) {
throw JPARSException.exceptionOccurred(e);
}
return null;
}
}