DOOM's OMFactory implementation should be stateless
---------------------------------------------------
Key: AXIOM-412
URL: https://issues.apache.org/jira/browse/AXIOM-412
Project: Axiom
Issue Type: Improvement
Components: DOOM
Affects Versions: 1.2.12
Reporter: Andreas Veithen
There is a sort of "impedance mismatch" between the Axiom API and DOM because
* the Axiom API is designed such that nodes are created using a factory
(OMFactory or SOAPFactory) that is expected to be a singleton and stateless;
* in the DOM API, the Document instance plays the role of node factory, and
each node (explicitly or implicitly) keeps a reference to the Document instance
from which it was created (the "owner document").
The approach currently used by DOOM to solve that issue is to have a stateful
OMFactory implementation which has a reference to a (OM)Document instance. That
(OM)Document instance is then used as the owner document for nodes created
using the Axiom API [Well, actually it is a bit more complicated and obscure
than that...]. For this to work, the application code is required to request an
OMFactory once and only once for each document created. This is one of the
reasons why in general code written for the standard Axiom implementation
(LLOM) doesn't work well when switching to DOOM. In addition, although the
implementation of that design is relatively simple, it makes DOOM quite obscure
from the user's perspective.
There is an alternative approach to solve the Axiom/DOM impedance mismatch
which doesn't require a stateful OMFactory implementation. It is based on the
following set of rules that determine how the DOM owner document is handled
when nodes are created and manipulated using the Axiom API:
(1) Nodes created using the Axiom API and for which a parent node is specified
will have as their owner document the owner document of the parent. This is
simply a consequence of the fact that DOM is designed such that two nodes that
are part of the same tree must have the same owner document.
(2) Nodes created using the Axiom API and for which no parent node is specified
will get a new owner document. That is unavoidable if one wants a
stateless/singleton OMFactory.
(3) When the Axiom API is used to add a node A as a child of another node B,
then the owner document of B becomes the new owner document of A and all its
descendants. In DOM parlance, this means that node A is automatically adopted
by the owner document of B. This rule ensures that any operation that is valid
with the LLOM implementation will also work with DOOM (without triggering a
WRONG_DOCUMENT_ERR exception and without violating the rule that all nodes in a
tree must have the same owner document).
(4) When a node is detached from its parent using the Axiom API (i.e. using
OMNode#detach), it will get a new owner document. This rule is not strictly
required to make the approach work; it merely exists for consistency because
together with the other rules it implies that every tree has a distinct owner
document (as long as only the Axiom API is used to manipulate the nodes).
If implemented literally, these rules would obviously have a performance impact
because (depending on the usage pattern) a large number of temporary Document
instances may be needed. In addition, rules (3) and (4) require an efficient
way to change the owner document of an entire tree (more efficient than to
traverse the entire tree). Therefore these rules would be supplemented by the
following design choices:
(5) Owner documents are created lazily, namely when explicitly requested using
DOM's Node#getOwnerDocument() API (or when DOOM needs to access data that it
choses to store in the owner document).
(6) Only the root node of a tree stores a reference to the owner document. As
noted above, all nodes in a tree must have the same owner document. Therefore
it is not necessary for a node to have references to both its parent and its
owner document. Instead, a node should have a single attribute that stores the
reference either to the parent (if it has a parent) or to the owner document
(if it has no parent), as well as a flag that indicates the meaning of the
reference (this is important if the reference points to a Document instance,
which would otherwise be ambiguous). With this design, changing the owner
document of a tree is O(1) instead of O(N) where N is the number of nodes in
the tree. However, requesting the owner document of a node is O(M) instead of
O(1) with M the depth of the tree. This is a good tradeoff considering that
* Axiom methods never need to check the owner document;
* DOM methods need to check the owner document more often (basically for every
node addition) than the owner document of a tree is changed, but M << N.
It should be noted that switching from the current design to the new design
proposed here is not entirely transparent for application code. It implies a
change in behavior if nodes are first created and manipulated using the Axiom
API and then later passed to DOM APIs such as appendChild. In that situation it
is likely that with the new design, the nodes have different owner documents,
while this was not the case with the old design (because the same OMFactory
instance was used). Such application code needs to be changed to use
Document#adoptNode where appropriate. However, it is expected that in the Axis2
universe, the impact will be limited to a few places in the SAAJ implementation
as well as Rampart. There are quite some examples where these two components
depended on incorrect behavior in DOOM's DOM implementation or other
implementation details, so that in general they can only be expected to work
with the Axiom version for which they were built. One may therefore assume that
the impact is acceptable.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]