All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.dynamic.DynamicEntityImpl Maven / Gradle / Ivy

There is a newer version: 5.0.0-B07
Show newest version
/*******************************************************************************
 * Copyright (c) 1998, 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.
 *
 * 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 java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//EclipseLink imports
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.jpa.rs.metadata.model.Link;
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.weaving.PersistenceWeavedRest;
import org.eclipse.persistence.internal.weaving.RelationshipInfo;
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.RemoteSession;
import static org.eclipse.persistence.internal.helper.Helper.getShortClassName;

/**
 * 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, PersistenceWeavedRest { public abstract DynamicPropertiesManager fetchPropertiesManager(); protected Map propertiesMap = new HashMap(); public DynamicEntityImpl() { postConstruct(); // life-cycle callback } public Map getPropertiesMap() { return propertiesMap; } 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 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); } } 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); } } public DynamicEntity set(String propertyName, Object value) throws DynamicException { return set(propertyName, value, true); } 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) { ValueHolderInterface vh = (ValueHolderInterface)wrapperValue; if (vh.isInstantiated()) { oldValue = vh.getValue(); } vh.setValue(value); wrapper.isSet(true); } else { oldValue = wrapperValue; wrapper.setValue(value); wrapper.isSet(true); } if (changeListener != null && firePropertyChange) { changeListener.propertyChange(new PropertyChangeEvent(this, propertyName, oldValue, value)); } return this; } public class PropertyWrapper { private Object value = null; private boolean isSet = false; public PropertyWrapper() { } public PropertyWrapper(Object value) { setValue(value); } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public boolean isSet() { return isSet; } public void isSet(boolean isSet) { this.isSet = isSet; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (isSet) { sb.append("[T]"); } else { if (value == null) { sb.append("[F]"); } else { sb.append("[d]"); } } if (value == null) { sb.append(""); } else { sb.append(value.toString()); } return sb.toString(); } } class UnknownMapping extends DatabaseMapping { public UnknownMapping(String propertyName) { setAttributeName(propertyName); } public void buildBackupClone(Object clone, Object backup, UnitOfWorkImpl unitOfWork) { } @Override public void buildClone(Object original, CacheKey cacheKey, Object clone, Integer refreshCascade, AbstractSession cloningSession) { } public void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object clone, CacheKey sharedCacheKey, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession) { } public void cascadePerformRemoveIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) { } public void cascadeRegisterNewIfRequired(Object object, UnitOfWorkImpl uow, Map visitedObjects) { } public ChangeRecord compareForChange(Object clone, Object backup, ObjectChangeSet owner, AbstractSession session) { return null; } public boolean compareObjects(Object firstObject, Object secondObject, AbstractSession session) { return false; } public void fixObjectReferences(Object object, Map objectDescriptors, Map processedObjects, ObjectLevelReadQuery query, RemoteSession session) { } public void iterate(DescriptorIterator iterator) { } public void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) { } public void mergeIntoObject(Object target, boolean isTargetUninitialized, Object source, MergeManager mergeManager, AbstractSession targetSession) { } } //PersistenceEntity API /** * Cache the primary key within the entity * * @see PersistenceEntity#_persistence_setId(Object) */ private Object primaryKey; protected CacheKey cacheKey; @SuppressWarnings("unchecked") public Object _persistence_getId() { return this.primaryKey; } @SuppressWarnings("unchecked") public void _persistence_setId(Object pk) { this.primaryKey = pk; } public CacheKey _persistence_getCacheKey(){ return this.cacheKey; } public void _persistence_setCacheKey(CacheKey cacheKey){ this.cacheKey = cacheKey; } //ChangeTracker API /** * ChangeListener used for attribute change tracking processed in the * property. Set through * {@link ChangeTracker#_persistence_setPropertyChangeListener(PropertyChangeListener)} */ private PropertyChangeListener changeListener = null; public PropertyChangeListener _persistence_getPropertyChangeListener() { return this.changeListener; } public void _persistence_setPropertyChangeListener(PropertyChangeListener listener) { this.changeListener = listener; } //FetchGroup API /** * FetchGroup cached by * {@link FetchGroupTracker#_persistence_setFetchGroup(FetchGroup)} */ private FetchGroup fetchGroup; /** * {@link FetchGroupTracker#_persistence_setShouldRefreshFetchGroup(boolean)} */ private boolean refreshFetchGroup = false; public FetchGroup _persistence_getFetchGroup() { return this.fetchGroup; } public void _persistence_setFetchGroup(FetchGroup group) { this.fetchGroup = group; } public void _persistence_setShouldRefreshFetchGroup(boolean shouldRefreshFetchGroup) { this.refreshFetchGroup = shouldRefreshFetchGroup; } public boolean _persistence_shouldRefreshFetchGroup() { return this.refreshFetchGroup; } /** * Return true if the attribute is in the fetch group being tracked. */ public boolean _persistence_isAttributeFetched(String attribute) { return this.fetchGroup == null || this.fetchGroup.containsAttributeInternal(attribute); } /** * Reset all attributes of the tracked object to the un-fetched state with * initial default values. */ public void _persistence_resetFetchGroup() { } public List _persistence_getRelationships(){ List relationships = (List)get("_persistence_relationshipInfo"); if (relationships == null){ relationships = new ArrayList(); _persistence_setRelationships(relationships); } return relationships; } public void _persistence_setRelationships(List relationships){ set("_persistence_relationshipInfo", relationships, false); } /* (non-Javadoc) * @see org.eclipse.persistence.internal.weaving.PersistenceWeavedRest#getPersistence_href() */ public Link _persistence_getHref() { return get("_persistence_href"); } /* (non-Javadoc) * @see org.eclipse.persistence.internal.weaving.PersistenceWeavedRest#_persistence_setHref(org.eclipse.persistence.internal.jpa.rs.metadata.model.Link) */ public void _persistence_setHref(Link href) { set("_persistence_href", href, false); } /** * Session cached by * {@link FetchGroupTracker#_persistence_setSession(Session)} */ private Session session; public Session _persistence_getSession() { return this.session; } public void _persistence_setSession(Session session) { this.session = session; } /** * String representation of the dynamic entity using the entity type name * and the primary key values - something like {Emp 10} or {Phone 234-5678 10} */ @Override public String toString() { // this will print something like {Emp 10} or {Phone 234-5678 10} StringBuilder sb = new StringBuilder(20); sb.append('{'); sb.append(getShortClassName(this.getClass())); if (primaryKey != null) { sb.append(' '); sb.append(primaryKey); } sb.append('}'); return sb.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy