Oracle® Application Server TopLink Application Developer's Guide
10g Release 2 (10.1.2) Part No. B15901-01 |
|
Previous |
Next |
OracleAS TopLink provides several session types that enable you to tailor the session to your application needs. This section describes the following OracleAS TopLink session types:
The server session and client session architecture is known collectively as a three-tier architecture. In this type of architecture, the server session provides session management for the clients, and the client session acts as a dedicated database session for each client or request.
Although they are two separate session types, use the client sessions and server sessions together. You define the server session in the sessions.xml
file. After you instantiate the server session, you acquire client sessions from it. Each client session can have only one associated server session, but a server session can support any number of client sessions.
In an OracleAS TopLink three-tier architecture, client sessions and server sessions both reside on the server. Client applications access the OracleAS TopLink application through a client session, and the client session communicates with the database using the server session.
The Enterprise JavaBean (EJB) container manages interaction with the database and OracleAS TopLink. The server session manages all aspects of persistence, such as caching, reading, and writing, but does so behind the scenes.
Although the server session and the client session are two different session types, you can treat them as a single unit in most cases, because they are both required to provide three-tier functionality to the application. The server session provides the client session to client applications, and also supplies the bulk of the session functionality. This section discusses some of the advantages and general concepts associated with the OracleAS TopLink three-tier design.
The three-tier design enables multiple clients to share persistent resources. The server session provides its client sessions with a shared live object cache, read and write connection pooling, and parameterized named queries. Client sessions also share descriptor metadata.
You can use client sessions and server sessions in any application server architecture that allows for shared memory and supports multiple clients. These architectures can include JSP, RMI, EKJB, CORBA, DCOM, HTML, and Servlet.
To support a shared object cache, client sessions must:
Implement any changes to the database with the OracleAS TopLink Unit of Work.
Share a common database login for reading (you can implement separate logins for writing).
For more information, see "Sessions and the Cache".
To read objects from the database the client must first acquire a client session from the server session. Acquiring a client session gives the client access to the session cache and the database through the server session.
Example 4-33 Acquiring a Client Session
ClientSession myClientSession = myServerSession.acquireClientSession();
After the client acquires a client session, it can send read requests to the server. The server session responds to these requests as follows:
If the object or data is in the session cache, then the server session returns the information back to the client.
If the object or data is not in the cache, then the server session reads the information from the database and stores the object in the session cache. The objects are then available for retrieval from the cache.
Because a server session processes each client request in a separate thread, this enables multiple clients to access the database connection pool concurrently.
Figure 4-7 illustrates how multiple clients read from the database using the server session.
Figure 4-7 Multiple Client Sessions Reading the Database Using the Server Session
To read objects from the database using a Client Session:
Start the application server.
Create a ServerSession
object and call login()
.
Call acquireClientSession()
to acquire a ClientSession
from the ServerSession
.
Execute read operations on the ClientSession
object.
Note: Do not use theServerSession object directly to read objects from the database.
|
Because the client session disables all database modification methods, a client session cannot create, change, or delete objects directly. Instead, the client must obtain a Unit of Work from the client session to perform database modification methods.
To write to the database, the client acquires a client session from the server session and then acquires a UnitOfWork
within that client session. The Unit of Work acts as an exclusive transactional object space, and ensures that any changes that are committed to the database also occur in the session cache.
Note: Although client sessions are thread-safe, do not use them to write across multiple threads. Multi-thread writes from the same client session can result in errors and a loss of data. |
To write to the database using a Unit of Work:
Start the application server.
Create a ServerSession
object and call login()
.
Call acquireClientSession()
to acquire a ClientSession
from the ServerSession
.
Acquire a UnitOfWork
object from the ClientSession
object.
For more information about the Unit of Work, see Chapter 7, "Transactions".
Perform the required updates, and then commit the UnitOfWork
.
Figure 4-8 Writing with Client Sessions and Server Sessions
The Unit of Work ensures that the client edits objects in a separate object transaction space. This feature enables clients to perform object transactions in parallel. When transactions commit, the Unit of Work makes any required changes in the database and then merges the changes into the shared OracleAS TopLink session cache. The modified objects are then available to all other users.
For more information about the Unit of Work, see to Chapter 7, "Transactions".
You can define several different server sessions in your application to support users with different data access rights. For example, your application may serve a group called "Managers," who has access rights to salary information, and a group called "Employees," who do not. Because each session you define in the sessions.xml
file has its own login information, you can create multiple sessions, each with its own login credentials, to meet the needs of both these groups.
The server session supports concurrent clients by providing each client with a dedicated thread of execution. Dedicated threads enable clients to operate asynchronously—that is, client processes execute as they are called and do not wait for other client processes to complete.
OracleAS TopLink safeguards thread safety with a concurrency manager. The concurrency manager ensures that no two threads interfere with each other when performing operations such as creating new objects, accessing valueholders, or executing a transaction on the database.
Not all JDBC drivers support concurrency. Those that do not may require a thread to have exclusive access to a JDBC connection when reading. Configure the server session to use exclusive read connection pooling in these cases.
When you instantiate the server session, it creates a pool of database connections. It then manages the connection pool based on your session configuration and shares the connections among its client sessions. The server session provides connections to client sessions on an as-needed basis. When the client session releases the connection, the server session recovers the connection and makes it available to other client processes. Reusing connections reduces the number of connections required by the application and allows a server session to support a larger number of clients.
By default, the OracleAS TopLink write connection pool maintains a minimum of five connections and a maximum of ten. You can change these settings as follows:
To change the settings for the entire project, adjust these settings in OracleAS TopLink Mapping Workbench.
For more information, see "Working with Connection Pools" in the Oracle Application Server TopLink Mapping Workbench User's Guide.
To change the settings for a particular server session, adjust these settings in the sessions.xml
file. You can make these changes using the OracleAS TopLink Sessions Editor, or manually add the following lines to the session
element in the file:
<session> ... <connection-pool> ... <max-connections>20</max-connections> <min-connections>10</min-connections> ... </connection-pool> ... </session>
Tip: To maintain compatibility with JDBC drivers that do not support many connections, the default number of connections is small. If your JDBC driver supports it, use a larger number of connections for reading and writing. |
The server session also supports multiple write connection pools and nonpooled connections. If your application server or JDBC driver also supports write connection pooling, you can configure the server session to use this feature. Set these options at the session level, and modify the session
element in the sessions.xml
file.
For more information, see "Configuring Sessions with the sessions.xml File".
Although a single connection supports multiple threads reading asynchronously, some JDBC drivers perform better with multiple read connections. OracleAS TopLink enables you to allocate multiple read connections, and balances the load across the connections, using a least-busy algorithm.
The server session maintains a pool of read connections and a pool of write connections for its client sessions. You can customize the following options either in the sessions.xml
file or in Java code:
Create a new connection pool and add it to the pools in the server session:
addConnectionPool(String poolName, JDBCLogin login, int minNumberOfConnections, int maxNumberOfConnections)
In Java code, configure the read connection pool:
useReadConnectionPool(int minNumberOfConnections, int maxNumberOfConnections)
In Java code, configure the read connection pool to allow only a single thread to access each connection:
useExclusiveReadConnectionPool(int minNumberOfConnections, int maxNumberOfConnections)
In Java code, set the maximum number of nonpooled connections:
setMaxNumberOfNonPooledConnections(int maxNumber)
The three ways to get connections from within a client session object correspond to three arguments you can pass with the acquireClientSession()
method on the server session:
Pass no argument (the zero argument). The acquired ClientSession
uses the default connection pool.
Pass a poolName
as an argument. The acquired ClientSession
uses a connection from the specified pool.
Pass a DatabaseLogin
object as an argument. The acquired ClientSession
uses a specified DatabaseLogin
object to obtain a connection.
By default, the server session does not allocate database connections for these client sessions until a Unit of Work commits to the database (a lazy database connection).
If you must establish a database connection immediately, configure the ConnectionPolicy
object to specify a connection option more suited to your needs, and pass the ConnectionPolicy
object as an argument.
The ConnectionPolicy
class provides the following methods to configure a client connection:
setPoolName(String poolName)
: Creates a connection from the named connection pool. You can also use the ConnectionPolicy(String poolName)
method.
setLogin(DatabaseLogin login)
: Sets up a connection by logging directly in to the database. You can also use the ConnectionPolicy(DatabaseLogin login)
method from the connection policy constructor.
useLazyConnection()
: Specifies whether the application uses a lazy connection (a connection that OracleAS TopLink instantiates only when required).
setLazyConnection(boolean isLazy)
: Specifies a lazy connection.
dontUseLazyConnection()
: Creates an active connection.
If you request a database connection when none is available, the method waits for the next available connection, rather than time out or return an error.
Table 4-10 and Table 4-11 summarize the most common public methods for ClientSession
and ServerSession
. For more information about the available methods for ClientSession
and ServerSession
, see the Oracle Application Server TopLink API Reference.
Table 4-10 Elements for Client Session
Element | Method Name |
---|---|
Executing a query object | executeQuery(DatabaseQuery query, Vector parameters)
|
Reading from the database | readAllObjects(Class domainClass, Expression expression)
|
Release | release()
|
Unit of Work | acquireUnitOfWork()
|
You can use a session amendment class to configure the server session and database login in ways not available through the deployment descriptor file. For example, you can:
Specify special settings for the JDBC driver. For example, if you are working with an incompatible database driver, you can implement parameter binding, to enable a different data conversion routine.
Access regular OracleAS TopLink features, such as database connections or caching, directly.
Define custom finder queries on one or more OracleAS TopLink descriptors (under EJB 1.1).
Enable native SQL support if your JDBC bridge does not support the JDBC standard SQL syntax.
Enable binding and parameterized SQL, to specify whether values are inlined directly into the generated SQL or are parameterized.
Enable batch writing, forcing the application to send groups of insert, update, and delete statements to the database in a single batch.
Optimize data conversion.
Databases usually require a valid user name and password to log in successfully. OracleAS TopLink applications maintain this information in the DatabaseLogin
class. All sessions must have a valid DatabaseLogin
instance before logging in to the database.
For more information about the DatabaseLogin
, see "Database Session".
To customize an EJB 1.1 application, register a session listener class that extends oracle.toplink.sessions.SessionEventAdaptor
. Configure the listener to listen for various session events, such as pre_login
and post_commit_unit_of_work
. To register the OracleAS TopLink session, define the event_listener_class
tag in the toplink-ejb-jar.xml
file, as follows:
<session> <event_listener_class> oracle.toplink.ejb.cmp.demos.sessionlistener </event_listener_class> </session>
Under EJB 2.0, you can invoke the DeploymentCustomization
interface, which implements the oracle.toplink.ejb.cmp.DeploymentCustomization
interface. You must also specify any class that implements this interface in the toplink-ejb-jar.xml
file. If you specify a class, then OracleAS TopLink instantiates the class during deployment and runs the code provided by the class.
The DeploymentCustomization
interface defines the following methods:
public String beforeLoginCustomization(Session session) throws Exception; public String afterLoginCustomization(Session session) throws Exception;
These methods are invoked immediately before and after OracleAS TopLink logs into the database for the first time (during bean deployment).
Example 4-34 Using the beforeLoginCustomization() Method
public String beforeLoginCustomization(Session session) throws Exception{ session.getLogin().useBinding(); return "beforeLogin customization successful"; }
The class implementing the DeploymentCustomization
interface should have a zero argument constructor. OracleAS TopLink sends the returned strings from each of the methods to the console of the J2EE container.
Specify the fully qualified name of the class that you want to use for this purpose in the customization-class
element of the toplink-ejb-jar.xml
deployment descriptor.
Example 4-35 illustrates the project portion of the toplink-ejb-jar.xml
deployment descriptor that specifies a customization class
.
Example 4-35 Customization Class in the toplink-ejb-jar.xml File
<session> <name>EmployeeDemo</name> <project-class> oracle.toplink.demos.ejb.cmp.wls.employee.EmployeeProject.class </project-class> <login> <connection-pool>ejbPool</connection-pool> </login> <customization-class> oracle.toplink.demos.ejb.cmp.wls.employee.EmployeeCustomizer </customization-class> </session>
A database session is the simplest session OracleAS TopLink offers. The database session offers functionality for a single user and a single database connection.
A database session contains and manages the following information:
An instance of Project
and DatabaseLogin
, which stores database login and configuration information
The JDBC connection and the database access
The descriptors for each of the application persistent classes
Identity maps that maintain object identity and act as a cache
An application opens a database session by creating an instance of the DatabaseSession
class, and initializing the project with the appropriate database login parameters. After initialization, the session:
Registers the OracleAS TopLink descriptors (see "Registering Descriptors")
Connects to the database
Establishes the session cache
After you register the descriptors, use the DatabaseSession
class to connect to the database, using the login()
method. If the log in parameters in the DatabaseLogin
class are incorrect, or if the connection cannot be established, OracleAS TopLink throws a DatabaseException
.
After a connection is established, the application can use the session to access the database. To test the connection, invoke the isConnected()
method. If the connection works, that method returns TRUE.
To interact with the database, the application uses the session querying methods or executes query objects. The interactions between the application and the database are collectively known as the query framework. For more information about querying, see Chapter 6, "Queries".
Although session query methods work well with database sessions, concurrency issues make the database session unsuited for three-tier applications.
To log out the session, use the logout()
method. To disconnect the session from the relational database and flush the session identity maps, call the logout()
method.
Because logging in to the database can be time-consuming, log out only when all database interactions are complete.
Applications that log out from the database do not have to reregister their descriptors if they log back in to the database.
Certain versions of Sybase JConnect prevent the execution of stored procedures with JDBC auto-commit. If you use OracleAS TopLink with a version of JConnect that causes this problem, use the handleTransactionsManuallyForSybaseJConnect()
method to handle the transactions manually.
To add transaction processing to a set of database operations:
At the start of the transaction set, call beginTransaction()
.
Specify a try-catch block that calls rollbackTransaction()
if a database exception is thrown.
At the end of the transaction set, call commitTransaction()
.
Note: The Unit of Work is already transaction bound and does not require these calls. |
Example 4-36 A Typical Manual Transaction
/** Update a group of employee records*/ void writeEmployees(Vector employees, Session session) { Employee employee; Enumeration employeeEnumeration = employees.elements(); try { session.beginTransaction(); while (employeeEnumeration.hasMoreElements()) { employee=(Employee) employeeEnumeration.nextElement(); session.writeObject(employee); } session.commitTransaction(); } catch (DatabaseException exception) { // If a database exception has been thrown, roll back the transaction. session.rollbackTransaction(); } }
Example 4-37 Creating a Session from an OracleAS TopLink Mapping Workbench Project
import oracle.toplink.tools.workbench.*; import oracle.toplink.sessions.* // Create the project object Project project = XMLProjectReader.read("C:\TopLink\example.xml"); DatabaseLogin loginInfo = project.getLogin(); loginInfo.setUserName("scott"); loginInfo.setPassword("tiger"); //Create a new instance of the session and login DatabaseSession session = project.createDatabaseSession(); try { session.login(); } catch (DatabaseException exception) { throw new RuntimeException("Database error occurred at login: " + exception.getMessage()); System.out.println("Login failed"); } /* Do any database interaction using the query framework, transactions or Units of Work */ ... // Log out when database interaction is over session.logout(); Creating and using a session from coded descriptors import oracle.toplink.sessions.*; //Create the project object. DatabaseLogin loginInfo = new DatabaseLogin(); loginInfo.useJDBCODBCBridge(); loginInfo.useSQLServer(); loginInfo.setDataSourceName("MS SQL Server"); loginInfo.setUserName("scott"); loginInfo.setPassword("tiger"); Project project = new Project(loginInfo); //Create a new instance of the session, register the descriptors, and login DatabaseSession session = project.createDatabaseSession(); session.addDescriptors(this.buildAllDescriptors()); try { session.login(); } catch (DatabaseException exception) { throw new RuntimeException("Database error occurred at login: " + exeption.getMessage()); System.out.println("Login failed"); } //Do any database interaction using the query framework, transactions or Units of Work ... //Log out when database interaction is over session.logout(); }
Table 4-12 summarizes the most common public methods for the DatabaseSession
class. For more information about the available methods for the DatabaseSession
class, see the Oracle Application Server TopLink API Reference.
Table 4-12 Elements for Database Session
Description | Method Name |
---|---|
Construction methods | Project.createDatabaseSession()
|
Log in to the database (Defaults to the user name and password from project login)
|
login()
|
Log out of the database | logout()
|
Execute predefined queries | executeQuery(String queryName)
|
Execute a query object | executeQuery(DatabaseQuery query)
|
Read from the database | readAllObjects(Class domainClass, Expression expression)
|
SQL logging (logging is off by default) | logMessages()
|
Debug | printIdentityMaps()
|
Transactions | beginTransaction()
|
Exception handlers (throw exceptions by default) | setExceptionHandler(ExceptionHandler handler)
|
JTA/JTS (Defaults to use JDBC transactions) | setExternalTransactionController(ExternalTransactionController controller)
|
Unit of Work | acquireUnitOfWork()
|
Write to the database | deleteObject(Object domainObject)
|
OracleAS TopLink provides the session broker to enable multiple database access. Use the session broker to access objects that are stored on multiple databases. The session broker:
Provides transparent multiple database access through a single OracleAS TopLink session
Enables objects to reference objects on other databases
Transparently manages new object storage in a multiple database environment
Manages single Unit of Work and transaction across multiple databases
Supports two-phase commit when integrated with a JTA-compliant driver; otherwise, uses a two-stage algorithm
The session broker is a powerful tool that enables you to use data that is split across multiple databases for a given application. An alternative to the session broker is to use multiple sessions to work with multiple databases:
If the data on each database is unrelated to data on the other databases, and relationships do not cross database boundaries, then you can create a separate session for each database. For example, you may have individual databases and associated sessions dedicated to each cost center.
This arrangement requires that you to manage each session manually and ensure that the class descriptors for your project reside in the correct session.
You can use additional sessions to house a regular batch job. In this case, you can create two or more sessions on the same database. In addition to the main session that supports client queries, you can create other sessions that support batch inserts at low-traffic times in your system. This enables you to maintain the client cache.
After the session broker is set up and logged in, it functions like a session, making multiple database access transparent. Because a session broker is more complex than a regular database session, it requires more work to create and configure.
To configure the session broker in the sessions.xml
file, configure sessions for use in the session broker, and then reference the sessions from within the session-broker
element. When the session manager instantiates the session broker, it also instantiates the referenced sessions.
For more information, see "session-broker Element".
Because the session broker references other sessions, configure these sessions before instantiating the session broker. Add all required descriptors to the session, but do not initialize the descriptor, or log the sessions in. The session broker manages these issues when you instantiate it.
After you configure a session, use the registerSession(String name, Session session)
method to register it with a SessionBroker
.
Example 4-38 Adding Sessions to a Session Broker
This code prepares and adds two sessions to a session broker.
Project p1 = ProjectReader.read(("C:\Test\Test1.project")); Project p2 = ProjectReader.read(("C:\Test\Test2.project")); /* modify the user name and password if they are not correct in the .project file */ p1.getLogin().setUserName("User1"); p1.getLogin().setPassword("password1"); p2.getLogin().setUserName("User2"); p2.getLogin().setPassword("password2"); DatabaseSession session1 = p1.createDatabaseSession(); DatabaseSession session2 = p2.createDatabaseSession(); SessionBroker broker = new SessionBroker(); broker.registerSession("broker1", session1); broker.registerSession("broker2", session2); broker.login();
When you call the login()
method on the session broker, the session broker logs in all contained sessions and initializes the descriptors in the sessions. After login, the session broker appears and functions as a regular session. OracleAS TopLink handles the multiple database access transparently.
Example 4-39 Writing to the Database
UnitOfWork uow = broker.acquireUnitOfWork(); Test test = (Test) broker.readObject(Test.class); Test testClone = uow.registerObject(test); . . . //change and manipulate the clone and any of its references . . . uow.commit(); //log out when finished broker.logout();
If you use a session broker, incorporate a JTA external transaction controller wherever possible. The external transaction controller provides a two-phase commit, which passes the SQL statements that are required to commit the transaction to the JTA driver. The JTA driver handles the entire commit process.
JTA guarantees that the transaction commits or rolls back completely, even if the transaction involves more than one database. If the commit to any one database fails, then all database transactions roll back. The two-phase commit is the safest method available to commit a transaction to the database.
Two-phase commit support requires integration with a JTA-compliant driver.
For more information about the JTA drivers, see "JTA".
If no JTA driver is available, then the session broker provides a two-stage commit algorithm. A two-stage commit differs from a two-phase commit because it guarantees data integrity only up to the point of the final commit of the transaction. If the SQL executes successfully on all databases, but the commit then fails on one database, only the database that experiences the commit failure rolls back.
Although unlikely, this scenario is possible. As a result, if your system does not include a JTA driver and you use a two-stage commit, build a mechanism into your application to deal with this type of potential problem.
The session broker operates in a seamless manner in a tree-tier environment. To use the session broker in a three-tier application, configure server sessions for the session broker.
Although you can configure your session broker in code, as illustrated in Example 4-40, we recommend you use the OracleAS TopLink Sessions Editor to specify a session broker in the sessions.xml
file.
For more information, see the Oracle Application Server TopLink Mapping Workbench User's Guide.
Example 4-40 Configuring a Session Broker in a Three-Tier Architecture in Java Code
Project p1 = ProjectReader.read(("C:\Test\Test1.project")) Project p2 = ProjectReader.read(("C:\Test\Test2.project")); /* Create Sessions for the SessionBroker */ Server sSession1 = p1.createServerSession(); Server sSession2 = p2.createServerSession(); /* Create the SessionBroker and assign the sessions to it */ SessionBroker broker = new SessionBroker(); broker.registerSession("broker1", sSession1); broker.registerSession("broker2", sSession2); broker.login();
When a three-tier session broker application uses server sessions to communicate with the database, clients require a client session to write to the database. Similarly, when you implement a session broker, the client requires a client session broker to write to the database.
A client session broker is a collection of client sessions, one from each server session associated with the session broker. When a client acquires a client session broker, the session broker collects one client session from each associated server session, and wraps the client sessions so that they appear as a single client session to the client application.
To request a client session broker, the client calls the acquireClientSessionBroker()
method.
Using the session broker is not the same as linking databases at the database level. If your database allows linking, use that functionality to provide multiple database access.
The session broker has the following limitations:
You cannot split multiple table descriptors across databases.
Each class must reside on only one database.
You cannot use joins through expressions across databases.
Many-to-many join tables and direct collection tables must reside on the same database as the source object.
Note: The "Advanced Use" section describes a workaround for this limitation. It uses an amendment to the descriptor. |
Many-to-many join tables and direct collection tables must be on the same database as the source object, because reading these tables requires a join that spans both databases. To get around this problem, use the setSessionName(String sessionName)
method on ManyToManyMapping
and DirectCollectionMapping
. This method indicates that the join table or direct collection table is on the same database as the target table.
Descriptor desc = session1.getDescriptor(Employee.class); ((ManyToManyMapping)desc.getObjectBuilder().getMappingForAttributeName("projects")).setSessionName("broker2");
DatabaseQuery
offers a similar method that supports nonobject queries.
Table 4-13 summarizes the most common public methods for SessionBroker
. For more information about the available methods for SessionBroker
, see the Oracle Application Server TopLink API Reference.
A remote session is a session that resides on the client. It communicates with a client session on the server, and the client session communicates with the server session on its behalf. Remote sessions handle , proxies, object identity, and the communication between the client and server layer.
Figure 4-9 Remote Session Model for a Three-tier Application
The remote session can also interact with a database session rather than a client session. The user sets this up on the server side.
When choosing between a client session and a database session, be aware that the database session is not suited to a distributed environment, because the database session enables only one user to interact with the database. However, if the remote session interacts with a client session, then multiple remote sessions can share a single database connection. The remote session also benefits from connection pooling.
Figure 4-10 Remote Session and a Database or a Client Session
The remote session model comprises of the following layers (also see Figure 4-11):
The application layer—a client side application talking to a remote session
The transport layer—a communication layer, RMI, or RMI-IIOP
The server layer—an OracleAS TopLink session communicating with a database
The request from the client application to the server travels down through the layers of a distributed system. A client that makes a request to the server session uses the remote session as a conduit to the server session. The client references the remote session, and the remote session forwards a request to the server session through the transport layer.
At runtime, the remote session builds its knowledge base by reading descriptors and mappings from the server side as they are needed. These descriptors and mappings are lightweight, because not all information is passed on to the remote session. The information needed to traverse an object tree and to extract primary keys from the given object is passed with the mappings and descriptors.
Figure 4-11 An Architectural Overview of the Remote Session
The application layer includes the application and the remote session. The remote session is a subclass of the session and maintains all the public protocols of the session, giving the appearance of working with the local database session.
The remote session maintains its own identity map and a hash table of all the descriptors read from the server. If the remote session can handle a request by itself, the request is not passed to the server. For example, a request for an object that is in the Remote session cache is processed by the remote session. However, if the object is not in the remote session cache, the request passes to the server session.
The transport layer is responsible for carrying the semantics of the invocation. It is a layer that hides all the protocol dependencies from the application and server layer.
The transport layer includes a remote connection that is an abstract entity through which all requests to the server are forwarded. Each remote session maintains a single remote connection that marshals and unmarshals all requests and responses on the client side.
The remote session supports communications over RMI and CORBA. It includes deployment classes and stubs for RMI, BEA WebLogic RMI, VisiBroker, OrbixWeb, BEA WebLogic EJB, and Oracle EJB.
The server layer includes a remote session controller dispatcher and a session. The remote session controller dispatcher marshals and unmarshals all responses and requests from the server side. This is a client side component.
The remote session controller dispatcher is an interface between the session and transport layers. It hides the specifics of the transport layer from the session.
The remote session represents a potential security risk, because it requires you to register a remote session controller dispatcher as a service that anyone can access. This can expose the entire database.
To reduce this threat, run a server manager as a service to hold the remote controller session dispatcher. All the clients must then communicate through the server manager, which implements the security model for accessing the remote session controller dispatcher.
On the client side, the user requests the remote session controller dispatcher. The manager returns a remote session controller dispatcher only if the user has access rights according to the security model built into the server manager.
To access the system, the remote session controller dispatcher on the client side creates a remote connection, and acquires a remote session from the remote connection. The API for the remote session is the same as for the session, and there is no user-visible difference between working on a session or a remote session.
Read queries are publicly available on the client side, but queries that modify objects must be performed using the Unit of Work.
Calling refresh methods on the remote session causes database reads, and may also cause cache updates if the data being refreshed is modified in the database. This can lead to poor performance.
To improve performance, configure refresh methods to run against the server session cache, by configuring the descriptor to always remotely refresh the objects in the cache on all queries. This technique ensures that all queries against the remote session refresh the objects from the server session cache, without the database access.
Cache hits on remote sessions still occur on read object queries based on the primary keys. If you want to avoid this, disable the remote session cache hits on read object queries based on the primary key.
Example 4-42 Refreshing on the Server Session Cache
// Get the PolicyHolder descriptor Descriptor holderDescriptor = remoteSession.getDescriptor(PolicyHolder.class); // Set refresh on the ServerSession cache holderDescriptor.alwaysRefreshCachedOnRemote(); // Disable remote cache hits, ensure all queries go to the ServerSession cache holderDescriptor.disableCacheHitsOnRemote();
The remote session supports indirection objects. An indirection object is a valueholder that can be invoked remotely on the client side. When invoked, the valueholder first checks to see if the requested object exists on the remote session. If not, then the associated valueholder on the server is instantiated to get the value that is then passed back to the client. Remote valueholders are used automatically; the code of the application does not change.
Remote session supports cursored streams, but not scrollable cursors.
For more information about enabling cursored streams, see "Java Streams".
Use a Unit of Work acquired from the remote session to modify objects on the database. A Unit of Work acquired from the remote session offers the user the same functionality as a Unit of Work acquired from the client session or the database session.
Example 4-43 and Example 4-44 demonstrate how to create a remote OracleAS TopLink session on a client that communicates with a remote session controller on a server that uses RMI. After creating the connection, the client application uses the remote session as it does with any other OracleAS TopLink session.
These examples assume that a class called RMIServerManager
exists on the server. It is not an OracleAS TopLink-enabled class. This class has a method that instantiates and returns an RMIRemoteSessionController
(an OracleAS TopLink server side interface).
Example 4-43 Client Acquiring RMIRemoteSessionController from Server
The client-side code gets a reference to the RMIServerManager
and uses this code to get the RMIRemoteSessionController
running on the server. The reference to the session controller is then used to create the RMIConnection
from which it acquires a remote session.
RMIServerManager serverManager = null; // Set the client security manager try { System.setSecurityManager(new RMISecurityManager()); } catch(Exception exception) { System.out.println("Security violation " + exception.toString()); } // Get the remote factory object from the Registry try { serverManager = (RMIServerManager) Naming.lookup("SERVER-MANAGER"); } catch (Exception exception) { System.out.println("Lookup failed " + exception.toString()); } // Start RMIRemoteSession on the server and create an RMIConnection RMIConnection rmiConnection = null; try { rmiConnection = new RMIConnection(serverManager.createRemoteSessionController()); } catch (RemoteException exception) { System.out.println("Error in invocation " + exception.toString()); } // Create a remote session which we can then use as a normal OracleAS TopLink Session Session session = rmiConnection.createRemoteSession();
Example 4-44 Server Creating RMIRemoteSessionController for Client
The RMIServerManager
uses this code to create and return an instance of an RMIRemoteSessionController
to the client. The controller sits between the remote client and the local OracleAS TopLink session.
RMIRemoteSessionController controller = null; try { /* Create instance of RMIRemoteSessionControllerDispatcher which implements RMIRemoteSessionController. The constructor takes an OracleAS TopLink session as a parameter */ controller = new RMIRemoteSessionControllerDispatcher (localTopLinkSession); } catch (RemoteException exception) { System.out.println("Error in invocation " + exception.toString()); } return controller;