org.eclipse.persistence.internal.dynamic.DynamicEntityImpl Maven / Gradle / Ivy
/*
* Copyright (c) 1998, 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, mnorman - Dynamic Persistence
// http://wiki.eclipse.org/EclipseLink/Development/Dynamic
// (https://bugs.eclipse.org/bugs/show_bug.cgi?id=200045)
//
package org.eclipse.persistence.internal.dynamic;
//javase imports
import static org.eclipse.persistence.internal.helper.Helper.getShortClassName;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.changetracking.ChangeTracker;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.dynamic.DynamicType;
import org.eclipse.persistence.exceptions.DynamicException;
import org.eclipse.persistence.indirection.IndirectContainer;
import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.eclipse.persistence.internal.descriptors.DescriptorIterator;
import org.eclipse.persistence.internal.descriptors.PersistenceEntity;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.queries.JoinedAttributeManager;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.ChangeRecord;
import org.eclipse.persistence.internal.sessions.MergeManager;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.internal.sessions.remote.ObjectDescriptor;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.queries.FetchGroup;
import org.eclipse.persistence.queries.FetchGroupTracker;
import org.eclipse.persistence.queries.ObjectBuildingQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.remote.DistributedSession;
/**
* This abstract class is used to represent an entity which typically is not
* realized in Java code. In combination with the DynamicClassLoader ASM is used
* to generate subclasses that will work within EclipseLink's framework. Since
* no concrete fields or methods exist on this class the mappings used must be
* customized to use a custom AttributeAccessor ({@link ValuesAccessor}).
*
* Type/Property Meta-model: This dynamic entity approach also includes a
* meta-model facade to simplify access to the types and property information so
* that clients can more easily understand the model. Each
* {@link DynamicTypeImpl} wraps the underlying EclipseLink
* relational-descriptor and the {@link DynamicPropertiesManager} wraps each mapping.
* The client application can use these types and properties to facilitate
* generic access to the entity instances and are required for creating new
* instances as well as for accessing the Java class needed for JPA and
* EclipseLink native API calls.
*
* @author dclarke, mnorman
* @since EclipseLink 1.2
*/
public abstract class DynamicEntityImpl implements DynamicEntity, PersistenceEntity,
ChangeTracker, FetchGroupTracker {
/**
* Fetch properties manager.
*
* @return the dynamic properties manager
*/
public abstract DynamicPropertiesManager fetchPropertiesManager();
protected Map propertiesMap = new HashMap<>();
/**
* Instantiates a new dynamic entity impl.
*/
protected DynamicEntityImpl() {
postConstruct(); // life-cycle callback
}
/**
* Gets the properties map.
*
* @return the properties map
*/
public Map getPropertiesMap() {
return propertiesMap;
}
/**
* Post construct.
*/
protected void postConstruct() {
DynamicPropertiesManager dpm = fetchPropertiesManager();
dpm.postConstruct(this);
}
/**
* Gets internal impl class of {@link DynamicType}.
*
* @return Dynamic type of this entity
* @throws DynamicException if type is null
*/
public DynamicTypeImpl getType() throws DynamicException {
DynamicType type = fetchPropertiesManager().getType();
if (type == null) {
throw DynamicException.entityHasNullType(this);
}
return (DynamicTypeImpl) type;
}
//DynamicEntity API
/* (non-Javadoc)
* @see org.eclipse.persistence.dynamic.DynamicEntity#get(java.lang.String)
*/
@Override
@SuppressWarnings({"unchecked"})
public T get(String propertyName) throws DynamicException {
DynamicPropertiesManager dpm = fetchPropertiesManager();
if (dpm.contains(propertyName)) {
if (_persistence_getFetchGroup() != null) {
String errorMsg = _persistence_getFetchGroup().onUnfetchedAttribute(this,
propertyName);
if (errorMsg != null) {
throw DynamicException.invalidPropertyName(dpm.getType(), propertyName);
}
}
PropertyWrapper wrapper = propertiesMap.get(propertyName);
if (wrapper == null) { // properties can be added after constructor is called
wrapper = new PropertyWrapper();
propertiesMap.put(propertyName, wrapper);
}
Object value = wrapper.getValue();
// trigger any indirection
if (value instanceof ValueHolderInterface) {
value = ((ValueHolderInterface) value).getValue();
}
else if (value instanceof IndirectContainer) {
value = ((IndirectContainer) value).getValueHolder().getValue();
}
try {
return (T) value;
} catch (ClassCastException cce) {
ClassDescriptor descriptor = getType().getDescriptor();
DatabaseMapping dm = null;
if (descriptor != null) {
dm = descriptor.getMappingForAttributeName(propertyName);
}
else {
dm = new UnknownMapping(propertyName);
}
throw DynamicException.invalidGetPropertyType(dm, cce);
}
}
else {
throw DynamicException.invalidPropertyName(dpm.getType(), propertyName);
}
}
/* (non-Javadoc)
* @see org.eclipse.persistence.dynamic.DynamicEntity#isSet(java.lang.String)
*/
@Override
public boolean isSet(String propertyName) throws DynamicException {
if (fetchPropertiesManager().contains(propertyName)) {
if (_persistence_getFetchGroup() != null &&
!_persistence_getFetchGroup().containsAttributeInternal(propertyName)) {
return false;
}
PropertyWrapper wrapper = propertiesMap.get(propertyName);
if (wrapper == null) { // properties can be added after constructor is called
wrapper = new PropertyWrapper();
propertiesMap.put(propertyName, wrapper);
}
return wrapper.isSet();
}
else {
throw DynamicException.invalidPropertyName(fetchPropertiesManager().getType(),
propertyName);
}
}
/* (non-Javadoc)
* @see org.eclipse.persistence.dynamic.DynamicEntity#set(java.lang.String, java.lang.Object)
*/
@Override
public DynamicEntity set(String propertyName, Object value) throws DynamicException {
return set(propertyName, value, true);
}
/**
* Sets the.
*
* @param propertyName the property name
* @param value the value
* @param firePropertyChange the fire property change
* @return the dynamic entity
* @throws DynamicException the dynamic exception
*/
public DynamicEntity set(String propertyName, Object value, boolean firePropertyChange) throws DynamicException {
DynamicPropertiesManager dpm = fetchPropertiesManager();
dpm.checkSet(propertyName, value); // life-cycle callback
if (_persistence_getFetchGroup() != null) {
String errorMsg = _persistence_getFetchGroup().onUnfetchedAttributeForSet(this,
propertyName);
if (errorMsg != null) {
throw DynamicException.invalidPropertyName(dpm.getType(), propertyName);
}
}
PropertyWrapper wrapper = propertiesMap.get(propertyName);
if (wrapper == null) { // properties can be added after constructor is called
wrapper = new PropertyWrapper();
propertiesMap.put(propertyName, wrapper);
}
Object oldValue = null;
Object wrapperValue = wrapper.getValue();
if (wrapperValue instanceof ValueHolderInterface) {
@SuppressWarnings({"unchecked"})
ValueHolderInterface