blob: c3e41c70a111699dc06686c099b6d11e9dd801be [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2013 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 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.
*
*
******************************************************************************/
package org.eclipse.persistence.jpa.rs.resources.common;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.Attribute;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.Descriptor;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.Link;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.LinkTemplate;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.PersistenceUnit;
import org.eclipse.persistence.internal.jpa.rs.metadata.model.Query;
import org.eclipse.persistence.internal.queries.ReportItem;
import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jpa.rs.MatrixParameters;
import org.eclipse.persistence.jpa.rs.PersistenceContext;
import org.eclipse.persistence.jpa.rs.PersistenceContextFactory;
import org.eclipse.persistence.jpa.rs.PersistenceContextFactoryProvider;
import org.eclipse.persistence.jpa.rs.QueryParameters;
import org.eclipse.persistence.jpa.rs.util.JPARSLogger;
import org.eclipse.persistence.jpa.rs.util.list.LinkList;
import org.eclipse.persistence.jpa.rs.util.list.QueryList;
import org.eclipse.persistence.mappings.DatabaseMapping;
/**
* @author gonural
*
*/
public abstract class AbstractResource {
public static final String SERVICE_VERSION_FORMAT = "v\\d\\.\\d";
protected PersistenceContextFactory factory;
public static final String SERVICE_VERSION_1_0 = "v1.0";
/**
* Sets the persistence factory.
*
* @param factory the new persistence factory
*/
public void setPersistenceFactory(PersistenceContextFactory factory) {
this.factory = factory;
}
/**
* Gets the persistence factory.
*
* @return the persistence factory
*/
public PersistenceContextFactory getPersistenceFactory() {
return getPersistenceFactory(Thread.currentThread().getContextClassLoader());
}
/**
* Gets the persistence factory.
*
* @return the persistence factory
*/
public PersistenceContextFactory getPersistenceFactory(ClassLoader loader) {
if (factory == null) {
factory = buildPersistenceContextFactory(loader);
}
return factory;
}
protected PersistenceContextFactory buildPersistenceContextFactory(ClassLoader loader){
ServiceLoader<PersistenceContextFactoryProvider> contextFactoryLoader = ServiceLoader.load(PersistenceContextFactoryProvider.class, loader);
for (PersistenceContextFactoryProvider provider: contextFactoryLoader){
PersistenceContextFactory factory = provider.getPersistenceContextFactory(null);
if (factory != null){
return factory;
}
}
return null;
}
/**
* Get a map of the matrix parameters associated with the URI path segment of the current request
*
* In JPA-RS, things that user sets (such as parameters of named queries, etc.) are treated as matrix parameters
* List of valid matrix parameters for JPA-RS is defined in MatrixParameters
* @see MatrixParameters
*
* @param info the info
* @param segment the segment
* @return the matrix parameters
*
*/
protected static Map<String, String> getMatrixParameters(UriInfo info, String segment) {
Map<String, String> matrixParameters = new HashMap<String, String>();
for (PathSegment pathSegment : info.getPathSegments()) {
if (pathSegment.getPath() != null && pathSegment.getPath().equals(segment)) {
for (Entry<String, List<String>> entry : pathSegment.getMatrixParameters().entrySet()) {
matrixParameters.put(entry.getKey(), entry.getValue().get(0));
}
return matrixParameters;
}
}
return matrixParameters;
}
/**
* Get the URI query parameters of the current request
*
* In JPA-RS, predefined attributes (such as eclipselink query hints) are treated as query parameters
* List of valid query parameters for JPA-RS is defined in QueryParameters
* @see QueryParameters
*
* @param info the info
* @return the query parameters
*
*/
protected static Map<String, Object> getQueryParameters(UriInfo info) {
Map<String, Object> queryParameters = new HashMap<String, Object>();
for (String key : info.getQueryParameters().keySet()) {
queryParameters.put(key, info.getQueryParameters().getFirst(key));
}
return queryParameters;
}
/**
* Creates the shell jaxb element list.
*
* @param reportItems the report items
* @return the list
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected List<JAXBElement> createShellJAXBElementList(List<ReportItem> reportItems, Object record) {
List<JAXBElement> jaxbElements = new ArrayList<JAXBElement>(reportItems.size());
if ((reportItems != null) && (reportItems.size() > 0)) {
for (int index = 0; index < reportItems.size(); index++) {
ReportItem reportItem = reportItems.get(index);
Object reportItemValue = record;
if (record instanceof Object[]) {
reportItemValue = ((Object[]) record)[index];
}
Class reportItemValueType = null;
if (reportItemValue != null) {
reportItemValueType = reportItemValue.getClass();
if (reportItemValueType == null) {
// try other paths to determine the type of the report item
DatabaseMapping dbMapping = reportItem.getMapping();
if (dbMapping != null) {
reportItemValueType = dbMapping.getAttributeClassification();
} else {
ClassDescriptor desc = reportItem.getDescriptor();
if (desc != null) {
reportItemValueType = desc.getJavaClass();
}
}
}
// so, we couldn't determine the type of the report item, stop here...
if (reportItemValueType == null) {
return null;
}
JAXBElement element = new JAXBElement(new QName(reportItem.getName()), reportItemValueType, reportItemValue);
jaxbElements.add(reportItem.getResultIndex(), element);
}
}
}
return jaxbElements;
}
protected static boolean isValidVersion(String version) {
if ((version == null) || (SERVICE_VERSION_1_0.equals(version))) {
return true;
}
return false;
}
protected PersistenceContext getPersistenceContext(String persistenceUnit, URI baseURI, String version, Map<String, Object> initializationProperties) {
if (!isValidVersion(version)) {
JPARSLogger.fine("unsupported_service_version_in_the_request", new Object[] { version });
throw new IllegalArgumentException();
}
return getPersistenceFactory().get(persistenceUnit, baseURI, version, initializationProperties);
}
protected String getRelationshipPartner(Map<String, String> matrixParams, Map<String, Object> queryParams) {
String partner = null;
// Fix for Bug 396791 - JPA-RS: partner should be treated as a query parameter
//
// For backwards compatibility, we check both, matrix and query parameters.
if ((queryParams != null) && (!queryParams.isEmpty())) {
partner = (String) queryParams.get(QueryParameters.JPARS_RELATIONSHIP_PARTNER);
}
if (partner == null) {
if ((matrixParams != null) && (!matrixParams.isEmpty())) {
partner = (String) matrixParams.get(MatrixParameters.JPARS_RELATIONSHIP_PARTNER);
}
}
return partner;
}
protected String marshallMetadata(Object metadata, String mediaType) throws JAXBException {
Class<?>[] jaxbClasses = new Class[] { Link.class, Attribute.class, Descriptor.class, LinkTemplate.class, PersistenceUnit.class, Query.class, LinkList.class, QueryList.class };
JAXBContext context = (JAXBContext) JAXBContextFactory.createContext(jaxbClasses, null);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, Boolean.FALSE);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, mediaType);
marshaller.setProperty(MarshallerProperties.JSON_REDUCE_ANY_ARRAYS, true);
StringWriter writer = new StringWriter();
marshaller.marshal(metadata, writer);
return writer.toString();
}
}