I am trying to access a MBean service deployed into JBOSS AS 7.1.1. My MBean service is also a Queue Listener. I am trying to get an instance of this MBean service to register it as a Queue Listener in another SAR.
I tried out this code but it is not working,
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName mbeanObject =
new ObjectName("myproject.service.Test:service=com.mytest.program");
TestServiceMBean handler = MBeanServerInvocationHandler.newProxyInstance(
server, mbeanObject, TestServiceMBean.class, false);
I also tried out this
TestServiceMBean testMBeanService =
(TestServiceMBean)server.getAttribute(mbeanObject, "Instance");
In both the cases I am not getting the instance of the TestServiceMBean. Can anyone please help me in getting the access to MBean Test service.
<mbean code="com.mytest.program.TestService"
name="myproject.service.Test:service=com.mytest.program">
</mbean>
Here's the code:
public class TestService implements TestServiceMBean, MessageListener {
Muthu;
For the AttributeNotFoundException: At least we know that the MBean is actually registered :) So the question is, does your TestService mbean define an attribute called Instance and does it have a return a type of TestServiceMBean and does it actually return this ? If not, that's what you need to do.
TestService:
public TestServiceMBean getInstance() {
return this;
}
TestServiceMBean:
public TestServiceMBean getInstance();
For the invocation handler, you should not need to cast, but the returned class will not have the name you expect. It's called Proxy0 because it is a synthetic dynamic proxy, but you should find that it does implement the TestServiceMBean interface and you should be able to invoke operations against it.
Related
Background:
In my project, I needed to have two factor authentication (by sending OTP to registered email) which I implemented by extending DaoAuthenticationProvider.
In order to identify reason of why OTP authentication has failed, my custom authentication provider throws new custom exceptions for example BadOtpException, ExpiredOtpException, ConsumedOtpException. All these exceptions are subclasses of BadCredentialsException. This authentication flow is working fine.
Issue:
The Authentication events that were earlier getting published while I was using DaoAuthenticationProvider are now not getting published with my custom authentication provider.
Cause:
Upon some troubleshooting I figured out that Grails Spring Security Core plugin uses DefaultAuthenticationEventPublisher to publish the events. And this class publishes events on the basis of exception mappings which contain exception name vs event name to resolve the event that needs to be published whenever exception occurs. And these mappings are configured in its constructor.
Since mappings of my custom exceptions are not present in this constructor, the authentication failure events are not getting published.
Tried Solution:
I tried overriding DefaultAuthenticationEventPublisher and added new exception mappings by invoking super.setAdditionalExceptionMappings(). Here is the custom event publisher:
class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {
CustomAuthenticationEventPublisher() {
}
CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super(applicationEventPublisher)
println('CustomAuthenticationEventPublisher')
Properties exceptionMappings = new Properties()
exceptionMappings.setProperty(BadOtpException.class.name, AuthenticationFailureBadCredentialsEvent.class.name)
super.setAdditionalExceptionMappings(exceptionMappings)
}
}
In resources.groovy, I registered my custom event publisher using following:
beans = {
authenticationEventPublisher(CustomAuthenticationEventPublisher)
}
But above solution is not working. Even the println() statement in the constructor is not getting logged. Seems like the bean is not getting registered.
Am I doing anything wrong in the above solution?
Is there any other way I can override the exception mappings?
With bit of more troubleshooting, I realized that zero argument constructor of the class CustomAuthenticationEventPublisher was being called instead of the other one.
So I tried setting the exception mappings in constructor and it worked.
Here is the code that worked form me:
class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {
CustomAuthenticationEventPublisher() {
println('CustomAuthenticationEventPublisher')
Properties exceptionMappings = new Properties()
exceptionMappings.setProperty(BadOtpException.class.name, AuthenticationFailureBadCredentialsEvent.class.name)
super.setAdditionalExceptionMappings(exceptionMappings)
}
CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super(applicationEventPublisher)
}
}
Thanks.
Usually I have seen in OSGi development that one service binds to another service. However I am trying to inject an OSGi service in a non-service class.
Scenario trying to achieve: I have implemented a MessageBusListener which is an OSGi service and binds to couple of more services like QueueExecutor etc.
Now one of the tasks of the MessageBusListener is to create a FlowListener (non-service class) which would invoke the flows based on the message content. This FlowListener requires OSGi services like QueueExecutor to invoke the flow.
One of the approach I tried was to pass the reference of the services while creating the instance of FlowListener from MessageBusListener. However when the parameterized services are deactivated and activated back, I think OSGi service would create a new instance of a service and bind to MessageBusListener, but FlowListener would still have a stale reference.
#Component
public class MessageBusListener
{
private final AtomicReference<QueueExecutor> queueExecutor = new AtomicReference<>();
#Activate
protected void activate(Map<String, Object> osgiMap)
{
FlowListener f1 = new FlowListener(queueExeciutor)
}
Reference (service = QueueExecutor.class, cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC)
protected void bindQueueExecutor(QueueExecutor queueExecutor)
{
this.queueExecutor = queueExecutor;
}
}
public class FlowListener
{
private final AtomicReference<QueueExecutor> queueExecutor;
FlowListener(QueueExecutor queueExecutor)
{
this.queueExecutor = queueExecutor;
}
queueExecutor.doSomething() *// This would fail in case the QueueExecutor
service was deactivated and activated again*
}
Looking forward to other approaches which could suffice my requirement.
Your approach is correct you just need to also handle the deactivation if necessary.
If the QueueExecutor disappears the MessageBuslistener will be shut down. You can handle this using a #Deactivate method. In this method you can then also call a sutdown method of FlowListener.
If a new QeueExecutor service comes up then DS will create a new MessageBuslistener so all should be fine.
Btw. you can simply inject the QueueExecutor using:
#Reference
QueueExecutor queueExecutor;
I registered my services.yml file like below :
services:
PMI.form.users_tasks:
class: PMI\UserBundle\Form\UsersTasksType
arguments:
EntityManager: "#doctrine.orm.default_entity_manager"
I can list it by php app/console container:debug, so that mean my service is registered properly.
In my UsersTasksType class I have like below :
class UsersTasksType extends AbstractType
{
protected $ur;
public function __construct(EntityManager $ur )
{
$this->setUr($ur);
}
// Get and setters
}
Does Dependency Injection mean that I don't have to pass the EntityManager to the class constructor anymore? Or what ?
Because when I have to run the code below :
$form = $this->createForm(new UsersTasksType(), $entity);
I get this error:
Catchable Fatal Error: Argument 1 passed to PMI\UserBundle\Form\UsersTasksType::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in C:\wamp\www\PMI_sf2\src\PMI\UserBundle\Controller\UsersTasksController.php on line 74 and defined in C:\wamp\www\PMI_sf2\src\PMI\UserBundle\Form\UsersTasksType.php line 19
And I have to do something below :
$em = $this->container->get('doctrine.orm.entity_manager');
$form = $this->createForm(new UsersTasksType($em), $entity);
So what would be the whole purpose of Dependency Injection ?
Dependency Injection basically gives one service (in this case, your UserTasksType) access to another service (in this case, your the entity manager).
arguments:
EntityManager: "#doctrine.orm.default_entity_manager"
These two lines tell Symfony to expect the entity manager service to be passed into the constructor when you instantiate a new UserTasksType object, which effectively gives your UserTasksType access to the entity manager.
If you aren't using the entity manager in your UserTasksType, there is no need to inject it in the constructor and you could get rid of the two lines above and the __construct() / setUr() methods in your UserTasksType.
A better example to help you understand DIC might be that you have a service that is written specifically to send emails (Swiftmail, for e.g.) and you need to inject it into another service so that service can send emails.
By adding
arguments: [ #mailer ]
to your service definition, your services constructor will expect your mailer service
__construct ($mailer)
{
$this->mailer = $mailer;
}
which will give it access to send emails
someFunction()
{
//do something useful, then send an email using the swift mailer service
$this->mailer->sendEmail();
}
Check out the latest Symfony docs for more of an explanation.
http://symfony.com/doc/current/book/service_container.html
I'm trying to invoke business logic via JMX (using 'standard' MBeans) in a web application in Websphere Application Server 7 with JTA switched on and would like to know why this business logic can't see the JTA UserTransaction when invoked from an MBean (because it can when invoked via the web app's UI).
When hibernate attempts to look up the UserTransaction via 'java:comp/UserTransaction', the following exception is thrown:
org.hibernate.TransactionException: Could not find UserTransaction in JNDI [java:comp/UserTransaction]
at org.hibernate.transaction.JTATransactionFactory.getUserTransaction(JTATransactionFactory.java:173)
at org.hibernate.transaction.JTATransactionFactory.createTransaction(JTATransactionFactory.java:149)
...
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:105)
at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:39)
at com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:220)
at com.sun.jmx.mbeanserver.PerInterface.getAttribute(PerInterface.java:77)
at com.sun.jmx.mbeanserver.MBeanSupport.getAttribute(MBeanSupport.java:228)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.getAttribute(DefaultMBeanServerInterceptor.java:678)
at com.sun.jmx.mbeanserver.JmxMBeanServer.getAttribute(JmxMBeanServer.java:650)
at com.ibm.ws.management.AdminServiceImpl.getAttribute(AdminServiceImpl.java:853)
at com.ibm.ws.management.remote.AdminServiceForwarder.getAttribute(AdminServiceForwarder.java:270)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1415)
at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:84)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1276)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1371)
at javax.management.remote.rmi.RMIConnectionImpl.getAttribute(RMIConnectionImpl.java:612)
at javax.management.remote.rmi._RMIConnectionImpl_Tie.getAttribute(_RMIConnectionImpl_Tie.java:578)
at javax.management.remote.rmi._RMIConnectionImpl_Tie._invoke(_RMIConnectionImpl_Tie.java:98)
at com.ibm.CORBA.iiop.ServerDelegate.dispatchInvokeHandler(ServerDelegate.java:622)
at com.ibm.CORBA.iiop.ServerDelegate.dispatch(ServerDelegate.java:475)
at com.ibm.rmi.iiop.ORB.process(ORB.java:513)
at com.ibm.CORBA.iiop.ORB.process(ORB.java:1574)
at com.ibm.rmi.iiop.Connection.respondTo(Connection.java:2841)
at com.ibm.rmi.iiop.Connection.doWork(Connection.java:2714)
at com.ibm.rmi.iiop.WorkUnitImpl.doWork(WorkUnitImpl.java:63)
at com.ibm.ejs.oa.pool.PooledThread.run(ThreadPool.java:118)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1563)
Caused by: javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name "comp/UserTransaction" not found in context "java:".]
at com.ibm.ws.naming.java.javaURLContextImpl.throwConfigurationExceptionWithDefaultJavaNS(javaURLContextImpl.java:428)
at com.ibm.ws.naming.java.javaURLContextImpl.lookup(javaURLContextImpl.java:399)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:214)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:154)
at javax.naming.InitialContext.lookup(InitialContext.java:455)
at org.hibernate.transaction.JTATransactionFactory.getUserTransaction(JTATransactionFactory.java:163)
... 53 more
Caused by: javax.naming.NameNotFoundException: Name "comp/UserTransaction" not found in context "java:".
at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1178)
at com.ibm.ws.naming.ipbase.NameSpace.lookup(NameSpace.java:1095)
at com.ibm.ws.naming.urlbase.UrlContextImpl.lookup(UrlContextImpl.java:1233)
at com.ibm.ws.naming.java.javaURLContextImpl.lookup(javaURLContextImpl.java:395)
... 57 more
This problem looks like it's more than just a hibernate configuration problem - hibernate is looking for the UserTransaction at what IBM say is the correct UserTransaction JNDI location ('java:comp/UserTransaction') - see this infocenter document.
Furthermore, I can reproduce the problem in a simple web app that has an MBean that does the lookup:
public class JTALookup extends NotificationBroadcasterSupport implements JTALookupMBean {
Log log = LogFactory.getLog(JTALookup.class);
/**
* {#inheritDoc}
* #see JTALookupMBean#lookupUserTransaction()
*/
#Override
public void lookupUserTransaction() {
try {
log.info("Attempting 'java:comp/UserTransaction' lookup");
Object usrTxn = new InitialContext().lookup("java:comp/UserTransaction");
log.info("Successfully looked up 'java:comp/UserTransaction' [" + usrTxn + "]." );
} catch (NamingException e) {
log.info("'java:comp/UserTransaction' lookup failed");
throw new RuntimeException("Failed to lookup JTA user transaction", e);
}
}
and a context listener that invokes the lookup during start up and then registers the MBean:
public void contextInitialized(ServletContextEvent sce) {
log.info("Initialising context");
JTALookup jtaLookup = new JTALookup();
jtaLookup.lookupUserTransaction(); // This succeeds
log.info("Looked up JTA transaction");
MBeanServer mbServer = AdminServiceFactory.getMBeanFactory().getMBeanServer();
log.info("Got MBeanServer");
try {
mbServer.registerMBean(jtaLookup, new ObjectName("webJTALookupStub:type=JTALookup"));
log.info("Registered dummy MBean");
} catch (Exception e) {
log.info("Failed to register dummy MBean");
throw new RuntimeException("Failed to register dummy MBean", e);
}
}
The lookup on 'java:comp/UserTransaction' succeeds during context initialisation, but fails (with a similar stack trace to that above) when invoked via jmx, like so:
public static void main(String[] args) {
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi://" + "your.server.name.co.uk" + ":" + "2809" + "/jndi/JMXConnector"
);
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.PROVIDER_URL, "corbaloc:iiop:gbbldd66.sys.chp.co.uk:2809/WsnAdminNameService");
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory");
// Establish the JMX connection.
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
// Get the MBean server connection instance.
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName("webJTALookupStub:type=JTALookup");
JTALookupMBean mBean = JMX.newMBeanProxy(mbsc, mbeanName, JTALookupMBean.class, true);
mBean.lookupUserTransaction(); // This fails
The 'Extending the WebSphere Application Server administrative system with custom MBeans' document in IBM's infocenter suggests that standard MBeans that have been tested in applications outside WAS should just work.
IBM do state that the UserTransaction lookup is not available to:
CMT Enterprise beans `http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/ae/cjta_glotran.html
Async Beans created by EJBs `http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/com/ibm/websphere/asynchbeans/package-summary.html?resultof=%22%61%73%79%6e%63%68%62%65%61%6e%22%20%22%75%73%65%72%74%72%61%6e%73%61%63%74%69%6f%6e%22%20%22%75%73%65%72%74%72%61%6e%73%61%63%74%22%20
Apologies for the non-functional links - I'm a new user and so can only post two working links.
Do plain old MBeans fall into either of these categories from IBM's point of view?
Interestingly, the UserTransaction appears to be available on JNDI lookup 'jta/UserTransaction' and using that as a fallback option seems to work - but:
WAS 7 is Java EE 5 compliant and as of J2EE 1.3 'java:comp/UserTransaction' is the specified JNDI location for the UserTransaction - see the J2EE 1.3 spec `http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf
Using a lookup from an earlier version of the EE specification seems like a potential source of other bugs, and might only be addressing part of my problem - the fact that WAS thinks my MBean's thread is not associated with an application could cause other issues.
One further point to note is that the UserTransaction is also hidden to threads for work submitted from the MBean to the application's work manager (an IBM work manager) - which could be because it's treating that work like it's an async bean submitted by an EJB?
Possible explanations that have occurred to me are:
There might issues with how IBM set up MBean threads in WAS 7 and associate then with the applications that register the MBeans.
There might be some additional configuration options for the MBean registration that would let WAS know that it should associate the MBean with the application that registered it. I have tried several alternative approaches but saw the same exception each time:
Registering the MBeans with UserCollaborators and xml descriptors
Registering them with ModelMBeanInfo
Registering them with the AdminService rather than the MBeanServer
Enhancing the ObjectName for the MBean with additional properties (Application, J2EEApplication) at registration
There might be some additional configuration options for the jmx client request that would let WAS know that it should associate the MBean invokation with the appropriate application. This forum post suggests it's possible to configure a client application to have access to the initial context: `http://www.ibm.com/developerworks/forums/thread.jspa?messageID=14021995
I might just not be supposed to try to use MBeans this way - despite IBM's statements that I should be able to. It's been suggested that EJBs are the appropriate solution for this kind of requirement.
Any light that can be shed on this problem would be greatly appreciated.
MBeans run on a separate thread than your application, so they don't have access to the application naming context in JNDI, and therefore they don't have access to your UserTransaction.
I think your final potential explanation is likely most accurate:
I might just not be supposed to try to use MBeans this way - despite IBM's statements that I should be able to. It's been suggested that EJBs are the appropriate solution for this kind of requirement.
MBeans may not be appropriate for this type of work. Rather, using EJBs or a web service might be more appropriate.
You have to set TransactionManagementType.BEAN on transactionManagement like so:
#TransactionManagement(TransactionManagementType.BEAN)
I am using Log4Net as a service which is injected into other services using StructureMap.
How do I ensure the log file includes the calling service class context (class name and/or thread) which is making the log4net calls?
Surely the calling class or thread will always be the logging service which doesn't help me understand where the logging calls are really coming from.
EDIT:
Register code:
ObjectFactory.Initialize(x =>
{
x.For<ILog>().AlwaysUnique().Use(s => s.ParentType == null ?
LogManager.GetLogger(s.BuildStack.Current.ConcreteType) :
LogManager.GetLogger(s.ParentType));
});
Service layer:
public class LoggerService : ILoggerService
{
private readonly ILog log;
public LoggerService(ILog logger)
{
log = logger;
log.Info("Logger started {0}".With(logger.Logger.Name));
}
public void Info(string message)
{
log.Info(message);
}
}
In the logging, I am still always getting the LoggerService as the context so I'll never see what actually called the logger. It doesn't seem to be working correctly. I feel like I'm missing something here...
Edit 2:
I've added a pastie link for a console app here:
http://pastie.org/1897389
I would expect the parent class to be logged but it isn't working at the simplest of levels.
You might want to have a look at Castle Dynamic proxy in order to solve it using AOP. There is an example of using it with Structure Map on the Structure Map Google Group.
Ayende has an example of AOP based logging using Log4Net and Windsor.
I use StructureMap in a lot of the code I generate and I have a StructureMap registry which I use to hook the logger into the context of the class that it is injected into.
For Reference, I'm using the 2.6.2 version of StructureMap but should be fine with 2.5+ where the new .For<>().Use<>() format is utilized.
public class CommonsRegistry : Registry
{
public CommonsRegistry()
{
For<ILogger>().AlwaysUnique().Use(s => s.ParentType == null ? new Log4NetLogger(s.BuildStack.Current.ConcreteType) : new Log4NetLogger(s.ParentType.UnderlyingSystemType.Name));
XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location), "Log.config")));
}
}
What this registry is doing is for anywhere the ILogger is injected, use the class that it's injected into is where the logging messages are logged to/context of.
*Also, in the second line (XmlConfigurator.ConfigureAndWatch) is where I tell Log4Net to get the logging information from the file "Log.config" instead of the application configuration file, you may or may not like that and can be omitted.
The code I use is a common IOC.Startup routine where I would pass if I would like to use the default registery.
ObjectFactory.Initialize(x =>
{
x.AddRegistry<CommonsRegistry>();
...
}
This gives me the calling class name in the logging instance where messages are logged to automatically and all that is required is to inject the logger into the class.
class foo
{
private readonly ILogger _log;
public foo(ILogger log)
{
_log = log;
}
}
Now the messages are logged as context/class "foo".