org.eclipse.persistence.sessions.remote.DistributedSession Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 1998, 2024 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:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.sessions.remote;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorQueryManager;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.internal.identitymaps.IdentityMapManager;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
import org.eclipse.persistence.internal.sessions.DistributedSessionIdentityMapAccessor;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.internal.sessions.remote.ObjectDescriptor;
import org.eclipse.persistence.internal.sessions.remote.RemoteConnection;
import org.eclipse.persistence.internal.sessions.remote.RemoteCursoredStream;
import org.eclipse.persistence.internal.sessions.remote.RemoteScrollableCursor;
import org.eclipse.persistence.internal.sessions.remote.RemoteValueHolder;
import org.eclipse.persistence.internal.sessions.remote.Transporter;
import org.eclipse.persistence.queries.CursoredStreamPolicy;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ScrollableCursorPolicy;
import org.eclipse.persistence.sessions.Login;
import org.eclipse.persistence.sessions.SessionProfiler;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* Purpose: Super class to all remote client session's.
*/
public abstract class DistributedSession extends DatabaseSessionImpl {
/** Connection to remote persistence service. */
protected transient RemoteConnection remoteConnection;
/** Cache if default classes have been read from server. */
protected boolean hasDefaultReadOnlyClasses;
/** Define if meta-data is initialized locally, or serialized from the server. */
protected boolean isMetadataRemote = true;
/**
* INTERNAL:
* Create a blank session, used for proxy session.
*/
protected DistributedSession(int nothing) {
}
/**
* PUBLIC:
* Creates a DistributedSession.
* @param remoteConnection remote session requires a remote connection. This must be accessed remotely from the client through RMI or CORBA.
*/
protected DistributedSession(RemoteConnection remoteConnection) {
this.remoteConnection = remoteConnection;
this.remoteConnection.initialize(this);
this.project = new org.eclipse.persistence.sessions.Project();
}
/**
* 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 abstract UnitOfWorkImpl acquireUnitOfWork();
/**
* PUBLIC:
* Start a transaction on the server.
* A unit of work should normally be used instead of transactions for the remote session.
*/
@Override
public void beginTransaction() {
// Acquire the mutex so session knows it is in a transaction.
getTransactionMutex().acquire();
startOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
getRemoteConnection().beginTransaction();
endOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
}
/**
* PUBLIC:
* Commit a transaction on the server.
* A unit of work should normally be used instead of transactions for the remote session.
*/
@Override
public void commitTransaction() {
startOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
getRemoteConnection().commitTransaction();
endOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
getTransactionMutex().release();
}
/**
* INTERNAL:
* Return remote cursor stream.
*/
public RemoteCursoredStream cursorSelectObjects(CursoredStreamPolicy policy) {
return getRemoteConnection().cursorSelectObjects(policy, this);
}
/**
* INTERNAL:
* Return remote scrollable cursor
*/
public RemoteScrollableCursor cursorSelectObjects(ScrollableCursorPolicy policy) {
return getRemoteConnection().cursorSelectObjects(policy, this);
}
/**
* 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 named query can be defined on the remote session or the server-side session.
*
* @see #addQuery(String, DatabaseQuery)
*/
@Override
public Object executeQuery(String queryName) throws DatabaseException {
return executeQuery(queryName, new Vector(1));
}
/**
* 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.
* The query is executed on the server-side session.
*
* @see DescriptorQueryManager#addQuery(String, DatabaseQuery)
*/
@Override
public Object executeQuery(String queryName, Class domainClass) throws DatabaseException {
return executeQuery(queryName, domainClass, new Vector(1));
}
/**
* 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, Vector argumentValues) throws DatabaseException {
startOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
Transporter transporter = getRemoteConnection().remoteExecuteNamedQuery(queryName, domainClass, argumentValues);
endOperationProfile(SessionProfiler.Remote, null, SessionProfiler.ALL);
transporter.getQuery().setSession(this);
return transporter.getQuery().extractRemoteResult(transporter);
}
/**
* 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, Vector argumentValues) throws DatabaseException {
if (containsQuery(queryName)) {
return super.executeQuery(queryName, argumentValues);
}
return executeQuery(queryName, null, argumentValues);
}
/**
* Execute the database query.
*/
@Override
public abstract Object executeQuery(DatabaseQuery query);
/**
* INTERNAL:
* Execute the database query.
*/
@Override
public Object executeQuery(DatabaseQuery query, AbstractRecord row) {
query.setTranslationRow(row);
return executeQuery(query);
}
/**
* INTERNAL:
* CR#2751
* Returns the set of read-only classes for the receiver. These class come from the
* Remote connection
*
* @return A Vector containing the Java Classes that are currently read-only.
*/
@Override
public List> getDefaultReadOnlyClasses() {
if (this.isMetadataRemote && !this.hasDefaultReadOnlyClasses) {
getProject().setDefaultReadOnlyClasses(getRemoteConnection().getDefaultReadOnlyClasses());
this.hasDefaultReadOnlyClasses = true;
}
return super.getDefaultReadOnlyClasses();
}
/**
* INTERNAL:
* Return the table descriptor specified for the class.
*/
@Override
public ClassDescriptor getDescriptor(Class domainClass) {
ClassDescriptor descriptor = getDescriptors().get(domainClass);
// If the descriptor is null then this means that descriptor must now be read from the server.
if (descriptor == null) {
if (!this.isMetadataRemote) {
return super.getDescriptor(domainClass);
}
startOperationProfile(SessionProfiler.RemoteMetadata, null, SessionProfiler.ALL);
descriptor = getRemoteConnection().getDescriptor(domainClass);
endOperationProfile(SessionProfiler.RemoteMetadata, null, SessionProfiler.ALL);
if (descriptor == null) {
return super.getDescriptor(domainClass);
}
getDescriptors().put(domainClass, descriptor);
String alias = descriptor.getAlias();
if (alias != null) {
getProject().addAlias(alias, descriptor);
}
descriptor.remoteInitialization(this);
}
return descriptor;
}
/**
* INTERNAL:
* Return the table descriptor specified for the class.
*/
@Override
public ClassDescriptor getDescriptorForAlias(String alias) {
ClassDescriptor descriptor = super.getDescriptorForAlias(alias);
// If the descriptor is null then this means that descriptor must now be read from the server.
if (descriptor == null) {
if (!this.isMetadataRemote) {
return null;
}
startOperationProfile(SessionProfiler.RemoteMetadata, null, SessionProfiler.ALL);
descriptor = getRemoteConnection().getDescriptorForAlias(alias);
endOperationProfile(SessionProfiler.RemoteMetadata, null, SessionProfiler.ALL);
if (descriptor == null) {
return null;
}
getDescriptors().put(descriptor.getJavaClass(), descriptor);
getProject().addAlias(alias, descriptor);
descriptor.remoteInitialization(this);
}
return descriptor;
}
/**
* INTERNAL:
* Return the descriptor.
*/
public ClassDescriptor getDescriptorCorrespondingTo(ClassDescriptor descriptor) {
return getDescriptors().get(descriptor.getJavaClass());
}
/**
* INTERNAL:
* Return the corresponding objects from the remote session for the objects read from the server.
*/
public abstract Object getObjectCorrespondingTo(Object serverSideDomainObject, Map