You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Yuval Zou <Yu...@gmail.com> on 2008/03/20 11:47:03 UTC

How to change the namespace position in the generate xml message (SOAP message)?

Hi,

Recently, I'm working on a web services client using CXF. But some request
messages can't be parsed by the web services server. I found the problem is
related to the namespace and prefix.
The correct message:
<?xml version="1.0" encoding="UTF-8"?>
<CreateItemRequest xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
 <AuthenticationData>
  <ServerDef>
   <ServerName>icmnlsdb</ServerName>
  </ServerDef>
  <LoginData>
   <UserID>icmadmin</UserID>
   <Password>********</Password>
  </LoginData>
 </AuthenticationData>
 <Item>
  <ItemXML>
   <CLAIM_1047 DATE_1047="2004-01-27" CLAIMNO_1047="1234" DESC_1047="This is
a claim regarding the accident.3">
    <properties xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
type="document"/>
    <VEHICLE_1047 VIN_1047="38">
     <OWNER_1047 FNAME_1047="Ben" LNAME_1047="Dover"/>
     <OWNER_1047 FNAME_1047="Eileen" LNAME_1047="Dover"/>
    </VEHICLE_1047>
    <VEHICLE_1047 VIN_1047="34">
     <OWNER_1047 FNAME_1047="I.P." LNAME_1047="Freely"/>
    </VEHICLE_1047>
    <ICMBASE>
     <resourceObject xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
MIMEType="image/tiff">
      <label name="base 1"/>
     </resourceObject>
    </ICMBASE>
   </CLAIM_1047>
  </ItemXML>
 </Item>
</CreateItemRequest>
The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in the
element that needs it in this correct message.

The mesage can't be parsed by server (sent by CXF):
<?xml version="1.0" encoding="UTF-8"?>
<CreateItemRequest xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
 <AuthenticationData>
  <ServerDef>
   <ServerName>icmnlsdb</ServerName>
  </ServerDef>
  <LoginData>
   <UserID>icmadmin</UserID>
   <Password>********</Password>
  </LoginData>
 </AuthenticationData>
 <Item>
  <ItemXML>
   <CLAIM_1047 DESC_1047="This is a claim regarding the accident.3"
CLAIMNO_1047="1234" DATE_1047="2004-01-27">
    <ns2:properties type="document"/>
    <VEHICLE_1047 VIN_1047="38">
     <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Ben"/>
     <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Eileen"/>
    </VEHICLE_1047>
    <VEHICLE_1047 VIN_1047="34">
     <OWNER_1047 LNAME_1047="Freely" FNAME_1047="I.P."/>
    </VEHICLE_1047>
    <ICMBASE>
     <ns2:resourceObject MIMEType="image/tiff">
      <ns2:label name="base 1"/>
     </ns2:resourceObject>
    </ICMBASE>
   </CLAIM_1047>
  </ItemXML>
 </Item>
</CreateItemRequest>

The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in the
root element.

Is there anyone who knows how to configure CXF to generate the XML message
in accordance with the first style? Or is there possible to manually modify
the generated message using out Interceptor?
Actually, I have tried to use interceptor the modify the output stream:
public StreamInterceptor() {
        super(Phase.PRE_STREAM);
        addBefore(SoapPreProtocolOutInterceptor.class.getName());
}

   public void handleMessage(Message message) {
     OutputStream os = message.getContent(OutputStream.class);
        CachedStream cs = new CachedStream();
        message.setContent(OutputStream.class, cs);

        message.getInterceptorChain().doIntercept(message);

        try {
            cs.flush();
            CachedOutputStream csnew = (CachedOutputStream)
message.getContent(OutputStream.class);
//            FileOutputStream fileOut = new
FileOutputStream("D:\\test.txt");
//            CachedOutputStream.copyStream(csnew.getInputStream(), fileOut,
1024);

            StringBuilder sb = new StringBuilder();
            csnew.writeCacheTo(sb);

            String tmpXML = sb.toString();
            System.out.println("#####OLD####" + tmpXML);
            while (tmpXML.indexOf("<ns2:")!=-1){
             String subTmp = tmpXML.substring(tmpXML.indexOf("<ns2:"));
             subTmp = subTmp.substring(1, subTmp.indexOf(" "));
             tmpXML = tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
"xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\<http://www.ibm.com/xmlns/db2/cm/api/1.0/schema/>"
");
             System.out.println("#####FIXED#######" + tmpXML);
            }

            InputStream in = new ByteArrayInputStream(tmpXML.getBytes());

            BufferedOutputStream bos = new BufferedOutputStream(os);
            CachedOutputStream.copyStream(in, bos, 1024);

            cs.close();
            in.close();
//            fileOut.close();
            bos.close();
            os.flush();

            message.setContent(OutputStream.class, os);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

But the above code can't handle the message stream with MTOM attachements.
It can't get the OutputStream at all. I don't know the reason.

Your help will be really appreciated. Thanks in advance!
Yuval Zou

Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Benson Margulies <bi...@gmail.com>.
The CXF JAXB binding has a custom namespace mapper which can be told to
control the prefixes. You can override it for further control. However, I'm
very skeptical as to the idea modifying where the prefixes are defined. You
might need to just make an interceptor that rewrites the XML.

On Thu, Mar 20, 2008 at 8:20 AM, Ian Roberts <i....@dcs.shef.ac.uk>
wrote:

> Yuval Zou wrote:
> > Hi,
> >
> > Recently, I'm working on a web services client using CXF. But some
> request
> > messages can't be parsed by the web services server. I found the problem
> is
> > related to the namespace and prefix.
> > The correct message:
> > <?xml version="1.0" encoding="UTF-8"?>
> > <CreateItemRequest xmlns="
> http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>  > [snip]
> > </CreateItemRequest>
> > The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in
> the
> > element that needs it in this correct message.
> >
> > The mesage can't be parsed by server (sent by CXF):
> > <?xml version="1.0" encoding="UTF-8"?>
> > <CreateItemRequest xmlns:ns2="
> http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> > xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>  > [snip]
> > </CreateItemRequest>
> >
> > The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in
> the
> > root element.
>
> In XML terms the two messages are exactly the same, so it's more the
> fault of whatever is parsing the message on the server side rather than
> of the XML generator in CXF.  Nontheless...
>
> If you're using JAXB databinding then you may be able to do what you
> want using a custom namespace prefix mapper in the data binding.
> Something like this (not tested but you get the idea):
>
> <jaxws:client ...>
>   <jaxws:dataBinding>
>     <bean class="org.apache.cxf.jaxb.JAXBDataBinding">
>       <property name="marshallerProperties">
>         <map>
>           <entry key="com.sun.xml.bind.namespacePrefixMapper">
>             <bean class="my.package.NoPrefixNamespaceMapper" />
>           </entry>
>         </map>
>       </property>
>     </bean>
>   </jaxws:dataBinding>
> </jaxws:client>
>
> Where NoPrefixNamespaceMapper is an implementation of
> com.sun.xml.bind.marshaller.NamespacePrefixMapper whose
> getPreferredPrefix method always returns "".  This should force the
> marshaller to only use prefixes when it absolutely has to.
>
> Ian
>
> --
> Ian Roberts               | Department of Computer Science
> i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK
>

Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Yuval Zou <Yu...@gmail.com>.
Hi Ian,

I have tried your solution but it seems not work as expected. I'm a beginner
of CXF and I'm not sure my implementation is correct. Could you please take
a look at it?
1. I created cxf.xml on the client side:
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      xmlns:soap="http://cxf.apache.org/bindings/soap"
      xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/bindings/soap
http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
  <jaxws:client id="cmwebserviceClient" 
    serviceClass="cm.webservices.CMWebServicePortType"
    address="http://localhost/CMBSpecificWebService/services/CMWebService">
    <jaxws:dataBinding>
     <bean class="org.apache.cxf.jaxb.JAXBDataBinding">
       <property name="marshallerProperties">
         <map>
           <entry key="com.sun.xml.bind.namespacePrefixMapper">
             <bean class="common.webservices.NoNamespacePrefixMapper" />
           </entry>
         </map>
       </property>
       <property name="namespaceMap">
    		<map>
   			<entry key="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema">
      			<value>cm</value>
   			</entry>
   			<entry key="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
      			<value>cmb</value>
   			</entry>   			
      		</map>
        </property>
     </bean>
   </jaxws:dataBinding>
</jaxws:client> 
</beans>
<property name="namespaceMap"> is insignificant. If it is removed, the
result is same.

2. Implemented the NoNamespacePrefixMapper:
public class NoNamespacePrefixMapper extends
		com.sun.xml.bind.marshaller.NamespacePrefixMapper {

	@Override
	public String getPreferredPrefix(String arg0, String arg1, boolean arg2) {
		return "";
	}

}

3. Get service:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"cxf.xml"});
        return (CMWebServicePortType)context.getBean("cmwebserviceClient");

4. Invoke the service operation. The xml message is still as before.

Is there anything wrong in these steps? Thanks!


ianroberts wrote:
> 
> Yuval Zou wrote:
>> Hi,
>> 
>> Recently, I'm working on a web services client using CXF. But some
>> request
>> messages can't be parsed by the web services server. I found the problem
>> is
>> related to the namespace and prefix.
>> The correct message:
>> <?xml version="1.0" encoding="UTF-8"?>
>> <CreateItemRequest
>> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>  > [snip]
>> </CreateItemRequest>
>> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in
>> the
>> element that needs it in this correct message.
>> 
>> The mesage can't be parsed by server (sent by CXF):
>> <?xml version="1.0" encoding="UTF-8"?>
>> <CreateItemRequest
>> xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
>> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>  > [snip]
>> </CreateItemRequest>
>> 
>> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in
>> the
>> root element.
> 
> In XML terms the two messages are exactly the same, so it's more the 
> fault of whatever is parsing the message on the server side rather than 
> of the XML generator in CXF.  Nontheless...
> 
> If you're using JAXB databinding then you may be able to do what you 
> want using a custom namespace prefix mapper in the data binding. 
> Something like this (not tested but you get the idea):
> 
> <jaxws:client ...>
>    <jaxws:dataBinding>
>      <bean class="org.apache.cxf.jaxb.JAXBDataBinding">
>        <property name="marshallerProperties">
>          <map>
>            <entry key="com.sun.xml.bind.namespacePrefixMapper">
>              <bean class="my.package.NoPrefixNamespaceMapper" />
>            </entry>
>          </map>
>        </property>
>      </bean>
>    </jaxws:dataBinding>
> </jaxws:client>
> 
> Where NoPrefixNamespaceMapper is an implementation of 
> com.sun.xml.bind.marshaller.NamespacePrefixMapper whose 
> getPreferredPrefix method always returns "".  This should force the 
> marshaller to only use prefixes when it absolutely has to.
> 
> Ian
> 
> -- 
> Ian Roberts               | Department of Computer Science
> i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK
> 
> 

-- 
View this message in context: http://www.nabble.com/How-to-change-the-namespace-position-in-the-generate-xml-message-%28SOAP-message%29--tp16176819p16194418.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Ian Roberts <i....@dcs.shef.ac.uk>.
Yuval Zou wrote:
> Hi,
> 
> Recently, I'm working on a web services client using CXF. But some request
> messages can't be parsed by the web services server. I found the problem is
> related to the namespace and prefix.
> The correct message:
> <?xml version="1.0" encoding="UTF-8"?>
> <CreateItemRequest xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
 > [snip]
> </CreateItemRequest>
> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in the
> element that needs it in this correct message.
> 
> The mesage can't be parsed by server (sent by CXF):
> <?xml version="1.0" encoding="UTF-8"?>
> <CreateItemRequest xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
 > [snip]
> </CreateItemRequest>
> 
> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put in the
> root element.

In XML terms the two messages are exactly the same, so it's more the 
fault of whatever is parsing the message on the server side rather than 
of the XML generator in CXF.  Nontheless...

If you're using JAXB databinding then you may be able to do what you 
want using a custom namespace prefix mapper in the data binding. 
Something like this (not tested but you get the idea):

<jaxws:client ...>
   <jaxws:dataBinding>
     <bean class="org.apache.cxf.jaxb.JAXBDataBinding">
       <property name="marshallerProperties">
         <map>
           <entry key="com.sun.xml.bind.namespacePrefixMapper">
             <bean class="my.package.NoPrefixNamespaceMapper" />
           </entry>
         </map>
       </property>
     </bean>
   </jaxws:dataBinding>
</jaxws:client>

Where NoPrefixNamespaceMapper is an implementation of 
com.sun.xml.bind.marshaller.NamespacePrefixMapper whose 
getPreferredPrefix method always returns "".  This should force the 
marshaller to only use prefixes when it absolutely has to.

Ian

-- 
Ian Roberts               | Department of Computer Science
i.roberts@dcs.shef.ac.uk  | University of Sheffield, UK

Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Daniel Kulp <dk...@apache.org>.
On Friday 21 March 2008, Yuval Zou wrote:
> Hi Dan,
>
> I have tried the second option. I modified the codes as you suggested.
> It works but the attachment data are still embeded in the cached
> stream. So the performance of the transformation is terrible. The code
> looks like below, could you please help to find if there is something
> wrong and how can I fix it? Thank you very much!

Try moving the interceptors inside the bounds of the 
AttachmentOutInterceptors:

First interceptor:
addAfter(AttachmentOutInterceptor.class.getName());

Second interceptor:
addBefore(AttachmentOutInterceptor.AttachmentOutEndingInterceptor.class.getName());

That should do the trick and only give you the root part.


Dan




>
> public class StreamInterceptor extends AbstractPhaseInterceptor {
>
> 	private StreamEndingInterceptor ending = new
> StreamEndingInterceptor(); public static final String ORIGINAL_OUTPUT
> = "original_output";
>
>     public StreamInterceptor() {
>         super(Phase.PRE_STREAM);
>         addBefore(AttachmentOutInterceptor.class.getName());
>     }
>
>     public void handleMessage(Message message) {
>     	OutputStream os = message.getContent(OutputStream.class);
>     	message.put(ORIGINAL_OUTPUT, os);
>     	CachedStream cs = new CachedStream();
>         message.setContent(OutputStream.class, cs);
>
> //    	message.getInterceptorChain().doIntercept(message);
>     	try {
> 			cs.flush();
> 		} catch (IOException e) {
> 			e.printStackTrace();
> 		}
>         message.getInterceptorChain().add(ending);
>     }
>
>     public void handleFault(Message message) {
>     }
>
>     public class StreamEndingInterceptor extends
> AbstractPhaseInterceptor {
>
> 		public StreamEndingInterceptor() {
> 			super(Phase.PRE_STREAM_ENDING);
>
> addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor.class
>.getName()); }
>
>     	public void handleMessage(Message message) {
> 			try {
> 				CachedOutputStream csnew = (CachedOutputStream)
> message.getContent(OutputStream.class);
> 				OutputStream os = (OutputStream) message.get(ORIGINAL_OUTPUT);
>
> 	            StringBuilder sb = new StringBuilder();
> 	            csnew.writeCacheTo(sb);
>
> 	            String tmpXML = sb.toString();
> 	            System.out.println("#####OLD#####" + tmpXML);
> 	            while (tmpXML.indexOf("<ns2:")!=-1){
> 		            String subTmp =
> tmpXML.substring(tmpXML.indexOf("<ns2:")); subTmp =
> subTmp.substring(1, subTmp.indexOf(" ")); tmpXML =
> tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
> "xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\" ");
> System.out.println("#####FIXED#####" + tmpXML); }
>
> 	            InputStream in = new
> ByteArrayInputStream(tmpXML.getBytes()); BufferedOutputStream bos =
> new BufferedOutputStream(os); CachedOutputStream.copyStream(in, bos,
> 1024);
>
> 	            csnew.close();
> 	            in.close();
> 	            bos.close();
> 	            os.flush();
>
> //	            message.setContent(OutputStream.class, os);
> 			} catch (IOException e) {
> 				e.printStackTrace();
> 			}
> 		}
>
> 	}
>
>     private class CachedStream extends CachedOutputStream {
>
>         public CachedStream() {
>             super();
>         }
>
>         protected void doFlush() throws IOException {
>             currentStream.flush();
>         }
>
>         protected void doClose() throws IOException {
>         }
>
>         protected void onWrite() throws IOException {
>         }
>
>     }
> }
>
> Yuval
>
> dkulp wrote:
> > This is definitely a bug for whomever is consuming that message.
> > According to the XML rules, both messages are equivilent.
> >
> > Couple options:
> >
> > 1) Best performing option:  write an interceptor that would be
> > immediately AFTER the StaxOutInterceptor that would take the
> > XMLStreamWriter and replace it with a new XMLStreamWriter that
> > wrappers the original, but overwrides the start element and
> > namespace map stuff so that it generates empty prefixes at all
> > times.  That StreamWriter might be a bit tricky to write if you
> > aren't familliar with StAX, but it would definitely be the best
> > performing as you wouln't break the streaming, you wouldn't need to
> > scan the byte[], etc....  FYI: your interceptor will also need to
> > set:
> > msg.put(AbstractOutDatabindingInterceptor.DISABLE_OUTPUTSTREAM_OPTIM
> >IZATION, Boolean.TRUE);
> > to make sure it actually uses the new StreamWriter in all cases.
> >
> >
> > 2) Next option: your CachedOutputStream stuff.....   This actually
> > will work, but you need to modify things a bit.  First off, it needs
> > to be split into two interceptors: (usually, it's one
> > interceptor.java that then has an inner class for the other.  See
> > the AttachmentOutInterceptor for example)
> >    a) First/Outer one will replace the OutputStream with the cached
> > output stream and record the original stream.   It will also then
> > add the second one to the chain. Make sure it's stuck before the
> > attachement stuff:
> >         super(Phase.PRE_STREAM);
> >         addBefore(AttachmentOutInterceptor.class.getName());
> >
> >    b) The second/inner interceptor would grab the Cached stream, do
> > the transformation, and flush back to original stream.   It would
> > be: super(Phase.PRE_STREAM_ENDING);
> >    addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor
> >                .class.getName());
> >
> > Dan
> >
> > On Thursday 20 March 2008, Yuval Zou wrote:
> >> Hi,
> >>
> >> Recently, I'm working on a web services client using CXF. But some
> >> request messages can't be parsed by the web services server. I
> >> found the problem is related to the namespace and prefix.
> >> The correct message:
> >> <?xml version="1.0" encoding="UTF-8"?>
> >> <CreateItemRequest
> >> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
> >> <AuthenticationData>
> >>   <ServerDef>
> >>    <ServerName>icmnlsdb</ServerName>
> >>   </ServerDef>
> >>   <LoginData>
> >>    <UserID>icmadmin</UserID>
> >>    <Password>********</Password>
> >>   </LoginData>
> >>  </AuthenticationData>
> >>  <Item>
> >>   <ItemXML>
> >>    <CLAIM_1047 DATE_1047="2004-01-27" CLAIMNO_1047="1234"
> >> DESC_1047="This is a claim regarding the accident.3">
> >>     <properties
> >> xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> >> type="document"/>
> >>     <VEHICLE_1047 VIN_1047="38">
> >>      <OWNER_1047 FNAME_1047="Ben" LNAME_1047="Dover"/>
> >>      <OWNER_1047 FNAME_1047="Eileen" LNAME_1047="Dover"/>
> >>     </VEHICLE_1047>
> >>     <VEHICLE_1047 VIN_1047="34">
> >>      <OWNER_1047 FNAME_1047="I.P." LNAME_1047="Freely"/>
> >>     </VEHICLE_1047>
> >>     <ICMBASE>
> >>      <resourceObject
> >> xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> >> MIMEType="image/tiff">
> >>       <label name="base 1"/>
> >>      </resourceObject>
> >>     </ICMBASE>
> >>    </CLAIM_1047>
> >>   </ItemXML>
> >>  </Item>
> >> </CreateItemRequest>
> >> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was
> >> put in the element that needs it in this correct message.
> >>
> >> The mesage can't be parsed by server (sent by CXF):
> >> <?xml version="1.0" encoding="UTF-8"?>
> >> <CreateItemRequest
> >> xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> >> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
> >>  <AuthenticationData>
> >>   <ServerDef>
> >>    <ServerName>icmnlsdb</ServerName>
> >>   </ServerDef>
> >>   <LoginData>
> >>    <UserID>icmadmin</UserID>
> >>    <Password>********</Password>
> >>   </LoginData>
> >>  </AuthenticationData>
> >>  <Item>
> >>   <ItemXML>
> >>    <CLAIM_1047 DESC_1047="This is a claim regarding the accident.3"
> >> CLAIMNO_1047="1234" DATE_1047="2004-01-27">
> >>     <ns2:properties type="document"/>
> >>     <VEHICLE_1047 VIN_1047="38">
> >>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Ben"/>
> >>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Eileen"/>
> >>     </VEHICLE_1047>
> >>     <VEHICLE_1047 VIN_1047="34">
> >>      <OWNER_1047 LNAME_1047="Freely" FNAME_1047="I.P."/>
> >>     </VEHICLE_1047>
> >>     <ICMBASE>
> >>      <ns2:resourceObject MIMEType="image/tiff">
> >>       <ns2:label name="base 1"/>
> >>      </ns2:resourceObject>
> >>     </ICMBASE>
> >>    </CLAIM_1047>
> >>   </ItemXML>
> >>  </Item>
> >> </CreateItemRequest>
> >>
> >> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was
> >> put in the root element.
> >>
> >> Is there anyone who knows how to configure CXF to generate the XML
> >> message in accordance with the first style? Or is there possible to
> >> manually modify the generated message using out Interceptor?
> >> Actually, I have tried to use interceptor the modify the output
> >> stream: public StreamInterceptor() {
> >>         super(Phase.PRE_STREAM);
> >>         addBefore(SoapPreProtocolOutInterceptor.class.getName());
> >> }
> >>
> >>    public void handleMessage(Message message) {
> >>      OutputStream os = message.getContent(OutputStream.class);
> >>         CachedStream cs = new CachedStream();
> >>         message.setContent(OutputStream.class, cs);
> >>
> >>         message.getInterceptorChain().doIntercept(message);
> >>
> >>         try {
> >>             cs.flush();
> >>             CachedOutputStream csnew = (CachedOutputStream)
> >> message.getContent(OutputStream.class);
> >> //            FileOutputStream fileOut = new
> >> FileOutputStream("D:\\test.txt");
> >> //            CachedOutputStream.copyStream(csnew.getInputStream(),
> >> fileOut, 1024);
> >>
> >>             StringBuilder sb = new StringBuilder();
> >>             csnew.writeCacheTo(sb);
> >>
> >>             String tmpXML = sb.toString();
> >>             System.out.println("#####OLD####" + tmpXML);
> >>             while (tmpXML.indexOf("<ns2:")!=-1){
> >>              String subTmp =
> >> tmpXML.substring(tmpXML.indexOf("<ns2:")); subTmp =
> >> subTmp.substring(1, subTmp.indexOf(" ")); tmpXML =
> >> tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
> >> "xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\<http://www
> >>.ib m.com/xmlns/db2/cm/api/1.0/schema/>" ");
> >>              System.out.println("#####FIXED#######" + tmpXML);
> >>             }
> >>
> >>             InputStream in = new
> >> ByteArrayInputStream(tmpXML.getBytes());
> >>
> >>             BufferedOutputStream bos = new
> >> BufferedOutputStream(os); CachedOutputStream.copyStream(in, bos,
> >> 1024);
> >>
> >>             cs.close();
> >>             in.close();
> >> //            fileOut.close();
> >>             bos.close();
> >>             os.flush();
> >>
> >>             message.setContent(OutputStream.class, os);
> >>         } catch (IOException ioe) {
> >>             ioe.printStackTrace();
> >>         }
> >>     }
> >>
> >> But the above code can't handle the message stream with MTOM
> >> attachements. It can't get the OutputStream at all. I don't know
> >> the reason.
> >>
> >> Your help will be really appreciated. Thanks in advance!
> >> Yuval Zou
> >
> > --
> > J. Daniel Kulp
> > Principal Engineer, IONA
> > dkulp@apache.org
> > http://www.dankulp.com/blog



-- 
J. Daniel Kulp
Principal Engineer, IONA
dkulp@apache.org
http://www.dankulp.com/blog

Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Yuval Zou <Yu...@gmail.com>.
Hi Dan,

I have tried the second option. I modified the codes as you suggested. It
works but the attachment data are still embeded in the cached stream. So the
performance of the transformation is terrible. The code looks like below,
could you please help to find if there is something wrong and how can I fix
it? Thank you very much!

public class StreamInterceptor extends AbstractPhaseInterceptor {
	
	private StreamEndingInterceptor ending = new StreamEndingInterceptor();
	public static final String ORIGINAL_OUTPUT = "original_output";	
	
    public StreamInterceptor() {
        super(Phase.PRE_STREAM);
        addBefore(AttachmentOutInterceptor.class.getName());
    }
    
    public void handleMessage(Message message) {
    	OutputStream os = message.getContent(OutputStream.class);
    	message.put(ORIGINAL_OUTPUT, os);
    	CachedStream cs = new CachedStream();
        message.setContent(OutputStream.class, cs);        
        
//    	message.getInterceptorChain().doIntercept(message);
    	try {
			cs.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
        message.getInterceptorChain().add(ending);
    }    

    public void handleFault(Message message) {
    }
    
    public class StreamEndingInterceptor extends AbstractPhaseInterceptor {
    	
		public StreamEndingInterceptor() {
			super(Phase.PRE_STREAM_ENDING);
		
addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor.class.getName()); 
		}
		
    	public void handleMessage(Message message) {
			try {
				CachedOutputStream csnew = (CachedOutputStream)
message.getContent(OutputStream.class);
				OutputStream os = (OutputStream) message.get(ORIGINAL_OUTPUT);

	            StringBuilder sb = new StringBuilder();
	            csnew.writeCacheTo(sb);
	            
	            String tmpXML = sb.toString();
	            System.out.println("#####OLD#####" + tmpXML);
	            while (tmpXML.indexOf("<ns2:")!=-1){
		            String subTmp = tmpXML.substring(tmpXML.indexOf("<ns2:"));
		            subTmp = subTmp.substring(1, subTmp.indexOf(" "));
		            tmpXML = tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
"xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\" ");
		            System.out.println("#####FIXED#####" + tmpXML);
	            }           
	            
	            InputStream in = new ByteArrayInputStream(tmpXML.getBytes());	            
	            BufferedOutputStream bos = new BufferedOutputStream(os);
	            CachedOutputStream.copyStream(in, bos, 1024);

	            csnew.close();
	            in.close();
	            bos.close();
	            os.flush();

//	            message.setContent(OutputStream.class, os);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
    	
	}

    private class CachedStream extends CachedOutputStream {
    	
        public CachedStream() {
            super();
        }
        
        protected void doFlush() throws IOException {
            currentStream.flush();
        }

        protected void doClose() throws IOException {
        }
        
        protected void onWrite() throws IOException {
        }
        
    }
}

Yuval
 

dkulp wrote:
> 
> 
> This is definitely a bug for whomever is consuming that message.   
> According to the XML rules, both messages are equivilent.
> 
> Couple options:
> 
> 1) Best performing option:  write an interceptor that would be 
> immediately AFTER the StaxOutInterceptor that would take the 
> XMLStreamWriter and replace it with a new XMLStreamWriter that wrappers 
> the original, but overwrides the start element and namespace map stuff 
> so that it generates empty prefixes at all times.  That StreamWriter 
> might be a bit tricky to write if you aren't familliar with StAX, but it 
> would definitely be the best performing as you wouln't break the 
> streaming, you wouldn't need to scan the byte[], etc....  FYI: your 
> interceptor will also need to set:
> msg.put(AbstractOutDatabindingInterceptor.DISABLE_OUTPUTSTREAM_OPTIMIZATION,
>         Boolean.TRUE);
> to make sure it actually uses the new StreamWriter in all cases.
> 
> 
> 2) Next option: your CachedOutputStream stuff.....   This actually will 
> work, but you need to modify things a bit.  First off, it needs to be 
> split into two interceptors: (usually, it's one interceptor.java that 
> then has an inner class for the other.  See the AttachmentOutInterceptor 
> for example)
>    a) First/Outer one will replace the OutputStream with the cached 
> output stream and record the original stream.   It will also then add 
> the second one to the chain. Make sure it's stuck before the attachement 
> stuff:
>         super(Phase.PRE_STREAM);
>         addBefore(AttachmentOutInterceptor.class.getName());
> 
>    b) The second/inner interceptor would grab the Cached stream, do the 
> transformation, and flush back to original stream.   It would be:
>    super(Phase.PRE_STREAM_ENDING);
>    addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor
>                .class.getName());
> 
> Dan
> 
> 
> 
> 
> On Thursday 20 March 2008, Yuval Zou wrote:
>> Hi,
>>
>> Recently, I'm working on a web services client using CXF. But some
>> request messages can't be parsed by the web services server. I found
>> the problem is related to the namespace and prefix.
>> The correct message:
>> <?xml version="1.0" encoding="UTF-8"?>
>> <CreateItemRequest
>> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>> <AuthenticationData>
>>   <ServerDef>
>>    <ServerName>icmnlsdb</ServerName>
>>   </ServerDef>
>>   <LoginData>
>>    <UserID>icmadmin</UserID>
>>    <Password>********</Password>
>>   </LoginData>
>>  </AuthenticationData>
>>  <Item>
>>   <ItemXML>
>>    <CLAIM_1047 DATE_1047="2004-01-27" CLAIMNO_1047="1234"
>> DESC_1047="This is a claim regarding the accident.3">
>>     <properties xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
>> type="document"/>
>>     <VEHICLE_1047 VIN_1047="38">
>>      <OWNER_1047 FNAME_1047="Ben" LNAME_1047="Dover"/>
>>      <OWNER_1047 FNAME_1047="Eileen" LNAME_1047="Dover"/>
>>     </VEHICLE_1047>
>>     <VEHICLE_1047 VIN_1047="34">
>>      <OWNER_1047 FNAME_1047="I.P." LNAME_1047="Freely"/>
>>     </VEHICLE_1047>
>>     <ICMBASE>
>>      <resourceObject
>> xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
>> MIMEType="image/tiff">
>>       <label name="base 1"/>
>>      </resourceObject>
>>     </ICMBASE>
>>    </CLAIM_1047>
>>   </ItemXML>
>>  </Item>
>> </CreateItemRequest>
>> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
>> in the element that needs it in this correct message.
>>
>> The mesage can't be parsed by server (sent by CXF):
>> <?xml version="1.0" encoding="UTF-8"?>
>> <CreateItemRequest
>> xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
>> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>>  <AuthenticationData>
>>   <ServerDef>
>>    <ServerName>icmnlsdb</ServerName>
>>   </ServerDef>
>>   <LoginData>
>>    <UserID>icmadmin</UserID>
>>    <Password>********</Password>
>>   </LoginData>
>>  </AuthenticationData>
>>  <Item>
>>   <ItemXML>
>>    <CLAIM_1047 DESC_1047="This is a claim regarding the accident.3"
>> CLAIMNO_1047="1234" DATE_1047="2004-01-27">
>>     <ns2:properties type="document"/>
>>     <VEHICLE_1047 VIN_1047="38">
>>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Ben"/>
>>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Eileen"/>
>>     </VEHICLE_1047>
>>     <VEHICLE_1047 VIN_1047="34">
>>      <OWNER_1047 LNAME_1047="Freely" FNAME_1047="I.P."/>
>>     </VEHICLE_1047>
>>     <ICMBASE>
>>      <ns2:resourceObject MIMEType="image/tiff">
>>       <ns2:label name="base 1"/>
>>      </ns2:resourceObject>
>>     </ICMBASE>
>>    </CLAIM_1047>
>>   </ItemXML>
>>  </Item>
>> </CreateItemRequest>
>>
>> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
>> in the root element.
>>
>> Is there anyone who knows how to configure CXF to generate the XML
>> message in accordance with the first style? Or is there possible to
>> manually modify the generated message using out Interceptor?
>> Actually, I have tried to use interceptor the modify the output
>> stream: public StreamInterceptor() {
>>         super(Phase.PRE_STREAM);
>>         addBefore(SoapPreProtocolOutInterceptor.class.getName());
>> }
>>
>>    public void handleMessage(Message message) {
>>      OutputStream os = message.getContent(OutputStream.class);
>>         CachedStream cs = new CachedStream();
>>         message.setContent(OutputStream.class, cs);
>>
>>         message.getInterceptorChain().doIntercept(message);
>>
>>         try {
>>             cs.flush();
>>             CachedOutputStream csnew = (CachedOutputStream)
>> message.getContent(OutputStream.class);
>> //            FileOutputStream fileOut = new
>> FileOutputStream("D:\\test.txt");
>> //            CachedOutputStream.copyStream(csnew.getInputStream(),
>> fileOut, 1024);
>>
>>             StringBuilder sb = new StringBuilder();
>>             csnew.writeCacheTo(sb);
>>
>>             String tmpXML = sb.toString();
>>             System.out.println("#####OLD####" + tmpXML);
>>             while (tmpXML.indexOf("<ns2:")!=-1){
>>              String subTmp =
>> tmpXML.substring(tmpXML.indexOf("<ns2:")); subTmp =
>> subTmp.substring(1, subTmp.indexOf(" ")); tmpXML =
>> tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
>> "xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\<http://www.ib
>>m.com/xmlns/db2/cm/api/1.0/schema/>" ");
>>              System.out.println("#####FIXED#######" + tmpXML);
>>             }
>>
>>             InputStream in = new
>> ByteArrayInputStream(tmpXML.getBytes());
>>
>>             BufferedOutputStream bos = new BufferedOutputStream(os);
>>             CachedOutputStream.copyStream(in, bos, 1024);
>>
>>             cs.close();
>>             in.close();
>> //            fileOut.close();
>>             bos.close();
>>             os.flush();
>>
>>             message.setContent(OutputStream.class, os);
>>         } catch (IOException ioe) {
>>             ioe.printStackTrace();
>>         }
>>     }
>>
>> But the above code can't handle the message stream with MTOM
>> attachements. It can't get the OutputStream at all. I don't know the
>> reason.
>>
>> Your help will be really appreciated. Thanks in advance!
>> Yuval Zou
> 
> 
> 
> -- 
> J. Daniel Kulp
> Principal Engineer, IONA
> dkulp@apache.org
> http://www.dankulp.com/blog
> 
> 

-- 
View this message in context: http://www.nabble.com/How-to-change-the-namespace-position-in-the-generate-xml-message-%28SOAP-message%29--tp16176819p16194931.html
Sent from the cxf-user mailing list archive at Nabble.com.


Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Yuval Zou <Yu...@gmail.com>.
Hi Dan,

Thanks a lot for your quick and detailed response!

I will try the options provided by you. Hope everything goes well~~ :)

Yuval



2008/3/20, Daniel Kulp <dk...@apache.org>:
>
>
> This is definitely a bug for whomever is consuming that message.
> According to the XML rules, both messages are equivilent.
>
> Couple options:
>
> 1) Best performing option:  write an interceptor that would be
> immediately AFTER the StaxOutInterceptor that would take the
> XMLStreamWriter and replace it with a new XMLStreamWriter that wrappers
> the original, but overwrides the start element and namespace map stuff
> so that it generates empty prefixes at all times.  That StreamWriter
> might be a bit tricky to write if you aren't familliar with StAX, but it
> would definitely be the best performing as you wouln't break the
> streaming, you wouldn't need to scan the byte[], etc....  FYI: your
> interceptor will also need to set:
> msg.put(
> AbstractOutDatabindingInterceptor.DISABLE_OUTPUTSTREAM_OPTIMIZATION,
>         Boolean.TRUE);
> to make sure it actually uses the new StreamWriter in all cases.
>
>
> 2) Next option: your CachedOutputStream stuff.....   This actually will
> work, but you need to modify things a bit.  First off, it needs to be
> split into two interceptors: (usually, it's one interceptor.java that
> then has an inner class for the other.  See the AttachmentOutInterceptor
> for example)
>    a) First/Outer one will replace the OutputStream with the cached
> output stream and record the original stream.   It will also then add
> the second one to the chain. Make sure it's stuck before the attachement
> stuff:
>         super(Phase.PRE_STREAM);
>         addBefore(AttachmentOutInterceptor.class.getName());
>
>    b) The second/inner interceptor would grab the Cached stream, do the
> transformation, and flush back to original stream.   It would be:
>    super(Phase.PRE_STREAM_ENDING);
>    addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor
>                .class.getName());
>
> Dan
>
>
>
>
>
> On Thursday 20 March 2008, Yuval Zou wrote:
> > Hi,
> >
> > Recently, I'm working on a web services client using CXF. But some
> > request messages can't be parsed by the web services server. I found
> > the problem is related to the namespace and prefix.
> > The correct message:
> > <?xml version="1.0" encoding="UTF-8"?>
> > <CreateItemRequest
> > xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
> > <AuthenticationData>
> >   <ServerDef>
> >    <ServerName>icmnlsdb</ServerName>
> >   </ServerDef>
> >   <LoginData>
> >    <UserID>icmadmin</UserID>
> >    <Password>********</Password>
> >   </LoginData>
> >  </AuthenticationData>
> >  <Item>
> >   <ItemXML>
> >    <CLAIM_1047 DATE_1047="2004-01-27" CLAIMNO_1047="1234"
> > DESC_1047="This is a claim regarding the accident.3">
> >     <properties xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> > type="document"/>
> >     <VEHICLE_1047 VIN_1047="38">
> >      <OWNER_1047 FNAME_1047="Ben" LNAME_1047="Dover"/>
> >      <OWNER_1047 FNAME_1047="Eileen" LNAME_1047="Dover"/>
> >     </VEHICLE_1047>
> >     <VEHICLE_1047 VIN_1047="34">
> >      <OWNER_1047 FNAME_1047="I.P." LNAME_1047="Freely"/>
> >     </VEHICLE_1047>
> >     <ICMBASE>
> >      <resourceObject
> > xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> > MIMEType="image/tiff">
> >       <label name="base 1"/>
> >      </resourceObject>
> >     </ICMBASE>
> >    </CLAIM_1047>
> >   </ItemXML>
> >  </Item>
> > </CreateItemRequest>
> > The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
> > in the element that needs it in this correct message.
> >
> > The mesage can't be parsed by server (sent by CXF):
> > <?xml version="1.0" encoding="UTF-8"?>
> > <CreateItemRequest
> > xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> > xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
> >  <AuthenticationData>
> >   <ServerDef>
> >    <ServerName>icmnlsdb</ServerName>
> >   </ServerDef>
> >   <LoginData>
> >    <UserID>icmadmin</UserID>
> >    <Password>********</Password>
> >   </LoginData>
> >  </AuthenticationData>
> >  <Item>
> >   <ItemXML>
> >    <CLAIM_1047 DESC_1047="This is a claim regarding the accident.3"
> > CLAIMNO_1047="1234" DATE_1047="2004-01-27">
> >     <ns2:properties type="document"/>
> >     <VEHICLE_1047 VIN_1047="38">
> >      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Ben"/>
> >      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Eileen"/>
> >     </VEHICLE_1047>
> >     <VEHICLE_1047 VIN_1047="34">
> >      <OWNER_1047 LNAME_1047="Freely" FNAME_1047="I.P."/>
> >     </VEHICLE_1047>
> >     <ICMBASE>
> >      <ns2:resourceObject MIMEType="image/tiff">
> >       <ns2:label name="base 1"/>
> >      </ns2:resourceObject>
> >     </ICMBASE>
> >    </CLAIM_1047>
> >   </ItemXML>
> >  </Item>
> > </CreateItemRequest>
> >
> > The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
> > in the root element.
> >
> > Is there anyone who knows how to configure CXF to generate the XML
> > message in accordance with the first style? Or is there possible to
> > manually modify the generated message using out Interceptor?
> > Actually, I have tried to use interceptor the modify the output
> > stream: public StreamInterceptor() {
> >         super(Phase.PRE_STREAM);
> >         addBefore(SoapPreProtocolOutInterceptor.class.getName());
> > }
> >
> >    public void handleMessage(Message message) {
> >      OutputStream os = message.getContent(OutputStream.class);
> >         CachedStream cs = new CachedStream();
> >         message.setContent(OutputStream.class, cs);
> >
> >         message.getInterceptorChain().doIntercept(message);
> >
> >         try {
> >             cs.flush();
> >             CachedOutputStream csnew = (CachedOutputStream)
> > message.getContent(OutputStream.class);
> > //            FileOutputStream fileOut = new
> > FileOutputStream("D:\\test.txt");
> > //            CachedOutputStream.copyStream(csnew.getInputStream(),
> > fileOut, 1024);
> >
> >             StringBuilder sb = new StringBuilder();
> >             csnew.writeCacheTo(sb);
> >
> >             String tmpXML = sb.toString();
> >             System.out.println("#####OLD####" + tmpXML);
> >             while (tmpXML.indexOf("<ns2:")!=-1){
> >              String subTmp =
> > tmpXML.substring(tmpXML.indexOf("<ns2:")); subTmp =
> > subTmp.substring(1, subTmp.indexOf(" ")); tmpXML =
> > tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
>
> > "xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\<http://www.ib
>
> >m.com/xmlns/db2/cm/api/1.0/schema/>" ");
> >              System.out.println("#####FIXED#######" + tmpXML);
> >             }
> >
> >             InputStream in = new
> > ByteArrayInputStream(tmpXML.getBytes());
> >
> >             BufferedOutputStream bos = new BufferedOutputStream(os);
> >             CachedOutputStream.copyStream(in, bos, 1024);
> >
> >             cs.close();
> >             in.close();
> > //            fileOut.close();
> >             bos.close();
> >             os.flush();
> >
> >             message.setContent(OutputStream.class, os);
> >         } catch (IOException ioe) {
> >             ioe.printStackTrace();
> >         }
> >     }
> >
> > But the above code can't handle the message stream with MTOM
> > attachements. It can't get the OutputStream at all. I don't know the
> > reason.
> >
> > Your help will be really appreciated. Thanks in advance!
> > Yuval Zou
>
>
>
>
> --
> J. Daniel Kulp
> Principal Engineer, IONA
> dkulp@apache.org
> http://www.dankulp.com/blog
>

Re: How to change the namespace position in the generate xml message (SOAP message)?

Posted by Daniel Kulp <dk...@apache.org>.
This is definitely a bug for whomever is consuming that message.   
According to the XML rules, both messages are equivilent.

Couple options:

1) Best performing option:  write an interceptor that would be 
immediately AFTER the StaxOutInterceptor that would take the 
XMLStreamWriter and replace it with a new XMLStreamWriter that wrappers 
the original, but overwrides the start element and namespace map stuff 
so that it generates empty prefixes at all times.  That StreamWriter 
might be a bit tricky to write if you aren't familliar with StAX, but it 
would definitely be the best performing as you wouln't break the 
streaming, you wouldn't need to scan the byte[], etc....  FYI: your 
interceptor will also need to set:
msg.put(AbstractOutDatabindingInterceptor.DISABLE_OUTPUTSTREAM_OPTIMIZATION,
        Boolean.TRUE);
to make sure it actually uses the new StreamWriter in all cases.


2) Next option: your CachedOutputStream stuff.....   This actually will 
work, but you need to modify things a bit.  First off, it needs to be 
split into two interceptors: (usually, it's one interceptor.java that 
then has an inner class for the other.  See the AttachmentOutInterceptor 
for example)
   a) First/Outer one will replace the OutputStream with the cached 
output stream and record the original stream.   It will also then add 
the second one to the chain. Make sure it's stuck before the attachement 
stuff:
        super(Phase.PRE_STREAM);
        addBefore(AttachmentOutInterceptor.class.getName());

   b) The second/inner interceptor would grab the Cached stream, do the 
transformation, and flush back to original stream.   It would be:
   super(Phase.PRE_STREAM_ENDING);
   addAfter(AttachmentOutInterceptor.AttachmentOutEndingInterceptor
               .class.getName());

Dan




On Thursday 20 March 2008, Yuval Zou wrote:
> Hi,
>
> Recently, I'm working on a web services client using CXF. But some
> request messages can't be parsed by the web services server. I found
> the problem is related to the namespace and prefix.
> The correct message:
> <?xml version="1.0" encoding="UTF-8"?>
> <CreateItemRequest
> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
> <AuthenticationData>
>   <ServerDef>
>    <ServerName>icmnlsdb</ServerName>
>   </ServerDef>
>   <LoginData>
>    <UserID>icmadmin</UserID>
>    <Password>********</Password>
>   </LoginData>
>  </AuthenticationData>
>  <Item>
>   <ItemXML>
>    <CLAIM_1047 DATE_1047="2004-01-27" CLAIMNO_1047="1234"
> DESC_1047="This is a claim regarding the accident.3">
>     <properties xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> type="document"/>
>     <VEHICLE_1047 VIN_1047="38">
>      <OWNER_1047 FNAME_1047="Ben" LNAME_1047="Dover"/>
>      <OWNER_1047 FNAME_1047="Eileen" LNAME_1047="Dover"/>
>     </VEHICLE_1047>
>     <VEHICLE_1047 VIN_1047="34">
>      <OWNER_1047 FNAME_1047="I.P." LNAME_1047="Freely"/>
>     </VEHICLE_1047>
>     <ICMBASE>
>      <resourceObject
> xmlns="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> MIMEType="image/tiff">
>       <label name="base 1"/>
>      </resourceObject>
>     </ICMBASE>
>    </CLAIM_1047>
>   </ItemXML>
>  </Item>
> </CreateItemRequest>
> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
> in the element that needs it in this correct message.
>
> The mesage can't be parsed by server (sent by CXF):
> <?xml version="1.0" encoding="UTF-8"?>
> <CreateItemRequest
> xmlns:ns2="http://www.ibm.com/xmlns/db2/cm/api/1.0/schema"
> xmlns="http://www.ibm.com/xmlns/db2/cm/beans/1.0/schema">
>  <AuthenticationData>
>   <ServerDef>
>    <ServerName>icmnlsdb</ServerName>
>   </ServerDef>
>   <LoginData>
>    <UserID>icmadmin</UserID>
>    <Password>********</Password>
>   </LoginData>
>  </AuthenticationData>
>  <Item>
>   <ItemXML>
>    <CLAIM_1047 DESC_1047="This is a claim regarding the accident.3"
> CLAIMNO_1047="1234" DATE_1047="2004-01-27">
>     <ns2:properties type="document"/>
>     <VEHICLE_1047 VIN_1047="38">
>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Ben"/>
>      <OWNER_1047 LNAME_1047="Dover" FNAME_1047="Eileen"/>
>     </VEHICLE_1047>
>     <VEHICLE_1047 VIN_1047="34">
>      <OWNER_1047 LNAME_1047="Freely" FNAME_1047="I.P."/>
>     </VEHICLE_1047>
>     <ICMBASE>
>      <ns2:resourceObject MIMEType="image/tiff">
>       <ns2:label name="base 1"/>
>      </ns2:resourceObject>
>     </ICMBASE>
>    </CLAIM_1047>
>   </ItemXML>
>  </Item>
> </CreateItemRequest>
>
> The namespace http://www.ibm.com/xmlns/db2/cm/api/1.0/schema was put
> in the root element.
>
> Is there anyone who knows how to configure CXF to generate the XML
> message in accordance with the first style? Or is there possible to
> manually modify the generated message using out Interceptor?
> Actually, I have tried to use interceptor the modify the output
> stream: public StreamInterceptor() {
>         super(Phase.PRE_STREAM);
>         addBefore(SoapPreProtocolOutInterceptor.class.getName());
> }
>
>    public void handleMessage(Message message) {
>      OutputStream os = message.getContent(OutputStream.class);
>         CachedStream cs = new CachedStream();
>         message.setContent(OutputStream.class, cs);
>
>         message.getInterceptorChain().doIntercept(message);
>
>         try {
>             cs.flush();
>             CachedOutputStream csnew = (CachedOutputStream)
> message.getContent(OutputStream.class);
> //            FileOutputStream fileOut = new
> FileOutputStream("D:\\test.txt");
> //            CachedOutputStream.copyStream(csnew.getInputStream(),
> fileOut, 1024);
>
>             StringBuilder sb = new StringBuilder();
>             csnew.writeCacheTo(sb);
>
>             String tmpXML = sb.toString();
>             System.out.println("#####OLD####" + tmpXML);
>             while (tmpXML.indexOf("<ns2:")!=-1){
>              String subTmp =
> tmpXML.substring(tmpXML.indexOf("<ns2:")); subTmp =
> subTmp.substring(1, subTmp.indexOf(" ")); tmpXML =
> tmpXML.replaceAll(subTmp, subTmp.substring(4) + " " +
> "xmlns=\"http://www.ibm.com/xmlns/db2/cm/api/1.0/schema\<http://www.ib
>m.com/xmlns/db2/cm/api/1.0/schema/>" ");
>              System.out.println("#####FIXED#######" + tmpXML);
>             }
>
>             InputStream in = new
> ByteArrayInputStream(tmpXML.getBytes());
>
>             BufferedOutputStream bos = new BufferedOutputStream(os);
>             CachedOutputStream.copyStream(in, bos, 1024);
>
>             cs.close();
>             in.close();
> //            fileOut.close();
>             bos.close();
>             os.flush();
>
>             message.setContent(OutputStream.class, os);
>         } catch (IOException ioe) {
>             ioe.printStackTrace();
>         }
>     }
>
> But the above code can't handle the message stream with MTOM
> attachements. It can't get the OutputStream at all. I don't know the
> reason.
>
> Your help will be really appreciated. Thanks in advance!
> Yuval Zou



-- 
J. Daniel Kulp
Principal Engineer, IONA
dkulp@apache.org
http://www.dankulp.com/blog