openjpa/openjpa-project/src/doc/manual/ref_guide_remote.xml

796 lines
33 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<chapter id="ref_guide_remote">
<title>
Remote and Offline Operation
</title>
<indexterm zone="ref_guide_remote">
<primary>
remote
</primary>
</indexterm>
<indexterm>
<primary>
offline
</primary>
<see>
remote
</see>
</indexterm>
<para>
The standard JPA runtime environment was originally just
<emphasis>local</emphasis> and
<emphasis>online</emphasis>. It is <emphasis>local</emphasis> in that components
such as <classname>EntityManager</classname>s and queries connect directly to
the datastore and execute their actions in the same JVM as the code using them.
It is <emphasis>online</emphasis> in that all changes to managed objects must be
made in the context of an active <classname> EntityManager</classname>. These
two properties, combined with the fact that <classname>
EntityManager</classname>s cannot be serialized for storage or network transfer,
made the standard JPA runtime difficult to incorporate into some enterprise and
client/server program designs.
</para>
<para>
JPA has now provided <emphasis>offline</emphasis> capability through the
detach() and merge() methods on the EntityManager interface. OpenJPA has
extended this to include additional detach...() and merge...() methods. All of
these are documented in
<link linkend="ref_guide_detach">Detach and Attach APIs</link>. In addition,
OpenJPA has added <emphasis>remote</emphasis> capability in the form of
<link linkend="ref_guide_event">Remote Commit Events</link>. The following
sections explain these capabilities in detail.
</para>
<section id="ref_guide_detach">
<title>
Detach and Attach
</title>
<indexterm zone="ref_guide_detach">
<primary>
detachment
</primary>
</indexterm>
<indexterm>
<primary>
attachment
</primary>
<see>
detachment
</see>
</indexterm>
<para>
The JPA Overview describes the specification's standard detach and attach APIs
in <xref linkend="jpa_overview_em_lifecycle"/>. This section enumerates
OpenJPA's enhancements to the standard behavior.
</para>
<section id="ref_guide_detach_behavior">
<title>
Detach Behavior
</title>
<indexterm zone="ref_guide_detach_behavior">
<primary>
detachment
</primary>
<secondary>
behavior
</secondary>
</indexterm>
<note>
<para>
In version 2.0, the detach behavior has changed from the previous
version. See the migration section
<link linkend="migration_detach_behavior">Detach Behavior</link> for details.
</para>
</note>
<para>
In JPA, objects detach automatically when they are serialized or when a
<link linkend="jpa_overview_emfactory_perscontext">persistence context</link>
ends. The specification also allows objects to be explicitly detached using
the following jakarta.persistence.EntityManager method:
</para>
<programlisting>
public void detach(Object)
</programlisting>
<para>
<ulink url="../../apidocs/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
<classname>OpenJPAEntityManager</classname></ulink>, however, provides
additional detach methods.
</para>
<programlisting>
public &lt;T&gt; T detachCopy(T pc):
public Object[] detachAll(Object... pcs):
public Collection detachAll(Collection pcs):
</programlisting>
<para>
The behavior of the detach operation is as follows:
<itemizedlist>
<listitem>
The detached objects are removed from the persistent context.
</listitem>
<listitem>
The objects are <emphasis>not</emphasis> flushed to the database.
</listitem>
<listitem>
If Cascade=detach is specified for a referenced entity, the detach
operation is cascaded. Otherwise, it is not.
</listitem>
<listitem>
For the detachCopy method only, the entity is copied for the return
value.
</listitem>
</itemizedlist>
</para>
</section>
<section id="ref_guide_attach_behavior">
<title>
Attach Behavior
</title>
<indexterm zone="ref_guide_attach_behavior">
<primary>
attachment
</primary>
<secondary>
behavior
</secondary>
</indexterm>
<para>
When attaching, OpenJPA uses several strategies to determine the optimal way to
merge changes made to the detached instance. As you will see, these strategies
can even be used to attach changes made to a transient instance which was never
detached in the first place.
</para>
<itemizedlist>
<listitem>
<para>
If the instance was detached and <link linkend="ref_guide_detach_graph">
detached state</link> is enabled, OpenJPA will use the detached state to
determine the object's version and primary key values. In addition, this state
will tell OpenJPA which fields were loaded at the time of detach, and in turn
where to expect changes. Loaded detached fields with null values will set the
attached instance's corresponding fields to null.
</para>
</listitem>
<listitem>
<para>
If the instance has a <literal>Version</literal> field,
OpenJPA will consider the object detached if the version field has a non-default
value, and new otherwise. Similarly, if the instance has
<literal>GeneratedValue</literal> primary key fields, OpenJPA will consider the
object detached if any of these fields have non-default values, and new
otherwise.
</para>
<para>
When attaching null fields in these cases, OpenJPA cannot distinguish between a
field that was unloaded and one that was intentionally set to null. In this
case, OpenJPA will use the current <link linkend="ref_guide_detach_graph">
detach state</link> setting to determine how to handle null fields: fields that
would have been included in the detached state are treated as loaded, and will
in turn set the corresponding attached field to null.
</para>
</listitem>
<listitem>
<para>
If neither of the above cases apply, OpenJPA will check to see if an instance
with the same primary key values exists in the database. If so, the object is
considered detached. Otherwise, it is considered new.
</para>
</listitem>
</itemizedlist>
<para>
These strategies will be assigned on a per-instance basis, such that during the
attachment of an object graph more than one of the above strategies may be used.
</para>
<para>
If you attempt to attach a versioned instance whose representation has changed
in the datastore since detachment, OpenJPA will throw an optimistic concurrency
exception upon commit or flush, just as if a normal optimistic conflict was
detected. When attaching an instance whose database record has been deleted
since detaching, or when attaching a detached instance into a manager that has a
stale version of the object, OpenJPA will throw an optimistic concurrency
exception from the attach method. In these cases, OpenJPA sets the <literal>
RollbackOnly</literal> flag on the transaction.
</para>
</section>
<section id="ref_guide_detach_graph">
<title>
Defining the Detached Object Graph
</title>
<indexterm zone="ref_guide_detach_graph">
<primary>
detachment
</primary>
<secondary>
defining the object graph
</secondary>
</indexterm>
<para>
When detached objects lose their association with the OpenJPA runtime, they also
lose the ability to load additional state from the datastore. It is important,
therefore, to populate objects with all the persistent state you will need
before detaching them. While you are free to do this manually, OpenJPA includes
facilities for automatically populating objects when they detach.
</para>
<section id="ref_guide_detach_state">
<title>
Detached State
</title>
<indexterm zone="ref_guide_detach_state">
<primary>
detachment
</primary>
<secondary>
detached state
</secondary>
</indexterm>
<para>
The <link linkend="openjpa.DetachState"><literal>openjpa.DetachState</literal>
</link> configuration property determines which fields and relations are
detached by default. All settings are recursive. They are:
</para>
<orderedlist>
<listitem>
<para>
<literal>loaded</literal>: Detach all fields and relations that are already
loaded, but don't include unloaded fields in the detached graph. This is the
default.
</para>
</listitem>
<listitem>
<para>
<literal>fetch-groups</literal>: Detach all fields and relations in the current
<link linkend="ref_guide_runtime">fetch configuration</link>. For more
information on custom fetch groups, see <xref linkend="ref_guide_fetch"/>.
</para>
</listitem>
<listitem>
<para>
<literal>all</literal>: Detach all fields and relations. Be very careful when
using this mode; if you have a highly-connected domain model, you could end up
bringing every object in the database into memory!
</para>
</listitem>
</orderedlist>
<para>
Any field that is not included in the set determined by the detach mode is set
to its Java default value in the detached instance.
</para>
<para>
The <literal>openjpa.DetachState</literal> option is actually a plugin string
(see <xref linkend="ref_guide_conf_plugins"/>) that allows you to also
configure the following options related to detached state:
</para>
<itemizedlist>
<listitem>
<para>
<literal>DetachedStateField</literal>: As described in
<xref linkend="ref_guide_attach_behavior"/> above, OpenJPA can take
advantage of a <emphasis>detached state field</emphasis> to make the attach
process more efficient. This field is added by the enhancer and is not visible
to your application. Set this property to one of the following values:
</para>
<itemizedlist>
<listitem>
<para>
<literal>transient</literal>: Use a transient detached state field. This gives
the benefits of a detached state field to local objects that are never
serialized, but retains serialization compatibility for client tiers without
access to the enhanced versions of your classes or the OpenJPA runtime.
This is the default.
</para>
</listitem>
<listitem>
<para>
<literal>true</literal>: Use a non-transient detached state field so that
objects crossing serialization barriers can still be attached efficiently. This
requires, however, that your client tier have the enhanced versions of your
classes and the OpenJPA runtime.
</para>
</listitem>
<listitem>
<para>
<literal>false</literal>: Do not use a detached state field. No OpenJPA runtime
will be required for client tiers.
</para>
</listitem>
</itemizedlist>
<para>
The detached state field is also used to determine when proxies should be
removed from entities during serialization. See the
<xref linkend="ref_guide_pc_scos_proxy_serial"/> section for more details.
</para>
<para>
You can override the setting of this property or declare your own detached state
field on individual classes using OpenJPA's metadata extensions. See
<xref linkend="ref_guide_detach_field"/> below.
</para>
</listitem>
<listitem>
<para>
<literal>DetachedStateManager</literal>: Whether to use a detached state
manager. A detached state manager makes attachment much more efficient. Like a
detached state field, however, it breaks serialization compatibility with the
unenhanced class if it isn't transient.
</para>
<para>
This setting piggybacks on the <literal>DetachedStateField</literal> setting
above. If your detached state field is transient, the detached state manager
will also be transient. If the detached state field is disabled, the detached
state manager will also be disabled. This is typically what you'll want. By
setting <literal> DetachedStateField</literal> to true (or transient) and
setting this property to false, however, you can use a detached state field
<emphasis role="bold">without</emphasis> using a detached state manager. This
may be useful for debugging or for legacy OpenJPA users who find differences
between OpenJPA's behavior with a detached state manager and OpenJPA's older
behavior without one.
</para>
</listitem>
<listitem>
<para>
<literal>AccessUnloaded</literal>: Whether to allow access to unloaded fields
of detached objects. Defaults to true. Set to false to throw an exception
whenever an unloaded field is accessed. This option is only available when you
use detached state managers, as determined by the settings above.
</para>
</listitem>
<listitem>
<para>
<literal>LiteAutoDetach</literal>: <emphasis role="bold">This option is ONLY valid for the <literal>loaded</literal>
DetachState setting.</emphasis> Detach all fields and relations as described by the loaded
property when an explicit detach is requested or when a
single Entity is being detached as part of serialization. When the entire
persistence context is being auto-detached ( <literal>openjpa.AutoDetach</literal> ),
the minimal amount of work will be completed to disassociate all Entities from
the persistence context. <emphasis role="bold">It is highly recommended that all Entities have a
@Version field when using this property</emphasis>. In addition, care needs to be taken
when this value is set to true as the following caveats apply:
<itemizedlist>
<listitem>
<para>
A relationship from a managed Entity to an unmanaged Entity which was detached by the lite detach setting will not be persisted.
</para>
</listitem>
<listitem>
<para>
When merging a detached Entity back into the persistence context any lazily loaded fields that were marked to null when detached will not be persisted.
</para>
</listitem>
</itemizedlist>
</para>
</listitem>
<listitem>
<para>
<literal>DetachProxyFields</literal>: <emphasis role="bold">This option is ONLY valid when used in conjunction with the <literal>LiteAutoDetach</literal>
DetachState setting.</emphasis> When detaching the persistence context, all proxies will be left in place. Note, that
all <literal>Large Result Sets</literal> will be removed.
</para>
<itemizedlist>
<listitem>
<literal>true(default)</literal>: All proxies will be removed and LRS fields will be removed.
</listitem>
<listitem>
<literal>false</literal>: All proxies will be left in place and LRS fields will be removed.
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<example id="ref_guide_detach_graph_confex">
<title>
Configuring Detached State
</title>
<programlisting>
&lt;property name="openjpa.DetachState" value="fetch-groups(DetachedStateField=true)"/&gt;
</programlisting>
</example>
<para>
You can also alter the set of fields that will be included in the detached graph
at runtime.
<ulink url="../../apidocs/org/apache/openjpa/persistence/OpenJPAEntityManager.html">
<classname>OpenJPAEntityManager</classname></ulink>s expose the following APIs
for controlling detached state:
</para>
<programlisting>
public DetachStateType getDetachState();
public void setDetachState(DetachStateType type);
</programlisting>
<para>
The <classname>DetachStateType</classname> enum contains the following values:
</para>
<programlisting>
enum DetachStateType {
FETCH_GROUPS,
LOADED,
ALL
}
</programlisting>
</section>
<section id="ref_guide_detach_field">
<title>
Detached State Field
</title>
<indexterm zone="ref_guide_detach_field">
<primary>
detachment
</primary>
<secondary>
detached state field
</secondary>
</indexterm>
<para>
When the detached state field is enabled, the OpenJPA enhancer adds an
additional field to the enhanced version of your class. This field of type
<classname>Object</classname>. OpenJPA uses this field for bookkeeping
information, such as the versioning data needed to detect optimistic concurrency
violations when the object is re-attached.
</para>
<para>
It is possible to define this detached state field yourself. Declaring this
field in your class metadata prevents the enhancer from adding any extra fields
to the class, and keeps the enhanced class serialization-compatible with the
unenhanced version. The detached state field must not be persistent. See
<xref linkend="detached-state-field"/> for details on how to declare a
detached state field.
</para>
<programlisting>
import org.apache.openjpa.persistence.*;
@Entity
public class Magazine
implements Serializable {
private String name;
@DetachedState private Object state;
...
}
</programlisting>
</section>
</section>
</section>
<section id="ref_guide_event">
<title>
Remote Event Notification Framework
</title>
<indexterm zone="ref_guide_event">
<primary>
remote
</primary>
<secondary>
events
</secondary>
</indexterm>
<indexterm>
<primary>
events
</primary>
<secondary>
remote
</secondary>
<see>
remote, events
</see>
</indexterm>
<para>
<indexterm>
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
RemoteCommitProvider
</tertiary>
</indexterm>
<indexterm>
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
RemoteCommitListener
</tertiary>
</indexterm>
The remote event notification framework allows a subset of the information
available through OpenJPA's transaction events (see
<xref linkend="ref_guide_runtime_pm_event"/>) to be broadcast to remote
listeners. OpenJPA's <link linkend="ref_guide_cache">data cache</link>, for
example, uses remote events to remain synchronized when deployed in multiple
JVMs.
</para>
<para>
To enable remote events, you must configure the <classname> EntityManagerFactory
</classname> to use a <literal>RemoteCommitProvider</literal> (see below).
</para>
<para>
When a <literal>RemoteCommitProvider</literal> is properly configured, you can
register
<ulink url="../../apidocs/org/apache/openjpa/event/RemoteCommitListener.html">
<classname>RemoteCommitListener</classname></ulink>s that will be alerted with
a list of modified object ids whenever a transaction on a remote machine
successfully commits.
</para>
<section id="ref_guide_event_conf">
<title>
Remote Commit Provider Configuration
</title>
<indexterm zone="ref_guide_event_conf">
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
configuration
</tertiary>
</indexterm>
<para>
OpenJPA includes built in remote commit providers for JMS and TCP communication.
</para>
<section id="ref_guide_event_conf_jms">
<title>
JMS
</title>
<indexterm zone="ref_guide_event_conf_jms">
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
JMS
</tertiary>
</indexterm>
<para>
The JMS remote commit provider can be configured by setting the
<link linkend="openjpa.RemoteCommitProvider"><literal>
openjpa.RemoteCommitProvider</literal></link> property to contain the
appropriate configuration properties. The JMS provider understands the following
properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>Topic</literal>: The topic that the remote commit provider should
publish notifications to and subscribe to for notifications sent from other
JVMs. Defaults to <literal>topic/OpenJPACommitProviderTopic</literal>
</para>
</listitem>
<listitem>
<para>
<literal>TopicConnectionFactory</literal>: The JNDI name of a <classname>
jakarta.jms.TopicConnectionFactory</classname> factory to use for finding topics.
Defaults to <literal> java:/ConnectionFactory</literal>. This setting may vary
depending on the application server in use; consult the application server's
documentation for details of the default JNDI name for the <classname>
jakarta.jms.TopicConnectionFactory</classname> instance. For example, under
Weblogic, the JNDI name for the TopicConnectionFactory is <literal>
jakarta.jms.TopicConnectionFactory</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>ExceptionReconnectAttempts</literal>: The number of times to attempt
to reconnect if the JMS system notifies OpenJPA of a serious connection error.
Defaults to 0, meaning OpenJPA will log the error but otherwise ignore it,
hoping the connection is still valid.
</para>
</listitem>
<listitem>
<para>
<literal>*</literal>: All other configuration properties will be interpreted as
settings to pass to the JNDI <classname>InitialContext</classname> on
construction. For example, you might set the <literal>java.naming.provider.url
</literal> property to the URL of the context provider.
</para>
</listitem>
</itemizedlist>
<para>
To configure a factory to use the JMS provider, your properties might look like
the following:
</para>
<example id="ref_guide_event_conf_jmsex">
<title>
JMS Remote Commit Provider Configuration
</title>
<programlisting>
&lt;property name="openjpa.RemoteCommitProvider"
value="jms(ExceptionReconnectAttempts=5)"/&gt;
</programlisting>
</example>
<note>
<para>
Because of the nature of JMS, it is important that you invoke <methodname>
EntityManagerFactory.close</methodname> when finished with a factory. If you do
not do so, a daemon thread will stay up in the JVM, preventing the JVM from
exiting.
</para>
</note>
</section>
<section id="ref_guide_event_conf_tcp">
<title>
TCP
</title>
<indexterm zone="ref_guide_event_conf_tcp">
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
TCP
</tertiary>
</indexterm>
<para>
The TCP remote commit provider has several options that are defined as host
specifications containing a host name or IP address and an optional port
separated by a colon. For example, the host specification <literal>
saturn.bea.com:1234</literal> represents an <classname>InetAddress</classname>
retrieved by invoking <methodname>InetAddress.getByName("saturn.bea.com")
</methodname> and a port of 1234.
</para>
<para>
<indexterm>
<primary>
TCP provider
</primary>
</indexterm>
The TCP provider can be configured by setting the <literal>
openjpa.RemoteCommitProvider</literal> plugin property to contain the
appropriate configuration settings. The TCP provider understands the following
properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>Port</literal>: The TCP port that the provider should listen on for
commit notifications. Defaults to 5636.
</para>
</listitem>
<listitem>
<para>
<literal>Addresses</literal>: A semicolon-separated list of IP addresses to
which notifications should be sent. No default value.
</para>
</listitem>
<listitem>
<para>
<literal>NumBroadcastThreads</literal>: The number of threads to create for the
purpose of transmitting events to peers. You should increase this value as the
number of concurrent transactions increases. The maximum number of concurrent
transactions is a function of the size of the connection pool. See the
<literal>MaxTotal</literal> property of <literal>
openjpa.ConnectionFactoryProperties</literal> in
<xref linkend="ref_guide_dbsetup_builtin"/>. Setting a value of 0 will
result in behavior where the thread invoking <methodname>commit</methodname>
will perform the broadcast directly. Defaults to 2.
</para>
</listitem>
<listitem>
<para>
<literal>RecoveryTimeMillis</literal>: Amount of time to wait in milliseconds
before attempting to reconnect to a peer of the cluster when connectivity to the
peer is lost. Defaults to 15000.
</para>
</listitem>
<listitem>
<para>
<literal>MaxIdle</literal>: The number of TCP sockets (channels) to keep open
to each peer in the cluster for the transmission of events. Defaults to 2.
</para>
</listitem>
<listitem>
<para>
<literal>MaxTotal</literal>: Total allowed number of TCP sockets
(channels) to open simultaneously between each peer in the cluster. Defaults to
2.
</para>
</listitem>
</itemizedlist>
<para>
To configure a factory to use the TCP provider, your properties might look like
the following:
</para>
<example id="ref_guide_event_conf_tcpex">
<title>
TCP Remote Commit Provider Configuration
</title>
<programlisting>
&lt;property name="openjpa.RemoteCommitProvider"
value="tcp(Addresses=10.0.1.10;10.0.1.11;10.0.1.12;10.0.1.13)"/&gt;
</programlisting>
</example>
</section>
<section id="ref_guide_event_conf_common">
<title>
Common Properties
</title>
<indexterm zone="ref_guide_event_conf_common">
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
common properties
</tertiary>
</indexterm>
<para>
In addition to the provider-specific configuration options above, all providers
accept the following plugin properties:
</para>
<itemizedlist>
<listitem>
<para>
<literal>TransmitPersistedObjectIds</literal>: Whether remote commit events
will include the object ids of instances persisted in the transaction. By
default only the class names of types persisted in the transaction are sent.
This results in smaller events and more efficient network utilization. If you
have registered your own remote commit listeners, however, you may require the
persisted object ids as well.
</para>
</listitem>
</itemizedlist>
<para>
To transmit persisted object ids in our remote commit events using the JMS
provider, we modify the previous example as follows:
</para>
<example id="ref_guide_event_conf_jms2ex">
<title>
JMS Remote Commit Provider transmitting Persisted Object Ids
</title>
<programlisting>
&lt;property name="openjpa.RemoteCommitProvider"
value="jms(ExceptionReconnectAttempts=5, TransmitPersistedObjectIds=true)"/&gt;
</programlisting>
</example>
</section>
</section>
<section id="ref_guide_event_customization">
<title>
Customization
</title>
<indexterm zone="ref_guide_event_customization">
<primary>
remote
</primary>
<secondary>
events
</secondary>
<tertiary>
customization
</tertiary>
</indexterm>
<para>
You can develop additional mechanisms for remote event notification be by
creating an implementation of the
<ulink url="../../apidocs/org/apache/openjpa/event/RemoteCommitProvider.html">
<classname> RemoteCommitProvider</classname></ulink> interface, possibly by
extending the
<ulink url="../../apidocs/org/apache/openjpa/event/AbstractRemoteCommitProvider.html">
<classname>AbstractRemoteCommitProvider</classname></ulink> abstract class..
</para>
</section>
</section>
</chapter>