You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by Anthony Fryer <ap...@hotmail.com> on 2014/06/14 07:45:12 UTC

Use single JAXBContext for multiple web services

Is it possible to configure a single JAXBContext to be reused by multiple
JAX-WS web services?  I want to test this to see if it speeds up my boot
time and uses less memory.

Searching on the web, i've found this link...

https://www.mail-archive.com/users@cxf.apache.org/msg35563.html

This suggests that it might be possible by configuring a "dataBinding"
property in cxf jaxws.  Is this property able to be configured in tomee?

On a side note, to me it looks like JAX-RS and JAX-WS use different
strategies for JAXBContexts.  In my project, JAX-RS had marshalling issues
if the ObjectFactory class didn't contain all required jaxb elements, but
JAX-WS didn't fail in that case.   But then JAX-RS seems to boot up much
faster than JAX-WS which i'm pretty sure is related to JAXBContext creation.



--
View this message in context: http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Use single JAXBContext for multiple web services

Posted by Romain Manni-Bucau <rm...@gmail.com>.
This works on trunk now ;)
Le 16 juin 2014 02:47, "Anthony Fryer" <ap...@hotmail.com> a écrit :

> Using "@<resourceId>" would be even better.  I was wishing for that the
> last
> few days.
>
> Cheers,
>
> Anthony
>
>
>
> --
> View this message in context:
> http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670026.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.
>

Re: Use single JAXBContext for multiple web services

Posted by Anthony Fryer <ap...@hotmail.com>.
Using "@<resourceId>" would be even better.  I was wishing for that the last
few days.

Cheers,

Anthony



--
View this message in context: http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670026.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Use single JAXBContext for multiple web services

Posted by Romain Manni-Bucau <rm...@gmail.com>.
About the doc: the site is http://svn.apache.org/repos/asf/tomee/site/trunk/
all the content is in "content" (yeah I know ;)). Add a page if you want
and link it where you judge it useful. Then just send us a patch on a jira
and we'll apply it.

PS: I'll add @xxx to link from a Service an existing resource instead of
using a wrapper the user needs to know



Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau


2014-06-15 13:25 GMT+02:00 Anthony Fryer <ap...@hotmail.com>:

> I implemented using the ResourceAsService wrapper as you suggested and it
> works.  I think that ResourceAsService could be useful enough to be
> included
> in tomee.
>
> My ResourceAsService class is....
>
> public class ResourceAsService {
>         private String resourceId;
>
>         public String getResourceId() {
>                 return resourceId;
>         }
>
>         public void setResourceId(String resourceId) {
>                 this.resourceId = resourceId;
>         }
>
>         public Object get() throws Exception {
>                 if (resourceId == null) {
>                         throw new IllegalArgumentException("Please specify
> a resourceId");
>                 }
>
>                 return
>
> SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb:Resource/"
> + resourceId);
>         }
>
> }
>
> My resources.xml now looks like this...
>
> <resources>
>
>    <Resource id="myJAXBContextResource"
> class-name="com.virginaustralia.service.GlobalJAXBContext"
> factory-name="getJAXBContext"/>
>
>    <Service id="myJAXBContextService"
> class-name="au.com.cyberavenue.cxf.ResourceAsService" factory-name="get">
>       resourceId = myJAXBContextResource
>    </Service>
>
>    <Service id="myJAXBDataBinding"
> class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
>       jaxbContext = $myJAXBContextService
>    </Service>
>
> </resources>
>
> And my GlobalJAXBContext class has gone back to this...
>
> public class GlobalJAXBContext {
>
>         public static JAXBContext getJAXBContext() {
>                 try {
>                         return JAXBContext.newInstance(new Class[] {
>
> com.virginaustralia.model.schema.utility.ObjectFactory.class,
>
>
> com.virginaustralia.service.contract.departure_management.ObjectFactory.class
> });
>                 } catch (JAXBException e) {
>                         e.printStackTrace();
>                 }
>
>                 return null;
>         }
> }
>
> and everything boots up quickly like before.  Thanks for the suggestion.
>
> As for documentation...i would if i get time from my project.  Is there
> documention on how to contribute?
>
>
>
> --
> View this message in context:
> http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670024.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.
>

Re: Use single JAXBContext for multiple web services

Posted by Anthony Fryer <ap...@hotmail.com>.
I implemented using the ResourceAsService wrapper as you suggested and it
works.  I think that ResourceAsService could be useful enough to be included
in tomee.

My ResourceAsService class is....

public class ResourceAsService {
	private String resourceId;

	public String getResourceId() {
		return resourceId;
	}

	public void setResourceId(String resourceId) {
		this.resourceId = resourceId;
	}
	
	public Object get() throws Exception {
		if (resourceId == null) {
			throw new IllegalArgumentException("Please specify a resourceId");
		}
		
		return
SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb:Resource/"
+ resourceId);
	}

}

My resources.xml now looks like this...

<resources>
   
   <Resource id="myJAXBContextResource"
class-name="com.virginaustralia.service.GlobalJAXBContext"
factory-name="getJAXBContext"/>

   <Service id="myJAXBContextService"
class-name="au.com.cyberavenue.cxf.ResourceAsService" factory-name="get">
      resourceId = myJAXBContextResource
   </Service>
   
   <Service id="myJAXBDataBinding"
class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
      jaxbContext = $myJAXBContextService
   </Service>
     
</resources> 

And my GlobalJAXBContext class has gone back to this...

public class GlobalJAXBContext {
	
	public static JAXBContext getJAXBContext() {
		try {
			return JAXBContext.newInstance(new Class[] {
							com.virginaustralia.model.schema.utility.ObjectFactory.class,
						
com.virginaustralia.service.contract.departure_management.ObjectFactory.class
});
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		return null;
	}
}

and everything boots up quickly like before.  Thanks for the suggestion.

As for documentation...i would if i get time from my project.  Is there
documention on how to contribute?



--
View this message in context: http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670024.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Use single JAXBContext for multiple web services

Posted by Romain Manni-Bucau <rm...@gmail.com>.
Hi

this is right and correctly done. Service are designed for CXF to get a
"prototype" scope (which is expected by default by cxf) and not a
singleton. You can get a resource in a service looking it up
(SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb:Resource/"
+ resourceId))

About $: do you want to contribute the doc? It only works between services
but is something important I think.

Another question: do you think using a Service wrapper to lookup a resource
transparently would be useful?

 <Service id="myResourceAsServiceInstance"
class-name="org.apache.openejb.resource.ResourceAsService"
factory-name="get">
     name = resourceId
  </Service>

Implementation would be something like:

public class ResourceAsService {
 private String resourceId = null; // + setter

 public Object create() throws Exception {
    if (id == null) {
       throw new IllegalArgumentException("Please specify a resourceId");
    }
    return SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext().lookup("openejb:Resource/"
+ resourceId);
 }
}





Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau


2014-06-15 2:55 GMT+02:00 Anthony Fryer <ap...@hotmail.com>:

> I've managed (after lots of pain and suffering) to get my web services
> using
> the same JAXBContext.  The great thing is this significantly speeds up my
> tomee boot time.  Before, tomee was taking 37594 ms to boot and now it is
> taking 10150 ms, so the performance gain is massive.  The steps i went
> through to get this to work are detailed below.
>
> I tried to follow the steps described in
> https://www.mail-archive.com/users@cxf.apache.org/msg35563.html, changing
> the spring config into tomee config.  So the idea was to try to create a
> global JAXBContext instance and then pass that as a constructor parameter
> into the org.apache.cxf.jaxb.JAXBDataBinding.  I thought I could do this
> using <Service> elements in my resources.xml file.
>
> I created a class to create the JAXBContext...
>
> public class GlobalJAXBContext {
>
>         public static JAXBContext getJAXBContext() {
>                 try {
>                         return JAXBContext.newInstance(new Class[] {
>
> com.virginaustralia.model.schema.utility.ObjectFactory.class,
>
>
> com.virginaustralia.service.contract.departure_management.ObjectFactory.class
> });
>                 } catch (JAXBException e) {
>                         e.printStackTrace();
>                 }
>
>                 return null;
>         }
> }
>
> Then I added the following to my resources.xml...
>
> <resources>
>    ...
>    <Service id="myJAXBContext"
> class-name="com.virginaustralia.service.GlobalJAXBContext "
> factory-name="getJAXBContext"/>
>
>   <Service id="myJAXBDataBinding"
> class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
>      jaxbContext = $myJAXBContext
>   </Service>
>
> </resources>
>
> Took me a long time and looking through source code to discover you can
> pass
> other services as a constructor parameter using the $<serviceId> notation.
>
> My openejb-jar.xml then looked like this...
>
> <openejb-jar xmlns="http://www.openejb.org/openejb-jar/1.1">
>
>    <ejb-deployment ejb-name="AcceptPaymentForAncillariesImpl">
>       <properties>
>          cxf.jaxws.databinding = myJAXBDataBinding
>       </properties>
>    </ejb-deployment>
>
>    <ejb-deployment ejb-name="ActivatePassengerBagTagImpl">
>       <properties>
>          cxf.jaxws.databinding = myJAXBDataBinding
>       </properties>
>    </ejb-deployment>
>
>    ... plus 30 other services similar to above
>
> </openejb-jar>
>
> Booting tomee after this change is where the errors started happening.
> First error was this one...
>
> org.apache.cxf.service.factory.ServiceConstructionException: Service class
>
> com.virginaustralia.service.contract.departure_management.DeletePassengerBagTagPortType
> method deletePassengerBagTag part
> {urn:www.virginaustralia.com:service:contract:departure-management}request
> cannot be mapped to schema. Check for use of a JAX-WS-specific type without
> the JAX-WS service factory bean.
>
> To fix this, i had to specify the wsdlLocation in the @WebService
> annotation.  Fortunately you can do this using a classpath url (this
> requires you to package the WSDL with the service and port classes
> generated
> using wsimport).
>
> @Stateless
> @Local(AcceptPaymentForAncillariesPortType.class)
> @WebService(
>                 portName="AcceptPaymentForAncillariesPortType",
>                 serviceName="AcceptPaymentForAncillariesService",
>                 targetNamespace =
> "urn:www.virginaustralia.com:service:contract:departure-management",
>
>
> endpointInterface="com.virginaustralia.service.contract.departure_management.AcceptPaymentForAncillariesPortType",
>
>
> wsdlLocation="classpath:/com/virginaustralia/service/contract/departure_management/AcceptPaymentForAncillaries.wsdl"
>                 )
> public class AcceptPaymentForAncillariesImpl implements
> AcceptPaymentForAncillariesPortType {
>  ...
> }
>
> After adding wsdlLocation to every service, I booted tomee, but the boot
> time was exactly the same.  Turns out that a new instance of the
> "myJAXBDataBinding" service defined in resources.xml was being instantiated
> for every web service.  And since i used the "myJAXBContext" as a
> constructor argument, a new JAXBContext was being created for every service
> and consequently i was no better off than before.
>
> I only wanted a single JAXBContext created, so I tried to configure it as a
> Resource instead of a Service as below...
>
> <resources>
>    ...
>    <Resource id="myJAXBContext"
> class-name="com.virginaustralia.service.GlobalJAXBContext "
> factory-name="getJAXBContext"/>
>
>   <Service id="myJAXBDataBinding"
> class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
>      jaxbContext = $myJAXBContext
>   </Service>
>
> </resources>
>
>
> Unfortunately when i tried that, the $myJAXBContext being passed as a
> constructor parameter was null.  Is there a way you can pass a resource to
> a
> service as a constructor parameter?
>
> To get around this, I had to change the Resource back to being a Service
> and
> modify my class that creates the JAXBContext to only return a singleton
> instance...
>
> public class GlobalJAXBContext {
>
>         private static JAXBContext jaxbContext = null;
>
>         public static JAXBContext getJAXBContext() {
>                 if (jaxbContext == null) {
>                         try {
>                                 jaxbContext = JAXBContext.newInstance(new
> Class[] {
>
> com.virginaustralia.model.schema.utility.ObjectFactory.class,
>
>
> com.virginaustralia.service.contract.departure_management.ObjectFactory.class
> });
>                         } catch (JAXBException e) {
>                                 e.printStackTrace();
>                         }
>                 }
>
>                 return jaxbContext;
>         }
>
> }
>
>
> After that change, all my services were booting up successfully and reusing
> a single JAXBContext.
>
> Regards,
>
> Anthony
>
>
>
> --
> View this message in context:
> http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670021.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.
>

Re: Use single JAXBContext for multiple web services

Posted by Anthony Fryer <ap...@hotmail.com>.
I've managed (after lots of pain and suffering) to get my web services using
the same JAXBContext.  The great thing is this significantly speeds up my
tomee boot time.  Before, tomee was taking 37594 ms to boot and now it is
taking 10150 ms, so the performance gain is massive.  The steps i went
through to get this to work are detailed below.

I tried to follow the steps described in
https://www.mail-archive.com/users@cxf.apache.org/msg35563.html, changing
the spring config into tomee config.  So the idea was to try to create a
global JAXBContext instance and then pass that as a constructor parameter
into the org.apache.cxf.jaxb.JAXBDataBinding.  I thought I could do this
using <Service> elements in my resources.xml file.

I created a class to create the JAXBContext...

public class GlobalJAXBContext {
	
	public static JAXBContext getJAXBContext() {
		try {
			return JAXBContext.newInstance(new Class[] {
							com.virginaustralia.model.schema.utility.ObjectFactory.class,
						
com.virginaustralia.service.contract.departure_management.ObjectFactory.class
});
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		return null;
	}
}

Then I added the following to my resources.xml...

<resources>
   ...
   <Service id="myJAXBContext"
class-name="com.virginaustralia.service.GlobalJAXBContext "
factory-name="getJAXBContext"/>
   
  <Service id="myJAXBDataBinding"
class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
     jaxbContext = $myJAXBContext
  </Service>

</resources> 

Took me a long time and looking through source code to discover you can pass
other services as a constructor parameter using the $<serviceId> notation.

My openejb-jar.xml then looked like this...

<openejb-jar xmlns="http://www.openejb.org/openejb-jar/1.1">

   <ejb-deployment ejb-name="AcceptPaymentForAncillariesImpl">
      <properties>
         cxf.jaxws.databinding = myJAXBDataBinding
      </properties>
   </ejb-deployment>
   
   <ejb-deployment ejb-name="ActivatePassengerBagTagImpl">
      <properties>
         cxf.jaxws.databinding = myJAXBDataBinding
      </properties>
   </ejb-deployment>

   ... plus 30 other services similar to above 

</openejb-jar>

Booting tomee after this change is where the errors started happening. 
First error was this one...

org.apache.cxf.service.factory.ServiceConstructionException: Service class
com.virginaustralia.service.contract.departure_management.DeletePassengerBagTagPortType
method deletePassengerBagTag part
{urn:www.virginaustralia.com:service:contract:departure-management}request
cannot be mapped to schema. Check for use of a JAX-WS-specific type without
the JAX-WS service factory bean.

To fix this, i had to specify the wsdlLocation in the @WebService
annotation.  Fortunately you can do this using a classpath url (this
requires you to package the WSDL with the service and port classes generated
using wsimport).

@Stateless
@Local(AcceptPaymentForAncillariesPortType.class)
@WebService(
		portName="AcceptPaymentForAncillariesPortType",
		serviceName="AcceptPaymentForAncillariesService",
		targetNamespace =
"urn:www.virginaustralia.com:service:contract:departure-management",
	
endpointInterface="com.virginaustralia.service.contract.departure_management.AcceptPaymentForAncillariesPortType",
	
wsdlLocation="classpath:/com/virginaustralia/service/contract/departure_management/AcceptPaymentForAncillaries.wsdl"
		)
public class AcceptPaymentForAncillariesImpl implements
AcceptPaymentForAncillariesPortType {
 ...
}

After adding wsdlLocation to every service, I booted tomee, but the boot
time was exactly the same.  Turns out that a new instance of the
"myJAXBDataBinding" service defined in resources.xml was being instantiated
for every web service.  And since i used the "myJAXBContext" as a
constructor argument, a new JAXBContext was being created for every service
and consequently i was no better off than before.

I only wanted a single JAXBContext created, so I tried to configure it as a
Resource instead of a Service as below...

<resources>
   ...
   <Resource id="myJAXBContext"
class-name="com.virginaustralia.service.GlobalJAXBContext "
factory-name="getJAXBContext"/>
   
  <Service id="myJAXBDataBinding"
class-name="org.apache.cxf.jaxb.JAXBDataBinding" constructor="jaxbContext">
     jaxbContext = $myJAXBContext
  </Service>

</resources> 


Unfortunately when i tried that, the $myJAXBContext being passed as a
constructor parameter was null.  Is there a way you can pass a resource to a
service as a constructor parameter?

To get around this, I had to change the Resource back to being a Service and
modify my class that creates the JAXBContext to only return a singleton
instance...

public class GlobalJAXBContext {
	
	private static JAXBContext jaxbContext = null;

	public static JAXBContext getJAXBContext() {
		if (jaxbContext == null) {
			try {
				jaxbContext = JAXBContext.newInstance(new Class[] {
								com.virginaustralia.model.schema.utility.ObjectFactory.class,
							
com.virginaustralia.service.contract.departure_management.ObjectFactory.class
});
			} catch (JAXBException e) {
				e.printStackTrace();
			}
		}
		
		return jaxbContext;
	}
	
}


After that change, all my services were booting up successfully and reusing
a single JAXBContext.

Regards,

Anthony



--
View this message in context: http://openejb.979440.n4.nabble.com/Use-single-JAXBContext-for-multiple-web-services-tp4670019p4670021.html
Sent from the OpenEJB User mailing list archive at Nabble.com.