[ 
https://issues.apache.org/jira/browse/MUSE-215?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12483802
 ] 

Vinh Nguyen commented on MUSE-215:
----------------------------------

I think I understand the problem now.

When Muse creates the SOAP xml before it calls a serializer, the DOM xml tree 
has its own document root.
When my serializer converts an object to xml, the initial Element result also 
has its own document root.
Finally, when Muse tries to combine my Element into the SOAP xml, it gets an 
exception about combining nodes from different documents.

For example, suppose my code ignores the QName specified by Muse:

    public Element toXML(Object obj, QName name)
    throws SoapFault
    {
        try
        {
            PropertyNameAndStringValueType type = 
(PropertyNameAndStringValueType)obj;
            return XmlUtils.getFirstElement(type.newDomNode());
        }
        catch (Exception exc)
        {
            throw new SoapFault(exc);
        }
    }

Then I get this exception:

org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different 
document than the one that created it.
        at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source)
        at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source)
        at org.apache.xerces.dom.NodeImpl.appendChild(Unknown Source)
        at 
org.apache.muse.core.serializer.ArraySerializer.toXML(ArraySerializer.java:175)

To get around this, the serializer is forced to create an Element that holds 
the QName passed in by Muse.
This way, Muse can easily add the serialized result into the SOAP xml without 
any DOM issues.

In order to do this, I have to first create an empty parent Element with the 
given QName. 
Then, in order to not lose any data, the actual serialized result is added as a 
child Element.  Like this:

    public Element toXML(Object obj, QName name)
    throws SoapFault
    {
        try
        {
            PropertyNameAndStringValueType type = 
(PropertyNameAndStringValueType)obj;
            Element parent = XmlUtils.createElement(name);
            Element child = XmlUtils.getFirstElement(type.newDomNode());
            parent.appendChild(parent.getOwnerDocument().importNode(child, 
true));
            return parent;
        }
        catch (Exception exc)
        {
            throw new SoapFault(exc);
        }
    }

This will avoid issues with Muse during serialization.  But, the problem is 
compounded now because later,
when the xml needs to be deserialized back to the Object, I must first strip 
off the extra layer before I
can get to the real Element.  Like this:

    public Object fromXML(Element xml)
    throws SoapFault
    {
        try
        {
            // Muse may provide an Element that has an extra wrapper, so search 
for the actual Element we want.
            // Then parse and convert.
            xml = XmlUtils.getElement(xml, 
PropertyNameAndStringValueDocument.type.getDocumentElementName());
            return 
PropertyNameAndStringValueDocument.Factory.parse(xml).getPropertyNameAndStringValue();
        }
        catch (Exception exc)
        {
            throw new SoapFault(exc);
        }
    }

So now, because of this extra layer, toXML() and fromXML() are dependent on 
each other, and a client must
either use these serializers, or must work around this bug by adding the extra 
layer when sending data.

Ideally, the serializer should not need to know what the caller is going to do 
with the result.
It should just translate an object exactly to its xml representation, and 
return just that.

It should be in the Muse layer just above the serializer that does the merging 
of Elements from
different document roots.  For example, if my operation takes in a list of 
PropertyNameAndStringValueType objects,
the Muse logic should be:

PropertyNameAndStringValue obj = 
PropertyNameAndStringValueTypeSerializer serializer = ...
Element objXML = serializer.toXML(obj);

Element operationBody = ...
operationBody.appendChild(operationBody.getOwnerDocument().importNode(objXML, 
true));

Note that serializer.toXML() does not need to pass in any QName since no extra 
QName needs to be involved.
Also, the result of toXML() should be the exact xml representation of the given 
object itself.


> Serializer.toXML() requires unnecessary parent element with specified QName
> ---------------------------------------------------------------------------
>
>                 Key: MUSE-215
>                 URL: https://issues.apache.org/jira/browse/MUSE-215
>             Project: Muse
>          Issue Type: Bug
>    Affects Versions: 2.2.0
>         Environment: Muse 2.2.0, JDK 1.5.0
>            Reporter: Vinh Nguyen
>         Assigned To: Dan Jemiolo
>             Fix For: 2.3.0
>
>         Attachments: TestApp.zip
>
>
> The issue applies to all Muse releases so far.
> I have this Get operation defined as:
>     <xs:element name="Get_queryName" type="xs:string"/>
>     <xs:element name="Get_arguments" 
> type="tns:PropertyNameAndStringValueType"/>
>     <xs:element name="Get">
>         <xs:complexType>
>             <xs:sequence>
>                 <xs:element ref="tns:Get_queryName" minOccurs="1" 
> maxOccurs="1"/>
>                 <xs:element ref="tns:Get_arguments" minOccurs="0" 
> maxOccurs="unbounded"/>
>             </xs:sequence>
>         </xs:complexType>
>     </xs:element>
> The java method is:
> public String get(String queryName, PropertyNameAndStringValueType[] 
> queryArgs)
> There is an issue with the Serializer.toXML(Object, QName) method.  It 
> requires the Element returned to have the QName specified in the parameter.  
> This forces my code to create a parent element with that QName, and then set 
> the real xml element as the child.  This causes an unnecessary xml layer on 
> the data, which the fromXML() method must strip away to get at the real data.
> The effect is two problems:
> 1) When an array of PropertyNameAndStringValueType objects is sent, each 
> object is wrapped in a parent element with the QName passed into toXML() by 
> Muse. The result is no longer a list of PropertyNameAndStringValueType 
> objects, but a list of <Get_arguments> objects.
> 2) The dependency on toXML() to add an extra element wrapper and fromXML() to 
> strip the wrapper, requires all clients to use the custom serializers.  
> Otherwise, if a client sends a properly formatted xml request without the 
> unnecessary list wrappers, and the server calls fromXML() to strip expected 
> wrappers, data will be lost and errors will occur.
> For example, I expected my client output to have one <Get_arguments> 
> containing a list of <PropertyNameAndStringValueType> elements like this:
>     <soap:Body>
>         <pfx1:Get xmlns:pfx1="http://schemas.cisco.com/Query";>
>             <pfx1:Get_queryName>TestQueryName</pfx1:Get_queryName>
>             <pfx1:Get_arguments>
>                     <quer:PropertyNameAndStringValue 
> xmlns:quer="http://schemas.cisco.com/Query";>
>                         <quer:propertyName>PropertyName 1</quer:propertyName>
>                         <quer:stringValue>String value 1</quer:stringValue>
>                     </quer:PropertyNameAndStringValue>
>                     <quer:PropertyNameAndStringValue 
> xmlns:quer="http://schemas.cisco.com/Query";>
>                         <quer:propertyName>PropertyName 2</quer:propertyName>
>                         <quer:stringValue>String value 2</quer:stringValue>
>                     </quer:PropertyNameAndStringValue>
>             </pfx1:Get_arguments>
>         </pfx1:Get>
>     </soap:Body>
> But instead, I get one <Get_arguments> containing a list of other 
> <Get_arguments> elements:
>     <soap:Body>
>         <pfx1:Get xmlns:pfx1="http://schemas.cisco.com/Query";>
>             <pfx1:Get_queryName>TestQueryName</pfx1:Get_queryName>
>             <pfx1:Get_arguments>
>                 <pfx1:Get_arguments>
>                     <quer:PropertyNameAndStringValue 
> xmlns:quer="http://schemas.cisco.com/Query";>
>                         <quer:propertyName>PropertyName 1</quer:propertyName>
>                         <quer:stringValue>String value 1</quer:stringValue>
>                     </quer:PropertyNameAndStringValue>
>                 </pfx1:Get_arguments>
>                 <pfx1:Get_arguments>
>                     <quer:PropertyNameAndStringValue 
> xmlns:quer="http://schemas.cisco.com/Query";>
>                         <quer:propertyName>PropertyName 2</quer:propertyName>
>                         <quer:stringValue>String value 2</quer:stringValue>
>                     </quer:PropertyNameAndStringValue>
>                 </pfx1:Get_arguments>
>             </pfx1:Get_arguments>
>         </pfx1:Get>
>     </soap:Body>
> Attached is my test program.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to