Generic Object Name to access datasource connection manager MBean in Liberty - java

I am trying to access DataSource ConnectionManager MBean using java client.I am able to access it when I specify the datasource name and JNDI name in Object Name.I need a generic approach which can be applicabe for any datasource in server.xml, since this is done as part of a framework that can be used in any application.
I tried multiple options but all the time I got 'javax.management.InstanceNotFoundException'.
Sample code is as given below:
<library id="oracle-lib">
<fileset dir="lib" includes="ojdbc6.jar"/>
</library>
<dataSource jndiName="jdbc/db" id="oracleDB" type="javax.sql.DataSource">
<jdbcDriver javax.sql.DataSource="oracle.jdbc.pool.OracleConnectionPoolDataSource" libraryRef="oracle-lib" />
<connectionManager agedTimeout="10" maxIdleTime="1800" connectionTimeout="180" minPoolSize="10" maxPoolSize="1" reapTime="180"/>
<properties.oracle user="user" password="password"
url="jdbc:oracle:thin:#//db-server:1521/db"/>
</dataSource>
Object name that worked:
ObjectName jvmQuery = new ObjectName("WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/db,name=dataSource[oracleDB]/ConnectionManager[default-0]")
Generic Object Names I tried:
1.WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
2.WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0],*
3.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
4.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0],*
5.WebSphere:service=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,name=dataSource[default-0]/ConnectionManager[default-0]
Could you please advise..
Thank you,
Biju

Query option #1 should work fine:
WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,*
I just tested it with several data sources in my configuration and got the following:
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds1,name=dataSource[ds1]/connectionManager
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds2,name=dataSource[ds2]/connectionManager
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/ds3,name=dataSource[ds3]/connectionManager[default-0]
Found MBean: WebSphere:type=com.ibm.ws.jca.cm.mbean.ConnectionManagerMBean,jndiName=jdbc/XAds,name=dataSource[XAds]/connectionManager
Keep in mind that Connection Manager MBeans are lazily created. If you are expecting to find an mbean in a query, make sure that you have gotten a connection from the data source before. Getting a connection from the data source will force a Connection Manager (and its MBean) to be created.

Related

I get the `DSRA9122E: com.ibm.ws.rsadapter.jdbc.WSJdbcConnection#d3t7e556 does not wrap any objects of type oracle.jdbc.OracleConnection

Am using Websphere 18 Liberty Version. When am trying to unwrap java.sql.connection to oracle.jdbc.OracleConnection I get the
`DSRA9122E: com.ibm.ws.rsadapter.jdbc.WSJdbcConnection#d3t7e556 does
not wrap any objects of type oracle.jdbc.OracleConnection
In sever.xml file am using ojdbc7.jar for datasource, also in application I added same jar from the same location. Still am facing the issue. I referred all links
WSJDBCConnection does not wrap objects of type oracle.jdbc.OracleConnection like this. Still am facing the same issue.
In order for Connection.unwrap to work properly, the Liberty DataSource and the Application must both load the vendor implementation class (oracle.jdbc.OracleConnection) from the same class loader.
Here is a simple example of how to configure both the dataSource and your application to use the same class loader to load from a single library that contains the Oracle JDBC driver,
<library id="OracleLib">
<fileset dir="${server.config.dir}/oracle"/>
</library>
<application location="myApp.war" >
<classloader commonLibraryRef="OracleLib"/>
</application>
<dataSource jndiName="jdbc/oracleDataSource">
<jdbcDriver libraryRef="OracleLib"/>
<properties.oracle .../>
</dataSource>
You don't need to unwrap to OracleConnection. You can use Connection object to establish the connection to the DB.
// Get a context for the JNDI look up
DataSource ds = getDataSource();
try (Connection connection = ds.getConnection()) {
{
executeBusinessLogicOnDatabase(connection));
......
}
connection.close();
}

How to get fixed object name for c3p0 mbeans object

I am using pooledDataSources in my application. ObjectName of Mbean for PooledDataSource contain variable part along with it. for example:
ObjectName = com.mchange.v2.c3p0:type=PooledDataSource[z8kfsx9c4bily2r1i962|23696a1b]
has variable as z8kfsx9c4bily2r1i962|23696a1b and it changes everytime i restart my service. I have to get fixed ObjectName for my mbean for monitoring purpose. I am using jmx for monitoring. I tried to override vmid property but it seems its a not writable property. Did a lot of research on this but running out of luck.
My Jmx Configuration is as following:
<jmxtrans-agent>
<queries>
<!-- C3P0 -->
<query objectName="com.mchange.v2.c3p0:type=PooledDataSource" attribute="threadPoolNumTasksPending" resultAlias="cp.threadPoolNumTasksPending"/>
</queries>
</jmxtrans-agent>
Thanks in advance
By default, c3p0 JMX names look like this:
com.mchange.v2.c3p0:type=PooledDataSource,identityToken=<variable, opaque token>
In order to get a constant identifier, you must set ensure that the property dataSourceName is set. The best way to do that is to give your DataSource a name upon construction:
ComboPooledDataSource cpds = new ComboPooledDataSource("Jojo")
But you can also set dataSourceName like any other c3p0 config property.
Then you'll have JMX names that look like:
com.mchange.v2.c3p0:type=PooledDataSource,identityToken=<variable, opaque token>,name=Jojo
Many JMX clients let you search on attributes, so this is sufficient to give yourself a permanent monitor.
If you really need a constant, fixed, JMX name, you can set the property
com.mchange.v2.c3p0.management.ExcludeIdentityToken=true
This can go in a c3p0.properties file, as a System property, or as a HOCON/typesafe config path, depending how you are configuring c3p0. If you set this property and also set dataSourceName (again, via a constructor or in your config), then your JMX name will be a predictable, fixed String, like
com.mchange.v2.c3p0:type=PooledDataSource,name=Jojo
It will be up to you to ensure these names are unique.
Note: com.mchange.v2.c3p0.management.ExcludeIdentityToken=true is a new-ish feature, please be sure you are using the latest c3p0-0.9.5.1
For more details, see c3p0's JMX configuration docs.

Pattern for JDNI datasource

I'm using a JNDI ressource in Tomcat8 for connecting to a MS-SQL database (Azure). Randomly I experience Connection closed exception, eventually preceeded by Connection peer reset events. When this happens, the service is dead (running into Connection closed for every request) and restarting the tomcat (redploying) is the only chance to get it up again.
On my way trying to solve this I double(triple)-checked every method for unclosed connections, I assure that every connection is opened as try-with-ressource.
Currently I'm trying to get a better understanding about JNDI ressources and the connection pooling, I'm asking what is the preferred pattern to implement a service class which is injected into other services. E.g. questions are
Where should the DataSource be allocated by calling ctx.lookup()? On method level or class scope? E.g. when using the hk2 #Service annotation it seems that a service is instantiated only once and not per request. Currently ctx.lookup() is invoced once (in the constructor) and the DataSource is stored in a class field and later on accessed by the methods using this.dataSource. Does this make sense ? Or should the DataSource be retrieved on every request (=method call)
How can I verify the execution of several options of the DataSource, e.g. testOnBorrow and removeAbandoned (see complete configuration below) are executed correctly? There is an option logAbandoned but I can not see anything in my logs. Where should this appear anyhow? Can I somehow specifiy a certain log level for the pool? I only found org.apache.tomcat.jdbc.pool, but this class seems only to be called when creating the pool (at least this is the only moment when logs appear, even on level FINEST).
Are there general patterns which I'm not aware of?
Here my current configuration:
<Resource name="jdbc/mssql"
auth="Container"
type="javax.sql.XADataSource"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="***"
password="***"
url="jdbc:sqlserver://***.database.windows.net:1433;database=***;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="55"
removeAbandonedOnMaintenance="true"
timeBetweenEvictionRunsMillis="34000"
minEvictableIdleTimeMillis="55000"
logAbandoned="true"
validationQuery="SELECT 1"
validationInterval="34000"
/>
Thx, gapvision
Gapvision, you can check this link - What is the good design pattern for connection pooling?
Probably, you would want to go with the object pool pattern.
Hope this helps !!
I'm asking what is the preferred pattern to implement a service class which is injected into other services.
Try spring data. It is very helpful in organizing resources to access data.
Without spring, without tomcat built-in features, you indeed need create your own singletons to allocate DataSource or ConnectionPool.
Without spring(assuming you build web app for tomcat), you can add to web.xml:
<resource-ref>
<description>H2DB</description>
<res-ref-name>jdbc/project1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
And in context.xml of tomcat:
<Resource name="jdbc/project1" auth="Container" type="javax.sql.DataSource" driverClassName="org.h2.Driver" url="jdbc:h2:tcp://localhost/~/project1" username="sa" password="" maxActive="20" maxIdle="10" maxWait="-1"/>
And then you can lookup data source in each request:
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/project1");
Connection conn = null;
try {
conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO USERS (NAME) VALUES (?)");
ps.setString(1,name);
ps.executeUpdate();
response.getWriter().write("added user "+name);
response.getWriter().write("\n");
} finally {
if (conn!=null) { conn.close(); }
}
Or you can create a singleton class and lookup DataSource once , on start or lazy, as singletons do.
But better try spring data.

comp/env/pool not found in context "java:"?

I have a web application trying to access a JNDI declared in WebSphere Application Server.
The JNDI is declared under Object pool managers. However, I'm receiving an error when I access the pool. The error says that comp/env/pool is not found in context "java:".
My code is written as follows:
InitialContext initialContext = new InitialContext();
ObjectPoolManager opm = (ObjectPoolManager)initialContext.lookup("java:comp/env/pool");
Accessing the pool via the code below works:
ObjectPoolManager opm = (ObjectPoolManager)initialContext.lookup("pool");
I'm confused because according to what I've found on the internet, java:comp/env/ is a default prefix for JNDI. So why does it cause an error in my case?
Thank you!
you can only use java:comp/env if you have declared a reference to the Object Pool in your web.xml under the resource-ref section.
See What is resource-ref in web.xml used for? for further explanation.

Mule-embedded: use the container's own jndiInitialFactory

Consider the following mule configuration and having mule embedded in a Web (Java EE) Application:
<jms:connector
name="jmsConnector"
connectionFactory-ref="jmsConnectionFactory"> <!-- From spring -->
<!-- JNDI Name Resover here? -->
</jms:connector>
<flow name="mainTestFlow">
<jms:inbound-endpoint connector-ref="jmsConnector"
queue="jms/MessageQueue" />
<logger level="INFO" category="mule.message.logging" message="Message arrived." />
</flow>
jmsConnectionFactory refers to a JMS Connection Factory defined in Spring, from:
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/QueueConnectionFactory" />
</bean>
The Queue Connection Factory was tested and is working.
The jms/MessageQueue queue name refers to a resource-ref defined in the web application web.xml file. This JNDI reference is bound at the container level to a javax.jms.Queue managed by the application server and connected to a proper messaging server (ActiveMQ, in this case).
However, Mule doesn't treat the queue="" attribute as a JNDI destination, but as the queue name itself. So, when the above code is initialized, it actually creates a new queue in ActiveMQ named "jms/MessageQueue". What I really wanted was that it correctly retrieved the queue from the JNDI reference in the Web Application descriptor.
Ok, you could say, all I had to do was to configure a JNDI Name Resolver at the JMS Connector and also add the jndiDestinations="true" and forceJndiDestinations="true" attributes to it.
This is acceptable:
<jms:default-jndi-name-resolver
jndiProviderUrl="tcp://localhost:1099"
jndiInitialFactory="???"/>
The real problem is that I don't want to place the real Initial Context Factory class name in the jndiInitialFactory, because it would fall into a container-specific definition. However, my application is sometimes deployed into JBoss 4.2.3, and sometimes, into WebSphere 7. Having 2 configurations and 2 EAR packages is not an option, due to our development process.
Anyway, is it anyhow possible to either tell Mule-ESB to assume the current container (as it is in embedded mode) as the default JNDI Initial Factory for lookups or provide a "generic" JNDI Initial Factory that would recognize the container's JNDI environment? That shouldn't be a problem, because a web application can refer to it's container JNDI environment without additional (or even visible) configuration.
If not possible, can I have my jms:inbound-endpoint refer to a javax.jms.Queue defined in Spring, just as the jms:connector does with the JMS Connection Factory? That would actually be rather elegant and clean, as Mule is Spring-friendly.
Thank you all in advance!
Solution
After much thought and consideration, I finally solved my problem by creating a custom JndiNameResolver wired up to spring JNDI facilities (JndiTemplate, for instance). This is far from the best solution, but I found that to be the one that would least interfere and tamper with Mule's and Spring's inner intricacies.
That said, here is the class:
package com.filcobra.mule;
import javax.naming.NamingException;
import org.mule.transport.jms.jndi.AbstractJndiNameResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jndi.JndiObjectLocator;
import org.springframework.jndi.JndiTemplate;
public class SpringJndiNameResolver extends AbstractJndiNameResolver implements InitializingBean {
private static Logger logger = LoggerFactory.getLogger(SpringJndiNameResolver.class);
private JndiTemplate jndiTemplate;
#Override
public void afterPropertiesSet() throws Exception {
if (jndiTemplate == null) {
jndiTemplate = new JndiTemplate();
}
}
#Override
public Object lookup(String name) throws NamingException {
Object object = null;
if (name != null) {
logger.debug("Looking up name "+name);
object = jndiTemplate.lookup(name);
logger.debug("Object "+object+" found for name "+name);
}
return object;
}
public JndiTemplate getJndiTemplate() {
return jndiTemplate;
}
public void setJndiTemplate(JndiTemplate jndiTemplate) {
this.jndiTemplate = jndiTemplate;
}
}
With that, the configuration falls back into the usual:
<spring:bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate" />
<jms:connector
name="jmsConnector"
connectionFactoryJndiName="java:comp/env/jms/MyConnectionFactory" <!-- from Resource-Ref -->
jndiDestinations="true"
forceJndiDestinations="true"
specification="1.1" >
<jms:custom-jndi-name-resolver class="com.filcobra.mule.SpringJndiNameResolver">
<spring:property name="jndiTemplate" ref="jndiTemplate"/>
</jms:custom-jndi-name-resolver>
</jms:connector>
With that, I was finally able to not have my Mule ESB installation tied up to a specific JMS vendor/implementation. In fact, the JMS (queues and factories) configuration is all left under the application server responsibility.
Nevertheless, one thing remained odd. I expected that the JMS endpoints also used my Jndi Name Resolver in order to lookup the queue from a resource-reference, or its JNDI Name, the same way it did with the Connection Factory. That wouldn't work whatsoever. I finally worked around that by placing the queue name itself, as created in the JMS server:
<flow name="mainTestFlow">
<jms:inbound-endpoint connector-ref="jmsConnector" queue="queue/myQueue"/> <!-- Queue Name, not JNDI Name -->
That worked. So, I'm assuming the JMS Connector doesn't try and look up the queue, but simply uses the connection factory (looked up or not) to directly access the JMS Server.
Regards!
I see the problem in the source code: basically if you provide an externally created connection factory, jndiDestinations and forceJndiDestinations are forcefully set to false.
I haven't messed with JNDI enough recently to provide a generic solution to your problem, which indeed would be the best.
What I would try would be to sub-class org.mule.transport.jms.Jms11Support, inject my Spring looked-up queues in it, rewire it internally to use these queues and, lastly, inject it in the Mule JMS connector itself.

Categories