| /* |
| * 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: |
| // tware - initial implementation as part of extensibility feature |
| // 01/11/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 01/16/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 02/04/2013-2.5 Guy Pelletier |
| // - 389090: JPA 2.1 DDL Generation Support |
| // 05/26/2016-2.7 Tomas Kraus |
| // - 494610: Session Properties map should be Map<String, Object> |
| package org.eclipse.persistence.internal.jpa; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import jakarta.persistence.Cache; |
| import jakarta.persistence.EntityGraph; |
| import jakarta.persistence.EntityManager; |
| import jakarta.persistence.EntityManagerFactory; |
| import jakarta.persistence.FlushModeType; |
| import jakarta.persistence.PersistenceException; |
| import jakarta.persistence.PersistenceUnitUtil; |
| import jakarta.persistence.Query; |
| import jakarta.persistence.SynchronizationType; |
| import jakarta.persistence.criteria.CriteriaBuilder; |
| import jakarta.persistence.metamodel.Metamodel; |
| |
| import org.eclipse.persistence.config.ReferenceMode; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.PersistenceUnitLoadingException; |
| import org.eclipse.persistence.internal.indirection.IndirectionPolicy; |
| import org.eclipse.persistence.internal.localization.ExceptionLocalization; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; |
| import org.eclipse.persistence.internal.sessions.coordination.MetadataRefreshCommand; |
| import org.eclipse.persistence.jpa.JpaEntityManagerFactory; |
| import org.eclipse.persistence.mappings.DatabaseMapping; |
| import org.eclipse.persistence.mappings.ForeignReferenceMapping; |
| import org.eclipse.persistence.queries.AttributeGroup; |
| import org.eclipse.persistence.queries.DatabaseQuery; |
| import org.eclipse.persistence.queries.FetchGroupTracker; |
| import org.eclipse.persistence.queries.ObjectLevelReadQuery; |
| import org.eclipse.persistence.queries.ReadQuery; |
| import org.eclipse.persistence.sessions.DatabaseSession; |
| import org.eclipse.persistence.sessions.Session; |
| import org.eclipse.persistence.sessions.UnitOfWork.CommitOrderType; |
| import org.eclipse.persistence.sessions.broker.SessionBroker; |
| import org.eclipse.persistence.sessions.coordination.CommandManager; |
| import org.eclipse.persistence.sessions.factories.SessionManager; |
| import org.eclipse.persistence.sessions.server.Server; |
| import org.eclipse.persistence.sessions.server.ServerSession; |
| |
| /** |
| * Wraps our implementation of EntityManagerFactory |
| * Most operations are forwarded to the delegate. This wrapper is used to enable |
| * the refreshMetadata functionality which allows you to switch the underlying metadata for |
| * an EMF after deploy time. |
| * @author tware |
| * |
| */ |
| public class EntityManagerFactoryImpl implements EntityManagerFactory, PersistenceUnitUtil, JpaEntityManagerFactory { |
| protected EntityManagerFactoryDelegate delegate; |
| |
| |
| /** |
| * Returns the id of the entity. A generated id is not guaranteed to be |
| * available until after the database insert has occurred. Returns null if |
| * the entity does not yet have an id |
| * |
| * @param entity |
| * @return id of the entity |
| * @throws IllegalArgumentException |
| * if the entity is found not to be an entity. |
| */ |
| public static Object getIdentifier(Object entity, AbstractSession session) { |
| ClassDescriptor descriptor = session.getDescriptor(entity); |
| if (descriptor == null) { |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class", new Object[] { entity })); |
| } |
| if (descriptor.getCMPPolicy() != null) { |
| return descriptor.getCMPPolicy().createPrimaryKeyInstance(entity, session); |
| } else { |
| // 308950: Alternatively, CacheImpl.getId(entity) handles a null CMPPolicy case for weaved and unweaved domain object |
| throw new IllegalArgumentException(ExceptionLocalization.buildMessage("jpa_persistence_util_non_persistent_class", new Object[] { entity })); |
| } |
| } |
| |
| |
| /** |
| * Determine the load state of an entity belonging to the persistence unit. |
| * This method can be used to determine the load state of an entity passed |
| * as a reference. An entity is considered loaded if all attributes for |
| * which FetchType EAGER has been specified have been loaded. The |
| * isLoaded(Object, String) method should be used to determine the load |
| * state of an attribute. Not doing so might lead to unintended loading of |
| * state. |
| * |
| * @param entity |
| * whose load state is to be determined |
| * @return false if the entity has not been loaded, else true. |
| */ |
| public static Boolean isLoaded(Object entity, AbstractSession session) { |
| ClassDescriptor descriptor = session.getDescriptor(entity); |
| if (descriptor == null) { |
| return null; |
| } |
| List<DatabaseMapping> mappings = descriptor.getMappings(); |
| Iterator<DatabaseMapping> i = mappings.iterator(); |
| while (i.hasNext()) { |
| DatabaseMapping mapping = i.next(); |
| if (!mapping.isLazy() && !isLoaded(entity, mapping.getAttributeName(), mapping)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Determine the load state of a given persistent attribute of an entity |
| * belonging to the persistence unit. |
| * |
| * @param entity |
| * containing the attribute |
| * @param attributeName |
| * name of attribute whose load state is to be determined |
| * @return false if entity's state has not been loaded or if the attribute |
| * state has not been loaded, otherwise true |
| */ |
| public static Boolean isLoaded(Object entity, String attributeName, AbstractSession session) { |
| ClassDescriptor descriptor = session.getDescriptor(entity); |
| if (descriptor == null) { |
| return null; |
| } |
| if (descriptor.hasFetchGroupManager()){ |
| if (!descriptor.getFetchGroupManager().isAttributeFetched(entity, attributeName)){ |
| return false; |
| } |
| } |
| DatabaseMapping mapping = descriptor.getMappingForAttributeName(attributeName); |
| if (mapping == null) { |
| return null; |
| } |
| return isLoaded(entity, attributeName, mapping); |
| } |
| |
| /** |
| * Check whether a named attribute on a given entity with a given mapping |
| * has been loaded. |
| * |
| * This method will check the valueholder or indirect collection for LAZY |
| * ForeignReferenceMappings to see if has been instantiated and otherwise |
| * check the fetch group. |
| * |
| * @param entity |
| * @param attributeName |
| * @param mapping |
| * @return |
| */ |
| public static boolean isLoaded(Object entity, String attributeName, DatabaseMapping mapping) { |
| if (mapping.isForeignReferenceMapping()) { |
| if (mapping.isLazy()) { |
| Object value = mapping.getAttributeValueFromObject(entity); |
| IndirectionPolicy policy = ((ForeignReferenceMapping) mapping).getIndirectionPolicy(); |
| return policy.objectIsInstantiated(value); |
| } |
| } |
| |
| if (entity instanceof FetchGroupTracker) { |
| return ((FetchGroupTracker) entity)._persistence_isAttributeFetched(attributeName); |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * Will return an instance of the Factory. Should only be called by |
| * EclipseLink. |
| * |
| * @param serverSession |
| */ |
| public EntityManagerFactoryImpl(AbstractSession serverSession) { |
| delegate = new EntityManagerFactoryDelegate(serverSession, this); |
| } |
| |
| public EntityManagerFactoryImpl(EntityManagerSetupImpl setupImpl, Map properties) { |
| delegate = new EntityManagerFactoryDelegate(setupImpl, properties, this); |
| } |
| |
| /** |
| * Create a dynamic persistence unit which does not use the persistence.xml. |
| * Instead all configuration is driven from the provided persistence unit |
| * properties and descriptors. |
| */ |
| public EntityManagerFactoryImpl(String persistenceUnitName, Map<String, Object> properties, List<ClassDescriptor> descriptors) { |
| delegate = new EntityManagerFactoryDelegate(persistenceUnitName, properties, descriptors, this); |
| } |
| |
| /** |
| * ADVANCED: |
| * Re-bootstrap this factory. This method will rebuild the EntityManagerFactory. It should be used |
| * in conjunction with a MetadataSource to allow mappings to be changed in a running system. All existing |
| * EntityMangers will continue to function with the old metadata, but new factories will use the new metadata. |
| * @param properties |
| */ |
| @Override |
| public void refreshMetadata(Map<String, Object> properties){ |
| EntityManagerSetupImpl setupImpl = delegate.getSetupImpl(); |
| if (setupImpl == null){ |
| throw PersistenceUnitLoadingException.cannotRefreshEntityManagerFactoryCreatedFromSession(delegate.getServerSession().getName()); |
| } |
| String sessionName = setupImpl.getSessionName(); |
| Map existingProperties = delegate.getProperties(); |
| Map deployProperties = new HashMap(); |
| deployProperties.putAll(existingProperties); |
| if (properties != null){ |
| deployProperties.putAll(properties); |
| } |
| EntityManagerSetupImpl newSetupImpl = setupImpl.refreshMetadata(properties); |
| EntityManagerFactoryDelegate oldDelegate = delegate; |
| delegate = new EntityManagerFactoryDelegate(newSetupImpl, deployProperties, this); |
| // This code has been added to allow validation to occur without actually calling createEntityManager |
| // RCM refresh command requires the DEPLOY_ON_STARTUP property is set to true so the listener can be added to the session. |
| try{ |
| if (newSetupImpl.shouldGetSessionOnCreateFactory(deployProperties)) { |
| ServerSession session = getServerSession(); |
| CommandManager rcm = session.getCommandManager(); |
| if (rcm != null && newSetupImpl.shouldSendMetadataRefreshCommand(deployProperties)) { |
| MetadataRefreshCommand command = new MetadataRefreshCommand(properties); |
| rcm.propagateCommand(command); |
| } |
| session.setRefreshMetadataListener(newSetupImpl); |
| } |
| } catch (RuntimeException ex) { |
| if(delegate != null) { |
| delegate.close(); |
| } else { |
| newSetupImpl.undeploy(); |
| } |
| synchronized(EntityManagerFactoryProvider.emSetupImpls){ |
| // bring back the old emSetupImpl and session |
| EntityManagerFactoryProvider.emSetupImpls.put(sessionName, setupImpl); |
| SessionManager.getManager().getSessions().put(sessionName, setupImpl.getSession()); |
| setupImpl.setIsMetadataExpired(false); |
| } |
| delegate = oldDelegate; |
| throw ex; |
| } |
| } |
| |
| /** |
| * INTERNAL: Returns the SessionBroker that the Factory will be using and |
| * initializes it if it is not available. This method makes use of the |
| * partially constructed session stored in our setupImpl and completes its |
| * construction |
| * TODO: should throw IllegalStateException if not SessionBroker |
| */ |
| @Override |
| public SessionBroker getSessionBroker() { |
| return delegate.getSessionBroker(); |
| } |
| |
| /** |
| * INTERNAL: Returns the ServerSession that the Factory will be using and |
| * initializes it if it is not available. This method makes use of the |
| * partially constructed session stored in our setupImpl and completes its |
| * construction |
| */ |
| @Override |
| public ServerSession getServerSession() { |
| return delegate.getServerSession(); |
| } |
| |
| /** |
| * Closes this factory, releasing any resources that might be held by this |
| * factory. After invoking this method, all methods on the instance will |
| * throw an {@link IllegalStateException}, except for {@link #isOpen}, which |
| * will return <code>false</code>. |
| */ |
| @Override |
| public synchronized void close() { |
| delegate.close(); |
| } |
| |
| /** |
| * Indicates whether or not this factory is open. Returns <code>true</code> |
| * until a call to {@link #close} is made. |
| */ |
| @Override |
| public boolean isOpen() { |
| return delegate.isOpen(); |
| } |
| |
| /** |
| * PUBLIC: Returns an EntityManager for this deployment. |
| */ |
| @Override |
| public EntityManager createEntityManager() { |
| return createEntityManagerImpl(null, null); |
| } |
| |
| /** |
| * PUBLIC: Returns an EntityManager for this deployment. |
| */ |
| @Override |
| public EntityManager createEntityManager(Map properties) { |
| return createEntityManagerImpl(properties, null); |
| } |
| |
| @Override |
| public EntityManager createEntityManager(SynchronizationType synchronizationType) { |
| return createEntityManagerImpl(null, synchronizationType); |
| } |
| |
| @Override |
| public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) { |
| return createEntityManagerImpl(map, synchronizationType); |
| } |
| |
| protected EntityManagerImpl createEntityManagerImpl(Map properties, SynchronizationType syncType) { |
| EntityManagerSetupImpl setupImpl = delegate.getSetupImpl(); |
| |
| if (setupImpl != null) { |
| if (setupImpl.isMetadataExpired()) { |
| String sessionName = setupImpl.getSessionName(); |
| EntityManagerSetupImpl storedImpl = null; |
| synchronized (EntityManagerFactoryProvider.emSetupImpls){ |
| storedImpl = EntityManagerFactoryProvider.emSetupImpls.get(sessionName); |
| } |
| if (storedImpl != null) { |
| delegate = new EntityManagerFactoryDelegate(storedImpl, delegate.getProperties(), this); |
| } |
| } |
| } |
| |
| return delegate.createEntityManagerImpl(properties, syncType); |
| } |
| |
| /** |
| * Gets the underlying implementation of the EntityManagerFactory. |
| * This method will return a version of EntityManagerFactory that is |
| * based on the available metadata at the time it is called. Future calls |
| * to refresh will not affect that metadata on this EntityManagerFactory. |
| * @return |
| */ |
| @Override |
| public EntityManagerFactoryDelegate unwrap(){ |
| return delegate; |
| } |
| |
| protected void verifyOpen() { |
| delegate.verifyOpen(); |
| } |
| |
| /** |
| * The method return user defined property passed in from |
| * EntityManagerFactory. |
| */ |
| public Object getProperty(String name) { |
| return delegate.getProperty(name); |
| } |
| |
| /** |
| * Return default join existing transaction property, allows reading through |
| * write connection. |
| */ |
| public boolean getBeginEarlyTransaction() { |
| return delegate.getBeginEarlyTransaction(); |
| } |
| |
| /** |
| * Set default join existing transaction property, allows reading through |
| * write connection. |
| */ |
| public void setBeginEarlyTransaction(boolean beginEarlyTransaction) { |
| delegate.setBeginEarlyTransaction(beginEarlyTransaction); |
| } |
| |
| /** |
| * Return default property, allows flush before query to be avoided. |
| */ |
| public FlushModeType getFlushMode() { |
| return delegate.getFlushMode(); |
| } |
| |
| /** |
| * Set default property, allows flush before query to be avoided. |
| */ |
| public void setFlushMode(FlushModeType flushMode) { |
| delegate.setFlushMode(flushMode); |
| } |
| |
| /** |
| * Return default property, allows weak unit of work references. |
| */ |
| public ReferenceMode getReferenceMode() { |
| return delegate.getReferenceMode(); |
| } |
| |
| /** |
| * Set default property, allows weak unit of work references. |
| */ |
| public void setReferenceMode(ReferenceMode referenceMode) { |
| delegate.setReferenceMode(referenceMode); |
| } |
| |
| /** |
| * Return default property to avoid resuming unit of work if going to be |
| * closed on commit anyway. |
| */ |
| public boolean getCloseOnCommit() { |
| return delegate.getCloseOnCommit(); |
| } |
| |
| /** |
| * Set default property to avoid resuming unit of work if going to be closed |
| * on commit anyway. |
| */ |
| public void setCloseOnCommit(boolean closeOnCommit) { |
| delegate.setCloseOnCommit(closeOnCommit); |
| } |
| |
| /** |
| * Return default property to avoid discover new objects in unit of work if |
| * application always uses persist. |
| */ |
| public boolean getPersistOnCommit() { |
| return delegate.getPersistOnCommit(); |
| } |
| |
| /** |
| * Return interface providing access to utility methods for the persistence |
| * unit. |
| * |
| * @return PersistenceUnitUtil interface |
| * @throws IllegalStateException |
| * if the entity manager factory has been closed. |
| */ |
| @Override |
| public PersistenceUnitUtil getPersistenceUnitUtil() { |
| return delegate.getPersistenceUnitUtil(); |
| } |
| |
| /** |
| * Set default property to avoid discover new objects in unit of work if |
| * application always uses persist. |
| */ |
| public void setPersistOnCommit(boolean persistOnCommit) { |
| delegate.setPersistOnCommit(persistOnCommit); |
| } |
| |
| /** |
| * Return default property to avoid discover new objects in unit of work if |
| * application always uses persist. |
| */ |
| public boolean getCommitWithoutPersistRules() { |
| return delegate.getCommitWithoutPersistRules(); |
| } |
| |
| /** |
| * Set default property to avoid discover new objects in unit of work if |
| * application always uses persist. |
| */ |
| public void setCommitWithoutPersistRules(boolean commitWithoutPersistRules) { |
| delegate.setCommitWithoutPersistRules(commitWithoutPersistRules); |
| } |
| |
| /** |
| * Return the default FlashClearCache mode to be used. Relevant only in case |
| * call to flush method followed by call to clear method. |
| * |
| * @see org.eclipse.persistence.config.FlushClearCache |
| */ |
| public String getFlushClearCache() { |
| return delegate.getFlushClearCache(); |
| } |
| |
| /** |
| * Set the default FlashClearCache mode to be used. Relevant only in case |
| * call to flush method followed by call to clear method. |
| * |
| * @see org.eclipse.persistence.config.FlushClearCache |
| */ |
| public void setFlushClearCache(String flushClearCache) { |
| delegate.setFlushClearCache(flushClearCache); |
| } |
| |
| /** |
| * Return the default to determine if does-exist should be performed on |
| * persist. |
| */ |
| public boolean shouldValidateExistence() { |
| return delegate.shouldValidateExistence(); |
| } |
| |
| /** |
| * Set the default to determine if does-exist should be performed on |
| * persist. |
| */ |
| public void setShouldValidateExistence(boolean shouldValidateExistence) { |
| delegate.setShouldValidateExistence(shouldValidateExistence); |
| } |
| |
| /** |
| * Access the cache that is associated with the entity manager |
| * factory (the "second level cache"). |
| * @return instance of the <code>Cache</code> interface |
| * @throws IllegalStateException if the entity manager factory has been closed |
| * @see jakarta.persistence.EntityManagerFactory#getCache() |
| * @since Java Persistence 2.0 |
| */ |
| @Override |
| public Cache getCache() { |
| return delegate.getCache(); |
| } |
| |
| /** |
| * @see jakarta.persistence.EntityManagerFactory#getProperties() |
| * @since Java Persistence API 2.0 |
| */ |
| @Override |
| public Map<String, Object> getProperties() { |
| return delegate.getProperties(); |
| } |
| |
| @Override |
| public DatabaseSessionImpl getDatabaseSession() { |
| return delegate.getDatabaseSession(); |
| } |
| /** |
| * @see jakarta.persistence.EntityManagerFactory#getCriteriaBuilder() |
| * @since Java Persistence 2.0 |
| */ |
| @Override |
| public CriteriaBuilder getCriteriaBuilder() { |
| return delegate.getCriteriaBuilder(); |
| } |
| |
| /** |
| * Return an instance of Metamodel interface for access to the metamodel of |
| * the persistence unit. |
| * |
| * @return Metamodel instance |
| * @throws IllegalStateException |
| * if the entity manager factory has been closed. |
| * @see jakarta.persistence.EntityManagerFactory#getMetamodel() |
| * @since Java Persistence 2.0 |
| */ |
| @Override |
| public Metamodel getMetamodel() { |
| return delegate.getMetamodel(); |
| } |
| |
| /** |
| * INTERNAL: Convenience function to allow us to reset the Metamodel in the |
| * possible case that we want to regenerate it. This function is outside of |
| * the JPA 2.0 specification. |
| * |
| * @param aMetamodel |
| * @since Java Persistence 2.0 |
| */ |
| public void setMetamodel(Metamodel aMetamodel) { |
| delegate.setMetamodel(aMetamodel); |
| } |
| |
| /** |
| * Determine the load state of a given persistent attribute of an entity |
| * belonging to the persistence unit. |
| * |
| * @param entity |
| * containing the attribute |
| * @param attributeName |
| * name of attribute whose load state is to be determined |
| * @return false if entity's state has not been loaded or if the attribute |
| * state has not been loaded, otherwise true |
| */ |
| @Override |
| public boolean isLoaded(Object entity, String attributeName) { |
| return delegate.isLoaded(entity, attributeName); |
| } |
| |
| /** |
| * Determine the load state of an entity belonging to the persistence unit. |
| * This method can be used to determine the load state of an entity passed |
| * as a reference. An entity is considered loaded if all attributes for |
| * which FetchType EAGER has been specified have been loaded. The |
| * isLoaded(Object, String) method should be used to determine the load |
| * state of an attribute. Not doing so might lead to unintended loading of |
| * state. |
| * |
| * @param entity |
| * whose load state is to be determined |
| * @return false if the entity has not been loaded, else true. |
| */ |
| @Override |
| public boolean isLoaded(Object entity) { |
| return delegate.isLoaded(entity); |
| } |
| |
| /** |
| * Returns the id of the entity. A generated id is not guaranteed to be |
| * available until after the database insert has occurred. Returns null if |
| * the entity does not yet have an id |
| * |
| * @param entity |
| * @return id of the entity |
| * @throws IllegalStateException |
| * if the entity is found not to be an entity. |
| */ |
| @Override |
| public Object getIdentifier(Object entity) { |
| return delegate.getIdentifier(entity); |
| } |
| |
| /** |
| * Return if updates should be ordered by primary key to avoid possible database deadlocks. |
| */ |
| public CommitOrderType getCommitOrder() { |
| return delegate.getCommitOrder(); |
| } |
| |
| /** |
| * Set updates should be ordered by primary key to avoid possible database deadlocks. |
| */ |
| public void setCommitOrder(CommitOrderType commitOrder) { |
| delegate.setCommitOrder(commitOrder); |
| } |
| |
| @Override |
| public void addNamedQuery(String name, Query query) { |
| QueryImpl queryImpl = query.unwrap(QueryImpl.class); |
| DatabaseQuery unwrapped = (DatabaseQuery) queryImpl.getDatabaseQueryInternal().clone(); |
| if (queryImpl.lockMode != null){ |
| ((ObjectLevelReadQuery)unwrapped).setLockModeType(queryImpl.lockMode.name(), getServerSession()); |
| } |
| if (unwrapped.isReadQuery()){ |
| ((ReadQuery)unwrapped).setInternalMax((queryImpl.getMaxResultsInternal())); |
| ((ReadQuery)unwrapped).setFirstResult((queryImpl.getFirstResult())); |
| } |
| this.getServerSession().addQuery(name, unwrapped, true); |
| } |
| |
| @Override |
| public <T> T unwrap(Class<T> cls) { |
| if (cls.equals(JpaEntityManagerFactory.class) || cls.equals(EntityManagerFactoryImpl.class)) { |
| return (T) this; |
| }else if (cls.equals(EntityManagerFactoryDelegate.class)) { |
| return (T) this.delegate; |
| }else if (cls.equals(Session.class) || cls.equals(AbstractSession.class)) { |
| return (T) this.delegate.getAbstractSession(); |
| } else if (cls.equals(DatabaseSession.class) || cls.equals(DatabaseSessionImpl.class)) { |
| return (T) this.getDatabaseSession(); |
| } else if (cls.equals(Server.class) || cls.equals(ServerSession.class)) { |
| return (T) this.getServerSession(); |
| } else if (cls.equals(SessionBroker.class)) { |
| return (T) this.getSessionBroker(); |
| } |
| throw new PersistenceException(ExceptionLocalization.buildMessage("unable_to_unwrap_jpa", new String[]{EntityManagerFactory.class.getName(),cls.getName()})); |
| } |
| |
| @Override |
| public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) { |
| AttributeGroup group = ((EntityGraphImpl)entityGraph).getAttributeGroup().clone(); |
| group.setName(graphName); |
| this.getServerSession().getAttributeGroups().put(graphName, group); |
| this.getServerSession().getDescriptor(((EntityGraphImpl)entityGraph).getClassType()).addAttributeGroup(group); |
| } |
| |
| } |