/******************************************************************************* * Copyright (c) 2014, 2015 Oracle. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Dmitry Kornilov - Initial implementation ******************************************************************************/ package org.eclipse.persistence.jpa.rs.util.xmladapters; 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.sessions.AbstractSession; import org.eclipse.persistence.internal.weaving.PersistenceWeavedRest; 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; import javax.xml.bind.annotation.adapters.XmlAdapter; import java.util.ArrayList; import java.util.Collection; /** * 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<T>(); // 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<T>(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<T>(); // 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); } }