blob: a1ab31d50008c14b6afe6fecf1891406eaea9577 [file] [log] [blame]
/*
* Copyright (c) 2014, 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:
// Dmitry Kornilov - Initial implementation
package org.eclipse.persistence.jpa.rs.util.xmladapters;
import java.util.ArrayList;
import java.util.Collection;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.CollectionWrapper;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.LinkV2;
import org.eclipse.persistence.internal.jpa.rs.weaving.PersistenceWeavedRest;
import org.eclipse.persistence.internal.sessions.AbstractSession;
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.util.CollectionProxy;
import org.eclipse.persistence.jpa.rs.util.IdHelper;
import org.eclipse.persistence.mappings.DatabaseMapping;
/**
* Collections adapter used in JPARS V2. Collections are wrapped into CollectionWrapper which has 'links'.
* @see CollectionWrapper
*
* @param <T> list generac type
*
* @author Dmitry Kornilov
* @since EclipseLink 2.6.0
*/
public class RestCollectionAdapter<T extends PersistenceWeavedRest> extends XmlAdapter<CollectionWrapper<T>, Collection<T>> {
protected PersistenceContext context;
public RestCollectionAdapter() {
super();
}
/**
* Instantiates a new RestCollectionAdapter.
*
* @param context persistent context
*/
public RestCollectionAdapter(PersistenceContext context) {
this.context = context;
}
@Override
@SuppressWarnings("unchecked")
public Collection<T> unmarshal(CollectionWrapper<T> v) throws Exception {
if (v == null) {
return null;
}
final Collection<T> result = new ArrayList<>();
// Check if links exist and items from there if it does
if (v.getLinks() != null && !v.getLinks().isEmpty()) {
for (final LinkV2 link : v.getLinks()) {
if (link.getRel().equals(ReservedWords.JPARS_REL_SELF) && link.getHref() != null) {
return loadItems(link.getHref());
}
}
}
if (v.getItems() != null) {
// Process each item (load from href, etc.)
final ReferenceAdapterV2<T> referenceAdapter = new ReferenceAdapterV2<>(context);
for (T item : v.getItems()) {
if (context != null) {
result.add(referenceAdapter.unmarshal(item));
} else {
result.add(item);
}
}
}
return result;
}
@Override
public CollectionWrapper<T> marshal(Collection<T> v) throws Exception {
if (v == null || v.isEmpty()) {
return null;
}
final CollectionWrapper<T> result = new CollectionWrapper<>();
// Currently it returns only links. It will return items when 'expand'
// feature will be implemented.
//result.setItems(v);
// Read links from the RestCollection wrapper
if (v instanceof CollectionProxy) {
CollectionProxy restCollection = (CollectionProxy)v;
result.setLinks(restCollection.getLinks());
}
return result;
}
private Collection loadItems(String href) throws Exception {
String uri = href.replace("\\/", "/");
uri = uri.substring(uri.indexOf("entity/"));
uri = uri.substring(uri.indexOf('/') + 1);
final String[] uriItems = uri.split("/");
final String entityType = uriItems[0];
final String entityId = uriItems[1];
final String attributeName = uriItems[2];
final ClassDescriptor descriptor = context.getDescriptor(entityType);
final Object id = IdHelper.buildId(context, descriptor.getAlias(), entityId);
final T entity = getObjectById(entityType, id);
final DatabaseMapping attributeMapping = descriptor.getMappingForAttributeName(attributeName);
if ((attributeMapping == null) || (entity == null)) {
throw JPARSException.databaseMappingCouldNotBeFoundForEntityAttribute(attributeName, entityType, entityId, null);
}
return (Collection) attributeMapping.getRealAttributeValueFromAttribute(attributeMapping.getAttributeValueFromObject(entity), entity, (AbstractSession)context.getServerSession());
}
@SuppressWarnings("unchecked")
private T getObjectById(String entityType, Object id) throws Exception {
final Object entity = context.find(null, entityType, id, null);
if (entity != null) {
return (T)entity;
}
// It is an error if the object referred by a link doesn't exist, so throw exception
throw JPARSException.objectReferredByLinkDoesNotExist(entityType, id);
}
}