Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021 IBM Corporation. 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:
// Oracle - initial API and implementation from Oracle TopLink
// 10/15/2010-2.2 Guy Pelletier
// - 322008: Improve usability of additional criteria applied to queries at the session/EM
// 06/30/2011-2.3.1 Guy Pelletier
// - 341940: Add disable/enable allowing native queries
// 09/09/2011-2.3.1 Guy Pelletier
// - 356197: Add new VPD type to MultitenantType
// 09/14/2011-2.3.1 Guy Pelletier
// - 357533: Allow DDL queries to execute even when Multitenant entities are part of the PU
// 05/14/2012-2.4 Guy Pelletier
// - 376603: Provide for table per tenant support for multitenant applications
// 08/11/2012-2.5 Guy Pelletier
// - 393867: Named queries do not work when using EM level Table Per Tenant Multitenancy.
// 11/29/2012-2.5 Guy Pelletier
// - 395406: Fix nightly static weave test errors
// 08/11/2014-2.5 Rick Curtis
// - 440594: Tolerate invalid NamedQuery at EntityManager creation.
// 09/03/2015 - Will Dazey
// - 456067: Added support for defining query timeout units
// 05/26/2016-2.7 Tomas Kraus
// - 494610: Session Properties map should be Map
package org.eclipse.persistence.internal.sessions;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.ReferenceMode;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.DescriptorQueryManager;
import org.eclipse.persistence.descriptors.TablePerMultitenantPolicy;
import org.eclipse.persistence.descriptors.invalidation.CacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.exceptions.ConcurrencyException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.EclipseLinkException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
import org.eclipse.persistence.exceptions.IntegrityChecker;
import org.eclipse.persistence.exceptions.IntegrityException;
import org.eclipse.persistence.exceptions.OptimisticLockException;
import org.eclipse.persistence.exceptions.QueryException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.history.AsOfClause;
import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.databaseaccess.Accessor;
import org.eclipse.persistence.internal.databaseaccess.Platform;
import org.eclipse.persistence.internal.descriptors.ObjectBuilder;
import org.eclipse.persistence.internal.helper.ConcurrencyManager;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.helper.QueryCounter;
import org.eclipse.persistence.internal.helper.linkedlist.ExposedNodeLinkedList;
import org.eclipse.persistence.internal.history.HistoricalSession;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.identitymaps.IdentityMapManager;
import org.eclipse.persistence.internal.indirection.DatabaseValueHolder;
import org.eclipse.persistence.internal.indirection.ProtectedValueHolder;
import org.eclipse.persistence.internal.indirection.ProxyIndirectionPolicy;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.queries.JoinedAttributeManager;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.internal.security.PrivilegedGetConstructorFor;
import org.eclipse.persistence.internal.security.PrivilegedInvokeConstructor;
import org.eclipse.persistence.internal.security.PrivilegedNewInstanceFromClass;
import org.eclipse.persistence.internal.sequencing.Sequencing;
import org.eclipse.persistence.internal.sessions.cdi.DisabledInjectionManager;
import org.eclipse.persistence.internal.sessions.cdi.InjectionManager;
import org.eclipse.persistence.logging.DefaultSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.logging.SessionLogEntry;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.foundation.AbstractTransformationMapping;
import org.eclipse.persistence.platform.database.DatabasePlatform;
import org.eclipse.persistence.platform.server.ServerPlatform;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.queries.Call;
import org.eclipse.persistence.queries.DataModifyQuery;
import org.eclipse.persistence.queries.DataReadQuery;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.DeleteObjectQuery;
import org.eclipse.persistence.queries.DoesExistQuery;
import org.eclipse.persistence.queries.InsertObjectQuery;
import org.eclipse.persistence.queries.JPAQueryBuilder;
import org.eclipse.persistence.queries.JPQLCall;
import org.eclipse.persistence.queries.ObjectBuildingQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.queries.SQLCall;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.queries.WriteObjectQuery;
import org.eclipse.persistence.sessions.CopyGroup;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.ExternalTransactionController;
import org.eclipse.persistence.sessions.Login;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.SessionEventManager;
import org.eclipse.persistence.sessions.SessionProfiler;
import org.eclipse.persistence.sessions.coordination.Command;
import org.eclipse.persistence.sessions.coordination.CommandManager;
import org.eclipse.persistence.sessions.coordination.CommandProcessor;
import org.eclipse.persistence.sessions.coordination.MetadataRefreshListener;
import org.eclipse.persistence.sessions.serializers.Serializer;
/**
* Implementation of org.eclipse.persistence.sessions.Session
* The public interface should be used.
* @see org.eclipse.persistence.sessions.Session
*
*
* Purpose: Define the interface and common protocol of an EclipseLink compliant session.
*
* Description: The session is the primary interface into EclipseLink,
* the application should do all of its reading and writing of objects through the session.
* The session also manages transactions and units of work. Normally the session
* is passed and used by the application controller objects. Controller objects normally
* sit behind the GUI and perform the business processes required for the application,
* they should perform all explicit database access and database access should be avoided from
* the domain object model. Do not use a globally accessible session instance, doing so does
* not allow for multiple sessions. Multiple sessions may required when performing things like
* data migration or multiple database access, as well the unit of work feature requires the usage
* of multiple session instances. Although session is abstract, any users of its subclasses
* should only cast the variables to Session to allow usage of any of its subclasses.
*
* Responsibilities:
*
*
Connecting/disconnecting.
*
Reading and writing objects.
*
Transaction and unit of work support.
*
Identity maps and caching.
*
* @see DatabaseSessionImpl
*/
public abstract class AbstractSession extends CoreAbstractSession implements org.eclipse.persistence.sessions.Session, CommandProcessor, Serializable, Cloneable {
/** ExceptionHandler handles database exceptions. */
transient protected ExceptionHandler exceptionHandler;
/** IntegrityChecker catch all the descriptor Exceptions. */
transient protected IntegrityChecker integrityChecker;
/** The project stores configuration information, such as the descriptors and login. */
transient protected Project project;
/** Ensure mutual exclusion of the session's transaction state across multiple threads.*/
transient protected ConcurrencyManager transactionMutex;
/** Manages the live object cache.*/
protected IdentityMapAccessor identityMapAccessor;
/** If Transactions were externally started */
protected boolean wasJTSTransactionInternallyStarted;
/** The connection to the data store. */
transient protected Collection accessors;
/** Allow the datasource platform to be cached. */
transient protected Platform platform;
/** Stores predefine reusable queries.*/
transient protected Map> queries;
/**
* Stores predefined reusable AttributeGroups.
*/
protected Map attributeGroups;
/** Stores predefined not yet parsed JPQL queries.*/
protected boolean jpaQueriesProcessed = false;
/** Resolves referential integrity on commits. */
transient protected CommitManager commitManager;
/** Tool that log performance information. */
transient protected SessionProfiler profiler;
/** Support being owned by a session broker. */
transient protected AbstractSession broker;
/** Used to identify a session when using the session broker. */
protected String name;
/** Keep track of active units of work. */
transient protected int numberOfActiveUnitsOfWork;
/**
* This collection will be used to store those objects that are currently locked
* for the clone process. It should be populated with an EclipseLinkIdentityHashMap
*/
protected Map objectsLockedForClone;
/** Destination for logged messages and SQL. */
transient protected SessionLog sessionLog;
/** When logging the name of the session is typed: class name + system hashcode. */
transient protected String logSessionString;
/** Stores the event listeners for this session. */
transient protected SessionEventManager eventManager;
/** Allow for user defined properties. */
protected Map properties;
/** Delegate that handles synchronizing a UnitOfWork with an external transaction. */
transient protected ExternalTransactionController externalTransactionController;
/** Last descriptor accessed, use to optimize descriptor lookup. */
transient protected ClassDescriptor lastDescriptorAccessed;
/** PERF: cache descriptors from project. */
transient protected Map, ClassDescriptor> descriptors;
/** PERF: cache table per tenant descriptors needing to be initialized per EM */
transient protected List tablePerTenantDescriptors;
/** PERF: cache table per tenant queries needing to be initialized per EM */
transient protected List tablePerTenantQueries;
// bug 3078039: move EJBQL alias > descriptor map from Session to Project (MWN)
/** Used to determine If a session is in a Broker or not */
protected boolean isInBroker;
/**
* Used to connect this session to EclipseLink cluster for distributed command
*/
transient protected CommandManager commandManager;
/**
* PERF: Cache the write-lock check to avoid cost of checking in every register/clone.
*/
protected boolean shouldCheckWriteLock;
/**
* Determined whether changes should be propagated to an EclipseLink cluster
*/
protected boolean shouldPropagateChanges;
/** Used to determine If a session is in a profile or not */
protected boolean isInProfile;
/** PERF: Quick check if logging is OFF entirely. */
protected boolean isLoggingOff;
/** PERF: Allow for finalizers to be enabled, currently enables client-session finalize. */
protected boolean isFinalizersEnabled;
/** List of active command threads. */
transient protected ExposedNodeLinkedList activeCommandThreads;
/**
* Indicates whether the session is synchronized.
* In case external transaction controller is used isSynchronized==true means
* the session's jta connection will be freed during external transaction callback.
*/
protected boolean isSynchronized;
/**
* Stores the default reference mode that a UnitOfWork will use when referencing
* managed objects.
* @see org.eclipse.persistence.config.ReferenceMode
*/
protected ReferenceMode defaultReferenceMode;
/**
* Default pessimistic lock timeout value.
*/
protected Integer pessimisticLockTimeoutDefault;
protected TimeUnit pessimisticLockTimeoutUnitDefault;
protected int queryTimeoutDefault;
protected TimeUnit queryTimeoutUnitDefault;
/** Allow a session to enable concurrent processing. */
protected boolean isConcurrent;
/**
* This map will hold onto class to static metamodel class references from JPA.
*/
protected Map staticMetamodelClasses;
/** temporarily holds a list of events that must be fired after the current operation completes.
* Initialy created for postClone events.
*/
protected List deferredEvents;
/** records that the UOW is executing deferred events. Events could cause operations to occur that may attempt to restart the event execution. This must be avoided*/
protected boolean isExecutingEvents;
/** Allow queries to be targeted at specific connection pools. */
protected PartitioningPolicy partitioningPolicy;
/** the MetadataRefreshListener is used with RCM to force a refresh of the metadata used within EntityManagerFactoryWrappers */
protected MetadataRefreshListener metadatalistener;
/** Stores the set of multitenant context properties this session requires **/
protected Set multitenantContextProperties;
/** Store the query builder used to parse JPQL. */
transient protected JPAQueryBuilder queryBuilder;
/** Set the Serializer to use by default for serialization. */
transient protected Serializer serializer;
/** Allow CDI injection of entity listeners **/
transient protected InjectionManager> injectionManager;
/**
* Indicates whether ObjectLevelReadQuery should by default use ResultSet Access optimization.
* Optimization specified by the session is ignored if incompatible with other query settings.
*/
protected boolean shouldOptimizeResultSetAccess;
/**
* Indicates whether Session creation should tolerate an invalid NamedQuery. If true, an exception
* will be thrown on .createNamedQuery(..) rather than at init time.
*/
protected boolean tolerateInvalidJPQL = false;
/**
* INTERNAL:
* Create and return a new session.
* This should only be called if the database login information is not know at the time of creation.
* Normally it is better to call the constructor that takes the login information as an argument
* so that the session can initialize itself to the platform information given in the login.
*/
protected AbstractSession() {
this.name = "";
this.queryTimeoutUnitDefault = DescriptorQueryManager.DefaultTimeoutUnit;
this.pessimisticLockTimeoutUnitDefault = DescriptorQueryManager.DefaultTimeoutUnit;
initializeIdentityMapAccessor();
// PERF - move to lazy init (3286091)
}
/**
* INTERNAL:
* Create a blank session, used for proxy session.
*/
protected AbstractSession(int nothing) {
}
/**
* PUBLIC:
* Create and return a new session.
* By giving the login information on creation this allows the session to initialize itself
* to the platform given in the login. This constructor does not return a connected session.
* To connect the session to the database login() must be sent to it. The login(userName, password)
* method may also be used to connect the session, this allows for the user name and password
* to be given at login but for the other database information to be provided when the session is created.
*/
protected AbstractSession(Login login) {
this(new org.eclipse.persistence.sessions.Project(login));
}
/**
* PUBLIC:
* Create and return a new session.
* This constructor does not return a connected session.
* To connect the session to the database login() must be sent to it. The login(userName, password)
* method may also be used to connect the session, this allows for the user name and password
* to be given at login but for the other database information to be provided when the session is created.
*/
protected AbstractSession(org.eclipse.persistence.sessions.Project project) {
this();
this.project = project;
if (project.getDatasourceLogin() == null) {
throw ValidationException.projectLoginIsNull(this);
}
// add the Project's queries as session queries
for (DatabaseQuery query : project.getQueries()) {
addQuery(query.getName(), query);
}
}
/**
* Return the Serializer to use by default for serialization.
*/
@Override
public Serializer getSerializer() {
return serializer;
}
/**
* Set the Serializer to use by default for serialization.
*/
@Override
public void setSerializer(Serializer serializer) {
this.serializer = serializer;
}
/**
* INTERNAL
* Return the query builder used to parser JPQL.
*/
public JPAQueryBuilder getQueryBuilder() {
if (this.queryBuilder == null) {
AbstractSession parent = getParent();
if (parent != null) {
this.queryBuilder = parent.getQueryBuilder();
} else {
this.queryBuilder = buildDefaultQueryBuilder();
}
}
return this.queryBuilder;
}
/**
* INTERNAL
* Set the query builder used to parser JPQL.
*/
public void setQueryBuilder(JPAQueryBuilder queryBuilder) {
this.queryBuilder = queryBuilder;
}
/**
* INTERNAL
* Build the JPQL builder based on session properties.
*/
protected JPAQueryBuilder buildDefaultQueryBuilder() {
String queryBuilderClassName = (String)getProperty(PersistenceUnitProperties.JPQL_PARSER);
if (queryBuilderClassName == null) {
queryBuilderClassName = "org.eclipse.persistence.internal.jpa.jpql.HermesParser";
//queryBuilderClassName = "org.eclipse.persistence.queries.ANTLRQueryBuilder";
}
String validation = (String)getProperty(PersistenceUnitProperties.JPQL_VALIDATION);
JPAQueryBuilder builder = null;
try {
Class extends JPAQueryBuilder> parserClass = null;
// use class.forName() to avoid loading parser classes for JAXB
// Use Class.forName not thread class loader to avoid class loader issues.
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
parserClass = AccessController.doPrivileged(new PrivilegedClassForName<>(queryBuilderClassName));
builder = AccessController.doPrivileged(new PrivilegedNewInstanceFromClass<>(parserClass));
} else {
parserClass = PrivilegedAccessHelper.getClassForName(queryBuilderClassName);
builder = PrivilegedAccessHelper.newInstanceFromClass(parserClass);
}
} catch (Exception e) {
throw new IllegalStateException("Could not load the JPQL parser class." /* TODO: Localize string */, e);
}
if (validation != null) {
builder.setValidationLevel(validation);
}
return builder;
}
/**
* INTERNAL:
* PERF: Used for quick turning logging ON/OFF entirely.
* @param loggingOff Logging is turned off when true
* and turned on when false.
*/
public void setLoggingOff(final boolean loggingOff) {
isLoggingOff = loggingOff;
}
/**
* INTERNAL:
* PERF: Used for quick check if logging is OFF entirely.
*/
public boolean isLoggingOff() {
return isLoggingOff;
}
/**
* INTERNAL:
* Called by a sessions queries to obtain individual query ids.
* CR #2698903
*/
public long getNextQueryId() {
return QueryCounter.getCount();
}
/**
* INTERNAL:
* Return a unit of work for this session not registered with the JTS transaction.
*/
public UnitOfWorkImpl acquireNonSynchronizedUnitOfWork() {
return acquireNonSynchronizedUnitOfWork(null);
}
/**
* INTERNAL:
* Return a unit of work for this session not registered with the JTS transaction.
*/
public UnitOfWorkImpl acquireNonSynchronizedUnitOfWork(ReferenceMode referenceMode) {
setNumberOfActiveUnitsOfWork(getNumberOfActiveUnitsOfWork() + 1);
UnitOfWorkImpl unitOfWork = new UnitOfWorkImpl(this, referenceMode);
if (shouldLog(SessionLog.FINER, SessionLog.TRANSACTION)) {
log(SessionLog.FINER, SessionLog.TRANSACTION, "acquire_unit_of_work_with_argument", String.valueOf(System.identityHashCode(unitOfWork)));
}
return unitOfWork;
}
/**
* INTERNAL:
* Constructs a HistoricalSession given a valid AsOfClause.
*/
@Override
public org.eclipse.persistence.sessions.Session acquireHistoricalSession(AsOfClause clause) throws ValidationException {
if ((clause == null) || (clause.getValue() == null)) {
throw ValidationException.cannotAcquireHistoricalSession();
}
if (!getProject().hasGenericHistorySupport() && !hasBroker() && ((getPlatform() == null) || !getPlatform().isOracle())) {
throw ValidationException.historicalSessionOnlySupportedOnOracle();
}
return new HistoricalSession(this, clause);
}
/**
* PUBLIC:
* Return a unit of work for this session.
* The unit of work is an object level transaction that allows
* a group of changes to be applied as a unit.
*
* @see UnitOfWorkImpl
*/
@Override
public UnitOfWorkImpl acquireUnitOfWork() {
UnitOfWorkImpl unitOfWork = acquireNonSynchronizedUnitOfWork(getDefaultReferenceMode());
unitOfWork.registerWithTransactionIfRequired();
return unitOfWork;
}
/**
* PUBLIC:
* Return a repeatable write unit of work for this session.
* A repeatable write unit of work allows multiple writeChanges (flushes).
*
* @see RepeatableWriteUnitOfWork
*/
public RepeatableWriteUnitOfWork acquireRepeatableWriteUnitOfWork(ReferenceMode referenceMode) {
return new RepeatableWriteUnitOfWork(this, referenceMode);
}
/**
* PUBLIC:
* Return a unit of work for this session.
* The unit of work is an object level transaction that allows
* a group of changes to be applied as a unit.
*
* @see UnitOfWorkImpl
* @param referenceMode The reference type the UOW should use internally when
* referencing Working clones. Setting this to WEAK means the UOW will use
* weak references to reference clones that support active object change
* tracking and hard references for deferred change tracked objects.
* Setting to FORCE_WEAK means that all objects will be referenced by weak
* references and if the application no longer references the clone the
* clone may be garbage collected. If the clone
* has uncommitted changes then those changes will be lost.
*/
@Override
public UnitOfWorkImpl acquireUnitOfWork(ReferenceMode referenceMode) {
UnitOfWorkImpl unitOfWork = acquireNonSynchronizedUnitOfWork(referenceMode);
unitOfWork.registerWithTransactionIfRequired();
return unitOfWork;
}
/**
* PUBLIC:
* Add an alias for the descriptor
*/
public void addAlias(String alias, ClassDescriptor descriptor) {
project.addAlias(alias, descriptor);
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed EJBQL queries.
*/
@Override
public void addJPAQuery(DatabaseQuery query) {
getProject().addJPAQuery(query);
}
/**
* INTERNAL:
* Return all pre-defined not yet parsed EJBQL multitenant queries.
*/
public void addJPATablePerTenantQuery(DatabaseQuery query) {
getProject().addJPATablePerTenantQuery(query);
}
/**
* PUBLIC:
* Return a set of multitenant context properties this session
*/
public void addMultitenantContextProperty(String contextProperty) {
getMultitenantContextProperties().add(contextProperty);
}
/**
* INTERNAL:
* Add the query to the session queries.
*/
protected synchronized void addQuery(DatabaseQuery query, boolean nameMustBeUnique) {
List queriesByName = getQueries().get(query.getName());
if (queriesByName == null) {
// lazily create Vector in Hashtable.
queriesByName = new ArrayList<>();
getQueries().put(query.getName(), queriesByName);
}
if (nameMustBeUnique){ // JPA addNamedQuery
if (queriesByName.size() <= 1){
queriesByName.clear();
}else{
throw new IllegalStateException(ExceptionLocalization.buildMessage("argument_keyed_named_query_with_JPA", new Object[]{query.getName()}));
}
}else{
// Check that we do not already have a query that matched it
for (Iterator enumtr = queriesByName.iterator(); enumtr.hasNext();) {
DatabaseQuery existingQuery = enumtr.next();
if (Helper.areTypesAssignable(query.getArgumentTypes(), existingQuery.getArgumentTypes())) {
throw ValidationException.existingQueryTypeConflict(query, existingQuery);
}
}
}
queriesByName.add(query);
}
/**
* PUBLIC:
* Add the query to the session queries with the given name.
* This allows for common queries to be pre-defined, reused and executed by name.
*/
@Override
public void addQuery(String name, DatabaseQuery query) {
query.setName(name);
addQuery(query, false);
}
/**
* PUBLIC:
* Add the query to the session queries with the given name.
* This allows for common queries to be pre-defined, reused and executed by name.
*/
public void addQuery(String name, DatabaseQuery query, boolean replace) {
query.setName(name);
addQuery(query, replace);
}
/**
* INTERNAL:
* Add a metamodel class to model class reference.
*/
public void addStaticMetamodelClass(String modelClassName, String metamodelClassName) {
if (staticMetamodelClasses == null) {
staticMetamodelClasses = new HashMap<>();
}
staticMetamodelClasses.put(modelClassName, metamodelClassName);
}
/**
* INTERNAL:
* Add a descriptor that is uses a table per tenant multitenant policy.
*/
protected void addTablePerTenantDescriptor(ClassDescriptor descriptor) {
getTablePerTenantDescriptors().add(descriptor);
}
/**
* INTERNAL:
* Add a query that queries a table per tenant entity
*/
protected void addTablePerTenantQuery(DatabaseQuery query) {
getTablePerTenantQueries().add(query);
}
/**
* INTERNAL:
* Called by beginTransaction() to start a transaction.
* This starts a real database transaction.
* Allows retry if the connection is dead.
*/
protected void basicBeginTransaction() throws DatabaseException {
Collection accessors = getAccessors();
if (accessors == null) {
return;
}
Accessor failedAccessor = null;
try {
for (Accessor accessor : accessors) {
failedAccessor = accessor;
basicBeginTransaction(accessor);
}
} catch (RuntimeException exception) {
// If begin failed, rollback ones already started.
for (Accessor accessor : accessors) {
if (accessor == failedAccessor) {
break;
}
try {
accessor.rollbackTransaction(this);
} catch (RuntimeException ignore) { }
}
throw exception;
}
}
/**
* INTERNAL:
* Called by beginTransaction() to start a transaction.
* This starts a real database transaction.
* Allows retry if the connection is dead.
*/
protected void basicBeginTransaction(Accessor accessor) throws DatabaseException {
try {
accessor.beginTransaction(this);
} catch (DatabaseException databaseException) {
// Retry if the failure was communication based? (i.e. timeout, database down, can no longer ping)
if ((!getDatasourceLogin().shouldUseExternalTransactionController()) && databaseException.isCommunicationFailure()) {
DatabaseException exceptionToThrow = databaseException;
Object[] args = new Object[1];
args[0] = databaseException;
log(SessionLog.INFO, SessionLog.TRANSACTION, "communication_failure_attempting_begintransaction_retry", args, null);
// Attempt to reconnect connection.
exceptionToThrow = retryTransaction(accessor, databaseException, 0, this);
if (exceptionToThrow == null) {
// Retry was a success.
return;
}
handleException(exceptionToThrow);
} else {
handleException(databaseException);
}
} catch (RuntimeException exception) {
handleException(exception);
}
}
/**
* INTERNAL:
* A begin transaction failed.
* Re-connect and retry the begin transaction.
*/
public DatabaseException retryTransaction(Accessor accessor, DatabaseException databaseException, int retryCount, AbstractSession executionSession) {
DatabaseException exceptionToThrow = databaseException;
// Attempt to reconnect connection.
int count = getLogin().getQueryRetryAttemptCount();
while (retryCount < count) {
try {
// if database session then re-establish
// connection
// else the session will just get a new
// connection from the pool
accessor.reestablishConnection(this);
accessor.beginTransaction(this);
return null;
} catch (DatabaseException newException) {
// Need to use last exception, as may not be a communication exception.
exceptionToThrow = newException;
// failed to get connection because of
// database error.
++retryCount;
try {
// Give the failover time to recover.
Thread.sleep(getLogin().getDelayBetweenConnectionAttempts());
Object[] args = new Object[1];
args[0] = exceptionToThrow;
log(SessionLog.INFO, SessionLog.TRANSACTION, "communication_failure_attempting_begintransaction_retry", args, null);
} catch (InterruptedException intEx) {
break;
}
}
}
return exceptionToThrow;
}
/**
* INTERNAL:
* Called in the end of beforeCompletion of external transaction synchronization listener.
* Close the managed sql connection corresponding to the external transaction,
* if applicable releases accessor.
*/
public void releaseJTSConnection() {
}
/**
* INTERNAL:
* Called by commitTransaction() to commit a transaction.
* This commits the active transaction.
*/
protected void basicCommitTransaction() throws DatabaseException {
Collection accessors = getAccessors();
if (accessors == null) {
return;
}
try {
for (Accessor accessor : accessors) {
accessor.commitTransaction(this);
}
} catch (RuntimeException exception) {
// Leave transaction uncommitted as rollback should be called.
handleException(exception);
}
}
/**
* INTERNAL:
* Called by rollbackTransaction() to rollback a transaction.
* This rolls back the active transaction.
*/
protected void basicRollbackTransaction() throws DatabaseException {
Collection accessors = getAccessors();
if (accessors == null) {
return;
}
RuntimeException exception = null;
for (Accessor accessor : accessors) {
try {
accessor.rollbackTransaction(this);
} catch (RuntimeException failure) {
exception = failure;
}
}
if (exception != null) {
handleException(exception);
}
}
/**
* INTERNAL:
* Attempts to begin an external transaction.
* Returns true only in one case -
* external transaction has been internally started during this method call:
* wasJTSTransactionInternallyStarted()==false in the beginning of this method and
* wasJTSTransactionInternallyStarted()==true in the end of this method.
*/
public boolean beginExternalTransaction() {
boolean externalTransactionHasBegun = false;
if (hasExternalTransactionController() && !wasJTSTransactionInternallyStarted()) {
try {
getExternalTransactionController().beginTransaction(this);
} catch (RuntimeException exception) {
handleException(exception);
}
if (wasJTSTransactionInternallyStarted()) {
externalTransactionHasBegun = true;
log(SessionLog.FINER, SessionLog.TRANSACTION, "external_transaction_has_begun_internally");
}
}
return externalTransactionHasBegun;
}
/**
* PUBLIC:
* Begin a transaction on the database.
* This allows a group of database modification to be committed or rolled back as a unit.
* All writes/deletes will be sent to the database be will not be visible to other users until commit.
* Although databases do not allow nested transaction,
* EclipseLink supports nesting through only committing to the database on the outer commit.
*
* @exception DatabaseException if the database connection is lost or the begin is rejected.
* @exception ConcurrencyException if this session's transaction is acquired by another thread and a timeout occurs.
*
* @see #isInTransaction()
*/
public void beginTransaction() throws DatabaseException, ConcurrencyException {
ConcurrencyManager mutex = getTransactionMutex();
// If there is no db transaction in progress
// beginExternalTransaction() starts an external transaction -
// provided externalTransactionController is used, and there is
// no active external transaction - so we have to start one internally.
if (!mutex.isAcquired()) {
beginExternalTransaction();
}
// For unit of work and client session multi threading is allowed as they are a context,
// this is required for JTS/RMI/CORBA/EJB stuff where the server thread can be different across calls.
if (isClientSession()) {
mutex.setActiveThread(Thread.currentThread());
}
// Ensure mutual exclusion and call subclass specific begin.
mutex.acquire();
if (!mutex.isNested()) {
if (this.eventManager != null) {
this.eventManager.preBeginTransaction();
}
basicBeginTransaction();
if (this.eventManager != null) {
this.eventManager.postBeginTransaction();
}
}
}
/**
* Check to see if the descriptor of a superclass can be used to describe this class
*
* @return ClassDescriptor
*/
protected ClassDescriptor checkHierarchyForDescriptor(Class> theClass){
return getDescriptor(theClass.getSuperclass());
}
/**
* allow the entity listener injection manager to clean itself up.
*/
public void cleanUpInjectionManager(){
if (injectionManager != null){
injectionManager.cleanUp(this);
}
}
/**
* PUBLIC:
* clear the integrityChecker. IntegrityChecker holds all the ClassDescriptor Exceptions.
*/
@Override
public void clearIntegrityChecker() {
setIntegrityChecker(null);
}
/**
* INTERNAL:
* Clear the the lastDescriptorAccessed cache.
*/
public void clearLastDescriptorAccessed() {
this.lastDescriptorAccessed = null;
}
/**
* INTERNAL:
* Clear the the descriptors cache.
*/
public void clearDescriptors() {
this.descriptors = null;
}
/**
* PUBLIC:
* Clear the profiler, this will end the current profile operation.
*/
@Override
public void clearProfile() {
setProfiler(null);
}
/**
* INTERNAL:
* Clones the descriptor
*/
@Override
public Object clone() {
// An alternative to this process should be found
try {
return super.clone();
} catch (Exception exception) {
throw new AssertionError(exception);
}
}
/**
* INTERNAL:
* Attempts to commit the running internally started external transaction.
* Returns true only in one case -
* external transaction has been internally committed during this method call:
* wasJTSTransactionInternallyStarted()==true in the beginning of this method and
* wasJTSTransactionInternallyStarted()==false in the end of this method.
*/
public boolean commitExternalTransaction() {
boolean externalTransactionHasCommitted = false;
if (hasExternalTransactionController() && wasJTSTransactionInternallyStarted()) {
try {
getExternalTransactionController().commitTransaction(this);
} catch (RuntimeException exception) {
handleException(exception);
}
if (!wasJTSTransactionInternallyStarted()) {
externalTransactionHasCommitted = true;
log(SessionLog.FINER, SessionLog.TRANSACTION, "external_transaction_has_committed_internally");
}
}
return externalTransactionHasCommitted;
}
/**
* PUBLIC:
* Commit the active database transaction.
* This allows a group of database modification to be committed or rolled back as a unit.
* All writes/deletes will be sent to the database be will not be visible to other users until commit.
* Although databases do not allow nested transaction,
* EclipseLink supports nesting through only committing to the database on the outer commit.
*
* @exception DatabaseException most databases validate changes as they are done,
* normally errors do not occur on commit unless the disk fails or the connection is lost.
* @exception ConcurrencyException if this session is not within a transaction.
*/
public void commitTransaction() throws DatabaseException, ConcurrencyException {
ConcurrencyManager mutex = getTransactionMutex();
// Release mutex and call subclass specific commit.
if (!mutex.isNested()) {
if (this.eventManager != null) {
this.eventManager.preCommitTransaction();
}
basicCommitTransaction();
if (this.eventManager != null) {
this.eventManager.postCommitTransaction();
}
}
// This MUST not be in a try catch or finally as if the commit failed the transaction is still open.
mutex.release();
// If there is no db transaction in progress
// if there is an active external transaction
// which was started internally - it should be committed internally, too.
if (!mutex.isAcquired()) {
commitExternalTransaction();
}
}
/**
* INTERNAL:
* Return if the two object match completely.
* This checks the objects attributes and their private parts.
*/
public boolean compareObjects(Object firstObject, Object secondObject) {
if ((firstObject == null) && (secondObject == null)) {
return true;
}
if ((firstObject == null) || (secondObject == null)) {
return false;
}
if (!(firstObject.getClass().equals(secondObject.getClass()))) {
return false;
}
ObjectBuilder builder = getDescriptor(firstObject.getClass()).getObjectBuilder();
return builder.compareObjects(builder.unwrapObject(firstObject, this), builder.unwrapObject(secondObject, this), this);
}
/**
* TESTING:
* Return true if the object do not match.
* This checks the objects attributes and their private parts.
*/
public boolean compareObjectsDontMatch(Object firstObject, Object secondObject) {
return !this.compareObjects(firstObject, secondObject);
}
/**
* PUBLIC:
* Return true if the pre-defined query is defined on the session.
*/
@Override
public boolean containsQuery(String queryName) {
return getQueries().containsKey(queryName);
}
/**
* PUBLIC:
* Return a complete copy of the object or of collection of objects.
* In case of collection all members should be either entities of the same type
* or have a common inheritance hierarchy mapped root class.
* This can be used to obtain a scratch copy of an object,
* or for templatizing an existing object into another new object.
* The object and all of its privately owned parts will be copied.
*
* @see #copy(Object, AttributeGroup)
*/
@Override
public Object copy(Object originalObjectOrObjects) {
return copy(originalObjectOrObjects, new CopyGroup());
}
/**
* PUBLIC:
* Return a complete copy of the object or of collection of objects.
* In case of collection all members should be either entities of the same type
* or have a common inheritance hierarchy mapped root class.
* This can be used to obtain a scratch copy of an object,
* or for templatizing an existing object into another new object.
* If there are no attributes in the group
* then the object and all of its privately owned parts will be copied.
* Otherwise only the attributes included into the group will be copied.
*/
@Override
public Object copy(Object originalObjectOrObjects, AttributeGroup group) {
if (originalObjectOrObjects == null) {
return null;
}
CopyGroup copyGroup = group.toCopyGroup();
copyGroup.setSession(this);
if(originalObjectOrObjects instanceof Collection) {
// it's a collection - make sure all elements use the same instance of CopyGroup.
Collection originalCollection = (Collection)originalObjectOrObjects;
Collection copies;
if(originalCollection instanceof List) {
copies = new ArrayList();
} else {
copies = new HashSet();
}
Iterator it = originalCollection.iterator();
while(it.hasNext()) {
copies.add(copyInternal(it.next(), copyGroup));
}
return copies;
}
// it's not a collection
return copyInternal(originalObjectOrObjects, copyGroup);
}
/**
* INTERNAL:
*/
public Object copyInternal(Object originalObject, CopyGroup copyGroup) {
if (originalObject == null) {
return null;
}
ClassDescriptor descriptor = getDescriptor(originalObject);
if (descriptor == null) {
return originalObject;
}
return descriptor.getObjectBuilder().copyObject(originalObject, copyGroup);
}
/**
* INTERNAL:
* Copy the read only classes from the unit of work
*
* Added Nov 8, 2000 JED for Patch 2.5.1.8
* Ref: Prs 24502
*/
public Vector copyReadOnlyClasses() {
return getDefaultReadOnlyClasses();
}
public DatabaseValueHolder createCloneQueryValueHolder(ValueHolderInterface attributeValue, Object clone, AbstractRecord row, ForeignReferenceMapping mapping) {
return new ProtectedValueHolder<>(attributeValue, mapping, this);
}
public DatabaseValueHolder createCloneTransformationValueHolder(ValueHolderInterface attributeValue, Object original, Object clone, AbstractTransformationMapping mapping) {
return new ProtectedValueHolder<>(attributeValue, mapping, this);
}
public InjectionManager createInjectionManager(Object beanManager){
try{
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
Class> elim = AccessController.doPrivileged(new PrivilegedClassForName<>(InjectionManager.DEFAULT_CDI_INJECTION_MANAGER, true, getLoader()));
Constructor> constructor = AccessController.doPrivileged(new PrivilegedGetConstructorFor<>(elim, new Class>[]{String.class}, false));
return AccessController.doPrivileged(new PrivilegedInvokeConstructor<>(constructor, new Object[]{beanManager}));
} else {
Class> elim = org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName(InjectionManager.DEFAULT_CDI_INJECTION_MANAGER, true, getLoader());
Constructor> constructor = PrivilegedAccessHelper.>getConstructorFor(elim, new Class>[] {Object.class}, false);
return PrivilegedAccessHelper.>invokeConstructor(constructor, new Object[] {beanManager});
}
} catch (Exception e){
logThrowable(SessionLog.FINEST, SessionLog.JPA, e);
}
return new DisabledInjectionManager<>();
}
/**
* INTERNAL:
* This method is similar to getAndCloneCacheKeyFromParent. It purpose is to get protected cache data from the shared cache and
* build/return a protected instance.
*/
public Object createProtectedInstanceFromCachedData(Object cached, Integer refreshCascade, ClassDescriptor descriptor){
CacheKey localCacheKey = getIdentityMapAccessorInstance().getCacheKeyForObject(cached);
if (localCacheKey != null && localCacheKey.getObject() != null){
return localCacheKey.getObject();
}
boolean identityMapLocked = this.shouldCheckWriteLock && getParent().getIdentityMapAccessorInstance().acquireWriteLock();
boolean rootOfCloneRecursion = false;
CacheKey cacheKey = getParent().getIdentityMapAccessorInstance().getCacheKeyForObject(cached);
try{
Object key = null;
Object lockValue = null;
long readTime = 0;
if (cacheKey != null){
if (identityMapLocked) {
checkAndRefreshInvalidObject(cached, cacheKey, descriptor);
} else {
// Check if we have locked all required objects already.
if (this.objectsLockedForClone == null) {
// PERF: If a simple object just acquire a simple read-lock.
if (descriptor.shouldAcquireCascadedLocks()) {
this.objectsLockedForClone = getParent().getIdentityMapAccessorInstance().getWriteLockManager().acquireLocksForClone(cached, descriptor, cacheKey, this);
} else {
checkAndRefreshInvalidObject(cached, cacheKey, descriptor);
cacheKey.acquireReadLock();
}
rootOfCloneRecursion = true;
}
}
key = cacheKey.getKey();
lockValue = cacheKey.getWriteLockValue();
readTime = cacheKey.getReadTime();
}
if (descriptor.hasInheritance()){
descriptor = this.getClassDescriptor(cached.getClass());
}
ObjectBuilder builder = descriptor.getObjectBuilder();
Object workingClone = builder.instantiateWorkingCopyClone(cached, this);
// PERF: Cache the primary key if implements PersistenceEntity.
builder.populateAttributesForClone(cached, cacheKey, workingClone, refreshCascade, this);
getIdentityMapAccessorInstance().putInIdentityMap(workingClone, key, lockValue, readTime, descriptor);
return workingClone;
}finally{
if (rootOfCloneRecursion){
if (this.objectsLockedForClone == null && cacheKey != null) {
cacheKey.releaseReadLock();
} else {
for (Iterator iterator = this.objectsLockedForClone.values().iterator(); iterator.hasNext();) {
((CacheKey)iterator.next()).releaseReadLock();
}
this.objectsLockedForClone = null;
}
executeDeferredEvents();
}
}
}
/**
* INTERNAL:
* Check if the object is invalid and refresh it.
* This is used to ensure that no invalid objects are registered.
*/
public void checkAndRefreshInvalidObject(Object object, CacheKey cacheKey, ClassDescriptor descriptor) {
if (isConsideredInvalid(object, cacheKey, descriptor)) {
ReadObjectQuery query = new ReadObjectQuery();
query.setReferenceClass(object.getClass());
query.setSelectionId(cacheKey.getKey());
query.refreshIdentityMapResult();
query.setIsExecutionClone(true);
this.executeQuery(query);
}
}
/**
* INTERNAL:
* Check if the object is invalid and *should* be refreshed.
* This is used to ensure that no invalid objects are cloned.
*/
public boolean isConsideredInvalid(Object object, CacheKey cacheKey, ClassDescriptor descriptor) {
if (cacheKey.getObject() != null) {
CacheInvalidationPolicy cachePolicy = descriptor.getCacheInvalidationPolicy();
// BUG#6671556 refresh invalid objects when accessed in the unit of work.
return (cachePolicy.shouldRefreshInvalidObjectsOnClone() && cachePolicy.isInvalidated(cacheKey));
}
return false;
}
/**
* INTERNAL:
* Add an event to the deferred list. Events will be fired after the operation completes
*/
public void deferEvent(DescriptorEvent event){
if (this.deferredEvents == null){
this.deferredEvents = new ArrayList<>();
}
this.deferredEvents.add(event);
}
/**
* PUBLIC:
* delete all of the objects and all of their privately owned parts in the database.
* The allows for a group of objects to be deleted as a unit.
* The objects will be deleted through a single transactions.
*
* @exception DatabaseException if an error occurs on the database,
* these include constraint violations, security violations and general database errors.
* @exception OptimisticLockException if the object's descriptor is using optimistic locking and
* the object has been updated or deleted by another user since it was last read.
*/
public void deleteAllObjects(Collection domainObjects) throws DatabaseException, OptimisticLockException {
for (Iterator objectsEnum = domainObjects.iterator(); objectsEnum.hasNext();) {
deleteObject(objectsEnum.next());
}
}
/**
* PUBLIC:
* Delete the object and all of its privately owned parts from the database.
* The delete operation can be customized through using a delete query.
*
* @exception DatabaseException if an error occurs on the database,
* these include constraint violations, security violations and general database errors.
* An database error is not raised if the object is already deleted or no rows are effected.
* @exception OptimisticLockException if the object's descriptor is using optimistic locking and
* the object has been updated or deleted by another user since it was last read.
*
* @see DeleteObjectQuery
*/
public Object deleteObject(Object domainObject) throws DatabaseException, OptimisticLockException {
DeleteObjectQuery query = new DeleteObjectQuery();
query.setObject(domainObject);
query.setIsExecutionClone(true);
return executeQuery(query);
}
/**
* PUBLIC:
* Return if the object exists on the database or not.
* This always checks existence on the database.
*/
@Override
public boolean doesObjectExist(Object object) throws DatabaseException {
DoesExistQuery query = new DoesExistQuery();
query.setObject(object);
query.checkDatabaseForDoesExist();
query.setIsExecutionClone(true);
return (Boolean) executeQuery(query);
}
/**
* PUBLIC:
* Turn off logging
*/
@Override
public void dontLogMessages() {
setLogLevel(SessionLog.OFF);
}
/**
* INTERNAL:
* End the operation timing.
*/
@Override
public void endOperationProfile(String operationName) {
if (this.isInProfile) {
getProfiler().endOperationProfile(operationName);
}
}
/**
* INTERNAL:
* End the operation timing.
*/
public void endOperationProfile(String operationName, DatabaseQuery query, int weight) {
if (this.isInProfile) {
getProfiler().endOperationProfile(operationName, query, weight);
}
}
/**
* INTERNAL:
* Updates the value of SessionProfiler state
*/
@Override
public void updateProfile(String operationName, Object value) {
if (this.isInProfile) {
getProfiler().update(operationName, value);
}
}
/**
* INTERNAL:
* Set the table per tenant. This should be called per client session after
* the start of a transaction. From JPA this method is called on the entity
* manager by setting the multitenant table per tenant property.
*/
public void updateTablePerTenantDescriptors(String property, Object value) {
// When all the table per tenant descriptors are set, we should initialize them.
boolean shouldInitializeDescriptors = hasTablePerTenantDescriptors();
for (ClassDescriptor descriptor : getTablePerTenantDescriptors()) {
TablePerMultitenantPolicy policy = (TablePerMultitenantPolicy) descriptor.getMultitenantPolicy();
if ((! policy.hasContextTenant()) && policy.usesContextProperty(property)) {
policy.setContextTenant((String) value);
}
shouldInitializeDescriptors = shouldInitializeDescriptors && policy.hasContextTenant();
}
if (shouldInitializeDescriptors) {
// Now that the correct tables are set on all table per tenant
// descriptors, we can go through the initialization phases safely.
try {
// First initialize basic properties (things that do not depend on anything else)
for (ClassDescriptor descriptor : tablePerTenantDescriptors) {
descriptor.preInitialize(this);
}
// Second initialize basic mappings
for (ClassDescriptor descriptor : tablePerTenantDescriptors) {
descriptor.initialize(this);
}
// Third initialize child dependencies
for (ClassDescriptor descriptor : tablePerTenantDescriptors) {
descriptor.postInitialize(this);
}
if (getIntegrityChecker().hasErrors()) {
handleSevere(new IntegrityException(getIntegrityChecker()));
}
} finally {
clearIntegrityChecker();
}
getCommitManager().initializeCommitOrder();
// If we have table per tenant queries, initialize and add them now
// once all the descriptors have been initialized.
if (hasTablePerTenantQueries()) {
for (DatabaseQuery query : getTablePerTenantQueries()) {
processJPAQuery(query);
}
}
}
}
/**
* INTERNAL:
* Updates the count of SessionProfiler event
*/
@Override
public void incrementProfile(String operationName) {
if (this.isInProfile) {
getProfiler().occurred(operationName, this);
}
}
/**
* INTERNAL:
* Updates the count of SessionProfiler event
*/
public void incrementProfile(String operationName, DatabaseQuery query) {
if (this.isInProfile) {
getProfiler().occurred(operationName, query, this);
}
}
/**
* INTERNAL:
* Causes any deferred events to be fired. Called after operation completes
*/
public void executeDeferredEvents(){
if (!this.isExecutingEvents && this.deferredEvents != null) {
this.isExecutingEvents = true;
try {
for (int i = 0; i < this.deferredEvents.size(); ++i) {
// the size is checked every time here because the list may grow
DescriptorEvent event = this.deferredEvents.get(i);
event.getDescriptor().getEventManager().executeEvent(event);
}
this.deferredEvents.clear();
} finally {
this.isExecutingEvents = false;
}
}
}
/**
* INTERNAL:
* Overridden by subclasses that do more than just execute the call.
* Executes the call directly on this session and does not check which
* session it should have executed on.
*/
public Object executeCall(Call call, AbstractRecord translationRow, DatabaseQuery query) throws DatabaseException {
if (query.getAccessors() == null) {
query.setAccessors(getAccessors());
}
try {
return basicExecuteCall(call, translationRow, query);
} finally {
if (call.isFinished()) {
query.setAccessors(null);
}
}
}
/**
* INTERNAL:
* Release (if required) connection after call.
*/
public void releaseConnectionAfterCall(DatabaseQuery query) {
}
/**
* PUBLIC:
* Execute the call on the database.
* The row count is returned.
* The call can be a stored procedure call, SQL call or other type of call.
*
Example:
*
session.executeNonSelectingCall(new SQLCall("Delete from Employee");
*
* @see #executeSelectingCall(Call)
*/
@Override
public int executeNonSelectingCall(Call call) throws DatabaseException {
DataModifyQuery query = new DataModifyQuery();
query.setIsExecutionClone(true);
query.setCall(call);
Integer value = (Integer)executeQuery(query);
if (value == null) {
return 0;
} else {
return value;
}
}
/**
* PUBLIC:
* Execute the sql on the database.
*
Example:
*
session.executeNonSelectingSQL("Delete from Employee");
* @see #executeNonSelectingCall(Call)
* Warning: Allowing an unverified SQL string to be passed into this
* method makes your application vulnerable to SQL injection attacks.
*/
@Override
public void executeNonSelectingSQL(String sqlString) throws DatabaseException {
executeNonSelectingCall(new SQLCall(sqlString));
}
/**
* PUBLIC:
* Execute the pre-defined query by name and return the result.
* Queries can be pre-defined and named to allow for their reuse.
*
* @see #addQuery(String, DatabaseQuery)
*/
@Override
public Object executeQuery(String queryName) throws DatabaseException {
DatabaseQuery query = getQuery(queryName);
if (query == null) {
throw QueryException.queryNotDefined(queryName);
}
return executeQuery(query);
}
/**
* PUBLIC:
* Execute the pre-defined query by name and return the result.
* Queries can be pre-defined and named to allow for their reuse.
* The class is the descriptor in which the query was pre-defined.
*
* @see DescriptorQueryManager#addQuery(String, DatabaseQuery)
*/
@Override
public Object executeQuery(String queryName, Class> domainClass) throws DatabaseException {
ClassDescriptor descriptor = getDescriptor(domainClass);
if (descriptor == null) {
throw QueryException.descriptorIsMissingForNamedQuery(domainClass, queryName);
}
DatabaseQuery query = descriptor.getQueryManager().getQuery(queryName);
if (query == null) {
throw QueryException.queryNotDefined(queryName, domainClass);
}
return executeQuery(query);
}
/**
* PUBLIC:
* Execute the pre-defined query by name and return the result.
* Queries can be pre-defined and named to allow for their reuse.
* The class is the descriptor in which the query was pre-defined.
*
* @see DescriptorQueryManager#addQuery(String, DatabaseQuery)
*/
@Override
public Object executeQuery(String queryName, Class> domainClass, Object arg1) throws DatabaseException {
Vector