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
Related
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.
I have a white label/multi-tennant server providing the same services, but branded for multiple customers. I want to use JMX to monitor the status of each customer (nbr of calls, nbr of errors, etc).
I know how to use Spring JMX annotations to wire up my POJOs (per the code below). What I really want is one MBean per customer, but because the customers are dynamically loaded up at server startup time I don't know how to wire this up using annotations.
Is this possible? If not, is it possible to instantiate my MBeans at startup time ?
#Component
#ManagedResource(objectName = "TravelAPI:name=Customer")
public class CustomerStatus extends GeneralCustomerStatus {
#ManagedAttribute
String customerId;
.
.
.
}
What I really want is one MBean per customer, but because the customers are dynamically loaded up at server startup time I don't know how to wire this up using annotations.
What we do is to have the entity that is actually instantiating your dynamic objects, register them with JMX via the MBeanExporter. We inject the MBeanExporter instance into the factory entity and then call MBeanExporter.registerManagedResource(...).
For example we do something like:
...
mbeanExporter.registerManagedResource(beanInstance);
...
#Required
public void setMbeanExporter(MBeanExporter mbeanExporter) {
this.mbeanExporter = mbeanExporter;
}
We also use a NamingPolicy so that the dynamic objects can provide their own names to make them unique. See more details about that here:
Change #ManagedResource objectName dynamically
As an aside, my SimpleJMX package has some code to help with dynamic objects.
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.
EJBs seem to be loaded lazily - whenever accessed.
However, I want to initialize them eagerly - i.e. whenever the container starts-up. How is this achieved (in JBoss in particular)
This topic gives some hints, but isn't quite satisfactory.
As of EJB 3.1, singleton beans can be notified of module start and stop:
#Singleton
#Startup
public class StartupBean {
#PostConstruct
private void postConstruct() { /* ... */ }
#PreDestroy
private void preDestroy() { /* ... */ }
}
Prior to EJB 3.1, there is no standard, EJB-only solution. I'd suggest adding a WAR to your EAR and using a servlet-context-listener.
According to Adam Bien's Real World Java EE Patterns - Rethinking Best Practices (see a summary of the patterns) and the Service Starter pattern, it is indeed as bkail suggests
with Java EE 6 = EJB 3.1 use #Singleton with #Startup (and perhaps also with #DependsOn)
prior to that the only standard and portable way is to use the Servlet API, e.g. a HttpServlet starting the EJBs in its init() method and load-on-startup set to 1 in web.xml.
I've got a NullPointerException using EJB3 in a J2SE environment (without EJB3 container)
Briefly, I've got a stateless bean implementing an interface.
When I call it in another class like in a main, a NullPointerException is triggered.
Sample:
#stateless
#Local(IMyInterface.class)
public class myBean implements IMyInterface{...}
public class Main{
#EJB
IMyInterface myInterface;
public static void main(String[] args){
Result result = myInterface.myBeanMethod(); // Exception happens here
}
}
I guess I miss some initialization stuff because the EJB is null when I first try to use it...
Thanks for your help,
EJBs can't work without a container. The dependencies (#EJB) are injected if the beans are instantiated by the container. If you are the one instantiating them, it is your responsibility to set the dependencies.
Furthermore, you are trying to use a non-static variable from a a static method - this won't even compile.
While you can use JPA (which is part of EJB 3) "Entity Beans" (actually, POJOs) in a J2SE environment, you can't use Session Beans without a container and you can't benefit from injection of resources using the #Resource or the more specialized #EJB and #WebServiceRef annotations in a non-managed environment, i.e. a container. In other words, only managed components support injection (Servlets, JSF Managed beans, EJB components, etc).
So, in your case, you'll need to:
Deploy your Session Bean in a Java EE container (like JBoss, GlassFish, WebLogic, etc)
Lookup the remote EJB using explicitly its global JNDI name. The code will look like that:
Foo foo = (Foo) new InitialContext().lookup("FooEJB");
A few additional remarks:
With EJB 3.0, the global JNDI name is container dependent so I can't tell you what it will be exactly (EJB 3.1 finally introduced "portable global JNDI names").
You'll need to set up the JNDI environment (which is container dependent) for the lookup either by providing a jndi.properties on the class path or by using the InitialContext(Hashtable) constructor.
You'll need to provide the application server "client library" on the class path of the client (which is obviously specific to each product).
Search for previous questions or open a new one if you need more specific guidance.