PK
BzDoa«, mimetypeapplication/epub+zipPK BzD iTunesMetadata.plistX§ū
This chapter describes TopLink's support for Oracle Database Continuous Query Notification (CQN), which allows you to use caching with a shared database in JPA.
Note: Oracle Database Continuous Query Notification was also formerly known as Oracle Database Change Notification. |
This chapter contains the following sections:
Use Case
Users want to use a shared cache with their JPA application, however, external applications update the same database data, or the cache is in a clustered environment. The cache may retain stale data.
Solution
The Oracle database provides an API to allow applications to register for notification of database changes. TopLink supports registering with the Oracle database and processing database change events to invalidate changed objects in the shared cache
Components
Oracle 11gR2 (11.2) (or higher) database
TopLink 12c (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
EclipseLink library: eclipselink.jar
JDBC library: ojdbc6.jar
.
JPA library: persistence.jar
.
Sample
For sample files that illustrate the use of Continuous Query Notification and shared caching in an application that uses JPA, see "EclipseLink/Examples/JPA/DCN" in the EclipseLink documentation.
http://wiki.eclipse.org/EclipseLink/Examples/JPA/DCN
EclipseLink provides a shared (L2) object cache that can reduce database access for objects and their relationships. This cache is enabled by default which is normally not a problem, unless the contents of the database are modified directly by other applications, or by the same application on other servers in a clustered environment. This may result in stale data in the cache.
If the contents of the database are modified, then a mechanism is needed to ensure that the contents of the cache are synchronized with the database. That mechanism is provided by EclipseLink's support for Oracle Continuous Query Notification. CQN allows shared caching to be used in the JPA environment.
Note: For more information on the Oracle Database Continuous Query Notification feature, see "Using Continuous Query Notification (CQN)" in Oracle Database Development Guide. See also "Continuous Query Notification" in Oracle Database JDBC Developer's Guide. |
EclipseLink supports registering with Oracle Database Continuous Query Notification to receive events from the database when the contents of a table changes. To detect changes, CQN uses the ROWID
to inform of row level changes in the primary table. EclipseLink includes the ROWID
in all queries for a CQN-enabled class. EclipseLink also selects the object's ROWID
after an insert operation. EclipseLink maintains a cache index on the ROWID
, in addition to the object's Id
. EclipseLink also selects the database transaction ID once for each transaction to avoid invalidating the cache on the server that is processing the transaction.
EclipseLink is enabled through the OracleChangeNotificationListener
(org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener
) listener class. This listener integrates with Oracle JDBC to receive database change events. To enable the listener, specify the full path to the OracleChangeNotificationListener
class as the value of the eclipselink.cache.database-event-listener
property in the persistence.xml
file.
By default, all entities in the domain are registered for change notification. However, you can selectively disable change notification for certain classes by tagging them in the Java files with the databaseChangeNotificationType
(org.eclipse.persistence.annotations.DatabaseChangeNotificationType
) attribute of the Cache
annotation. The value of this attribute determines the type of database change notification an entity should use. The default value of the databaseChangeNotificationType
attribute is Invalidate
. To disable change notification for a class, set the value of the attribute to None
.
The databaseChangeNotificationType
attribute is relevant only if the persistence unit has been configured with a database event listener, such as the OracleChangeNotificationListener
class, that receives database change events. This allows the EclipseLink cache to be invalidated or updated from database changes.
Oracle strongly suggests that you use optimistic locking (writes on stale data will fail and automatically invalidate the cache) in your transactions. If you include an @Version
annotation in your entity, then the version column in the primary table will always be updated, and the object will always be invalidated.
This section contains the following tasks to enable shared caching in a JPA environment:
The solution presumes that you are working with an Oracle 11gR2 (11.2) or higher database that contains the tables that you are interested in.
Among other permissions, the database user must be granted the CHANGE
NOTIFICATION
privilege. To do this, you must have a DBA privilege, such as SYS
, or have your database administrator apply it:
grant change notification to
user
The following example illustrates granting the change notification privilege to user SCOTT
.
...
define user="SCOTT"
define pass="tiger"
grant create session, alter session to &&user
/
grant resource, connect to &&user
/
grant select any dictionary to &&user
/
grant select any table to &&user
/
grant change notification to &&user
/
...
Ensure that the eclipselink.jar
EclipseLink library, the ojdbc6.jar
JDBC library, the persistence.jar
JPA library, and the domain classes are present on the classpath.
By default, all entities in the domain will participate in change notification. There are several different ways to limit the entities that will participate. For example, the entity classes can be indicated by the <entity class...>
element in the orm.xml
file, indicated with the <exclude-unlisted-classes>
element in the persistence.xml
file, or contained in a JAR file.
Note: The |
Entity classes can also be excluded by using a Cache
annotation attribute in the Java files. For more information, see Section 22.2.6.2, "Exclude Classes from Change Notification (Optional)."
Another way to identify the entity classes is to use the <class>
element in the persistence.xml
file. The following example indicates that the Order
, OrderLine
, and Customer
classes in the model
package will participate in change notification. For an example of a complete persistence.xml
file, see Example 22-1.
... <class>model.Order</class> <class>model.OrderLine</class> <class>model.Customer</class> ...
Use the eclipselink.cache.database-event-listener
property to identify the database event listener. The org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener
class is the listener for Continuous Query Notification. This allows the EclipseLink cache to be invalidated by database events.
The following example illustrates the eclipselink.cache.database-event-listener
property configured with the OracleChangeNotificationListener
class. For an example of a complete persistence.xml
file, see Example 22-1.
... <properties> <property name="eclipselink.cache.database-event-listener" value="org.eclipse.persistence.platform.database.oracle.dcn.OracleChangeNotificationListener"/> </properties> ...
Note that you can also use:
<property name="eclipselink.cache.database-event-listener" value="DCN">
Example 22-1 illustrates an example of a complete persistence.xml
file. The classes that will participate in change notification are the Order
, OrderLine
, and Customer
classes from the model
package. The eclipselink.cache.database-event-listener
property is set to the full path of the OracleChangeNotificationListener
class.
Note: A |
Example 22-1 Sample persistence.xml File
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd" version="2.0"> <persistence-unit name="acme" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>model.Order</class> <class>model.OrderLine</class> <class>model.Customer</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="eclipselink.cache.database-event-listener" value="DCN"/> </properties> </persistence-unit> </persistence>
Typically, to participate in change notification, no changes are needed to the Java classes which correspond to database tables. However, setting optimistic locking with the @Version
annotation is strongly suggested.
If you want to exclude classes that are listed in the persistence unit, you can tag them in the Java files. EclipseLink tracks changes only to the primary table. If you want changes to secondary tables to also be tracked, you can indicate this in the Java files.
Oracle strongly suggests that you use optimistic locking: writes on stale data will fail and automatically invalidate the cache. Include an @Version
annotation in your entity; the version column in the primary table will always be updated, and the older version of the object will always be invalidated.
In Example 22-2 the @Version
annotation is defined for the entity Customer
. Note that getters and setters are defined for the version
variable.
Example 22-2 Defining the @Version Annotation
... @Entity @Table(name="DBE_CUSTOMER") public class Customer implements Serializable { @Id @GeneratedValue(generator="CUST_SEQ") @TableGenerator(name="CUST_SEQ") @Column(name="CUST_NUMBER") private long id;@Version
private long version;
...public long getVersion()
{return version;
}public void setVersion(long version) {
this.version = version;
} ...
Use the databaseChangeNotificationType
attribute of the Cache
annotation to identify the classes for which you do not want change notifications. To exclude a class from change notification, set the attribute to DatabaseChangeNotificationType.NONE
, as illustrated in the following example.
...
@Entity
@Cache(databaseChangeNotificationType=DatabaseChangeNotificationType.NONE)
public class Order {
...
EclipseLink tracks changes only to the primary table. If any updates occur in a secondary table, EclipseLink will not invalidate the object. If you want changes to secondary tables to be tracked as well, add the @Version
annotation to the entity.
CQN listens only for events from the primary table. It does not track changes in secondary tables, or relationships tables. The reason for this is that Oracle CQN only tracks the ROWID
, so there is no correlation from the ROWID
of the primary, secondary and relationship tables. Thus, to receive events when a secondary or relationship table changes, the version in the primary table must change so that the event is returned.
EclipseLink's support for Continuous Query Notification has the following limitations:
Changes to an object's secondary tables will not trigger them to be invalid unless a @Version
annotation is used and updated in the primary table.
Changes to an object's OneToMany
, ManyToMany
, and ElementCollection
relationships will not trigger it to be invalid, unless an @Version
annotation is used and updated in the primary table.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
"Using Continuous Query Notification (CQN)" in Oracle Database Development Guide.
"Continuous Query Notification" in Oracle Database JDBC Developer's Guide.
"EclipseLink/Examples/JPA/DCN"āThis page describes an example of cache sharing in a JPA environment that employs DCN. Sample files and instructions for running the example are included. See the EclipseLink documentation:
This chapter describes how to use Oracle TopLink as the persistence provider for applications deployed to JBoss Application Server 7.1.
This chapter contains the following sections:
Use Case
TopLink can be used with a number of popular Java EE application servers, including JBoss Application Server.
Solution
Configure JBoss to use EclipseLink runtime, and deploy applications developed using EclipseLink APIs.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
JBoss Application Server 7.x.
A compliant Java Database Connectivity (JDBC) database, such as Oracle Database, Oracle Express, MySQL, the HSQL database embedded in JBoss Application Server, etc.
JBoss Application Server implements the Java Platform, Enterprise Edition (Java EE). JBoss 7 fully supports Java EE 6, while JBoss 6 officially supports only the Java EE 6 Web Profile.
By configuring JBoss to support EclipseLink, you can take advantage of EclipseLink's full support for Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), including EclipseLink's extensions to those technologies, as well as EclipseLink Database Web Services (DBWS) to access to relational database artifacts via a Web service.
To develop, deploy and run EclipseLink applications in JBoss Application Server 7, you must create EclipseLink as a module of JBoss. You must also create other modules, such as a JDBC driver, etc., in order to run applications.
This section contains the following tasks for using EclipseLink with JBoss 7.1:
Ensure that you have installed the following components:
JBoss, version 7 or later. These instructions are based on JBoss release 7.1.1.
Download JBoss from http://www.jboss.org/jbossas/downloads/
. The version of JBoss must be identified as "Certified Java EE6." Version 7.1.1 or later is recommended.
TopLink 12c Release 1 (12.1.2) or later.
Download TopLink from http://www.oracle.com/technetwork/middleware/toplink/downloads/index.html
.
Any compliant Java Database Connectivity (JDBC) database including Oracle Database, Oracle Express, MySQL, the HSQL database embedded in JBoss Application Server, and so on.
Note: Oracle XML DB (XDB) and JBoss Application Server both use port |
For the Oracle Database, see http://www.oracle.com/technetwork/database/enterprise-edition/overview/index.html
. For the Oracle Database, Express Edition, see http://www.oracle.com/technetwork/database/express-edition/overview/index.html
. For MySQL, see http://www.oracle.com/us/products/mysql/index.html
. For information about the embedded HSQL database, see the JBoss documentation.
While it is not required, you may want to use a Java development environment (IDE) for convenience during development. For example JDeveloper, Oracle Enterprise Pack for Eclipse, and NetBeans all provide sophisticated Java EE development tools that support TopLink.
For JDeveloper, see http://www.oracle.com/technetwork/developer-tools/jdev/downloads/index.html
. For Oracle Enterprise Pack for Eclipse, see http://www.oracle.com/technetwork/developer-tools/eclipse/overview/index.html
. For NetBeans, see http://www.oracle.com/us/products/tools/050845.html
.
To configure EclipseLink as a module in JBoss:
Create a directory as follows:
JBOSS_ HOME
\modules\org\eclipse\persistence\main
Copy eclipselink.jar
to the directory created in step 1. (The eclipselink.jar
file is located in the oracle_common\modules\oracle.toplink_
ver_no
directory created by the TopLink quick installer.)
Create a module.xml
file in the directory created in step 1, with the following content:
<module xmlns="urn:jboss:module:1.1" name="org.eclipse.persistence"> <resources> <resource-root path="eclipselink.jar"/> <!-- Insert resources here --> </resources> <dependencies> <module name="javax.api"/> <module name="javax.persistence.api"/> <module name="javax.transaction.api"/> <module name="javax.validation.api"/> <module name="javax.xml.bind.api"/> <module name="org.antlr"/> <module name="org.apache.commons.collections"/> <module name="org.dom4j"/> <module name="org.javassist"/> <module name="org.jboss.logging"/> <module name="com.oracle.ojdbc6"/> </dependencies> </module>
Add the Oracle thin driver ojdbc6.jar
as a module within JBoss, as follows:
Create the module directory:
JBOSS_ HOME
\modules\com\oracle\ojdbc6\main
Copy ojdbc6.jar
to the module directory created in step 1.
Create a module.xml
file in the module directory created in step 1, with the following contents:
<module xmlns="urn:jboss:module:1.1" name="com.oracle.ojdbc6"> <resources> <resource-root path="ojdbc6.jar"/> <!-- Insert resources here --> </resources> <dependencies> <module name="javax.api"/> </dependencies> </module>
Create the driver definition and create the data source.
The following instructions tell how to configure JBoss for running in standalone mode, using the standalone.xml
configuration file. For instructions on how to use domain.xml
to configure JBoss for running in domain mode, see the JBoss documentation.
In the standalone configuration file JBOSS_ HOME
\standalone\configuration\standalone.xml
, find the following:
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
In that section, configure the data source. The following example shows a configuration for the Oracle Database, using the Oracle JDBC Thin driver. For instructions on configuring other data sources, see the JBoss documentation.
<subsystem xmlns="urn:jboss:domain:datasources:1.0"> <datasources> <datasource jndi-name="java:/EclipseLinkDS" pool-name="EclipseLinkDS" enabled="true" jta="true" use-java-context="true" use-ccm="true"> <connection-url>jdbc:oracle:thin:node_name.example.com:1521:TOPLINK</connection-url> <driver>oracle</driver> <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation> <pool> <prefill>true</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>Smith</user-name> <password>password</password> </security> </datasource> <driver name="oracle" module="com.oracle.ojdbc6"> <xa-datasource-class>oracle.jdbc.OracleDriver</xa-datasource-class> </driver> </datasources> </subsystem>
Starting with JBoss Application Server 7.1, you must create an Application User to get started, because remote access to the JNDI tree is secured by default, and you must provide login credentials. Therefore, at a minimum, you just create an Application User to be able to deploy an application to the server. If you want to use the JBoss administration console for administration tasks, for example to view the JNDI tree, you must also create an Administration User.
To create user credentials, use the JBoss add-user.bat
utility, located in JBOSS_HOME
\bin\
.
For more information about security in JBoss Application Server, refer to the JBoss documentation.
Modify JBoss properties, as follows:
## JBoss-7.x server.factory=org.jboss.naming.remote.client.InitialContextFactory java.naming.factory.url.pkgs=org.jboss.ejb.client.naming server.depend=jboss-client.jar jboss.server=${jboss.home}/standalone server.lib=${jboss.home}/bin/client server.url=remote://localhost:4447 server.user=usera server.pwd=passworda jboss.naming.client.ejb.context=true
Add junit.jar
in the ear
under the \lib
directory.
Because of a classloading issue in JBoss, you must list all your entity classes in persistence.xml
. You can use either <class>
elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes>
element.
Add both jndi.properties
and jboss-ejb-client.properties
in the client classpath.
Start JBoss by running standalone.bat
(for a single-server configuration) or domain.bat
file (in a clustered environment) in JBOSS_ HOME
\bin\
.
For information on different ways to configure and start JBoss, see the JBoss documentation.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
JBoss Community at http://www.jboss.org
.
This chapter describes Oracle TopLink performance features, provided by EclipseLink, and how to monitor and optimize EclipseLink-enabled applications.
This chapter contains the following sections:
Use Case
Users want to improve the performance of their TopLink-enabled application.
Solution
TopLink provides many configuration options that can improve performance, such as caching. In addition, there are ways to improve the performance of specific functions, such as using Join Fetching for queries.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
Sample
See the following EclipseLink samples for related information:
EclipseLink includes a number of performance features that make it the industry's best performing and most scalable JPA implementation. These features include:
The EclipseLink cache is an in-memory repository that stores recently read or written objects based on class and primary key values. The cache helps improve performance by holding recently read or written objects and accessing them in-memory to minimize database access.
Caching allows you to:
Set how long the cache lives and the time of day, a process called cache invalidation.
Configure cache types (Weak, Soft, SoftCache, HardCache, Full) on a per entity basis.
Configure cache size on a per entity basis.
Coordinate clustered caches.
EclipseLink defines these entity caching annotations:
@Cache
@TimeOfDay
@ExistenceChecking
EclipseLink also provides a number of persistence unit properties that you can specify to configure the EclipseLink cache (see "Persistence Property Extensions Reference" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink). These properties might compliment or provide an alternative to the usage of annotations.
EclipseLink uses identity maps to cache objects in order to enhance performance, as well as maintain object identity. You can control the cache and its behavior by using the @Cache
annotation in your entity classes. Example 18-1 shows how to implement this annotation.
Example 18-1 Using the @Cache Annotation
@Entity @Table(name="EMPLOYEE") @Cache ( type=CacheType.WEAK, isolated=false, expiry=600000, alwaysRefresh=true, disableHits=true, coordinationType=INVALIDATE_CHANGED_OBJECTS ) public class Employee implements Serializable { ... }
For more information about object caching and using the @Cache
annotation, see "@Cache" in the Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
The scope of a query, the amount of data returned, and how that data is returned can all affect the performance of a EclipseLink-enabled application. EclipseLink query mechanisms enhance query performance by providing these features:
This section describes how these features improve performance.
EclipseLink uses the eclipselink.read-only
hint, QueryHint
(@QueryHint
) to retrieve read-only results back from a query. On nontransactional read operations, where the requested entity types are stored in the shared cache, you can request that the shared instance be returned instead of a detached copy.
For more information about read-only queries, see the documentation for the read-only hint in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Join Fetching enhances performance by enabling the joining and reading of the related objects in the same query as the source object. Enable Join Fetching by using the @JoinFetch
annotation, as shown in Example 18-2. This example shows how the @JoinFetch
annotation specifies the Employee
field managedEmployees
.
Example 18-2 Enabling JoinFetching
@Entity
public class Employee implements Serializable {
...
@OneToMany(cascade=ALL, mappedBy="owner")
@JoinFetch(value=OUTER)
public Collection<Employee> getManagedEmployees() {
return managedEmployees;
}
...
}
For more details on Join Fetching, see "@JoinFetch" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
The eclipselink.batch
hint supplies EclipseLink with batching information so subsequent queries of related objects can be optimized in batches instead of being retrieved one-by-one or in one large joined read. Batch reading is more efficient than joining because it avoids reading duplicate data. Batching is only allowed on queries that have a single object in their select clause.
If you have large queries that return a large number of objects you can improve performance by reducing the number database hits required to satisfy the selection criteria. To do this, use the The eclipselink.jdbc.fetch-size
hint. This hint specifies the number of rows that should be fetched from the database when more rows are required (depending on the JDBC driver support level). Most JDBC drivers default to a fetch size of 10, so if you are reading 1000 objects, increasing the fetch size to 256 can significantly reduce the time required to fetch the query's results. The optimal fetch size is not always obvious. Usually, a fetch size of one half or one quarter of the total expected result size is optimal. Note that if you are unsure of the result set size, incorrectly setting a fetch size too large or too small can decrease performance.
Slow paging can result in significant application overhead; however, EclipseLink includes a variety of solutions for improving paging results; for example, you can:
Configure the first and maximum number of rows to retrieve when executing a query.
Perform a query on the database for all of the ID values that match the criteria and then use these values to retrieve specific sets.
Configure EclipseLink to return a ScrollableCursor
object from a query by using query hints. This returns a database cursor on the query's result set and allows the client to scroll through the results page by page.
For details on improving paging performance, see "How to use EclipseLink Pagination" in the EclipseLink online documentation, at:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Pagination#How_to_use_EclipseLink_Pagination
EclipseLink uses a shared cache mechanism that is scoped to the entire persistence unit. When operations are completed in a particular persistence context, the results are merged back into the shared cache so that other persistence contexts can use them. This happens regardless of whether the entity manager and persistence context are created in Java SE or Java EE. Any entity persisted or removed using the entity manager will always be kept consistent with the cache.
You can specify how the query should interact with the EclipseLink cache by using the eclipselink.cache-usage
hint. For more information, see "cache usage" in tJava Persistence API (JPA) Extensions Reference for Oracle TopLink.
Mapping performance is enhanced by these features:
This section describes these features.
When you declare a class read-only, clones of that class are neither created nor merged greatly improving performance. You can declare a class as read-only within the context of a unit of work by using the addReadOnlyClass()
method.
To configure a read-only class for a single unit of work, specify that class as the argument to addReadOnlyClass()
:
myUnitofWork.addReadOnlyClass(B.class);
To configure multiple classes as read-only, add them to a vector and specify that vector as the argument to addReadOnlyClass()
:
myUnitOfWork.addReadOnlyClasses(myVectorOfClasses);
For more information about using read-only objects to enhance performance, see "@ReadOnly" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Weaving is a technique of manipulating the byte-code of compiled Java classes. The EclipseLink JPA persistence provider uses weaving to enhance both JPA entities and Plain Old Java Object (POJO) classes for such things as lazy loading, change tracking, fetch groups, and internal optimizations.Weaving can be performed either dynamically at runtime, when entities are loaded, or statically at compile time by post-processing the entity .class
files. By default, EclipseLink uses dynamic weaving whenever possible. This includes inside an Java EE 5/6 application server and in Java SE when the EclipseLink agent is configured. Dynamic weaving is recommended as it is easy to configure and does not require any changes to a project's build process
For details on how to use weaving to enhance application performance, see "weaving" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
To optimize performance during data transactions, use change tracking,. Change tracking allows you to tune the way EclipseLink detects changes that occur during a transaction. You should choose the strategy based on the usage and data modification patterns of the entity type as different types may have different access patterns and hence different settings, and so on.
Enable change tracking by using the @ChangeTracking
annotation, as shown in Example 18-3.
Example 18-3 Enabling Change Tracking
@Entity
@Table(name="EMPLOYEE")
@ChangeTracking(OBJECT) (
public class Employee implements Serializable {
...
}
For more details on change tracking, see "@ChangeTracking" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Database performance features in EclipseLink include:
This section describes these features.
Establishing a connection to a data source can be time-consuming, so reusing such connections in a connection pool can improve performance. EclipseLink uses connection pools to manage and share the connections used by server and client sessions. This feature reduces the number of connections required and allows your application to support many clients.
By default, EclipseLink sessions use internal connection pools. These pools allow you to optimize the creation of read connections for applications that read data only to display it and only infrequently modify data. The also allow you to use Workbench to configure the default (write) and read connection pools and to create additional connection pools for object identity or any other purpose.
In addition to internal connection pools, you can also configure EclipseLink to use any of these types of connection pools:
External connection pools; you must use this type of connection pool to integrate with external transaction controller (JTA).
Default (write) and read connection pools;
Sequence connection pools; Use these types of pools when your application requires table sequencing (that is, non-native sequencing) and you are using an external transaction controller. Application-specific connection pools; These are connection pools that you can create and use for any application purpose, provided you are using internal EclipseLink connection pools in a session.
For more information about using connection pools with EclipseLink, see the following topics in Understanding Oracle TopLink:
"Understanding Connections"
"Understanding Connection Pools"
Parameterized SQL can prevent the overall length of an SQL query from exceeding the statement length limit that your JDBC driver or database server imposes. Using parameterized SQL along with prepared statement caching can improve performance by reducing the number of times the database SQL engine parses and prepares SQL for a frequently called query
By default, EclipseLink enables parameterized SQL but not prepared statement caching. You should enable statement caching either in EclipseLink when using an internal connection pool or in the data source when using an external connection pool and want to specify a statement cache size appropriate for your application.
To enable parameterized SQL, add this line to the persistence.xml
file that is in the same path as your domain classes:
<property name="eclipselink.jdbc.bind-parameters" value="true"/>
To disable parameterized SQL, change value=
to false
.
For more information about using parameterized SQL and statement caching, see "jdbc.bind-parameters" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Batch writing helps optimize transactions with multiple write operations. Batch writing is enabled by using the EclipseLink JDBC extension batch-writing. You set one of the following parameter this property into the session at deployment time:
JDBC; Use JDBC batch writing.
Buffered; Do not use either JDBC batch writing nor native platform batch writing.
Oracle-JDBC; Use both JDBC batch writing and Oracle native platform batch writing and use OracleJDBC
in your property map.
None; Disable batch writing.
For more information about batch writing, see "jdbc.batch-writing" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
EclipseLink provides monitoring and optimization tools, as described in Section 18.2, "Monitoring and Optimizing EclipseLink-Enabled Applications".
The most important challenge to performance tuning is knowing what to optimize. To improve the performance of your application, identify the areas of your application that do not operate at peak efficiency. This section contains information about these subjects:
Task 1: Measure EclipseLink Performance with the EclipseLink Profiler
Task 2: Identify Sources of Application Performance Problems
EclipseLink provides a diverse set of features to measure and optimize application performance. You can enable or disable most features in the descriptors or session, making any resulting performance gains global.Performance considerations are present at every step of the development cycle. Although this implies an awareness of performance issues in your design and implementation, it does not mean that you should expect to achieve the best possible performance in your first pass.
For example, if optimization complicates the design, leave it until the final development phase. You should still plan for these optimizations from your first iteration, to make them easier to integrate later.
The most important concept associated with tuning your EclipseLink application is the idea of an iterative approach. The most effective way to tune your application is to do the following tasks:
The EclipseLink performance profiler helps you identify performance problems by logging performance statistics for every executed query in a given session.
The EclipseLink performance profiler logs the following information to the log file.
Table 18-1 Information Logged by the EclipseLink Performance Profiler
Information Logged | Description |
---|---|
Query Class |
Query class name. |
Domain Class |
Domain class name. |
Total Time |
Total execution time of the query, including any nested queries (in milliseconds). |
Local Time |
Execution time of the query, excluding any nested queries (in milliseconds). |
Number of Objects |
The total number of objects affected. |
Number of Objects Handled per Second |
How many objects were handled per second of transaction time. |
Logging |
the amount of time spent printing logging messages (in milliseconds). |
SQL Prepare |
The amount of time spent preparing the SQL script (in milliseconds). |
SQL Execute |
The amount of time spent executing the SQL script (in milliseconds). |
Row Fetch |
The amount of time spent fetching rows from the database (in milliseconds) |
Cache |
The amount of time spent searching or updating the object cache (in milliseconds) |
Object Build |
The amount of time spent building the domain object (in milliseconds) |
query Prepare |
the amount of time spent to prepare the query prior to execution (in milliseconds) |
SQL Generation |
the amount of time spent to generate the SQL script before it is sent to the database (in milliseconds) |
The EclipseLink performance profiler is an instance of org.eclipse.persistence.tools.profiler.PerformanceProfiler
class. To enable it, add the following line to the persistence.xml
file:
<property name="eclipselink.profiler" value="PerformanceProfiler.logProfiler"/>
In addition to enabling the EclipseLink profiler, The PerformanceProfiler
class public API also provides the functionality describes in Table 18-2:
Table 18-2 Additional PerformanceProfiler Functionality
To... | Use... |
---|---|
Disable the profiler |
|
Organize the profiler log into a summary of all the individual operation profiles including operation statistics like the shortest time of all the operations that were profiled, the total time of all the operations, the number of objects returned by profiled queries, and the total time that was spent in each kind of operation that was profiled |
|
Organize the profiler log into a summary of all the individual operation profiles by query |
|
Organize the profiler log into a summary of all the individual operation profiles by class. |
|
You can see profiling results by opening the profile log in a text reader, such as Notepad.
The profiler output file indicates the health of a EclipseLink-enabled application.
Example 18-4 shows an sample of the EclipseLink profiler output.
Example 18-4 Performance Profiler Output
Begin Profile of{ ReadAllQuery(com.demos.employee.domain.Employee) Profile(ReadAllQuery,# of obj=12, time=139923809,sql execute=21723809, prepare=49523809, row fetch=39023809, time/obj=11623809,obj/sec=8) } End Profile
Example 18-4 shows the following information about the query:
ReadAllQuery(com.demos.employee.domain.Employee)
: specific query profiled, and its arguments.
Profile(ReadAllQuery
: start of the profile and the type of query.
# of obj=12
: number of objects involved in the query.
time=139923809
: total execution time of the query (in milliseconds).
sql execute=21723809
: total time spent executing the SQL statement.
prepare=49523809
: total time spent preparing the SQL statement.
row fetch=39023809
: total time spent fetching rows from the database.
time/obj=116123809
: number of nanoseconds spent on each object.
obj/sec=8
: number of objects handled per second.
Areas of the application where performance problems could occur include the following:
Identifying General Performance Optimization
Schema
Mappings and Descriptors
Sessions
Cache
Data Access
Queries
Unit of Work
Application Server and Database Optimization
Task 3: Modify Poorly-Performing Application Components provides some guidelines for dealing with problems in each of these areas.
For each source of application performance problems listed in Section 18.2.3, "Task 2: Identify Sources of Application Performance Problems", you can try specific workarounds, as described in this section.
Avoid overriding EclipseLink default behavior unless your application requires it. Some of these defaults are suitable for a development environment; you should change these defaults to suit your production environment. These defaults may include:
Batch writing ā See "jdbc.batch-writing" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Statement caching ā See "jdbc.cache-statements" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Read and write connection pool size ā See "connection-pool" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Session cache size ā See "maintain-cache" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Use the Workbench rather than manual coding. These tools are not only easy to use: the default configuration they export to deployment XML (and the code it generates, if required) represents best practices optimized for most applications.
Optimization is an important consideration when you design your database schema and object model. Most performance issues occur when the object model or database schema is too complex, as this can make the database slow and difficult to query. This is most likely to happen if you derive your database schema directly from a complex object model.
To optimize performance, design the object model and database schema together. However, allow each model to be designed optimally: do not require a direct one-to-one correlation between the two.
Possible ways to optimize the schema include:
Aggregating two tables into one
Splitting one table into many
Using a collapsed hierarchy
Choosing one out of many
See "Data Storage Schema" in Understanding Oracle TopLink for additional information.
If you find performance bottlenecks in your mapping and descriptors, try these solutions:
Always use indirection (lazy loading). It is not only critical in optimizing database access, but also allows EclipseLink to make several other optimizations including optimizing its cache access and unit of work processing. See "cache-usage" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Avoid using method access in your EclipseLink mappings, especially if you have expensive or potentially dangerous side-effect code in your get or set methods; use the default direct attribute access instead. See "Using Method or Direct Field Access" in the Understanding Oracle TopLink.
Avoid using the existence checking option checkCacheThenDatabase on descriptors, unless required by the application. The default existence checking behavior offers better performance. See "@ExistenceChecking" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Avoid expensive initialization in the default constructor that EclipseLink uses to instantiate objects. Instead, use lazy initialization or use an EclipseLink instantiation policy to configure the descriptor to use a different constructor. See "@InstantiationCopyPolicy" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
You can often improve performance through caching, even in a clustered environment by implementing cache coordination. Cache coordination allows multiple, possibly distributed instances of a session to broadcast object changes among each other so that each session's cache can be kept up-to-date. For detailed information about optimizing cache behavior, see "Understanding Caching" in Understanding Oracle TopLink and the following examples:
Depending on the type of data source your application accesses, EclipseLink offers a variety of Login
options that you can use to tune the performance of low level data reads and writes. For optimizing higher-level data reads and writes, "Understanding Data Access" in Understanding Oracle TopLink offers several techniques to improve data access performance for your application. These techniques show you how to:
Optimize JDBC driver properties.
Optimize data format.
Use batch writing for optimization.
Use Outer-Join Reading with Inherited Subclasses.
Use Parameterized SQL (Parameter Binding) and Prepared Statement Caching for Optimization.
EclipseLink provides an extensive query API for reading, writing, and updating data. "Understanding EclipseLink Queries" in Understanding Oracle TopLink offers several techniques to improve query performance for your application. These techniques show you how to:
Use parameterized SQL and prepared statement caching for optimization.
Use named queries for optimization.
Use batch and join reading for optimization.
Use partial object queries and fetch groups for optimization.
Use read-only queries for optimization.
Use JDBC fetch size for optimization.
Use cursored streams and scrollable cursors for optimization.
Use result set pagination for optimization.
It also includes links to read and write optimization examples.
To optimize the application server and database performance, consider these techniques:
Configuring your application server and database correctly can have a big impact on performance and scalability. Ensure that you correctly optimize these key components of your application in addition to your EclipseLink application and persistence.
For your application or Java EE server, ensure your memory, thread pool and connection pool sizes are sufficient for your server's expected load, and that your JVM has been configured optimally.
Ensure that your database has been configured correctly for optimal performance and its expected load.
Finally, after identifying possible performance bottlenecks and taking some action on them, rerun your application, again with the profiler enabled (see Section 18.2.2.1, "Enabling the EclipseLink Profiler"). Review the results and, if more action is required, follow the procedures outlined in Section 18.2.4, "Task 3: Modify Poorly-Performing Application Components".
This chapter tells how to migrate applications using "native" TopLink object-relational mapping (ORM) APIs to the current EclipseLink APIs.
The EclipseLink libraries have been the core libraries in Oracle TopLink staring with TopLink 11g, Release 1 (11.1.1).
This chapter contains the following sections:
Use Case
A developer wants to upgrade an application that uses the older TopLink native ORM to use a current EclipseLink ORM implementation.
Solution
Follow the instructions in this chapter to upgrade the application.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
(Optional) EclipseLink Workbench.
"Native" TopLink ORM refers to the API, configuration files, and tools for object-relational mapping that evolved in TopLink before the Java Persistence API (JPA) standardized an object-relational mapping API. Full JPA support was introduced in Oracle TopLink 10g (10.1.3.1.0), via TopLink Essentials. However, native TopLink continued to be supported.
Prior to the TopLink 11g (11.1.1) release, Oracle contributed the TopLink source code--including TopLink JPA and native TopLink--to the Eclipse Foundation, where it was used to form the basis of the open-source EclipseLink persistence services project. Then, in TopLink 11g Release 1 (11.1.1), Oracle started to include EclipseLink in TopLink, providing TopLink's core functionality.
TopLink developers using TopLink versions 11.1.1.0.0 though 11.1.1.6.0 have access to native TopLink ORM in either the proprietary Oracle toplink.jar
or in the EclipseLink eclipselink.jar
. In toplink.jar
, the classes are in packages whose names start with oracle.toplink.*
. In eclipselink.jar
, those package names begin instead with org.eclipselink.persistence
.
Note: The |
You can migrate applications that use oracle.toplink.*
packages from toplink.jar
to use org.eclipselink.persistence.
packages from eclipselink.jar
. The application functionality remains the same, but migrating to eclipselink.jar
provides the most up-to-date code base. After migrating, you will have access to other TopLink features and will be better prepared to convert your application to use JPA or one of the other persistence services included in current versions of TopLink.
This chapter explains how to use the renaming tool that is packaged with stand-alone TopLink to easily change the package names in your application and how to perform other actions necessary to migrate to the current code base.
Note: Following the instructions in this chapter will update your application to use the current EclipseLink code base. Doing so retains the design and functionality of your application as originally implemented. However, these instructions do not describe how to convert a native TopLink-based application to use JPA or any of the other persistence services in current versions of TopLink. See the other TopLink documentation sources for that information. |
This section contains the following tasks:
Section 7.2.2, "Task 2: Replace Deprecated and Removed Native APIs"
Section 7.2.5, "Task 5: Convert Oracle TopLink Workbench Projects (Optional)"
TopLink 12c (12.1.2) or later.
All TopLink downloads starting with 11g include the renaming tool discussed in this chapter.
Note: The renaming tool is not included with embedded versions of TopLink, for example in Oracle WebLogic Server or Oracle Glassfish. You must download the standalone TopLink installer. |
Download TopLink from http://www.oracle.com/technetwork/middleware/toplink/downloads/index.html
. For installation instructions, see Chapter 2, "Installing Oracle TopLink.".
(Optional) EclipseLink Workbench. The EclipseLink Workbench is available in EclipseLink downloads. See the EclipseLink download page at http://www.eclipse.org/eclipselink/downloads/
.
APIs that were deprecated in releases before TopLink 11g Release 1 (11.1.1) were removed in EclipseLink and therefore are not included in current versions of TopLink. If your application uses any of those deprecated APIs or any APIs that were already replaced or removed from TopLink, you must update the application to use current APIs.
The following sections lists the replaced and removed APIs, with suggested substitutions:
Note: When suggested replacements are in |
The following tables list the APIs removed as of TopLink 11g Release 1 (11.1.1.1.). Use the replacement API listed in the tables.
Table 7-1 changetracking (oracle.toplink.descriptors.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
|
|
|
|
|
Table 7-2 databaseaccess (oracle.toplink.internal*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
|
Table 7-4 mappings (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
Table 7-5 objectrelational (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
|
Table 7-6 oraclespecific (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
.oraclespecific.TopLinkXMLType FootĀ 2Ā |
Whole class |
None |
FootnoteĀ 1Ā oracle.toplink.oraclespecific.Oracle9Specific
was moved to an internal package and renamed to oracle.toplink.internal.platform.database.oracle.Oracle9Specific
. The replacement public API for oracle.toplink.oraclespecific.Oracle9Specific
is oracle.toplink.platform.database.oracle.Oracle9Specific
.
FootnoteĀ 2Ā oracle.toplink.oraclespecific.TopLinkXMLType
was a miscellaneous class, which does not have a replacement API.
Table 7-7 publicinterface (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
|
Whole class |
|
FootnoteĀ 1Ā oracle.toplink.publicinterface.DatabaseSession
was moved to an internal package and renamed to oracle.toplink.internal.sessions.DatabaseSessionImpl
. The replacement public API for oracle.toplink.publicinterface.DatabaseSession
is oracle.toplink.sessions.DatabaseSession
.
FootnoteĀ 2Ā oracle.toplink.publicinterface.Session
was moved to an internal package and renamed to oracle.toplink.internal.sessions.AbstractSessionImpl
. The replacement public API for oracle.toplink.publicinterface.Session
is oracle.toplink.sessions.Session
.
FootnoteĀ 3Ā oracle.toplink.publicinterface.UnitOfWork
was moved to an internal package and renamed to oracle.toplink.internal.sessionl.UnitOfWorkImpl
. The replacement public API for oracle.toplink.publicinterface.UnitOfWork
is oracle.toplink.sessions.UnitOfWork
.
Table 7-9 entitymanager (oracle.toplink.sessions.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
All classes |
All methods |
JPA: see Section 7.2.2.4.1, "JPA Persistence Provider Implementation," |
Table 7-10 sessionconfiguration (oracle.toplink.tools.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
All methods |
None |
Table 7-11 xml (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole package |
|
|
Whole package |
|
|
Whole package |
. |
|
Whole package |
|
|
Whole package |
|
Table 7-12 XMLCommandConverter (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole class |
None |
|
Whole class |
None |
|
Whole class |
None |
|
"error_loading_resources" |
None |
|
"error_parsing_resources" |
None |
|
"unexpect_argument" |
None |
Table 7-13 Remote Protocols (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
Whole package |
None |
|
Whole package |
None |
|
Whole package |
None |
|
References for any of |
None |
|
References for any of |
None |
|
Whole class |
None |
|
Whole class |
None |
|
Whole class |
None |
|
References for any of |
None |
The following tables list the APIs deprecated in the releases prior to TopLink 11g Release 1 (11.1.1) and therefore removed in that release, due to the substitution of EclipseLink libraries. Use the replacement API indicated.
Note: Because deprecated classes and moved classes have the same name, you may get compile errors if you use |
Table 7-15 mappings (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
|
|
Table 7-16 descriptors (oracle.toplink.*)
Class Name | Method Name | Replacement APIs |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
The following classes were removed in the release prior to TopLink 11g Release 1 (11.1.1):
OTSTransactionController
OTSSynchronizationListener
OracleSequenceDefinition
(use SequenceObjectDefinition
instead)
TimeTenSequenceDefinition
(use SequenceObjectDefinition
instead)
Other API changes include the following:
Section 7.2.2.4.1, "JPA Persistence Provider Implementation."
Section 7.2.2.4.2, "Session Finalizers Disabled by Default."
Section 7.2.2.4.3, "Vector and Hashtable Return Types Changed to List or Map."
The persistence provider implementation in all TopLink releases since 11g (11.1.1) is packaged in eclipselink.jar
. It replaces all previous implementations, for example:
toplink.jar
toplink-essentials.jar
In TopLink 11g (11.1.1) Technology Preview 3, session finalizers were disabled by default to improve performance. To enable session finalizers, use Session method setIsFinalizersEnabled(true).
Any Session
or ClassDescriptor
method that returns Vector
or Hashtable
will eventually be changed to return List
or Map
, respectively. To prepare for this change, cast Vector
and Hashtable
return types to List
or Map
, respectively. For example, although the Javadoc for ClassDescriptor
method getMappings
is java.util.Vector
, you should cast the returned value to List
:
List mappings = (List) descriptor.getMappings();
Other changes that now return Map
include the following:
ClassDescriptor.getQueryKeys()
ClassDescriptor.getProperties()
DescriptorQueryManager.getQueries()
EISInteraction.getProperties()
Session.getProperties()
Session.getQueries()
getAttributesToAlwaysInclude()
getSpecialOperations()
getValuesToExclude()s
Starting with TopLink 11g, Release 1 (11.1.1), all EclipseLink libraries are included in TopLink. EclipseLink provides the core TopLink functionality, which now includes support for JPA 2.x, JAXB, and other standards-based persistence services, as well as extensions to those standards. In addition, TopLink continues to support native TopLink APIs; however, all oracle.toplink.*
packages are now renamed to org.eclipse.persistence.*
.
To migrate your application to use the new code base, you must rename the packages in your code. To facilitate this, a package renamer tool is included with the TopLink installation. Use this tool on all of the following:
project source code
project.xml
file
persistence.xml
file
sessions.xml
file
The package renamer is located in the toplink_install_directory
\toplink\utils\rename
directory. Windows and UNIX/LINUX scripts are included.
To run the package renamer using the scripts, do the following:
Find the packageRename.cmd
(Windows) and packageRename.sh
(UNIX/LINUX) scripts in toplink_install_directory
\toplink\utils\rename
directory.
Run either packageRename.cmd
or packageRename.sh
with the following arguments:
sourceLocation
- The directory containing the files to rename.
targetLocation
- The destination directory for the renamed files. The package renamer removes any existing Java and XML files, so it is advisable to specify an empty directory.
For example:
packageRename c:/mySourceLocation c:/myDestinationLocation
The package renamer performs a recursive directory search for Java and XML files to rename. The renamed version of each file is saved in the corresponding directory in the target location
The package renamer can rename TopLink XML configuration files, but depending on the type of file, you may need to make additional changes.
You can continue to use sessions.xml
files as is. For a more forward-compatible solution, run the renamer on your sessions.xml
files.
Deployment XML files from TopLink 10.1.3 and above can be read by TopLink 11.1.1 and later. You can continue to use those files or for a more forward compatible solution, run the renamer on these files and replace the version string in the "XML Header" with the following:
"Eclipse Persistence Services"
To use TopLink as a persistence provider, you must run the renamer on your persistence.xml
files. The renamer updates the persistence provider to be EclipseLink and also update any native TopLink specific properties to the EclipseLink equivalent.
In releases prior to TopLink 11g Release 1 (11.1.1), a graphical editing tool called Oracle TopLink Workbench was available for configuring descriptors and mapping your project. That tool is no longer available from Oracle, but a comparable tool, the EclipseLink Workbench is available from the Eclipse Foundation. You can convert old TopLink Workbench projects into EclipseLink Workbench projects and then use the output in current Oracle TopLink applications. You can also import Workbench projects into Oracle JDeveloper.
Note: EclipseLink Workbench is open-source software and is therefore not supported by Oracle. |
To convert Oracle TopLink Workbench (.mwp
) project to an EclipseLink Workbench project:
Use the package renamer (as described above) to migrate your Oracle TopLink Workbench project source.
Open the Oracle TopLink Workbench project with EclipseLink Workbench.
EclipseLink Workbench detects the project and displays a message asking if you want to save in the current version of the Workbench.
Click Save Now and select a new directory location in which to save the project.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
The following topics introduce the new and changed features of Oracle TopLink and other significant changes that are described in this guide, and provides pointers to additional information. This book is the new edition of the formerly titled Solution Guide for Oracle TopLink.
Oracle TopLink 12c (12.1.2) includes the following new and changed features that are documented in this book. This list does not necessarily include all new or changed features in this release. It only includes the new features that are documented in this book.
Quick installer, which installs TopLink into a location of your choice, including over an existing Oracle home. See Chapter 2, "Installing Oracle TopLink."
Client isolation, where multiple application tenants may share database tables and schemas. This allows applications to manage entities for multiple tenants in the same application. See Chapter 14, "Tenant Isolation Using TopLink."
JSON bindings, for converting objects directly to and from JavaScript Object Notation (JSON). This can be useful when creating RESTful services, using JSON messages with Java API for RESTful Web Services (JAX-RS) services. See Chapter 16, "Converting Objects to and from JSON Documents,"
RESTful persistence, where Java Persistence API (JPA) entities can be exposed through standards-based RESTful services such as JAX-RS, using either JSON or XML media. See Chapter 20, "Exposing JPA Entities Through RESTful Data Services."
TopLink Live Data queries ("live queies"), where live queries track changes to the backing data store. See Chapter 21, "Keeping Data Fresh Using TopLink Live Data Queries."
Support for Oracle Database Continuous Query Notification (CQN),, which allows the database to notify TopLink of database changes so that cached objects can be invalidated in the shared cache. See Chapter 22, "Using Database Events to Invalidate the Cache."
NoSQL database support, allowing objects to be mapped to non-relational (NoSQL) data sources. See Chapter 23, "Using TopLink with NoSQL Databases,".
For a complete list of the changes in this release, see http://www.oracle.com//toplink/
.
For 12c (12.1.2), this guide has been updated in several ways. Following are the sections that have been added or changed.
Moved installation information from appendix to Chapter 2, "Installing Oracle TopLink," and replaced old information with information about the new quick installer.
Added new chapter, Chapter 5, "Using TopLink with JBoss 7 Application Server," to describe how TopLink can be used with applications deployed to JBoss Application Server 7.1.
Added new chapter, Chapter 6, "Using TopLink with IBM WebSphere Application Server," to describe how TopLink can be used with applications deployed to IBM WebSphere Application Server
Added new chapter, Chapter 7, "Migrating from Native TopLink," to describe migrate applications using "native" TopLink object-relational mapping (ORM) APIs to the current EclipseLink APIs, which have been the core libraries in TopLink staring with TopLink 11g, Release 1 (11.1.1).
Added information about data partitioning in Chapter 10, "Scaling Applications in Clusters."
Split Chapter 11, "Providing Software as a Service." into four chapters:
Chapter 11, "Providing Software as a Service." This is now just an overview of the following three chapters.
Chapter 14, "Tenant Isolation Using TopLink" and also updated this chapter with information about Virtual Private Database (VPD) multi-tenancy and table-per-tenant multi-tenancy
Added new chapter, Chapter 16, "Converting Objects to and from JSON Documents," to describe how to convert objects directly to and from JSON
Added information about weaving to Chapter 17, "Testing JPA Outside a Container," to describe how to use the persistence unit JAR file to test an application outside theĀ container (for instance, in applications for the Java Platform, Standard Edition (Java SE platform)).
Added new chapter, Chapter 19, "Scaling JPA Applications Using TopLink Grid with Oracle Coherence," to describe how applications can use TopLink Grid to achieve high availability and increase performance.
Added new chapter, Chapter 20, "Exposing JPA Entities Through RESTful Data Services," to describe how to expose JPA entities through Java Persistence API-RESTful Services (JPA-RS), using either JSON or XML media.
Added new chapter, Chapter 21, "Keeping Data Fresh Using TopLink Live Data Queries," to describe how to use TopLink live queries to track changes to the backing data store.
Added new chapter, Chapter 22, "Using Database Events to Invalidate the Cache," to describe how to use EclipseLink Database Change Notification (DCN) for shared caching in a JPA environment. DCN allows the database to notify EclipseLink of database changes. The changed objects are invalidated in the EclipseLink shared cache. Stale data can be discarded, even if other applications access the same data in the database.
Added new chapter, Chapter 24, "Using Oracle TopLink with the Oracle Database," to describe how to use the Oracle Database features that are supported by TopLink.
This chapter provides instructions for making JPA entities and JAXB beans extensible. Mappings can be added or modified externally, without modifying the entity or bean source file and without redeploying the persistence unit. This feature is useful in a Software-as-a-Service environment where multiple clients can share applications and data sources. It is also useful for customizing an application during installation rather than during development.
This chapter contains the following sections:
Use Case
Users want to establish a SaaS environment, where applications and data sources are shared by multiple clients.
Solution
Use the TopLink extensibility feature to extend JPA entities and JAXB beans by using external mappings.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
Use the @VirtualAccessMethods
annotation to specify that an entity is extensible. By using virtual properties in an extensible entity, you can specify mappings external to the entity. This allows you to modify the mappings without modifying the entity source file and without redeploying the entity's persistence unit.
Extensible entities are useful in a multi-tenant (or SaaS) architecture where a shared, generic application can be used by multiple clients (tenants). Tenants have private access to their own data, and to data shared with other tenants.
Using extensible entities, you can:
Build an application where some mappings are common to all users and some mappings are user-specific.
Add mappings to an application after it is made available to a customer (even post-deployment).
Use the same EntityManagerFactory
interface to work with data after mappings have changed.
Provide an additional source of metadata to be used by an application.
To create and support an extensible JPA entity:
Configure the entity by annotating the entity class with @VirtualAccessMethods
(or using the XML <access-methods>
), adding get
and set
methods for the property values, and adding a data structure to store the extended attributes and values, as described in the following sections:
Annotate the entity with @VirtualAccessMethods
to specify that it is extensible and to define virtual properties.
Table 12-1 describes the attributes available to the @VirtualAccessMethods
annotation.
Table 12-1 Attributes for the @VirtualAccessMethods Annotation
Attribute | Description |
---|---|
|
The name of the Default: Required? No |
|
The name of the Default: Required? No |
Add get(String)
and set(String, Object)
methods to the entity. The get()
method returns a value by property name and the set()
method stores a value by property name. The default names for these methods are get
and set
, and they can be overridden with the @VirtualAccessMethods
annotation.
EclipseLink weaves these methods if weaving is enabled, which provides support for lazy loading, change tracking, fetch groups, and internal optimizations.
Note: Weaving is not supported when using virtual access methods with |
Add a data structure to store the extended attributes and values, that is, the virtual mappings. These can then be mapped to the database. See Section 12.1.1.3, "Task 3: Provide Additional Mappings."
A common way to store the virtual mappings is in a Map
object (as shown in Example 12-1), but you can also use other strategies.
When using field-based access, annotate the data structure with @Transient
so the structure cannot be used for another mapping. When using property-based access, @Transient
is unnecessary.
Example 12-1 illustrates an entity class that uses property access.
Example 12-1 Entity Class that Uses Property Access
@Entity
@VirtualAccessMethods
public class Customer{
@Id
private int id;
...
@Transient
private Map<String, Object> extensions;
public <T> T get(String name) {
return (T) extentions.get(name);
}
public Object set(String name, Object value) {
return extensions.put(name, value);
}
As an alternative to, or in addition to, using the @VirtualAccessMethods
annotation, you can use an access="VIRTUAL"
attribute on a mapping element (such as <basic>
), for example:
<basic name="idNumber" access="VIRTUAL" attribute-type="String"> <column name="FLEX_COL1"/> </basic>
To set virtual access methods as the defaults for the persistence unit, use the <access>
and <access-methods>
elements, for example:
<persistence-unit-metadata> <xml-mapping-metadata-complete/> <exclude-default-mappings/> <persistence-unit-defaults> <access>VIRTUAL</access> <access-methods set-method="get" get-method="set"/> </persistence-unit-defaults> </persistence-unit-metadata>
Provide database tables with extra columns to store virtual attribute values. For example, the following Customer
table includes two predefined columns, ID
and NAME
, and three columns for storing the attribute values, EXT_1
, EXT_2
, EXT_3
:
CUSTOMER
table
INTEGER
ID
VARCHAR
NAME
VARCHAR
EXT_1
VARCHAR
EXT_2
VARCHAR
EXT_3
You can then specify which of the FLEX
columns should be used to persist an extended attribute, as described in "Task 3: Provide Additional Mappings".
To provide additional mappings, add the mappings with the column
and access-methods
attributes to the eclipselink-orm.xml
file, for example:
<basic name="idNumber" access="VIRTUAL" attribute-type="String"> <column name="FLEX_COL1"/> </basic>
Configure persistence unit properties to indicate that the application should retrieve the flexible mappings from the eclipselink-orm.xml
file. You can set persistence unit properties using the persistence.xml
file or by setting properties on the EntityManagerFactory
interface, as described in the following sections.
For more information about external mappings, see Chapter 13, "Using an External MetaData Source."
In the persistence.xml
file, use the eclipselink.metadata-source
property to use the default eclipselink-orm.xml
file. Use the eclipselink.metadata-source.xml.url
property to use a different file at the specified location, for example:
<property name="eclipselink.metadata-source" value="XML"/> <property name="eclipselink.metadata-source.xml.url" value="foo://bar"/>
Extensions are added at bootstrap time through access to a metadata repository. The metadata repository is accessed through a class that provides methods to retrieve the metadata it holds. EclipseLink includes a metadata repository implementation that supports XML repositories.
Specify the class to use and any configuration information for the metadata repository through persistence unit properties. The EntityManagerFactory
interface integrates additional mapping information from the metadata repository into the metadata it uses to bootstrap.
You can provide your own implementation of the class to access the metadata repository. Each metadata repository access class must specify an individual set of properties to use to connect to the repository.
You can subclass either of the following classes:
org.eclipse.persistence.internal.jpa.extensions.MetadataRepository
org.eclipse.persistence.internal.jpa.extensions.XMLMetadataRepository
In the following example, the properties that begin with com.foo
are subclasses defined by the developer.
<property name="eclipselink.metadata-source" value="com.foo.MetadataRepository"/> <property name="com.foo.MetadataRepository.location" value="foo://bar"/> <property name="com.foo.MetadataRepository.extra-data" value="foo-bar"/>
If you change the metadata and you want an EntityManager
instance based on the new metadata, you must call the refreshMetadata()
method on the EntityManagerFactory
interface to refresh the data. The next EntityManager
instance will be based on the new metadata.
The refreshMetadata()
method takes a map of properties that can be used to override the properties previously defined for the metadata-source
element.
Example 12-2 illustrates the following:
Field access is used for non-extension fields.
Virtual access is used for extension fields, using defaults (get(String)
and set(String, Object)
).
The get(String)
and set(String, Object)
methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods
.
These items are illustrated in bold font.
Example 12-2 Virtual Access Using Default get and set Method Names
@Entity@VirtualAccessMethods
public class Address { @Id private int id;@Transient
private Map<String, Object> extensions; public int getId(){ return id; }public <T> T get(String name) {
return (T) extentions.get(name);
}public Object set(String name, Object value) {
return extensions.put(name, value);
} . . .
Example 12-3 illustrates the following:
Field access is used for non-extension fields.
The @VirtualAccessMethods
annotation overrides methods to be used for getting and setting.
The get(String)
and set(String, Object)
methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods
.
The XML for extended mapping indicates which get()
and set()
method to use.
These items are illustrated in bold font.
Example 12-3 Overriding get and set Methods
@Entity@VirtualAccessMethods(get="getExtension", set="setExtension")
public class Address { @Id private int id;@Transient
private Map<String, Object> extensions; public int getId(){ return id; }public <T> T getExtension(String name) {
return (T) extensions.get(name);
}public Object setExtension(String name, Object value) {
return extensions.put(name, value);
} ...<basic name="name" access="VIRTUAL" attribute-type="String">
<column name="FLEX_1"/>
</basic>
Example 12-4 illustrates the following:
Property access is used for non-extension fields.
Virtual access is used for extension fields, using defaults (get(String)
and set(String, Object)
).
The extensions are mapped in a portable way. @Transient
is not required, because property access is used.
The get(String)
and set(String, Object)
methods will be woven, even if no mappings use them, because of the presence of @VirtualAccessMethods
.
These items are illustrated in bold font.
Example 12-4 Using Property Access
@Entity @VirtualAccessMethods public class Address { private int id; private Map<String, Object> extensions; @Id public int getId(){ return id; } public <T> T get(String name) {return (T) extensions.get(name);
}public Object set(String name, Object value) {
return extensions.put(name, value);
} ...
Use the @XmlVirtualAccessMethods
annotation to specify that a JAXB bean is extensible. By using virtual properties in an extensible bean, you can specify mappings external to the bean. This allows you to modify the mappings without modifying the bean source file and without redeploying the bean's persistence unit.
In a multi-tenant (or SaaS) architecture, a single application runs on a server, serving multiple client organizations (tenants). Good multi-tenant applications allow per-tenant customizations. When these customizations are made to data, it can be difficult for the binding layer to handle them. JAXB is designed to work with domain models that have real fields and properties. EclipseLink extensions to JAXB introduce the concept of virtual properties which can easily handle this use case. Virtual properties are defined by the Object-XML metadata file, and provide a way to extend a class without modifying the source.
This section has the following subsections:
To create and support an extensible JAXB bean:
Configure the bean by annotating the bean class with the @XmlVirtualAccessMethods
, adding get
and set
methods for the property values, and adding a data structure to store the extended attributes and values. Alternatively, you can use the <xml-virtual-access-methods>
element in eclipselink-orm.xml
.
Annotate the bean with @XmlVirtualAccessMethods
to specify that it is extensible and to define virtual properties.
Table 12-2 describes the attributes available to the @XmlVirtualAccessMethods
annotation.
Table 12-2 Attributes for the @XmlVirtualAccessMethods Annotation
Attribute | Description |
---|---|
|
The name of the getter method to use for the virtual property. This method must take a single Default: Required? No |
|
The name of the setter method to use for the virtual property. This method must take a Default: Required? No |
Add get(String)
and set(String, Object)
methods to the bean. The get()
method returns a value by property name and the set()
method stores a value by property name. The default names for these methods are get
and set
, and they can be overridden with the @XmlVirtualAccessMethods
annotation.
Add a data structure to store the extended attributes and values, that is, the virtual mappings. These can then be mapped to the database. See "Task 2: Provide Additional Mappings".
A common way to store the virtual mappings is in a Map
, but you can use other ways, as well. For example you could store the virtual mappings in a directory system.
When using field-based access, annotate the data structure with @XmlTransient
so it cannot use it for another mapping. When using property-based access, @XmlTransient
is unnecessary.
As an alternative to, or in addition to, using @XmlVirtualAccessMethods
, you can use the XML equivalents, for example:
XML to enable virtual access methods using get
and set
:
<xml-virtual-access-methods/>
XML to enable virtual access methods using put
instead of set
(default):
<xml-virtual-access-methods set-method="put"/>
XML to enable virtual access methods using retrieve
instead of get
(default):
<xml-virtual-access-methods get-method="retrieve"/>
XML to enable virtual access methods using retrieve
and put
instead of get
and set
(default):
<xml-virtual-access-methods get-method="retrieve" set-method="put"/>
To provide additional mappings, add the mappings to the eclipselink-oxm.xml
file, for example:
<xml-element java-attribute="idNumber"/>
The examples in this section illustrate how to use extensible JAXB beans. The example begins with the creation of a base class that other classes can extend. In this case the extensible classes are for Customers
and PhoneNumbers
. Mapping files are created for two separate tenants. Even though both tenants share several real properties, they will define virtual properties that are unique to their requirements.
Example 12-5 illustrates a base class, ExtensibleBase
, which other extensible classes can extend. In the example, the use of the @XmlTransient
annotation prevents ExtensibleBase
from being mapped as an inheritance relationship. The real properties represent the parts of the model that will be common to all tenants. The per-tenant extensions will be represented as virtual properties.
Example 12-5 A Base Class for Extensible Classes
package examples.virtual; import java.util.HashMap; import java.util.Map; import javax.xml.bind.annotation.XmlTransient; import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods;@XmlTransient
@XmlVirtualAccessMethods(setMethod="put")
public class ExtensibleBase { private Map<String, Object> extensions = new HashMap<String, Object>();public <T> T get(String property) {
return (T) extensions.get(property);
} public void put(String property, Object value) { extensions.put(property, value); } }
Example 12-6 illustrates the definition of a Customer
class. The Customer
class is extensible because it inherits from a domain class that has been annotated with @XmlVirtualAccessMethods
.
Example 12-6 An Extensible Customer Class
package examples.virtual;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer extends ExtensibleBase
{
private String firstName;
private String lastName;
private Address billingAddress;
public String Ø2WĶgetFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Address getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(Address billingAddress) {
this.billingAddress = billingAddress;
}
}
Example 12-7 illustrates an Address
class. It is not necessary for every class in your model to be extensible. In this example, the Address
class does not have any virtual properties.
Example 12-7 A Nonextensible Address Class
package examples.virtual; public class Address { private String street; public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } }
Example 12-8 illustrates a PhoneNumber
class. Like Customer
, PhoneNumber
will be an extensible class.
Example 12-8 An Extensible PhoneNumber Class
package examples.virtual;
import javax.xml.bind.annotation.XmlValue;
public class PhoneNumber extends ExtensibleBase
{
private String number;
@XmlValue
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
The examples in this section define two separate tenants. Even though both tenants share several real properties, the corresponding XML representation can be quite different due to virtual properties.
Tenant 1
The first tenant is an online sporting goods store that requires the following extensions to its model:
Customer ID
Customer's middle name
Shipping address
A collection of contact phone numbers
Type of phone number (that is, home, work, or cell)
The metadata for the virtual properties is captured in the eclipselink-oxm.xml
mapping file or in files using the eclipselink-orm.xml
schema. Virtual properties are mapped in the same way as real properties. Some additional information is required, including type (since this cannot be determined through reflection), and for collection properties, a container type. The virtual properties defined below for Customer
are middleName
, shippingAddress
, and phoneNumbers
. For PhoneNumber
, the virtual property is the type
property.
Example 12-9 illustrates the binding-tenant1.xml
mapping file.
Example 12-9 Defining Virtual Properties for Tenant 1
<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="examples.virtual"> <java-types> <java-type name="Customer"> <xml-type prop-order="firstName middleName lastName billingAddress shippingAddress phoneNumbers"/> <java-attributes> <xml-attribute java-attribute="id" type="java.lang.Integer"/> <xml-element java-attribute="middleName" type="java.lang.String"/> <xml-element java-attribute="shippingAddress" type="examples.virtual.Address"/> <xml-element java-attribute="phoneNumbers" name="phoneNumber" type="examples.virtual.PhoneNumber" container-type="java.util.List"/> </java-attributes> </java-type> <java-type name="PhoneNumber"> <java-attributes> <xml-attribute java-attribute="type" type="java.lang.String"/> </java-attributes> </java-type> </java-types> </xml-bindings>
The get
and set
methods are used on the domain model to interact with the real properties and the accessors defined on the @XmlVirtualAccessMethods
annotation are used to interact with the virtual properties. The normal JAXB mechanisms are used for marshal and unmarshal operations. Example 12-10 illustrates the Customer
class code for tenant 1 to obtain the data associated with virtual properties.
Example 12-10 Tenant 1 Code to Provide the Data Associated with Virtual Properties
...
Customer customer = new Customer();
//Set Customer's real properties
customer.setFirstName("Jane");
customer.setLastName("Doe");
Address billingAddress = new Address();
billingAddress.setStreet("1 Billing Street");
customer.setBillingAddress(billingAddress);
//Set Customer's virtual 'middleName' property
customer.put("middleName", "Anne");
//Set Customer's virtual 'shippingAddress' property
Address shippingAddress = new Address();
shippingAddress.setStreet("2 Shipping Road");
customer.put("shippingAddress", shippingAddress);
List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();
customer.put("phoneNumbers", phoneNumbers);
PhoneNumber workPhoneNumber = new PhoneNumber();
workPhoneNumber.setNumber("555-WORK");
//Set the PhoneNumber's virtual 'type' property
workPhoneNumber.put("type", "WORK");
phoneNumbers.add(workPhoneNumber);
PhoneNumber homePhoneNumber = new PhoneNumber();
homePhoneNumber.setNumber("555-HOME");
//Set the PhoneNumber's virtual 'type' property
homePhoneNumber.put("type", "HOME");
phoneNumbers.add(homePhoneNumber);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "examples/virtual/binding-tenant1.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, properties);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
...
Example 12-11 illustrates the XML output from the Customer
class for tenant 1.
Example 12-11 XML Output from the Customer Class for Tenant 1
<?xml version="1.0" encoding="UTF-8"?> <customer> <firstName>Jane</firstName> <middleName>Anne</middleName> <lastName>Doe</lastName> <billingAddress> <street>1 Billing Street</street> </billingAddress> <shippingAddress> <street>2 Shipping Road</street> </shippingAddress> <phoneNumber type="WORK">555-WORK</phoneNumber> <phoneNumber type="HOME">555-HOME</phoneNumber> </customer>
Tenant 2
The second tenant is a streaming media provider that offers on-demand movies and music to its subscribers. It requires a different set of extensions to the core model:
A single contact phone number
For this tenant, the mapping file is also used to customize the mapping of the real properties.
Example 12-12 illustrates the binding-tenant2.xml
mapping file.
Example 12-12 Defining Virtual Properties for Tenant 2
<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="examples.virtual"> <xml-schema namespace="urn:tenant1" element-form-default="QUALIFIED"/> <java-types> <java-type name="Customer"> <xml-type prop-order="firstName lastName billingAddress phoneNumber"/> <java-attributes> <xml-attribute java-attribute="firstName"/> <xml-attribute java-attribute="lastName"/> <xml-element java-attribute="billingAddress" name="address"/><xml-element
java-attribute="phoneNumber"
type="examples.virtual.PhoneNumber"/>
</java-attributes> </java-type> </java-types> </xml-bindings>
Example 12-13 illustrates the tenant 2 Customer
class code to obtain the data associated with virtual properties.
Example 12-13 Tenant 2 Code to Provide the Data Associated with Virtual Properties
...
Customer customer = new Customer();
customer.setFirstName("Jane");
customer.setLastName("Doe");
Address billingAddress = new Address();
billingAddress.setStreet("1 Billing Street");
customer.setBillingAddress(billingAddress);
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.setNumber("555-WORK");
customer.put("phoneNumber", phoneNumber);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "examples/virtual/binding-tenant2.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class, Address.class}, properties);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
...
Example 12-14 illustrates the XML output from the Customer
class for tenant 2.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
Code Sample
"@VirtualAccessMethods
" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.)
"Configuring Virtual Access Methods" in Developing JAXB Applications Using Oracle TopLink
Solutions Guide for Oracle TopLink
12c (12.1.2)
E28610-02
August 2013
This document describes a number of scenarios, or use cases, that illustrate TopLink features and typical TopLink development processes.
Oracle Fusion Middleware Solutions Guide for Oracle TopLink, 12c (12.1.2)
E28610-02
Copyright Ā© 2013,Ā Oracle and/or its affiliates. All rights reserved.
This software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.
The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.
If this is software or related documentation that is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007). Oracle America, Inc., 500 Oracle Parkway, Redwood City, CA 94065.
This software or hardware is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications that may create a risk of personal injury. If you use this software or hardware in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure its safe use. Oracle Corporation and its affiliates disclaim any liability for any damages caused by use of this software or hardware in dangerous applications.
Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
Intel and Intel Xeon are trademarks or registered trademarks of Intel Corporation. All SPARC trademarks are used under license and are trademarks or registered trademarks of SPARC International, Inc. AMD, Opteron, the AMD logo, and the AMD Opteron logo are trademarks or registered trademarks of Advanced Micro Devices. UNIX is a registered trademark of The Open Group.
This software or hardware and documentation may provide access to or information on content, products, and services from third parties. Oracle Corporation and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services.
With Oracle TopLink, you can develop a single application and then deploy it for different clients, or "tenants," with varying degrees of application and data isolation and of tenant-specific functionality. For example, a large company may develop a single payroll application to be used by multiple divisions. Each division has access to its own data and to shared data, but they cannot see any other division's data.
This chapter contains the following sections:
Use Case
Multiple application clients must share data sources, with private access to their data, for example in a Software as a Service (SaaS) environment.
Solution
Decide on a strategy for tenant isolation; then use TopLink's tenant isolation features to implement the strategy.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
A compliant Java Database Connectivity (JDBC) database, such as Oracle Database, Oracle Express, or MySQL.
EclipseLink offers considerable flexibility in how you can design and implement features for isolating tenants. Possibilities include the following:
Application Isolation options
Separate container/server
Separate application within the same container/server
Separate entity manager factory and shared cache within the same application
Shared entity manager factory with tenant isolation per entity manager
Data isolation options
Separate database
Separate schema/tablespace
Separate tables
Shared table with row isolation
Query filtering
Oracle Virtual Private Database (VPD)
EclipseLink includes the following options for providing multi-tenancy in the data source:
Single-table multi-tenancy allows tenants to share tables. Each tenant has its own rows, identified by discriminator columns, and those rows are invisible to other tenants. See Using Single-Table Multi-Tenancy.
With table-per-tenant multi-tenancy, each tenant has its own table or tables, identified by table tenant discriminators, and those tables are invisible to other users. See Using Table-Per-Tenant Multi-Tenancy.
With (VDP) multi-tenancy, tenants use a VDP database, which provides the functionality to support multiple tenants sharing the same table. See Using VPD Multi-Tenancy.
EclipseLink further provides tenant-specific extensions through extensible entities using extensible entities and MetadataSource
. For information about those features, see Chapter 12, "Making JPA Entities and JAXB Beans Extensible," and Chapter 13, "Using an External MetaData Source."
With single-table multi-tenancy, any table (Table
or SecondaryTable
) to which an entity or mapped superclass maps can include rows for multiple tenants. Access to tenant-specific rows is restricted to the specified tenant.
Tenant-specific rows are associated with the tenant by using one or more tenant discriminator columns. Discriminator columns are used with application context values to limit what a persistence context can access.
The results of queries on the mapped tables are limited to the tenant discriminator value(s) provided as property values. This applies to all insert, update, and delete operations on the table. When multi-tenant metadata is applied at the mapped superclass level, it is applied to all subentities unless they specify their own multi-tenant metadata.
Note: In the context of single-table multi-tenancy, āsingle-tableā means multiple tenants can share a single table, and each tenant's data is distinguished from other tenants' data via the discriminator column(s). It is possible to use multiple tables with single-table multi-tenancy; but in that case, an entity's persisted data is stored in multiple tables, and multiple tenants can share all the tables. |
The following tasks provide instructions for using single-table multi-tenancy:
To implement and use single-table multi-tenancy, you need:
TopLink 12c Release 1 (12.1.2) or later.
Download TopLink from http://www.oracle.com/technetwork/middleware/toplink/downloads/index.html
.
Any compliant Java Database Connectivity (JDBC) database, including Oracle Database, Oracle Database Express Edition (Oracle Database XE), or MySQL. These instructions are based on Oracle Database XE 11g Release 2.
For the certification matrix, see http://www.oracle.com/technetwork/middleware/ias/index-099524.html
Single-table multi-tenancy can be enabled declaratively using the @Multitenant
annotation, in an Object Relational Mapping (ORM) XML file using the <multitenant>
element, or by using annotations and XML together.
To use the @Multitenant
annotation, include it with an @Entity
or @MappedSuperclass
annotation. For example:
@Entity @Table(name=āEMPā) @Multitenant(SINGLE_TABLE) public class Employee { }
Note: Single-table is the default multi-tenancy type, so |
Note: The |
Discriminator columns are used together with an associated application context to indicate which rows in a table an application tenant can access.
Tenant discriminator columns can be specified declaratively using the @TenantDiscriminatorColumn
annotation or in an object-relational (ORM) XML file using the <tenant-discriminator-column>
element.
The following characteristics apply to discriminator columns:
Tenant discriminator column(s) must always be used with @Multitenant
(or <multitenant>
in the ORM XML file). You cannot specify the tenant discriminator column(s) only.
The tenant discriminator column is assumed to be on the primary table unless another table is explicitly specified.
On persist, the values of tenant discriminator columns are populated from their associated context properties.
When a multi-tenant entity is specified, the tenant discriminator column can default. Its default values are:
Name = TENANT_ID
(the database column name)
Context property = eclipselink.tenant.id
(the context property used to populate the database column)
Tenant discriminator columns are application definable. That is, the discriminator column is not tied to a specific column for each shared entity table. You can use TENANT_ID
, T_ID
, etc.
There is no limit on the number of tenant discriminator columns an application can define.
Any name can be used for a discriminator column.
Generated schemas include specified tenant discriminator columns.
Tenant discriminator columns can be mapped or unmapped:
When a tenant discriminator column is mapped, its associated mapping attribute must be marked as read only.
Both mapped and unmapped properties are used to form the additional criteria when issuing a SELECT query.
To use the @TenantDiscriminatorColumn
annotation, include it with @Multitenant
annotation on an entity or mapped superclass, and optionally include the name
and contextProperty
attributes. If you do not specify these attributes, the defaults name = "TENANT-ID"
and contextProperty = "eclipselink.tenant-id"
are used.
For example:
@Entity @Multitenant(SINGLE_TABLE) @TenantDiscriminatorColumn(name = "TENANT", contextProperty = "multitenant.id") public class Employee { }
To specify multiple tenant discriminator columns, include multiple @TenantDiscriminatorColumn
annotations within the @TenantDiscriminatorColumns
annotation, and include the table where the column is located if it is not located on the primary table. For example:
@Entity @Table(name = "EMPLOYEE") @SecondaryTable(name = "RESPONSIBILITIES") @Multitenant(SINGLE_TABLE) @TenantDiscriminatorColumns({ @TenantDiscriminatorColumn(name = "TENANT_ID", contextProperty = "employee-tenant.id", length = 20) @TenantDiscriminatorColumn(name = "TENANT_CODE", contextProperty = "employee-tenant.code", discriminatorType = STRING, table = "RESPONSIBILITIES") } ) public Employee() { ... }
To use the <tenant-discriminator-column>
element, include the element within a <multitenant>
element and optionally include the name
and context-property
attributes. If you do not specify these attributes, the defaults name = "TENANT-ID"
and contextProperty = "eclipselink.tenant-id"
are used.
For example:
<entity class="model.Employee"> <multitenant> <tenant-discriminator-column name="TENANT" context-property="multitenant.id"/> </multitenant> ... </entity>
To specify multiple columns, include additional <tenant-discriminator-column>
elements, and include the table where the column is located if it is not located on the primary table. For example:
<entity class="model.Employee"> <multitenant type="SINGLE_TABLE"> <tenant-discriminator-column name="TENANT_ID" context-property="employee-tenant.id" length="20"/> <tenant-discriminator-column name="TENANT_CODE" context-property="employee-tenant.id" discriminator-type="STRING" table="RESPONSIBILITIES"/> </multitenant> <table name="EMPLOYEE"/> <secondary-table name="RESPONSIBILITIES"/> ... </entity>
Tenant discriminator columns can be mapped to a primary key or to another column. The following example maps the tenant discriminator column to the primary key on the table during DDL generation:
@Entity @Table(name = "ADDRESS") @Multitenant @TenantDiscriminatorColumn(name = "TENANT", contextProperty = "tenant.id", primaryKey = true) public Address() { ... }
The following example uses the ORM XML file to map the tenant discriminator column to a primary key:
<entity class="model.Address"> <multitenant> <tenant-discriminator-column name="TENANT" context-property="multitenant.id" primary-key="true"/> </multitenant> <table name="ADDRESS"/> ... </entity>
The following example maps the tenant discriminator column to another column named AGE
:
@Entity @Table(name = "Player") @Multitenant @TenantDiscriminatorColumn(name = "AGE", contextProperty = "tenant.age") public Player() { ... @Basic @Column(name="AGE", insertable="false", updatable="false") public int age; }
The following example uses the ORM XML file to map the tenant discriminator column to another column named AGE
:
<entity class="model.Player"> <multitenant> <tenant-discriminator-column name="AGE" context-property="tenant.age"/> </multitenant> <table name="PLAYER"/> ... <attributes> <basic name="age" insertable="false" updatable="false"> <column name="AGE"/> </basic> ... </attributes> ... </entity>
In addition to configuring discriminator columns at the entity and mapped superclass levels, you can also configure them at the persistence-unit-defaults
and entity-mappings
levels to provide defaults. Defining the metadata at the these levels follows similar JPA metadata defaulting and overriding rules.
Specify default tenant discriminator column metadata at the persistence-unit-defaults
level in the ORM XML file. When defined at this level, the defaults apply to all entities of the persistence unit that have specified a multi-tenant type of SINGLE_TABLE
minus those that specify their own tenant discriminator metadata. For example:
<persistence-unit-metadata> <persistence-unit-defaults> <tenant-discriminator-column name="TENANT_ID" context-property="tenant.id"/> </persistence-unit-defaults> </persistence-unit-metadata>
You can also specify tenant discriminator column metadata at the entity-mappings
level in the ORM XML file. A setting at this level overrides a persistence unit default and applies to all entities with a multi-tenant type of SINGLE_TABLE
of the mapping file, minus those that specify their own tenant discriminator metadata. For example:
<entity-mappings> ... ... <tenant-discriminator-column name="TENANT_ID" context-property="tenant.id"/> ... </entity-mappings>
Runtime context properties are used in conjunction with the multi-tenancy configuration on an entity (or mapped superclass) to implement the multi-tenancy strategy. For example, the tenant ID assigned to a tenant discriminator column for an entity is used at runtime (via an entity manager) to restrict access to data, based on that tenant's ownership of (or access to) the rows and tables of the database.
At runtime, multi-tenancy properties can be specified in a persistence unit definition or passed to a create entity manager factory call.
The order of precedence for tenant discriminator column properties is as follows:
EntityManager
EntityManagerFactory
Application context (when in a Java EE container)
For example, to set the configuration on a persistence unit in persistence.xml
:
<persistence-unit name="multitenant"> ... <properties> <property name="tenant.id" value="707"/> ... </properties> </persistence-unit>
Alternatively, to set the properties programmatically:
HashMap properties = new HashMap(); properties.put("tenant.id", "707"); ... EntityManager em = Persistence.createEntityManagerFactory("multi-tenant", properties).createEntityManager();
Note: Swapping tenant IDs during a live |
By default, tenants share the entity manager factory. A single application instance with a shared EntityManagerFactory
for a persistence unit can be responsible for handling requests from multiple tenants.
The following example shows a shared entity manager factory configuration:
EntityManager em = createEntityManager(MULTI_TENANT_PU); em.getTransaction().begin(); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "my_id");
When using a shared entity manager factory, the L2 cache is by default not shared, and therefore multi-tenant entities have an ISOLATED
cache setting.
To share the cache, set the eclipselink.multitenant.tenants-share-cache
property to true
. This results in multi-tenant entities having a PROTECTED cache setting.
Caution: Queries that use the cache may return data from other tenants when using the |
To create an entity manager factory that is not shared, set the eclipselink.multitenant.tenants-share-emf
property to false
.
When the entity manager factory is not shared, you must use the eclipselink.session-name
property to provide a unique session name, as shown in the following example. This ensures that a unique server session and cache are provided for each tenant. This provides full caching capabilities. For example,
HashMap properties = new HashMap(); properties.put("tenant.id", "707"); properties.put("eclipselink.session-name", "multi-tenant-707"); ... EntityManager em = Persistence.createEntityManagerFactory("multitenant", properties).createEntityManager();
Another example:
HashMap properties = new HashMap(); properties.put(PersistenceUnitProperties.MULTITENANT_SHARED_EMF, "false"); properties.put(PersistenceUnitProperties.SESSION_NAME, "non-shared-emf-for-this-emp"); properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "this-emp"); ... EntityManager em = Persistence.createEntityManagerFactory("multi-tenant-pu", properties).createEntityManager();
An example in the persistence unit definition:
<persistence-unit name="multi-tenant-pu"> ... <properties> <property name="eclipselink.multitenant.tenants-share-emf" value="false"/> <property name="eclipselink.session-name" value="non-shared-emf-for-this-emp"/> <property name="eclipselink.tenant-id" value="this-emp"/> ... </properties> </persistence-unit>
When configuring properties at the level of the entity manager, you must specify the caching strategies, because the same server session can be used for each tenant. For example, you can set up an isolation level (L1 cache) to ensure no shared tenant information exists in the L2 cache. These settings are set when creating the entity manager factory.
HashMap tenantProperties = new HashMap(); properties.put("tenant.id", "707"); HashMap cacheProperties = new HashMap(); properties.put("eclipselink.cache.shared.Employee", "false"); properties.put("eclipselink.cache.size.Address", "10"); properties.put("eclipselink.cache.type.Contract", "NONE"); ... EntityManager em = Persistence.createEntityManagerFactory("multitenant", cacheProperties).createEntityManager(tenantProperties); ...
The tenant discriminator column is used at runtime through entity manager operations and querying. The tenant discriminator column and value are supported through the following entity manager operations:
persist()
find()
refresh()
The tenant discriminator column and value are supported through the following queries:
Named queries
Update all
Delete all
Note: Multi-tenancy is not supported through named native queries. To use named native queries in a multi-tenant environment, manually handle any multi-tenancy issues directly in the query. In general, it is best to avoid named native queries in a multi-tenant environment. |
Inheritance strategies are configured by specifying the inheritance type (@javax.persistence.Inheritance
). Single-table multi-tenancy can be used in an inheritance hierarchy, as follows:
Multi-tenant metadata can be applied only at the root level of the inheritance hierarchy when using a SINGLE_TABLE
or JOINED
inheritance strategy.
You can also specify multi-tenant metadata within a TABLE_PER_CLASS
inheritance hierarchy. In this case, every entity has its own table, with all its mapping data (which is not the case with SINGLE_TABLE
or JOINED
strategies). Consequently, in the TABLE_PER_CLASS
strategy, some entities of the hierarchy may be multi-tenant, while others may not be. The other inheritance strategies can only specify multi-tenancy at the root level, because you cannot isolate an entity to a single table to build only its type.
Table-per-tenant multi-tenancy allows multiple tenants of an application to isolate their data in one or more tenant-specific tables. Multiple tenants' tables can be in a shared schema, identified using a prefix or suffix naming pattern; or they can be in separate, tenant-specific schemas. Table-per-tenant entities can be mixed with other multi-tenant type entities within the same persistence unit.
The table-per-tenant multi-tenant type is used in conjunction with:
A tenant table discriminator that specifies the type of discriminator (schema or name with prefix or suffix)
A tenant ID to identify the user (configured per entity manager or at the entity manager factory, if isolating the table-per-tenant per persistence unit.)
A single application instance with a shared EntityManagerFactory
for a persistence unit can be responsible for handling requests from multiple tenants.
Alternatively, separate EntityManagerFactory
instances can be used for each tenant. (This is required when using extensions per tenant.) In this case, tenant-specific schema and table names are defined in an eclipselink-orm.xml
configuration file. A MetadataSource
must be registered with a persistence unit. The MetadataSource
is used to support additional persistence unit metadata provided from outside the application.
For information about MetadataSource
, see Chapter 13, "Using an External MetaData Source." See also metadata-source
in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
The table-per-tenant multi-tenant type enables individual tenant table(s) to be used at the entity level. A tenant context property must be provided on each entity manager after a transaction has started.
Table
and SecondaryTable
) for the entity are individual tenant tables based on the tenant context. Relationships within an entity that uses a join or a collection table are also assumed to exist within the table-per-tenant context.
Multi-tenant metadata can only be applied at the root level of the inheritance hierarchy when using a SINGLE_TABLE
or JOINED
inheritance strategy. Multi-tenant metadata can be specified in a TABLE_PER_CLASS
inheritance hierarchy
The following tasks provide instructions for using table-per-tenant multi-tenancy:
To implement and use table-per-tenant multi-tenancy, you need:
TopLink 12c Release 1 (12.1.2) or later.
Download TopLink from http://www.oracle.com/technetwork/middleware/toplink/downloads/index.html
.
Any compliant Java Database Connectivity (JDBC) database, including Oracle Database, Oracle Database Express Edition (Oracle Database XE), or MySQL. These instructions are based on Oracle Database XE 11g Release 2.
For the certification matrix, see http://www.oracle.com/technetwork/middleware/ias/index-099524.html
Table-per-tenant multi-tenancy can be enabled declaratively using the @Multitenant
annotation; or in an Object Relational Mapping (ORM) XML file using the <multitenant>
element, or using annotations and XML together.
To use the @Multitenant
annotation, include the annotation with an @Entity
or @MappedSuperclass
annotation and include the TABLE_PER_TENANT
attribute.
For example:
@Entity @Multitenant(TABLE_PER_TENANT ...) public class Employee { }
The TABLE_PER_TENANT
attribute states that clients have a dedicated table or tables (Table
and SecondaryTable
) associated with the entity.
The tenant table discriminator describes the type of table discriminator to use in a table-per-tenant multi-tenancy strategy. The tenant table discriminator is identified by a property. You can define your own identifier or use the default property: org.eclipse.persistence.config.PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT = "eclipselink.tenant-id"
The tenant table discriminator can be specified at the entity or mapped superclass level, and it must always be accompanied with a Multitenant(TABLE_PER_TENANT)
specification. It is not sufficient to specify only a tenant table discriminator.
The tenant table discriminator is used together with an associated application context to indicate which table or tables an application tenant can access.
Use the @TenantTableDiscriminator
annotation to specify which tables are associated with which tenants. The tenant table discriminator must include a type and a context property:
Use the type
attribute to identify what type of discriminator to use:
Use PREFIX
to apply the tenant table discriminator as a prefix to all multi-tenant tables.
Use SUFFIX
to apply the tenant table discriminator as a suffix to all multi-tenant tables.
Use SCHEMA
to apply the tenant table discriminator as a schema to all multi-tenant tables. This strategy requires appropriate database provisioning.
Use the contextProperty
attributes to identify the user. The value of the context property is a tenant ID that identifies the user. This can be configured for an entity manager or, if you want to isolate the table-per-tenant per persistence unit, an entity manager factory.
For example:
@Entity @Table(name=āEMPā) @Multitenant(TABLE_PER_TENANT) @TenantTableDiscriminator(type=SCHEMA, contextProperty="eclipselink-tenant.id") public class Employee { ... }
To use the <tenant-table-discriminator>
element, include the element within a <multitenant>
element and include the name
and context-property
attributes. For example:
<entity class="Employee"> <multitenant type="TABLE_PER_TENANT"> <tenant-table-discriminator type="SCHEMA" context-property="eclipselink-tenant.id"/> </multitenant> <table name="EMP"> ... </entity>
At runtime, specify the context property using a persistence unit definition passed to an entity manager factory or set on an individual entity manager. For example:
<persistence-unit name="multitenant"> ... <properties> <property name="tenant.id" value="707"/> ... </properties> </persistence-unit>
To specify a context property at runtime programmatically:
HashMap properties = new HashMap(); properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "707"); EntityManager em = Persistence.createEntityManagerFactory("multitenant-pu", properties).createEntityManager();
An entity manager property definition follows:
EntityManager em = Persistence.createEntityManagerFactory("multitenant-pu").createEntityManager(); em.beginTransaction(); em.setProperty("other.tenant.id.property", "707"); em.setProperty(EntityManagerProperties.MULTITENANT_PROPERTY_DEFAULT, "707"); ...
The tenant discriminator column is used at runtime through entity manager operations and querying. The tenant discriminator column and value are supported through the following entity manager operations:
persist()
find()
refresh()
The tenant discriminator column and value are supported through the following queries:
Named queries
Update all
Delete all
Note: Multi-tenancy is not supported through named native queries. To use named native queries in a multi-tenant environment, manually handle any multi-tenancy issues directly in the query. In general, it is best to avoid named native queries in a multi-tenant environment. |
A Virtual Private Database (VPD) uses security controls to restrict access to database objects based on various parameters.
For example, the Oracle Virtual Private Database supports security policies that control database access at the row and column level. Oracle VPD adds a dynamic WHERE
clause to SQL statements issued against the table, view, or synonym to which the security policy was applied.
Oracle Virtual Private Database enforces security directly on the database tables, views, or synonyms. Because security policies are attached directly to these database objects, and the policies are automatically applied whenever a user accesses data, there is no way to bypass security.
When a user directly or indirectly accesses a table, view, or synonym that is protected with an Oracle Virtual Private Database policy, Oracle Database dynamically modifies the SQL statement of the user. This modification creates a WHERE condition (called a predicate) returned by a function implementing the security policy. Oracle Virtual Private Database modifies the statement dynamically, transparently to the user, using any condition that can be expressed in or returned by a function. Oracle Virtual Private Database policies can be applied to SELECT, INSERT, UPDATE, INDEX, and DELETE statements.
When using EclipseLink VPD multitanancy, the database handles the tenant filtering on all SELECT, INSERT, UPDATE, INDEX and DELETE queries.
To use EclipseLink VPD multi-tenancy, you must first configure VPD in the database and then specify multi-tenancy on the entity or mapped superclass, as shown in the following example, using @Multitenant
and @TenantDiscriminatorColumn
:
The following tasks provide instructions for using VPD multi-tenancy with Oracle Virtual Private Database:
To implement and use VPD multi-tenancy, you need:
TopLink 12c Release 1 (12.1.2) or later.
Download TopLink from http://www.oracle.com/technetwork/middleware/toplink/downloads/index.html
.
Any compliant Java Database Connectivity (JDBC) database that supports VDP, for example, Oracle Virtual Private Database.
For the certification matrix, see http://www.oracle.com/technetwork/middleware/ias/index-099524.html
In this example, an Oracle Virtual Private Database is configured with a policy and a stored procedure. The policy is a call to the database that tells the database to use a stored function to limit the results of a query. In this example, the function is called ident_func
, and it is run whenever a SELECT
, UPDATE
or DELETE
is performed on the SCOTT.TASK
table. The policy is created as follows:
CALL DBMS_RLS.ADD_POLICY ('SCOTT', 'TASK', 'todo_list_policy', 'SCOTT', 'ident_func', 'select, update, delete'));
The function defined below is used by VPD to limit the data based on the identifier that is passed in to the connection. The function uses the USER_ID
column in the table to limit the rows. The rows are limited, based on what is set in the client_identifier
variable in the userenv
context.
CREATE OR REPLACE FUNCTION ident_func (p_schema IN VARCHAR2 DEFAULT NULL, p_object IN VARCHAR2 DEFAULT NULL) RETURN VARCHAR2 AS BEGIN RETURN 'USER_ID = sys_context(''userenv'', ''client_identifier'')'; END;
As described above, VPD is configured to use the USER_ID
column to limit access to rows. Therefore, you must tell EclipseLink to auto-populate the USER_ID
column on inserts. The following code uses EclipseLink multi-tenancy and specifies that the client identifier is passed in to the entity managers using a property called tenant.id
. Because the filtering is done by VPD on the database, you must turn off caching on this entity to avoid leakage across users.
@Entity @Multitenant(VPD) @TenantDiscriminatorColumn(name = "USER_ID", contextProperty = "tenant.id") @Cacheable(false) public class Task implements Serializable { ... ...
When single-table and table-per-tenant multi-tenancy are enabled, a client identifier is auto appended to any generated SQL. However, when VPD is used to limit the access to data, the auto-appending of the identifier should be turned off.
Beginning with TopLink 12c Release 1 (12.1.2), disable criteria generation as follows:
Add the following properties to persistence.xml
.
Include the following to set and clear the VPD identifier:
<property name="eclipselink.session-event-listener" value="example.VPDSessionEventAdapter" />
Include the following to provide one connection per entity manager:
<property name="eclipselink.jdbc.exclusive-connection.mode" value="Always" />
Include the following to allow native queries to be runnable from EclipseLink. This is required for creating VPD artifacts:
<property name="eclipselink.jdbc.allow-native-sql-queries" value="true" /> </properties>
For example:
<properties> <property name="eclipselink.session-event-listener" value="example.VPDSessionEventAdapter" /> <property name="eclipselink.jdbc.exclusive-connection.mode" value="Always" /> <property name="eclipselink.jdbc.allow-native-sql-queries" value="true" /> ... </properties>
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
Code Sample
See the following in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.)
Oracle TopLink is a powerful and flexible Java persistence framework for storing Java objects in a data store, such as a relational database or a NoSQL database, and for converting Java objects to XML or JSON documents. TopLink provides APIs and a run-time environment for implementing the persistence layer of Java Platform, Standard Edition (Java SE platform), and Java Platform, Enterprise Edition (Java EE platform) applications.
TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional features, including Oracle TopLink Grid, which integrates EclipseLink JPA with the Oracle Coherence cache.
For more information about the EclipseLink project, see "Eclipse Persistence Services Project (EclipseLink) home" at http://www.eclipse.org/eclipselink/
.
This guide, Solutions Guide for Oracle TopLink, documents a number of scenarios, or use cases, that illustrate TopLink features and typical TopLink development processes. These are not tutorials that lead you step-by-step through every task required to complete a project. Rather, they document general processes and key details for solving particular problems and then provide links to other documentation for more information.
"Oracle TopLink" and "TopLink" describe the full Oracle product, including all the included EclipseLink libraries, features, and APIs, plus the additional Oracle features. The names "Oracle TopLink" and "TopLink" are used in a general way in this documentation to refer to the whole product and at times more specifically to the Oracle-only features. The term "EclipseLink" is used when referring to the EclipseLink features included in TopLink.
To make good use of this guide, you should already be familiar with the following:
The concepts and programming practices of the Java SE platform and the Java EE platform. In the current release, TopLink supports Java EE 6. For more information, see the following.
Java
Java home page: http://www.oracle.com/us/technologies/java/index.html
Java EE 5 Tutorial: http://download.oracle.com/javaee/5/tutorial/doc/bnbpy.html
Java EE 6 Tutorial: http://download.oracle.com/javaee/6/tutorial/doc/bnbpy.html
Any of the thousands of books and websites devoted to Java.
Oracle Java EE Application Servers
Oracle WebLogic Server home page: http://www.oracle.com/technetwork/middleware/weblogic/overview/index.html
Oracle GlassFish Server home page: http://www.oracle.com/technetwork/middleware/glassfish/overview/index.html
Oracle Java EE Integrated Development Environments
Oracle JDeveloper: http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html
Oracle Enterprise Pack for Eclipse: http://www.oracle.com/technetwork/developer-tools/eclipse/overview/index.html
If you are working with EclipseLink JPA, you should be familiar with the concepts and programming practices of JPA 2.0, as specified in the Java Persistence 2.0 specification at http://jcp.org/aboutJava/communityprocess/final/jsr317/index.html
.
If you are working with EclipseLink JAXB, you should be familiar with the concepts and programming practices of JAXB 2.0, as specified in the The Java Architecture for XML Binding (JAXB) 2.0 specification at http://jcp.org/en/jsr/detail?id=222
.
If you are using JSON data-interchange format, you should be familiar with the concepts and programming practices of JSON, as described at http://www.json.org/
. For XML, see http://www.w3.org/XML/
If you are working with EclipseLink DBWS, you should be familiar with the concepts and programming practices of JAX-WS 2.0, as specified in the Java API for XML-Based Web Services (JAX-WS) 2.0 specification at http://jcp.org/en/jsr/detail?id=224
.
If you are working with REpresentational State Transfer (REST) service, you should be familiar with concepts and programming practices of REST, as specified in "JSR 311: JAX-RS: The Java API for RESTful Web Services" at http://jcp.org/en/jsr/detail?id=311
.
The use cases documented in this guide are as follows:
Chapter 2, "Installing Oracle TopLink" - How to download and install standalone TopLink.
Chapter 3, "Using TopLink with WebLogic Server" - How to use TopLink with WebLogic Server.
Chapter 4, "Using TopLink with GlassFish Server" - How to use TopLink with GlassFish Server.
Chapter 5, "Using TopLink with JBoss 7 Application Server" - How to use TopLink with JBoss 7 Application Server.
Chapter 6, "Using TopLink with IBM WebSphere Application Server," - How to use TopLink with IBM WebSphere Application Server.
Chapter 7, "Migrating from Native TopLink" - How to how to migrate applications using native TopLink object-relational mapping (ORM) API to the current EclipseLink API.
Section 8, "Migrating from Hibernate to TopLink" - How to migrate applications from using Hibernate JPA to using EclipseLink JPA.
Chapter 9, "Using Multiple Databases with a CompositeĀ Persistence Unit" - How to expose multiple persistence units (each with unique sets of entity types) as a single persistence context.
Chapter 10, "Scaling Applications in Clusters" - How to configure EclipseLink applications to ensure scalability in clustered application server environments.
Chapter 11, "Providing Software as a Service" - Overview of TopLink Software as a Service (SaaS) features.
Chapter 12, "Making JPA Entities and JAXB Beans Extensible" - How to make JPA entities or JAXB beans extensible.
Chapter 13, "Using an External MetaData Source" - How to use an external metadata source.
Chapter 14, "Tenant Isolation Using TopLink" - How to support multiple application tenants who share data sources, including tables and schemas.
Chapter 15, "Mapping JPA to XML" - How to map JPA entities to XML using EclipseLink JAXB.
Chapter 17, "Testing JPA Outside a Container" - How to test your EclipseLink JPA application outside the container.
Chapter 18, "Enhancing Performance" - Getting the best performance out of TopLink.
Chapter 19, "Scaling JPA Applications Using TopLink Grid with Oracle Coherence" - How to use TopLink Grid to achieve high availability and increase performance.
Chapter 20, "Exposing JPA Entities Through RESTful Data Services" - How to expose entities through RESTful services using EclipseLink Java Persistence API for RESTful Services (JPA-RS).
Chapter 21, "Keeping Data Fresh Using TopLink Live Data Queries" - Using TopLink live queries to track changes to the backing data store.
Chapter 22, "Using Database Events to Invalidate the Cache" - How to use EclipseLink Database Change Notification (DCN) for caching with a shared database in JPA.
Chapter 23, "Using TopLink with NoSQL Databases" - How to use EclipseLink to map objects to non-relational (that is, no SQL) data sources.
This chapter provides instructions for understanding and using EclipseLink features in Oracle TopLink that are designed specifically to support the Oracle Database platform.
This chapter contains the following sections:
Use Case
Oracle TopLink offers a persistence solution that is designed to work with any database. However, applications that plan to use the Oracle Database platform can take advantage of enhanced support for the Oracle Database.
Solution
The solution is achieved by using various TopLink APIs and Oracle products. Applications choose to implement different Oracle TopLink APIs based on the Oracle Database feature or products being used.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
Oracle Database
Additional Oracle Database and Middleware products are required depending on the features that an application chooses to use.
EclipseLink includes enhanced support for the Oracle Database platform. Applications that have standardized on the Oracle Database can take advantage of this support to gain ease-of-use, increase performance and scalability, and enhance security. EclipseLink includes support for native Oracle JDBC-specific APIs, PL/SQL, Oracle Real Application Clusters (RAC), Oracle Virtual Private Database, Oracle Proxy Authentication, and Oracle Spatial and Graph. Refer to the Oracle Database documentation for details on these technologies.
Much of the Oracle Database platform support is contained in the org.eclipse.persistence.platform.database.oracle*
package. For details on the APIs, see Java API Reference for Oracle TopLink.
The solution in this section is organized according to technology. The organization allows developers to easily understand the different parts of the solution and choose specific parts to implement.
This section includes the following topics:
Oracle Database platform support is provided in the org.eclipse.persistence.platform.database.OraclePlatform
class, the org.eclipse.persistence.platform.database.oracle*
packages, and the org.eclipse.persistence.mappings.xdb
package for Oracle XML Database support. For details on the API, see Java API Reference for Oracle TopLink. For details on specific Oracle SQL types, see Oracle Database JDBC Java API Reference.
The following support is provided for the Oracle Database:
Batch writing with optimistic locking
Native SQL for byte[]
, Date
, Time
, Timestamp
and Calendar
Support for BLOB
and CLOB
database types using Oracle JDBC specific LOBLocator
for large values
Note: For non-Oracle thin JDBC drivers or applications environments where the thin driver is wrapped, it is possible to turn off |
Native support for outer join syntax (+) =
Native Sequencing (SELECT SEQ_NAME.NEXTVAL FROM DUAL
)
Native SQL/ROWNUM support for MaxRows
and FirstResult
filtering.
Hierarchical selects (connect by prior)
Returning clause
Custom expression functions (REGEXP_LIKE
, LOCATE
, ATAN2
, LOG
, CONCAT
, SYSDATE
(Date, Time, Today), EXCEPT
)
PLSQL data types, stored functions, stored procedure syntax for invoking and parameter passing, output parameters and output cursors. See Section 24.2.2, "Using Oracle PL/SQL With EclipseLink."
Timestamp query for use in optimistic locking using SYSDATE
and SYSTIMESTAMP
Multi-byte support of NCHAR
, NSTRING
, and NCLOB
Support of TIMESTAMP
, TIMESTAMPTZ
, and TIMESTAMPLTZ
Oracle XML Database support of XMLType
field and custom XSQL functions (extract
, extractValue
, existsNode
, isFragment
, getStringVal
, and getNumberVal
)
XDK XML parser
Flashback Querying in Historical Sessions
Object-relational Mappings (ReferenceMapping, StructureMapping, NestedTableMapping, ArrayMapping, ObjectArrayMapping)
Oracle AQ
Oracle Real Application Clusters. See Section 24.2.5, "Using EclipseLink with Oracle RAC."
Virtual Private Database (VPD), including Oracle Label Security. Section 24.2.3, "Using Oracle Virtual Private Database."
Proxy Authentication. See Section 24.2.4, "Using Oracle Proxy Authentication."
EclipseLink includes APIs for use with Oracle PL/SQL. The APIs are located in the org.eclipse.persistence.platform.database.oracle.plsql
package and the org.eclipse.persistence.platform.database.oracle.annotations
package.
This Section contains the following topics:
Oracle PL/SQL stored functions can be used to return complex PL/SQL data-types such as RECORD
types and TABLE
types. PL/SQL types are not supported by Oracle JDBC, so these types must be translated to Oracle OBJECT
types and VARRAY
types. OBJECT
types are returned as java.sql.Struct
and VARRAY
as java.sql.Array
types in JDBC.
Executing PL/SQL stored functions or procedures requires defining mirror OBJECT
and VARRAY
types for the RECORD
and TABLE
types. OBJECT
types can be mapped to classes annotated with either @Entity
or @Embeddable
using the @Struct
annotation. Typically, classes annotated with @Embeddable
are used, unless the OBJECT
type defines an Id
and can be stored in a table. Nested OBJECT
and VARRAY
types are mapped using the @Structure
and @Array
annotations.
Use the PLSQLStoredFunctionCall
class or the @NamedPLSQLStoredFunctionQuery
annotation to call a stored function using PL/SQL types. The PLSQLStoredProcedureCall
class and the @NamedPLSQLStoredProcedureQuery
annotation also exist for stored procedures. Use the StoredFunctionCall
class, the @NamedStoredFunctionQuery
annotation, the StoredProcedureCall
class, and the @NamedStoredProcedureQuery
annotation for stored functions and procedure that do not return complex PL/SQL types.
To execute an Oracle PL/SQL stored function:
Task 1: Create an Oracle Stored Function That Returns a PL/SQL Record Type
Task 4: Execute a PL/SQL Stored Function Using JpaEntityManager
Task 5: Define a Stored Function Using @NamedPLSQLStoredFunctionQuery
CREATE OR REPLACE PACKAGE EMP_PKG AS TYPE EMP_REC IS RECORD (F_NAME VARCHAR2(30), L_NAME VARCHAR2(30), SALARY NUMBER(10,2)); FUNCTION GET_EMP RETURN EMP_REC; END EMP_PKG; CREATE OR REPLACE PACKAGE BODY EMP_PKG AS FUNCTION GET_EMP RETURN EMP_REC AS P_EMP EMP_REC; BEGIN P_EMP.F_NAME := 'Bob'; P_EMP.F_NAME := 'Smith'; P_EMP.SALARY := 30000; RETURN P_EMP; END; END EMP_PKG;
CREATE OR REPLACE TYPE EMP_TYPE AS OBJECT (F_NAME VARCHAR2(30), L_NAME VARCHAR2(30), SALARY NUMBER(10,2))
@Embeddable @Struct(name="EMP_TYPE", fields={"F_NAME", "L_NAME", "SALARY"}) public class Employee { @Column(name="F_NAME") private String firstName; @Column(name="L_NAME") private String lastName; @Column(name="SALARY") private BigDecimal salary; ... }
import javax.persistence.Query; import org.eclipse.persistence.platform.database.orcle.plsql. PLSQLStoredFunctionCall; import org.eclipse.persistence.queries.ReadAllQuery; DataReadQuery databaseQuery = new DataReadQuery(); databaseQuery.setResultType(DataReadQuery.VALUE); PLSQLrecord record = new PLSQLrecord(); record.setTypeName("EMP_PKG.EMP_REC"); record.setCompatibleType("EMP_TYPE"); record.setJavaType(Employee.class); record.addField("F_NAME", JDBCTypes.VARCHAR_TYPE, 30); record.addField("L_NAME", JDBCTypes.VARCHAR_TYPE, 30); record.addField("SALARY", JDBCTypes.NUMERIC_TYPE, 10, 2); PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall(record); call.setProcedureName("EMP_PKG.GET_EMP"); databaseQuery.setCall(call); Query query = ((JpaEntityManager)entityManager.getDelegate()). createQuery(databaseQuery); Employee result = (Employee)query.getSingleResult();
@NamedPLSQLStoredFunctionQuery(name="getEmployee", functionName="EMP_PKG.GET_EMP", returnParameter=@PLSQLParameter(name="RESULT", databaseType="EMP_PKG.EMP_REC")) @Embeddable @Struct(name="EMP_TYPE", fields={"F_NAME", "L_NAME", "SALARY"}) @PLSQLRecord(name="EMP_PKG.EMP_REC", compatibleType="EMP_TYPE", javaType=Employee.class,fields={@PLSQLParameter(name="F_NAME"), @PLSQLParameter(name="L_NAME"), @PLSQLParameter(name="SALARY", databaseType="NUMERIC_TYPE")}) public class Employee { ... }
Query query = entityManager.createNamedQuery("getEmployee"); Employee result = (Employee)query.getSingleResult();
The standard way of handling a stored procedure is to build an instance of the StoredProcedureCall
class. However, the arguments must be compatible with the JDBC specification. To handle Oracle PL/SQL arguments (for example, BOOLEAN
, PLS_INTEGER
, PL/SQL record, and so on), use the PLSQLStoredProcedureCall
class.
Note: the |
The following example demonstrates handling PL/SQL arguments using the PLSQLStoredProcedureCall
class. The example is based on the following target procedure:
PROCEDURE bool_in_test(x IN BOOLEAN)
Example of Using the PLSQLStoredProcedureCall Class
import java.util.List; import java.util.ArrayList; import org.eclipse.persistence.logging.SessionLog; import org.eclipse.persistence.platform.database.jdbc.JDBCTypes; import org.eclipse.persistence.platform.database.oracle.Oracle10Platform; import org.eclipse.persistence.platform.database.oracle.OraclePLSQLTypes; import org.eclipse.persistence.platform.database.oracle.PLSQLStoredProcedureCall; import org.eclipse.persistence.queries.DataModifyQuery; import org.eclipse.persistence.sessions.DatabaseLogin; import org.eclipse.persistence.sessions.DatabaseSession; import org.eclipse.persistence.sessions.Project; import org.eclipse.persistence.sessions.Session; public class TestClass { public static String DATABASE_USERNAME = "username"; public static String DATABASE_PASSWORD = "password"; public static String DATABASE_URL = "jdbc:oracle:thin:@localhost:1521:ORCL"; public static String DATABASE_DRIVER = "oracle.jdbc.driver.OracleDriver"; public static void main(String[] args) { Project project = new Project(); DatabaseLogin login = new DatabaseLogin(); login.setUserName(DATABASE_USERNAME); login.setPassword(DATABASE_PASSWORD); login.setConnectionString(DATABASE_URL); login.setDriverClassName(DATABASE_DRIVER); login.setDatasourcePlatform(new Oracle10Platform()); project.setDatasourceLogin(login); Session s = project.createDatabaseSession(); s.setLogLevel(SessionLog.FINE); ((DatabaseSession)s).login(); PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall(); call.setProcedureName("bool_in_test"); call.addNamedArgument("X", OraclePLSQLTypes.PLSQLBoolean); DataModifyQuery query = new DataModifyQuery(); query.addArgument("X"); query.setCall(call); List queryArgs = new ArrayList(); queryArgs.add(Integer.valueOf(1)); s.executeQuery(query, queryArgs); } }
The following log excerpt shows the target procedure being invoked from an anonymous PL/SQL block:
...[EclipseLink Info]: 2007.11.23 01:03:23.890--DatabaseSessionImpl(15674464)-- Thread(Thread[main,5,main])-- login successful [EclipseLink Fine]: 2007.11.23 01:03:23.968--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE X_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:1); BEGIN bool_in_test(X=>X_TARGET); END; bind => [:1 => 1]
Note: Notice the conversion of the Integer to a PL/SQL |
A Stored Procedure may have a mix of regular and non JDBC arguments. Use the PLSQLStoredProcedureCall
class when at least one argument is a non JDBC type. In addition, some additional information may be required for the JDBC type (length, scale or precision) because the target procedure is invoked from an anonymous PL/SQL block. The example is based on the following target procedure:
PROCEDURE two_arg_test(x IN BOOLEAN, y IN VARCHAR)
Example of Mixing JDBC Arguments With NonJDBC Arguments
import org.eclipse.persistence.platform.database.jdbc.JDBCTypes; ... PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall(); call.setProcedureName("two_arg_test"); call.addNamedArgument("X", OraclePLSQLTypes.PLSQLBoolean); call.addNamedArgument("Y", JDBCTypes.VARCHAR_TYPE, 40); DataModifyQuery query = new DataModifyQuery(); query.addArgument("X"); query.addArgument("Y"); query.setCall(call); List queryArgs = new ArrayList(); queryArgs.add(Integer.valueOf(0)); queryArgs.add("test"); boolean worked = false; String msg = null; s.executeQuery(query, queryArgs);
The following log excerpt shows the target procedure being invoked from an anonymous PL/SQL block:
[EclipseLink Fine]: 2007.11.23 02:54:46.109--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE X_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:1); Y_TARGET VARCHAR(40) := :2; BEGIN two_arg_test(X=>X_TARGET, Y=>Y_TARGET); END; bind => [:1 => 0, :2 => test]
The following example demonstrates a stored procedure that contain both IN
and OUT
arguments and is based on the following target procedure:
PROCEDURE two_arg_in_out(x OUT BINARY_INTEGER, y IN VARCHAR) AS BEGIN x := 33; END;
Example of Handling IN and OUT Arguments
import static org.eclipse.persistence.platform.database.oracle.OraclePLSQLTypes. BinaryInteger; ... PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall(); call.setProcedureName("two_arg_in_out"); call.addNamedOutputArgument("X", OraclePLSQLTypes.BinaryInteger); call.addNamedArgument("Y", JDBCTypes.VARCHAR_TYPE, 40); DataReadQuery query = new DataReadQuery(); query.setCall(call); query.addArgument("Y"); List queryArgs = new ArrayList(); queryArgs.add("testsdfsdfasdfsdfsdfsdfsdfsdfdfsdfsdffds"); boolean worked = false; String msg = null; List results = (List)s.executeQuery(query, queryArgs); DatabaseRecord record = (DatabaseRecord)results.get(0); BigDecimal x = (BigDecimal)record.get("X"); if (x.intValue() != 33) { System.out.println("wrong x value"); }
The following log excerpt shows the target procedure being invoked from an anonymous PL/SQL block:
[EclipseLink Fine]: 2007.11.23 03:15:25.234--DatabaseSessionImpl(15674464)-- Connection(5807702)--Thread(Thread[main,5,main])-- DECLARE Y_TARGET VARCHAR(40) := :1; X_TARGET BINARY_INTEGER; BEGIN two_arg_in_out(X=>X_TARGET, Y=>Y_TARGET); :2 := X_TARGET; END; bind => [:1 => testsdfsdfasdfsdfsdfsdfsdfsdfdfsdfsdffds, X => :2]
Note: The order in which arguments are bound at runtime must be altered. Anonymous PL/SQL blocks must process the ordinal markers ( |
Anonymous PL/SQL blocks cannot natively handle IN OUT
arguments. The arguments must be split into two parts: an IN-half and an OUT-half. The following example demonstrates a stored procedure that handles IN OUT arguments and is based on the following target procedure:
PROCEDURE two_args_inout(x VARCHAR, y IN OUT BOOLEAN) AS BEGIN y := FALSE; END;
Example of Handling IN OUT Arguments
... PLSQLStoredProcedureCall call = new PLSQLStoredProcedureCall(); call.setProcedureName("two_args_inout"); call.addNamedArgument("X", JDBCTypes.VARCHAR_TYPE, 20); call.addNamedInOutputArgument("Y", OraclePLSQLTypes.PLSQLBoolean); DataReadQuery query = new DataReadQuery(); query.addArgument("X"); query.addArgument("Y"); query.setCall(call); List queryArgs = new ArrayList(); queryArgs.add("test"); queryArgs.add(Integer.valueOf(1)); List results = (List)s.executeQuery(query, queryArgs); DatabaseRecord record = (DatabaseRecord)results.get(0); Integer bool2int = (Integer)record.get("Y"); if (bool2int.intValue() != 0) { System.out.println("wrong bool2int value"); }
The following log excerpt shows the target procedure being invoked from an anonymous PL/SQL block:
[EclipseLink Fine]: 2007.11.23 03:39:55.000--DatabaseSessionImpl(25921812)-- Connection(33078541)--Thread(Thread[main,5,main])-- DECLARE X_TARGET VARCHAR(20) := :1; Y_TARGET BOOLEAN := SYS.SQLJUTL.INT2BOOL(:2); BEGIN two_args_inout(X=>X_TARGET, Y=>Y_TARGET); :3 := SYS.SQLJUTL.BOOL2INT(Y_TARGET); END; bind => [:1 => test, :2 => 1, Y => :3]
Note: The |
EclipseLink supports Oracle Virtual Private Database (VPD). Oracle VPD is a server-enforced, fine-grained access control mechanism. Oracle VPD ties a security policy to a table by dynamically appending SQL statements with a predicate to limit data access at the row level. You can create your own security policies, or use Oracle's custom implementation called Oracle Label Security (OLS). For details about Oracle VPD, see Oracle Database Security Guide. For details about Oracle Label Security, see Oracle Label Security Administrator's Guide.
For details about using Oracle VPD with Multitenancy, see Section 14.4, "Using VPD Multi-Tenancy."
To use the Oracle Database VPD feature in an EclipseLink application, an isolated cache should be used. Any entity that maps to a table that uses Oracle VPD should have the descriptor configured as isolated. In addition, you typically use exclusive connections.
To support Oracle VPD, you must implement session event handlers that the are invoked during the persistence context's life cycle. The session event handler you must implement depends on whether or not you are using Oracle Database proxy authentication.
Oracle VPD with Oracle Database Proxy Authentication
By using Oracle Database proxy authentication, you can set up Oracle VPD support entirely in the database. That is, rather than session event handlers to execute SQL, the database performs the required setup in an after login trigger using the proxy session_user.
For details on using Oracle proxy authentication, see Section 24.2.4, "Using Oracle Proxy Authentication."
Oracle VPD Without Oracle Database Proxy Authentication
If you are not using Oracle Database proxy authentication, implement session event handlers for the following session events:
postAcquireExclusiveConnection
: used to perform Oracle VPD setup at the time a dedicated connection is allocated to an isolated session and before the isolated session user uses the connection to interact with the database.
preReleaseExclusiveConnection
: used to perform Oracle VPD cleanup at the time the isolated session is released and after the user is finished interacting with the database.
In the implementation of these handlers, you can obtain the required user credentials from the associated session's properties.
JPA and EclipseLink are typically used in a middle tier/server environment with a shared connection pool. A connection pool allows database connections to be shared to avoid the cost of reconnecting to the database. Typically, the user logs into the application but does not have their own database login as a shared login is used for the connection pool. The provides a mechanism to set a proxy user on an existing database connection. This allows for a shared connection pool to be used, but to also gives the database a user context.
Oracle proxy authentication is configured using the following persistence unit properties on an EntityManager
object:
"eclipselink.oracle.proxy-type" : oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME, PROXYTYPE_CERTIFICATE, PROXYTYPE_DISTINGUISHED_NAME
oracle.jdbc.OracleConnection.PROXY_USER_NAME :
user_name
oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD :
password
oracle.jdbc.OracleConnection.PROXY_DISTINGUISHED_NAME
oracle.jdbc.OracleConnection.PROXY_CERTIFICATE
oracle.jdbc.OracleConnection.PROXY_ROLES
Note: This connection is only used for writing by default; reads still use the shared connection pool. To force reads to also use the connection, the |
To setup proxy authentication, create an EntityManager
object and set the persistence unit properties. Three examples are provided:
Task: Audit Only Writes
To configure proxy authentication when auditing only writes:
Map properties = new HashMap(); properties.put("eclipselink.oracle.proxy-type", oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password); properties.put("eclipselink.jdbc.exclusive-connection.mode", "Transactional"); properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "true"); EntityManager em = factory.createEntityManager(properties);
Task: Audit Reads and Writes
To configure proxy authentication when auditing reads and writes:
Map properties = new HashMap(); properties.put("eclipselink.oracle.proxy-type", oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password); properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always"); properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false"); EntityManager em = factory.createEntityManager(properties);
Task: Configure Proxy Authentication in Java EE Applications
If a JEE and JTA managed entity manager is used, specifying a proxy user and password can be more difficult, as the entity manager and JDBC connection is not under the applications control. The persistence unit properties can still be specified on an EntityManager
object as long as this is done before establishing a database connection.
If using JPA 2.0, the setProperty
API can be used:
em.setProperty("eclipselink.oracle.proxy-type", oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME); em.setProperty(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user); em.setProperty(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password); em.setProperty("eclipselink.jdbc.exclusive-connection.mode", "Always"); em.setProperty("eclipselink.jdbc.exclusive-connection.is-lazy", "false");
Otherwise, the getDelegate
API can be used:
Map properties = new HashMap(); properties.put("eclipselink.oracle.proxy-type", oracle.jdbc.OracleConnection.PROXYTYPE_USER_NAME); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_NAME, user); properties.put(oracle.jdbc.OracleConnection.PROXY_USER_PASSWORD, password); properties.put("eclipselink.jdbc.exclusive-connection.mode", "Always"); properties.put("eclipselink.jdbc.exclusive-connection.is-lazy", "false"); ((org.eclipse.persistence.internal.jpa.EntityManagerImpl)em.getDelegate()). setProperties(properties);
By default, EclipseLink maintains a shared (L2) object cache. This is fine for auditing, but if Oracle VPD or user based security is used to prevent the reading of certain tables/classes, then the cache may need to be disabled for these secure classes. To disable the shared cache, see "Disabling Entity Caching".
If the database user is used to check security for reads, then set the eclipselink.jdbc.exclusive-connection.mode
property to Isolated
to only use the user connection for reads for the classes whose shared cache has been disabled (isolated).
The Oracle Virtual Private Database (VPD) feature allows for row level security within the Oracle database. Typically, database security only allows access privileges to be assigned per table. Row level security allows different users to have access to different rows within each table.
The Oracle proxy authentication features in EclipseLink can be used to support Oracle VPD. The proxy user allows for the row level security to be checked. When using Oracle VPD, it is also important to disable shared caching for the secured objects as these objects should not be shared. To disable the shared cache, see "Disabling Entity Caching".
Oracle Real Application Clusters (RAC) extends the Oracle Database so that you can store, update, and efficiently retrieve data using multiple database instances on different servers at the same time. Oracle RAC provides the software that manages multiple servers and instances as a single group. Applications use Oracle RAC features to maximize connection performance and availability and to mitigate down-time due to connection problems. Applications have different availability and performance requirements and implement Oracle RAC features accordingly. For details on Oracle RAC, see the Oracle Real Application Clusters Administration and Deployment Guide.
The Oracle Database and the Oracle WebLogic Server both provide connection pool implementations that can create connections to a RAC database and take advantage of various Oracle RAC features. The features include Fast Connection Failover (FCF), Run-Time Connection Load Balancing (RCLB), and connection affinity. In WebLogic Server, applications create JDBC data sources (Multi Data Source or GridLink Data Source) to connect to a RAC-enabled database. Standalone applications use the Universal Connection Pool (UCP) JDBC connection pool API (ucp.jar
) to create data sources. Both connection pool implementations require the Oracle Notification Service library (ons.jar
). This library is the primary means by which the connection pools register for, and listen to, RAC events. For those new to these technologies, refer to the Oracle Universal Connection Pool for JDBC Developer's Guide and the Administering JDBC Data Sources for Oracle WebLogic Server.
This sections assumes that you have an Oracle JDBC driver and Oracle RAC-enabled database. Make sure that the RAC-enabled database is operational and that you know the connection URL. In addition, download the database Oracle Client software that contains the ons.jar
file. The ucp.jar
file is included with the Oracle Database.
The tasks in this section are used to connect to a RAC-enabled database from a persistence application implemented in Oracle WebLogic Server.
Refer to Chapter 3, "Using TopLink with WebLogic Server," and Administering JDBC Data Sources for Oracle WebLogic Server for details about configuring a data source in WebLogic Server for Oracle RAC.
Edit the persistence.xml
file and include the name of the data source within a persistence unit configuration. For example:
<persistence-unit name="OrderManagement"> <jta-data-source>jdbc/MyOrderDB</jta-data-source> ... </persistence-unit>
The tasks in this section are used to connect to a RAC database from a standalone persistence application. The tasks demonstrate how to use UCP data sources which are required for advanced RAC features.
A UCP data source is used to connect to a RAC database. The data source can specify advanced RAC configuration. For details on using advanced RAC features with UCP, see Oracle Universal Connection Pool for JDBC Developer's Guide. The following example creates a data source and enables FCF and configures ONS.
PoolDataSource datasource = PoolDataSourceFactory.getPoolDataSource(); datasource.setONSConfiguration(ānodes=host1:4200,host2:4200ā); datasource.setFastConnectionFailoverEnabled(true); datasource.setConnectionFactoryClassName(āoracle.jdbc.pool.OracleDataSourceā); datasource.setURL(ājdbc:oracle:thin:@DESCRIPTION= (LOAD_BALANCE=on) (ADDRESS=(PROTOCOL=TCP)(HOST=host1)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host3)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=host4)(PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=service_name)))ā);
Applications that do not require the advanced features provided by RAC and UCP can connect to a RAC-enabled database using the native connection pool in EclipseLink. In this case, edit the persistence.xml
file for you applications and add the RAC URL connection string for a persistence unit. For example:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0"> <persistence-unit name="my-app" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/> <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin@(DESCRIPTION= "+ "(LOAD_BALANCE=on)"+ "(ADDRESS=(PROTOCOL=TCP)(HOST=rac_node) (PORT=1521))"+ "(ADDRESS=(PROTOCOL=TCP)(HOST=racnode2) (PORT=1521))"+ "(CONNECT_DATA=(SERVICE_NAME=service_name))")"/> <property name="javax.persistence.jdbc.user" value="user_name"/> <property name="javax.persistence.jdbc.password" value="password"/> </properties> </persistence-unit> </persistence>
To use the persistence unit, instantiate an EntityManagerFactory
as follows:
Persistence.createEntityManagerFactory("my-app");
To use the UCP data source, instantiate an EntityManagerFactory
an pass in the data source as follows:
Map properties = new HashMap(); properties.add("javax.persistence.nonJtaDataSource", datasource); Persistence.createEntityManagerFactory(properties);
EclipseLink provides added support for querying Oracle Spatial and Graph data in the Oracle Database. Oracle Spacial and Graph is used to location-enable applications. It provides advanced features for spatial data and analysis and for physical, logical, network, and social and semantic graph applications. The spatial features provide a schema and functions that facilitate the storage, retrieval, update, and query of collections of spatial features in an Oracle database. For details about developing Oracle Spacial and Graph applications, see Oracle Spatial and Graph Developer's Guide. To use Oracle Spatial and Graph within WebLogic Server, see Chapter 3, "Task 7: Extend the Domain to Use Advanced Oracle Database Features,"
EclipseLink applications can construct expressions that use Oracle Spacial and Graph operators. See the org.eclipse.persistence.expressions.spatial
API for details. For Example:
ExpressionBuilder builder = new ExpressionBuilder(); Expression withinDistance = SpatialExpressions.withinDistance(myJGeometry1, myJGeometry2, "DISTANCE=10"); session.readAllObjects(GeometryHolder.class, withinDistance);
The above expression requires a oracle.spatial.geometry.JGeometry
object. Use the EclipseLink org.eclipse.persistence.platform.database.oracle.converters.JGeometryConverter
converter to convert the JGeometry
object as it is read and written from the Oracle database. The JGeometryConverter
object must be added to the Oracle Database platform either with the addStructConverter(StructConverter)
method or specified in the sessions.xml
file. The JGeometry
type must also be available on the classpath.
The following example demonstrates how to use the FUNCTION
JPA extension to perform Oracle Spatial queries. For details on the FUNCTION
extension, see Java Persistence API (JPA) Extensions Reference for Oracle TopLink:
SELECT a FROM Asset a, Geography geo WHERE geo.id = :id AND a.id IN :id_list AND FUNCTION('ST_INTERSECTS', a.geometry, geo.geometry) = 'TRUE' SELECT s FROM SimpleSpatial s WHERE FUNCTION('MDSYS.SDO_RELATE', s.jGeometry, :otherGeometry, :params) = 'TRUE' ORDER BY s.id ASC
See the following links for additional resources about the solutions discussed in this chapter.
This chapter provides instructions for storing mapping information in a metadata source that is external to the running application, so you can dynamically override or extend mappings in a deployed application.
This chapter contains the following sections:
Use Case
Users want to establish a SaaS environment, where applications are shared by multiple clients.
Solution
Employ TopLink SaaS features, such as extensibility, multi-tenancy, and external metadata sources.
Components
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
You can store your mapping information in a metadata source that is external to the running application. Because the mapping information is retrieved when the application creates the persistence unit, you can dynamically override or extend mappings in a deployed application.
With EclipseLink, you can use the eclipselink-orm.xml
file to support advanced mapping types and options. This file can override the standard JPA orm.xml
mapping configuration file.
To use an external metadata source for your mapping information, perform the following tasks:
In your persistence unit, specify the external metadata source by defining an eclipselink.metadata.source
property and assign as its value a class that implements org.eclipse.persistence.jpa.metadata.MetadataSource
. For example:
<property name="eclipselink.metadata-source" value="mypackage.MyMetadataSource"/>
You are free to provide the metadata location in your class as you choose, for example:
public class AdminMetadataSource extends XMLMetadataSource { @Override public XMLEntityMappings getEntityMappings(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) { String leagueId = (String) properties.get(LEAGUE_CONTEXT); properties.put(PersistenceUnitProperties.METADATA_SOURCE_XML_URL, "http://myserverlocation/rest/" + leagueId + "/orm"); return super.getEntityMappings(properties, classLoader, log); } }
To access the metadata file, the server must provide URL access to the mapping file by using any of the following:
Static file serving
A server-based solution with its own mapping file or a mapping file built on-demand from stored mapping information
Some other web technology.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter.
For additional information about JPA deployment, see the following sections of the JPA Specification (http://jcp.org/en/jsr/detail?id=317
):
Section 7.2, "Bootstrapping in Java SE Environments"
Chapter 7, "Container and Provider Contracts for Deployment and Bootstrapping"
For more information about persistence unit properties, see PersistenceUnitProperties
class in Oracle Fusion Middleware Java API Reference for EclipseLink.
For more information about the APIs, see the following in Java Persistence API (JPA) Extensions Reference for Oracle TopLink:
This chapter describes how to use Oracle TopLink as the persistence provider for applications deployed to Oracle GlassFish Server.
This chapter contains the following sections:
Use Case
Users want to run applications that employ JPA on Oracle GlassFish Server.
Solution
The Oracle GlassFish platform provides full support for EclipseLink. Developers writing applications for the GlassFish Server platform can achieve full Java-to-data source integration that complies with the Java Persistence API (JPA) 2.0 specification. EclipseLink allows you to integrate Java applications with any data source, without compromising ideal application design or data integrity.
Components
GlassFish Server 3.1.2.
TopLink 12c Release 1 (12.1.2) or later.
Note: TopLink's core functionality is provided by EclipseLink, the open source persistence framework from the Eclipse Foundation. EclipseLink implements Java Persistence API (JPA), Java Architecture for XML Binding (JAXB), and other standards-based persistence technologies, plus extensions to those standards. TopLink includes all of EclipseLink, plus additional functionality from Oracle. |
Any compliant JDBC database including Oracle Database, Oracle Database Express Edition, MySQL, and so on.
While it is not required, you may want to use a Java EE integrated development environment (IDE) for convenience during development.
Oracle GlassFish Server is the reference implementation of the Java Platform, Enterprise Edition (Java EE platform) specification. Built using the GlassFish Server Open Source Edition, GlassFish Server delivers a flexible, lightweight, and production-ready Java EE platform.
GlassFish Server is part of the Oracle Fusion Middleware application grid portfolio of products and is ideally suited for applications requiring lightweight infrastructure with the most up-to-date implementation of the Java EE platform. GlassFish Server complements Oracle WebLogic Server, which is designed to run the broader portfolio of Oracle Fusion Middleware and large-scale enterprise applications.
By adding TopLink support, developers writing applications for the GlassFish Server platform can achieve full Java-to-data source integration that complies with the Java Persistence API (JPA) 2.0 specification. TopLink allows you to integrate Java applications with any data source, without compromising ideal application design or data integrity. In addition, TopLink gives your GlassFish Server platform applications the ability to store (that is, persist) and retrieve business domain objects using a relational database or an XML data source as a repository.
While GlassFish Server can use other persistence providers and TopLink can be used with other application servers, using GlassFish Server with TopLink provides a number of advantages:
TopLink is included in all GlassFish Server distributions and is the default JPA provider.
TopLink allows applications running on GlassFish Server to use Oracle Coherence caches. Coherence is a Java-based in-memory application grid product that provides data caching, data replication, and distributed computing services. TopLink includes features that allow deployed applications to use Coherence data caches and to incorporate TopLink Grid as an object-to-relational persistence framework. How to use this feature is beyond the scope of this guide. See Integrating Oracle Coherence for more information.
TopLink logging integration in GlassFish Server provides a comprehensive, integrated logging infrastructure.
EclipseLink JAXB is also included in GlassFish versions 3.1.2 and later. Although it is not the default JAXB implementation, it can be used in JAX-WS and JAX-RS applications. For more information, see: http://blog.bdoughan.com/2012/02/glassfish-312-is-full-of-moxy.html
GlassFish Server supports the Oracle Application Development Framework (Oracle ADF), an end-to-end Java EE framework, based on Struts and JavaServer Faces (JSF). Oracle ADF simplifies application development by providing infrastructure services and a visual and declarative development experience. TopLink and Oracle ADF together provide a complete Java EE application infrastructure. Oracle ADF is beyond the scope of this guide. See Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Figure 4-1 illustrates how GlassFish Server and TopLink are related to and used with other Oracle products. The following are examples of using GlassFish Server and TopLink with other Oracle Middleware products:
Use EclipseLink as the persistence provider.
Use Oracle Coherence (through Oracle TopLink Grid integration) for data caching, data replication and distributed computing services.
Use GlassFish as the application server.
Use the Oracle database for persisting data.
Note: Oracle Coherence and TopLink Grid are beyond the scope of this guide. For information about Coherence, see Developing Applications with Oracle Coherence, and follow links to other Coherence documentation. For information about TopLink Grid, see Integrating Oracle Coherence. |
To run EclipseLink JPA applications in GlassFish Server, you must configure the server and coordinate certain server and application settings. These are described in the following tasks.
This document is based on the following products and tools, although the principles apply to any supported database or development environment. It is assumed that the software is already installed, except where noted in later sections.
GlassFish Server 3.1.2.
For more information and downloads, see http://www.oracle.com/technetwork/middleware/glassfish/overview/index.html
on the Oracle Technology Network.
EclipseLink 2.4.1.
For more information and downloads, see http://www.eclipse.org/eclipselink/
on the EclipseLink website.
Any compliant JDBC database including Oracle Database, Oracle Database Express Edition, MySQL, and so on.
For Oracle Database, see http://www.oracle.com/technetwork/database/enterprise-edition/overview/index.html
.
For Oracle Database Express Edition, see http://www.oracle.com/technetwork/database/express-edition/overview/index.html
.
For MySQL, see http://www.oracle.com/us/products/mysql/index.html
.
While it is not required, you may want to use a Java EE integrated development environment (IDE) for convenience during development. For example, Oracle JDeveloper, Oracle Enterprise Pack for Eclipse, and NetBeans all provide sophisticated Java EE development tools.
For JDeveloper, see http://www.oracle.com/technetwork/developer-tools/jdev/downloads/index.html
.
For Oracle Enterprise Pack for Eclipse, see http://www.oracle.com/technetwork/developer-tools/eclipse/overview/index.html
.
For NetBeans, see http://www.oracle.com/us/products/tools/050845.html
.
EclipseLink is included with the GlassFish Server distribution. You can find instructions for installing and configuring in the Oracle GlassFish Server Documentation Library.
The EclipseLink modules appear as separate JAR files in the modules
directory.
* \glassfish\modules . . . o org.eclipse.persistence.antlr.jar o org.eclipse.persistence.asm.jar o org.eclipse.persistence.core.jar o org.eclipse.persistence.jpa.jar o org.eclipse.persistence.jpa.modelgen.jar o org.eclipse.persistence.moxy.jar o org.eclipse.persistence.oracle.jar . . .
Note:
|
Object-XML (also known as JAXB support) is a component that enables you to bind Java classes to XML schemas. This support is provided by the org.eclipse.persistence.moxy.jar
.
Configuring an Oracle database as a JDBC resource for a Java EE application involves the following steps:
To integrate the JDBC driver, copy its JAR file into the domain and then restart the domain and instances to make the driver available.
Copy the JAR file for the JDBC driver into the domain's lib
subdirectory, for example:
cd /home/gfuser/glassfish3 cp oracle-jdbc-drivers/ojdbc6.jar glassfish/domains/domain1/lib
Note that you do not have to restart GlassFish Server; the drivers are picked up dynamically.
If the application uses Oracle Database-specific extensions provided by EclipseLink, then the driver must be copied to the lib/ext
directory. For more information, see "Oracle Database Enhancements" in the Oracle GlassFish Server Application Development Guide.
You can use the GlassFish Server Administration Console or the command line to restart instances in the domain to make the JDBC driver available to the instances.
To use the GlassFish Server Administration Console:
In the GlassFish Server Administration Console, expand the Cluster node. Select the node for the cluster and on its General Information page, click the Instances tab. Select the instances you want to restart. For more information, see "To Start Clustered GlassFish Server Instances" in GlassFish Server Administration Console Online Help.
To start a standalone instance, expand the Standalone Instances node. For each instance that you are starting, select the instance in the Server Instances table. Click Start. The status of each instance is updated in the Server Instances table when the instance is started. For more information, see "To Start Standalone GlassFish Server Instances" in GlassFish Server Administration Console Online Help.
To use the command line:
Run the restart-instance
subcommand to restart the instances. These commands assume that your instances are named pmd-i1
and pmd-i2
.
restart-instance pmd-i1 restart-instance pmd-i2
You can create a JDBC connection pool from the GlassFish Server Administration Console or from the command line.
To use the GlassFish Server Administration Console:
In the GlassFish Server Administration Console, expand the Common Tasks node, then click the Create New JDBC Connection Pool button in the Common Tasks page. Specify the name of the pool, the resource type, the name of the database provider, the data source and driver class names, and other details. For more information, see "To Create a JDBC Connection Pool" in GlassFish Server Administration Console Online Help.
To use the command line:
Use the create-jdbc-connection-pool
subcommand to create the JDBC connection pool, specifying the database connectivity values. In this command, note the use of two backslashes (\\
) preceding the colons in the URL property value. These backslashes cause the colons to be interpreted as part of the property value instead of as separators between property-value pairs, for example:
create-jdbc-connection-pool --datasourceclassname oracle.jdbc.pool.OracleDataSource --restype javax.sql.DataSource --property User=smith\\:Password=password\\:url=jdbc\\:oracle\\:thin\\:@node_name.example.com\\:1521\\:smithdb poolbvcallbackbmt
Verify connectivity to the database.
ping-connection-pool pool_name
You can use the GlassFish Server Administration Console to create the JDBC resource or you can use the command line.
To use the GlassFish Server Administration Console:
In the GlassFish Server Administration Console, expand the Resources node, then the JDBC node, then the JDBC Resources node to open the JDBC Resources page. Provide a unique JNDI resource name and associate the resource with a connection pool. For more information, see "To Create a JDBC Resource" in the GlassFish Server Administration Console Online Help.
To use the command line:
Use the create-jdbc-resource
subcommand to create the JDBC resource, and name it so that the application can discover it using JNDI lookup, for example:
create-jdbc-resource --connectionpoolid poolbvcallbackbmt jdbc/bvcallbackbmt
Example 4-1 illustrates a sample persistence.xml
file that specifies the default persistence provider for EclipseLink, org.eclipse.persistence.jpa.PersistenceProvider
. For more information about this file, see "About the Persistence Unit" in Understanding Oracle TopLink.
If you are using the default persistence provider, then you can specify additional database properties described in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
Several of the values you enter in the file must match the values you chose when you defined the cluster, connection, and connection pool properties in GlassFish Server, as follows:
JDBC Data Source Properties:
Name: The name of the data source, which is typically the same as the JNDI name, for example jdbc/bvcallbackbmt
.
JNDI Name: The JNDI path to where this data source is bound. This must be the same name as the value for the <jta-data-source>
element in persistence.xml
, for example jdbc/bvcallbackbmt
.
Database Type: Oracle
Database Driver: (default) Oracle's Driver (Thin XA) for Instance connections; Versions: 9.0.1 and later
Connection Properties:
Database Name: The name of the database, for example, XE
for Oracle Database Express Edition samples.
Host Name: The IP address of the database server, for example 127.0.0.1
for a locally hosted database.
Port: The port number on which your database server listens for connection requests, for example, 1521
, the default for Oracle Database Express Edition 11g.
Database User Name: The database account user name used to create database connections, for example hr
for Oracle Database Express Edition 11g samples.
Password: Your password.
Select Targets:
Servers / Clusters: Select the administration server, managed servers, or clusters to which you want to deploy the data source. You can choose one or more.
The sample persistence.xml
file in Example 4-1 highlights the properties defining the persistence provider, the JTA data source, and logging details. In this example, the logging level is set to FINE
. At this level, SQL code generated by EclipseLink is logged to the server.log
file. For more information about these properties, see:
Example 4-1 Sample persistence.xml File
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="pu1" transaction-type="JTA"><provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/bvcallbackbmt</jta-data-source>
<properties><property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
The persistence provider defines the implementation of JPA. It is defined in the provider
element of the persistence.xml
file. Persistence providers are vendor-specific. The persistence provider for EclipseLink is org.eclipse.persistence.jpa.PersistenceProvider
.
You specify the database connection details in the persistence.xml
file. GlassFish Server uses the bundled Java DB (Derby) database by default, named jdbc/__default
. To use a nondefault database, such as the Oracle Database, either specify a value for the jta-data-source
element, or set the transaction-type
element to RESOURCE_LOCAL
and specify a value for the non-jta-data-source
element.
If you are using the default persistence provider, org.eclipse.persistence.jpa.PersistenceProvider
, then the provider attempts to automatically detect the database type based on the connection metadata. This database type is used to issue SQL statements specific to the detected database type. You can specify the optional eclipselink.target-database
property to guarantee that the database type is correct.
For more information about specifying database properties in a persistence.xml
file for GlassFish Server, see "Specifying the Database for an Application" in the Oracle GlassFish Server Application Development Guide.
EclipseLink provides a logging utility even though logging is not part of the JPA specification. Hence, the information provided by the log is EclipseLink JPA-specific. With EclipseLink, you can enable logging to view the following information:
Configuration details
Information to facilitate debugging
The SQL that is being sent to the database
You can specify logging in the persistence.xml
file. EclipseLink logging properties let you specify the level of logging and whether the log output goes to a file or standard output. Because the logging utility is based on java.util.logging
, you can specify a logging level to use.
The logging utility provides nine levels of logging control over the amount and detail of the log output. Use eclipselink.logging.level
to set the logging level, for example:
<property name="eclipselink.logging.level" value="FINE"/>
By default, the log output goes to System.out
or to the console. To configure the output to be logged to a file, set the property eclipselink.logging.file
, for example:
<property name="eclipselink.logging.file" value="output.log"/>
EclipseLink's logging utility is pluggable, and several different logging integrations are supported, including java.util.logging
. To enable java.util.logging
, set the property eclipselink.logging.logger
, for example:
<property name="eclipselink.logging.logger" value="JavaLogger"/>
While running inside GlassFish Server, EclipseLink is configured by GlassFish Server to use JavaLogger
by default. The log is always redirected to the GlassFish Server server.log
file. For more information, see "Setting Log Levels" in Oracle GlassFish Server Administration Guide.
For more information about EclipseLink logging and the levels of logging available in the logging utility, see "Persistence Property Extensions Reference" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.
"Configuring the Java Persistence Provider" in the GlassFish Server Application Development Guide describes server-specific considerations on setting up GlassFish Server to run applications that employ JPA.
It provides more information about these topics:
"Specifying the Database for an Application," for information about database connection properties
"Specifying the Persistence Provider for an Application," for setting the default or non-default persistence provider for an application
"Primary Key Generation Defaults," for the default persistence provider's primary key generation defaults
"Automatic Schema Generation," for information on annotations and options to manage automatic schema generation
"Restrictions and Optimizations," for restrictions and performance optimizations that affect using the Java Persistence API
To creat7Čše an application that uses EclipseLink as its JPA persistence provider, you may want to use a Java EE IDE for convenience during development. For example, JDeveloper, Oracle Enterprise Pack for Eclipse, and NetBeans provide sophisticated Java EE development tools, including support for EclipseLink. See "Key Tools" in Understanding Oracle TopLink.
For guidance in writing your application, see these topics from the "Configuring the Java Persistence Provider" chapter in Oracle GlassFish Server Application Development Guide.
For information about deploying to GlassFish Server, see "Deploy Applications or Modules," "To Deploy an Enterprise Application," and "To Deploy a Web Application" in GlassFish Server Administration Console Online Help. See also the Oracle GlassFish Server Application Deployment Guide.
For instructions for starting a deployed application from the GlassFish Server Administration Console, see "Application Client Launch" and "To Launch an Application" in GlassFish Server Administration Console Online Help.
GlassFish Server provides a monitoring service to track the health and performance of an application. For information about monitoring an application from the console, see the "Monitoring" and "Monitoring Data" topics in GlassFish Server Administration Console Online Help. For information about monitoring the application from the command line, see "Administering the Monitoring Service" in Oracle GlassFish Server Administration Guide.
See the following resources for more information about the technologies and tools used to implement the solutions in this chapter:
Oracle TopLink, with its core features provided by EclipseLink, the open source persistence framework from the Eclipse Foundation, delivers a standards-based enterprise Java solution for all of your relational, XML, and JSON persistence requirements, based on high performance and scalability, developer productivity, and flexibility in architecture and design.
A variety of engineers use TopLink. Users of TopLink are expected to be proficient in the use of technologies and services related to TopLink (for example, Java Persistence API). This guide does not include details about related common tasks, but focuses on TopLink functionality.
Users of this guide include:
Developers who want to develop applications using any of the following technologies for persistence services:
Java Persistence API (JPA) 2.n plus EclipseLink JPA extensions
Java Architecture for XML Binding 2.n (JAXB) plus EclipseLink Object-XML extensions
EclipseLink Database Web Services (DBWS)
Developers should be familiar with the concepts and programming practices of Java Platform, Standard Edition (Java SE platform), and Java Platform, Enterprise Edition (Java EE platform).
Developers using EclipseLink JPA should be familiar with the concepts and programming practices of JPA 2.1, as specified in the Java Persistence Architecture 2.1 specification at http://jcp.org/en/jsr/detail?id=338
.
Developers using EclipseLink Object-XML should be familiar with the concepts and programming practices of JAXB 2.0, as specified in the Java Architecture for XML Binding 2.0 specification at http://jcp.org/aboutJava/communityprocess/pfd/jsr222/index.html
.
Developers using EclipseLink DBWS should be familiar with the concepts and programming practices of JAX-WS 2.0, as specified in the Java API for XML-Based Web Services 2.0 specification at http://jcp.org/aboutJava/communityprocess/pfd/jsr222/index.html
.
Administrators and deployers who want to deploy and manage applications using TopLink persistence technologies. These users should be familiar with basic operations of the chosen application server.
For information about Oracle's commitment to accessibility, visit the Oracle Accessibility Program website at http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc
.
Access to Oracle Support
Oracle customers have access to electronic support through My Oracle Support. For information, visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info
or visit http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs
if you are hearing impaired.
For more information, see the following documents:
Java Persistence API (JPA) Extensions Reference for Oracle TopLink
Developing Persistence Architectures Using Oracle TopLink Database Web Services Developer's Guide
EclipseLink Documentation Center at http://www.eclipse.org/eclipselink/documentation/
The following text conventions are used in this guide:
Convention | Meaning |
---|---|
boldface |
Boldface type indicates graphical user interface elements associated with an action, or terms defined in text or the glossary. |
italic |
Italic type indicates book titles, emphasis, or placeholder variables for which you supply particular values. |
|
Monospace type indicates commands within a paragraph, URLs, code in examples, text that appears on the screen, or text that you enter. |
|
Bold monospace type is used in code examples to emphasize certain items. |