You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2011/12/13 00:08:22 UTC
svn commit: r1213491 -
/webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml
Author: veithen
Date: Mon Dec 12 23:08:21 2011
New Revision: 1213491
URL: http://svn.apache.org/viewvc?rev=1213491&view=rev
Log:
Started to think about the redesign of the LifecycleManager API in Axiom 1.3.
Modified:
webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml
Modified: webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml?rev=1213491&r1=1213490&r2=1213491&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml (original)
+++ webservices/commons/trunk/modules/axiom/src/docbkx/devguide.xml Mon Dec 12 23:08:21 2011
@@ -605,6 +605,181 @@ javax.xml.stream.XMLOutputFactory=com.be
</chapter>
<chapter>
+ <title><classname>LifecycleManager</classname> design (Axiom 1.3)</title>
+ <para>
+ The <classname>LifecycleManager</classname> API is used by the MIME handling code in Axiom
+ to manage the temporary files that are used to buffer the content of attachment parts.
+ The <classname>LifecycleManager</classname> implementation is responsible to track the temorary
+ files that have been created and to ensure that they are deleted when they are no longer used.
+ In Axiom 1.2.x, this API has multiple issues and a redesign is required for Axiom 1.3.
+ </para>
+ <section>
+ <title>Issues with the <classname>LifecycleManager</classname> API in Axiom 1.2.x</title>
+ <orderedlist>
+ <listitem>
+ <para>
+ Temporary files that are not cleaned up explicitly by application code will only be removed
+ when the JVM stops (<classname>LifecycleManagerImpl</classname> registers a shutdown hook
+ and maintains a list of files that need to be deleted when the JVM exits). This means that
+ temporary files may pile up, causing the file system to fill.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>LifecycleManager</classname> also has a method <methodname>deleteOnTimeInterval</methodname>
+ that deletes a file after some specified time interval. However, the implementation creates a new
+ thread for each invocation of that method, which is generally not acceptable in high performance
+ use cases.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ One of the stated design goals (see <ulink url="https://issues.apache.org/jira/browse/AXIOM-192">AXIOM-192</ulink>)
+ of the <classname>LifecycleManager</classname> API was to wrap the files in <classname>FileAccessor</classname> objects to
+ <quote>keep track of activity that occurs on the files</quote>. However, as pointed out in
+ <ulink url="https://issues.apache.org/jira/browse/AXIOM-185">AXIOM-185</ulink>, since
+ <classname>FileAccessor</classname> has a method that returns the corresponding <classname>File</classname>
+ object, this goal has not been reached.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ As noted in <ulink url="https://issues.apache.org/jira/browse/AXIOM-382">AXIOM-382</ulink>, the fact
+ that <classname>LifecycleManagerImpl</classname> registers a shutdown hook which is never unregistered
+ causes a class loader leak in J2EE environments.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In an attempt to work around the issues related to <classname>LifecycleManager</classname> (in particular
+ the first item above), <ulink url="https://issues.apache.org/jira/browse/AXIOM-185">AXIOM-185</ulink>
+ introduced another class called <classname>AttachmentCacheMonitor</classname> that implements a timer
+ based mechanism to clean up temporary files. However, this change causes other issues:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ The existence of this API has a negative impact on Axiom's architectural integrity because it
+ has functionality that overlaps with <classname>LifecycleManager</classname>. This means that
+ we now have two completely separate APIs that are expected to serve the same purpose, but
+ none of them addresses the problem properly.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>AttachmentCacheMonitor</classname> automatically creates a timer, but there is no
+ way to stop that timer. This means that this API can only be used if Axiom is integrated
+ into the container, but not when it is deployed with an application.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Fortunately, that change was only meant as a workaround to solve a particular issue in WebSphere
+ (see APAR <ulink url="http://www-01.ibm.com/support/docview.wss?rs=180&uid=swg1PK91497">PK91497</ulink>),
+ and once the <classname>LifecycleManager</classname> API is redesigned to solve that issue,
+ <classname>AttachmentCacheMonitor</classname> no longer has a reason to exist.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>LifecycleManager</classname> is an abstract API (interface), but refers to
+ <classname>FileAccessor</classname> which is placed in an <literal>impl</literal> package.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <classname>FileAccessor</classname> uses the <classname>MessagingException</classname> class
+ from JavaMail, although Axiom no longer relies on this API to parse or create MIME messages.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+ <section>
+ <title>Cleanup strategy for temporary files</title>
+ <para>
+ As pointed out in the previous section, one of the primary problems with the
+ <classname>LifecycleManager</classname> API in Axiom 1.2.x is that temporary files that are
+ not cleaned up explicitly by application code (e.g. using the <methodname>purgeDataSource</methodname> method
+ defined by <classname>DataHandlerExt</classname>) are only removed when the JVM exits.
+ A timer based strategy that deletes temporary file after a given time interval (as proposed
+ by <classname>AttachmentCacheMonitor</classname>) is not reliable
+ because in some use cases, application code may keep a reference to the attachment part for
+ a long time before accessing it again.
+ </para>
+ <para>
+ The only reliable strategy is to take advantage of finalization, i.e. to rely on the garbage
+ collector to trigger the deletion of temporary files that are no longer used. For this to work
+ the design of the API (and its default implementation) must satisfy the following two conditions:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ All access to the underlying file must be strictly encapsulated, so that the file
+ is only accessible as long as there is a strong reference to the object that
+ encapsulates the file access. This is necessary to ensure that the file can
+ be safely deleted once there is no longer a strong reference and the
+ object is garbage collected.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Java guarantees that the finalizer is invoked before the instance is garbage
+ collected. However, instances are not necessarily garbage collected before the
+ JVM exits, and in that case the finalizer is never invoked. Therefore, the
+ implementation must delete all existing temporary files when the JVM exits.
+ The API design should also take into account that some implementations of
+ the <classname>LifecycleManager</classname> API may want to trigger this
+ cleanup before the JVM exits, e.g. when the J2EE application in which
+ Axiom is deployed is stopped.
+ </para>
+ </listitem>
+ </orderedlist>
+ <para>
+ The first condition can be satisfied by redesigning the <classname>FileAccessor</classname>
+ such that it never leaks the name of the file it represents (neither as a <classname>String</classname>
+ nor a <classname>File</classname> object). This in turn means that the
+ <classname>CachedFileDataSource</classname> class must be removed from the Axiom API.
+ In addition, the <methodname>getInputStream</methodname> method defined by
+ <classname>FileAccessor</classname> must no longer return a simple <classname>FileInputStream</classname>
+ instance, but must use a wrapper that keeps a strong reference to the <classname>FileAccessor</classname>,
+ so that the <classname>FileAccessor</classname> can't be garbage collected while the
+ input stream is still in use.
+ </para>
+ <para>
+ To satisfy the second condition, one may want to use <methodname>File#deleteOnExit</methodname>.
+ However, this method causes a native memory leak, especially when used with temporary files,
+ which are expected to have unique names (see
+ <ulink url="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4513817">bug 4513817</ulink>).
+ Therefore this can only be implemented using a shutdown hook. However, a shutdown hook will
+ cause a class loader leak if it is used improperly, e.g. if it is registered by an application deployed
+ into a J2EE container and not unregistered when that application is stopped. For this
+ particular case, it is possible to create a special <classname>LifecycleManager</classname>
+ implementation, but for this to work, the lifecycle of this type of <classname>LifecycleManager</classname>
+ must be bound to the lifecycle of the application, e.g. using a
+ <classname>ServletContextListener</classname>. This is not always possible and this approach
+ is therefore not suitable for the default <classname>LifecycleManager</classname> implementation.
+ </para>
+ <para>
+ To avoid the class loader leak, the default <classname>LifecycleManager</classname> implementation
+ should register the shutdown hook when the first temporary file is registered and
+ automatically unregister the shutdown hook again when there are no more temporary files.
+ This implies that the shutdown hook is repeatedly registered and unregistered. However, since
+ these are relatively cheap operations<footnote><para>Since the JRE typically uses an
+ <classname>IdentityHashMap</classname> to store shutdown hooks, the only overhead is caused
+ by Java 2 security checks and synchronization.</para></footnote>, this should not be a concern.
+ </para>
+ <para>
+ An additional complication is that when the shutdown hook is executed, the temporary files
+ may still be in use. This contrasts with the finalizer case where encapsulation guarantees
+ that the file is no longer in use. This situation doesn't cause an issue on Unix platforms (where it is possible
+ to delete a file while it is still open), but needs to be handled properly on Windows.
+ This can only be achieved if the <classname>FileAccessor</classname> keeps track of
+ created streams, so that it can forcibly close the underlying <classname>FileInputStream</classname> objects.
+ </para>
+ </section>
+ </chapter>
+
+ <chapter>
<title>Release process</title>
<section>
<title>Release preparation</title>