org.eclipse.persistence.jpa.rs.util.IdHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 2011, 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:
// dclarke/tware - initial
package org.eclipse.persistence.jpa.rs.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.internal.descriptors.PersistenceEntity;
import org.eclipse.persistence.internal.dynamic.DynamicEntityImpl;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.jpa.CMP3Policy;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.jpa.JpaHelper;
import org.eclipse.persistence.jpa.rs.PersistenceContext;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.queries.FetchGroupTracker;
import org.eclipse.persistence.sessions.DatabaseSession;
/**
* EclipseLink helper class used for converting composite key values passed into
* JAX-RS calls as query or matrix parameters into a value that can be used in a
* find.
*
* @author dclarke
* @since EclipseLink 2.4.0
*/
public class IdHelper {
private static final String SEPARATOR_STRING = "+";
@SuppressWarnings("rawtypes")
public static Object buildId(PersistenceContext app, String entityName, String idString) {
DatabaseSession session = app.getServerSession();
ClassDescriptor descriptor = app.getDescriptor(entityName);
List pkMappings = descriptor.getObjectBuilder().getPrimaryKeyMappings();
List pkIndices = new ArrayList<>();
int index = 0;
int multitenantPKMappings = 0;
for (DatabaseMapping mapping : pkMappings) {
if (mapping.isMultitenantPrimaryKeyMapping()) {
multitenantPKMappings++;
} else {
pkIndices.add(new SortableKey(mapping, index));
index++;
}
}
Collections.sort(pkIndices);
// Handle composite key in map
Object[] keyElements = new Object[pkMappings.size() - multitenantPKMappings];
StringTokenizer tokenizer = new StringTokenizer(idString, SEPARATOR_STRING);
int tokens = tokenizer.countTokens();
if (tokens + multitenantPKMappings != pkMappings.size()) {
throw new RuntimeException("Failed, incorrect number of keys values");
}
index = 0;
Iterator iterator = pkIndices.iterator();
while (tokenizer.hasMoreTokens()) {
SortableKey key = iterator.next();
String token = tokenizer.nextToken();
DatabaseMapping mapping = key.getMapping();
Class> attributeClasification = mapping.getAttributeClassification();
if (attributeClasification == null) {
if ((mapping.getFields() != null) && (!mapping.getFields().isEmpty())) {
attributeClasification = mapping.getFields().get(0).getType();
}
}
Object idValue = session.getDatasourcePlatform().getConversionManager().convertObject(token, attributeClasification);
keyElements[key.getIndex()] = idValue;
index++;
}
if (descriptor.hasCMPPolicy()) {
CMP3Policy policy = (CMP3Policy) descriptor.getCMPPolicy();
return policy.createPrimaryKeyInstanceFromPrimaryKeyValues((AbstractSession) session, new int[] { 0 }, keyElements);
}
if (keyElements.length == 1) {
return keyElements[0];
}
return keyElements;
}
public static String stringifyId(Object entity, String typeName, PersistenceContext app) {
ClassDescriptor descriptor = app.getDescriptor(typeName);
List pkMappings = descriptor.getObjectBuilder().getPrimaryKeyMappings();
if (pkMappings.isEmpty()) {
return "";
}
List pkIndices = new ArrayList<>();
int index = 0;
for (DatabaseMapping mapping : pkMappings) {
pkIndices.add(new SortableKey(mapping, index));
index++;
}
Collections.sort(pkIndices);
StringBuilder key = new StringBuilder();
Iterator sortableKeys = pkIndices.iterator();
List refObjectdbFields = null;
while (sortableKeys.hasNext()) {
DatabaseMapping mapping = sortableKeys.next().getMapping();
ClassDescriptor refDesc = mapping.getReferenceDescriptor();
List dbFields = mapping.getDescriptor().getPrimaryKeyFields();
if (refDesc != null) {
refObjectdbFields = refDesc.getFields();
}
if ((refObjectdbFields != null) && (!refObjectdbFields.isEmpty())) {
for (DatabaseField dbField : dbFields) {
String dbFieldName = dbField.getName();
String refObjectDbFieldName = null;
if (refDesc != null) {
for (DatabaseField refObjectDbField : refObjectdbFields) {
refObjectDbFieldName = refObjectDbField.getName();
if ((refObjectDbFieldName != null) && (dbFieldName != null)) {
if (dbFieldName.equals(refObjectDbFieldName)) {
List refMappings = refDesc.getMappings();
for (DatabaseMapping refMapping : refMappings) {//
DatabaseField field = refMapping.getField();
if (field != null) {
String fieldName = field.getName();
if (mapping instanceof OneToOneMapping) {
Map targetToSourceKeyFields = ((OneToOneMapping) mapping).getTargetToSourceKeyFields();
Map sourceToTargetFields = ((OneToOneMapping) mapping).getTargetToSourceKeyFields();
if ((targetToSourceKeyFields != null) && (!targetToSourceKeyFields.isEmpty())) {
if (targetToSourceKeyFields.containsKey(refObjectDbField)) {
if ((sourceToTargetFields != null) && (!sourceToTargetFields.isEmpty())) {
if (sourceToTargetFields.containsKey(field)) {
if ((fieldName != null) && (dbFieldName.equals(fieldName))) {
Object value = descriptor.getObjectBuilder().getBaseValueForField(dbField, entity);
Object realAttributeValue = refMapping.getRealAttributeValueFromAttribute(refMapping.getAttributeValueFromObject(value), value, (AbstractSession) app.getServerSession());
key.append(realAttributeValue);
}
}
}
}
}
}
}
}
}
}
}
}
}
} else {
Object part = mapping.getAttributeValueFromObject(entity);
key.append(part);
}
if (sortableKeys.hasNext()) {
key.append(SEPARATOR_STRING);
refObjectdbFields = null;
}
}
return key.toString();
}
/**
* build a shell of an object based on a primary key. The object shell will be an instance of the object with
* only primary key populated
*/
public static Object buildObjectShell(PersistenceContext context, String entityType, Object id) {
ClassDescriptor descriptor = context.getDescriptor(entityType);
List pkMappings = descriptor.getObjectBuilder().getPrimaryKeyMappings();
Object entity = null;
if (descriptor.hasCMPPolicy()) {
CMP3Policy policy = (CMP3Policy) descriptor.getCMPPolicy();
entity = policy.createBeanUsingKey(id, (AbstractSession) context.getServerSession());
} else if (DynamicEntity.class.isAssignableFrom(descriptor.getJavaClass())) {
DynamicEntityImpl dynamicEntity = (DynamicEntityImpl) context.newEntity(entityType);
// if there is only one PK mapping, we assume the id object
// represents the value of that mapping
if (pkMappings.size() == 1) {
dynamicEntity.set(pkMappings.get(0).getAttributeName(), id);
} else {
// If there are more that one PK, we assume an array as produced
// by buildId() above with the keys
// based on a sorted order of PK fields
List pkIndices = new ArrayList<>();
int index = 0;
for (DatabaseMapping mapping : pkMappings) {
pkIndices.add(new SortableKey(mapping, index));
index++;
}
Collections.sort(pkIndices);
Object[] keyElements = (Object[]) id;
for (SortableKey key : pkIndices) {
dynamicEntity.set(key.getMapping().getAttributeName(), keyElements[key.getIndex()]);
}
}
entity = dynamicEntity;
} else {
throw new RuntimeException("Could not create shell for entity.");
}
if (entity instanceof PersistenceEntity) {
((PersistenceEntity) entity)._persistence_setId(id);
}
if (entity instanceof FetchGroupTracker) {
((FetchGroupTracker) entity)._persistence_setSession(JpaHelper.getDatabaseSession(context.getEmf()));
}
return entity;
}
static List getPrimaryKey(PersistenceContext context, String entityName) {
ClassDescriptor descriptor = context.getDescriptor(entityName);
List pkMappings = descriptor.getObjectBuilder().getPrimaryKeyMappings();
List pkIndices = new ArrayList<>();
int index = 0;
for (DatabaseMapping mapping : pkMappings) {
if (!mapping.isMultitenantPrimaryKeyMapping()) {
pkIndices.add(new SortableKey(mapping, index));
index++;
}
}
Collections.sort(pkIndices);
return pkIndices;
}
private static class SortableKey implements Comparable {
private DatabaseMapping mapping;
private int index;
public SortableKey(DatabaseMapping mapping, int index) {
this.mapping = mapping;
this.index = index;
}
@Override
public int compareTo(SortableKey o) {
if (this.equals(o)) {
return 0;
} else if (mapping.getAttributeName().equals(o.getMapping().getAttributeName())) {
return Integer.compare(index, o.getIndex());
} else {
return mapping.getAttributeName().compareTo(o.getMapping().getAttributeName());
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SortableKey that = (SortableKey) o;
if (index != that.index) return false;
if (!mapping.equals(that.mapping)) return false;
return true;
}
@Override
public int hashCode() {
int result = mapping.hashCode();
result = 31 * result + index;
return result;
}
public DatabaseMapping getMapping() {
return mapping;
}
public int getIndex() {
return index;
}
}
}