Web Service Client in a Stateless Enterprise Bean - java

What is the correct way to implement a stateless EJB 3.1 for invoking a web service. My client works as a Servlet, but I want to move the invocation into a EEJ bean. I have to add username and password in the SOAP header envelop to access the WS, which is working fine.
The service the the servlet is using looks like this;
#WebServiceClient(name = "MessageService", targetNamespace = "http://...", wsdlLocation = "...wsdl")
public class MessageService
extends Service
Can I wrap MessageService in a Stateless EJB or should the bean itself use #WebServiceRef (as in the tutorial) without wrapping the MessageService ?
Tutorial

Local Service
If the client and the provider lives in same EAR or WAR on the application server, can be invoked like a ordinal EJB. e.g.
#WebService
#Stateless
public class CalculatorBean implements Calculator {
public int add(int a, int b) {
return a + b;
}
}
The CalculatorBean is threadsafe. All business logic that occurs within the add method
is part of a container-managed transaction and not participate in any global transaction.
Alternatively, the client code can look up in the JNDI namespace.
Remote Service
The runtime can inject a service object or a port object into a member variable annotated with javax.xml.ws.WebServiceRef.
#WebServiceRef(CalculatorService.class)
private Calculator port;
The CalculatorService class is annotated with the javax.xml.ws.WebServiceClient annotation (the client of the service), which has a wsdlLocation attribute.
If you want to wrap the WebService into the EJB, see this answer. For read a discussion about this, see EJB and Web Services: getting the best of both worlds.

Related

Referencing EJB Local home from a POJO class of a separate web application

I am trying to port 2 EJB modules in my application from EJB2.1 to EJB3.0. I am using the Eclipse Kepler IDE and regenerated the session beans using an EJB3.0 configuration. I am not using an ejb-jar.xml because in EJB 3.0 that is supposed to be redundant. I have instead used annotations for marking my bean as Stateless and specifying the Local and Local Home Interfaces. I have still kept the Local Home interface since I wanted the basic structure of my project to be similar to what it was in EJB2.1. I have also done away with the xml bindings for the EJB while migrating.
We are using a WAS 7 application server for deployment and while the EJB is getting successfully deployed without errors, I am getting a naming Exception while looking up my Local Home interface from a separate POJO class of a different web application it is required in. I basically want to call the create() method of the Local Home interface after referencing the EJB Local Home. Adding code samples below:
Session Bean:
#Stateless
#Local(AccessLDAPSessionLocal.class)
#LocalHome(AccessLDAPSessionLocalHome.class)
public class AccessLDAPSessionBean implements AccessLDAPSessionLocal {
//Business Logic
}
Local Interface:
public interface AccessLDAPSessionLocal {
//business Interface
}
Local Home Interface:
public interface AccessLDAPSessionLocalHome extends EJBLocalHome {
public AccessLDAPSessionLocal create() throws CreateException;
}
Pojo class referencing the Local Home interface:
public static AccessLDAPSessionLocal getAccessLDAPSessionBean() throws NamingException, CreateException {
if (accessLDAPSessionBean == null) {
InitialContext context = new InitialContext();
Object obj = context.lookup("java:global/AccessLDAP/AccessLDAPSessionBean!com.ibm.asset.hrportal.core.ejb.ldap.AccessLDAPSessionLocalHome");
accessLDAPSessionBean = ((AccessLDAPSessionLocalHome) obj).create();
}
return accessLDAPSessionBean;
}
Also my Local and Local Home interfaces are inside my EJB client which I use as a jar file, while my Session Bean is inside the actual EJB which is used as an EAR.
Following is the error I am getting:
NamingException::javax.naming.NameNotFoundException: Name global not found in context "java:".
Am I missing some configuration resulting in the failure of JNDI lookup? Any help would be gratefully appreciated. Thanks in advance.
WebSphere Application Server 7.0 is only an implementation of EJB 3.0, but the java:global namespace wasn't added until EJB 3.1, which wasn't implemented in WebSphere Application Server until 8.0. As with all EJB 3.0 implementations, you will need to lookup a vendor-specific binding name. You can find the WebSphere Application Server binding name by looking at the CNTR0167I messages in SystemOut.log. See the EJB 3.0 application bindings overview topic in the Knowledge Center if you would like to customize this binding name.
Regardless, it is not a best practice to directly lookup EJBs by their binding name. Instead, you should use an EJB reference. In EJB 3.0, that means using an annotation like this in an EE managed object (such as a servlet or another EJB):
#EJB
private AccessLDAPSessionLocalHome home;
In this case, the EJB container is required to find a target EJB within the same application that contains the EJB reference, so you do not need to explicitly configure a target binding name for the EJB reference.
If you need to access the EJB reference from a utility class rather than an EE managed class, then declare the EJB reference with a name on a managed class (such as a servlet or another EJB), and look it up from the utility class:
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class)
public class MyServlet { ... }
public class MyUtility {
...
InitialContext context = new InitialContext();
Object obj = context.lookup("java:comp/env/ejb/accessHome");
...
}
You can configure multiple such EJB references on the same managed EE class using the #EJBs annotation:
#EJBs({
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class),
#EJB(name = "ejb/other" beanInterface = Other.class)
})
public class MyServlet { ... }
If your EJB is packaged in a separate EAR, then note that this is not a portable configuration. See the "Local client views" section of the EJB modules topic in the Knowledge Center. Additionally, you will need to explicitly configure a binding name for the EJB reference.
I think the way you are looking up the ejb is not correct. The JNDI name would be something like "java:comp/env/". ejb-ref-name would be part of your web.xml
Also, you will need to give providerURL and factoryName to the context object before doing the lookup.

Access JSF2 Managed Bean from RESTful Web Service

I have an application scoped managed bean which contains a list read from the database. Whenever another application makes changes to the database, it should trigger the web service to update the list in the managed bean.
I've tried
FacesContext context = FacesContext.getCurrentInstance();
ApplicationBean application= (ApplicationBean) context.getApplication().evaluateExpressionGet(context, "#{applicationBean}", ApplicationBean.class);
The context variable was null, probably because the web service isn't called in the JSF context.
The REST resource class looks something like this:
#Path("/application")
public class ApplicationResource {
#PUT
#Path("{id}")
#Consumes(MediaType.TEXT_PLAIN)
#Produces(MediaType.TEXT_PLAIN)
public void updateIdCache(#PathParam("id") String internalid) {
ApplicationBean application = ???;
application.update(id);
return;
}
}
The application server in use is tomcat 6. How is it done correctly?
Thanks & best regards
Don't think what you want is possible with JSF managed beans.
CDI beans have this functionality though.
JAX-WS with CDI:
http://weblogs.java.net/blog/jitu/archive/2010/02/19/jax-ws-cdi-java-ee-6-0
CDI implementation weld is commonly used:
Getting started with weld (covers tomcat 6)
http://docs.jboss.org/weld/reference/1.0.0/en-US/html/gettingstarted.html
btw I love to work with CDI and I only use tomcat 6/7

Deploying CXF service endpoint with Spring dependency injection

I'm trying to inject spring bean into class annotated with #WebService and #SOAPBinding annnotations.
#WebService(targetNamespace = JAXWSMessageHandler.MY_URL)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class JAXWSMessageHandler {
private StorageManager bufferContainer;
public void setBufferContainer(StorageManager storageManager){
this.bufferContainer = storageManager;
}
and I get the following exception:
Service class soap.service.JAXWSMessageHandler method setBufferContainer part {http://myurl/myproject/v1}setBufferContainer cannot be mapped to schema. Check for use of a JAX-WS-specific type without the JAX-WS service factory bean.
It seems that the operation used by spring is expected to be defined in WSDL by CXF. I think I can hack it with singleton mediator class that would allow communication from WebService class to my business class,however, it doesn't sound good to me and I'd like to do that properly. Any hints how to do that?
JAX-WS is interpreting the method signatures on the annotated class as web service operations. My guess is that if you used constructor injection (instead of setter injection), the problem would go away.
I think I have a better solution:
Presumably you are using #WebMethod to annotate the methods you want to expose on your web service?
Well you can also add a #WebMethod annotation to your setter method, and set the attribute 'exclude' to be true. This means that this method will not be expected to be defined in your wsdl.
#WebService(targetNamespace = JAXWSMessageHandler.MY_URL)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class JAXWSMessageHandler {
private StorageManager bufferContainer;
#WebMethod(exclude=true)
public void setBufferContainer(StorageManager storageManager){
this.bufferContainer = storageManager;
}

how to Inject an EJB into a java class

I want to inject an EJB3 into a java class which is not an EJB.
these classes are both on the same server and application.
Is that possible ...and if yes ..then how ?
Thanks,
Perhaps you should supply more information about your work environment. The usage of CDI changes the whole specturm. You can inject it when you use CDI, otherwise you can only inject it into other EJB's and servlets (if your application server supports it).
Otherwise you can do a lookup using
Context ctx = new InitialContext();
MyEjb ejb = (MyEjb) ctx.lookup("java:comp/env/myEjb");
You can supply a name in the #EJB annotation you supply together with your #Stateless/#Stateful annotation.
#Stateless
#EJB(name="myEjb", beanInterface=MyEjb.class)
public class myEjbImpl implements MyEjb{
// code goes here
}
You can't inject it, but you can make a lookup for that EJB:
Look here:
http://www.roseindia.net/ejb/ejb-lookup.shtml
During the deploymentprocess of your EJB you may see, the Name of your Bean.

How to expose a Stateless EJB method as MBean (on Jboss)?

I have a stateless EJB (3) that uses internal cache which is refreshed automatically every 24 hours. I would like to expose a MBean method to be able to force cache expiration or even cache reload on this EJB via JMX console on Jboss 4.2.
Can someone share an example on how to code this scenario? I'm totally new to JMX when it comes to creating my own beans.
Should I create an MBean that calls my EJB or is it possible to expose a specific EJB method as an Mbean interface by using annotation on EJB itself?
EJB looks like this:
#Stateless
#Local(BusinessCalendar.class)
public class BusinessCalendarBean implements BusinessCalendar {
synchronized private LocalDateKitCalculatorsFactory getCalculatorFactory() {
LocalDateKitCalculatorsFactory ldkc = (LocalDateKitCalculatorsFactory) CacheService.get(CACHE_KEY);
if (ldkc == null) {
ldkc = getCalculatorFactory();
CacheService.put(CACHE_KEY, ldkc);
}
return ldkc;
}
public function expireCache() {
// I would like to expose this as JMX managed method
}
...
}
Update:
This is surely valid for WildFly 10+, jBOSS EAP 6.x or 7.x. But I suspect the mechanisms are no longer proprietary and shall work very similarly in other app servers.
JBoss specific annotations #Service / #Management were removed when JavaEE 6 standardized Singletons. A MBean (always a singleton so that all JMX clients see the same consistent JMX data application-wide) becomes an EE6+ Singleton exposed via JMX as follows:
define an interface with a name ending in "...MXBean" (compulsory)
create a #Singleton and #Startup class that implements this interface
define #PostConstruct and #PreDestroy methods to register/unregister the MBean
the register/unregister code is like:
objectName = new javax.management.ObjectName("com.acme.example.jmx:type=" + this.getClass().getName());
platformMBeanServer = java.lang.management.ManagementFactory.getPlatformMBeanServer();
platformMBeanServer.registerMBean(this, objectName);
The getters/setters defined in your "...MXBean" interface become JMX attributes, other methods are mapped to operations as specified in JMX Specifications under "lexical design patterns"
Have you looked at the online JBoss configuration guide yet? This may be of some help:
http://www.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.2.0.cp08/html/Server_Configuration_Guide/EJB3_Services-Message_Driven_Beans.html

Categories