Retrieving Datasource JDBC connection string via JMX from IBM Websphere - jdbc

I would like to know if it is possible to retrieve a Datasource's JDBC connection String from IBM Websphere Application Server. I already have access to the datasource's JMX Bean but no attribute or operation (see below) seems to expose the JDBC connection URL String. Does anybody know how to retrieve this information?
Attributes:
dbcDriver: WebSphere:name=...
connectionFactoryType: interface javax.sql.DataSource
dataSourceName:
dataStoreHelperClass: description: New JDBC Datasource
loginTimeout: statementCacheSize: 10
jtaEnabled: true
testConnection: true
testConnectionInterval: 180
objectName: WebSphere:name=...
stateManageable: false
statisticsProvider: false
eventProvider: false
authMechanismPreference: 0
stuckTimerTime: 0
stuckTime: 0
stuckThreshold: 0
surgeThreshhold: -1
surgeCreationInterval: 0
connectionTimeout: 180
maxConnections: 10
minConnections: 1
purgePolicy: FailingConnectionOnly
reapTime: 180
unusedTimeout: 1800
agedTimeout: 0
freePoolDistributionTableSize: 5
freePoolPartitions: 1
sharedPoolPartitions: 200
holdTimeLimit: 10
diagnosticProviderName: ...
name: TaggingDatenquelle
Description: New JDBC Datasource
jndiName: jdbc/name
category:
Operations:
getJdbcDriver:
getConnectionFactoryClass:
getDataSourceName:
getDataStoreHelperClass:
getDescription:
getLoginTimeout:
getStatementCacheSize:
isJTAEnabled:
getProperty:
getTestConnection:
setTestConnection:
getTestConnectionInterval:
setTestConnectionInterval:
getObjectNameStr:
isStateManageable:
isStatisticsProvider:
isEventProvider:
getAuthMechanismPreference:
getStuckTimerTime:
setStuckTimerTime:
getStuckTime:
setStuckTime:
getStuckThreshold:
setStuckThreshold:
getSurgeThreshhold:
setSurgeThreshhold:
getSurgeCreationInterval:
setSurgeCreationInterval:
getConnectionTimeout:
setConnectionTimeout:
getMaxConnections:
setMaxConnections:
getMinConnections:
setMinConnections:
getPurgePolicy:
setPurgePolicy:
getReapTime:
setReapTime:
getUnusedTimeout:
setUnusedTimeout:
getAgedTimeout:
setAgedTimeout:
getFreePoolDistributionTableSize:
getFreePoolPartitions:
getSharedPoolPartitions:
getHoldTimeLimit:
setHoldTimeLimit:
showPoolContents:
showAllPoolContents:
purgePoolContents:
purgePoolContents:
purgePoolContents:
getPoolContents:
getAllPoolContents:
showAllocationHandleList:
pause:
resume:
getStatus:
getDiagnosticProviderName:
getDiagnosticProviderId:
getRegisteredDiagnostics:
configDump:
stateDump:
selfDiagnostic:
localize:
getName:
getDescription:
getJndiName:
getCategory:
=====================================

In short, no you can not get the connection URL from any of the currently provided JMX beans.
The only way that WebSphere Liberty exposes the JDBC connection URL is thorugh the java.sql.DatabaseMetaData.getURL() API. If you can get a reference to a DataSource object (via JNDI lookup or #Resource injection), you can get a connection from that, get the DatabaseMetaData and then call getURL().
DataSource ds = (DataSource) new InitialContext().lookup("jdbc/name");
String url = ds.getConnection().getMetaData().getURL();

Related

How to set namespace and item expiration for a symfony5 redis cachepool

I try to configure two cache pools in my Synfony5 app to use a certain namespace and set a default expiration date for the items. After trying for the umpteenth time the umteenth variation I get the feeling that my configuration is going in circles.
What I understood so far:
In the constructor of the RedisAdapter you can set the namespace and the default expiration time
In the createConnection method you set the url of your redis server.
However the constructor of the RedisAdapter seems to already need a redis client (= redis connection?)
RedisAdapter:
/**
* #param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redisClient The redis client
* #param string $namespace The default namespace
* #param int $defaultLifetime The default lifetime
*/
public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{
$this->init($redisClient, $namespace, $defaultLifetime, $marshaller);
}
How can I inject my namespaces and defaultLifetimes into the RedisAdapter?
What I tried so far:
cache.yaml:
framework:
cache:
pools:
cache.sap:
adapter: cache.adapter.redis
provider: app.service.puc_sap_redis_adapter
cache.pers:
adapter: cache.adapter.redis
provider: app.service.puc_pers_redis_adapter
services.yaml:
app.my_redis_adapter:
class: 'Redis'
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- 'redis://%env(string:REDIS_URL)%:%env(int:REDIS_PORT)%'
- { retry_interval: 2, timeout: 5 }
app.service.puc_sap_redis_adapter:
class: Symfony\Component\Cache\Adapter\RedisAdapter
arguments:
$redisClient: '#app.my_redis_adapter'
$namespace: 'sapData'
$defaultLifetime: '%env(SAP_CACHE_TIMEOUT)%'
app.service.puc_pers_redis_adapter:
class: Symfony\Component\Cache\Adapter\RedisAdapter
arguments:
$redisClient: '#app.my_redis_adapter'
$namespace: 'persData'
$defaultLifetime: '%env(CACHE_TIMEOUT)%'
This gets me the error message:
line: 62,
file: "/var/www/vendor/symfony/cache/Traits/RedisTrait.php",
message: "\"Symfony\\Component\\Cache\\Traits\\RedisTrait::init()\"
expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\\ClientInterface,
\"Symfony\\Component\\Cache\\Adapter\\RedisAdapter\" given."
How can I configure the namespaces and expiration time for my two cache pools?
After several days of blood, sweat and tears I leave this here so nobody else will have to experience this deep desperation.
This is how it works. You will need no extra class "just" this nifty cache.yaml in the folder for your environment:
framework:
cache:
pools:
cache.sap:
adapter: app.cache.adapter.sap_redis # custom namespace and item expiration defined there
provider: app.cache.custom_redis_provider # Which server connection should be used
cache.pers:
adapter: app.cache.adapter.pers_redis # custom namespace and item expiration defined there
provider: app.cache.custom_redis_provider # Which server connection should be used
services:
app.cache.custom_redis_provider: # this defines our connection to the redis server
class: \Redis
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- 'redis://%env(string:REDIS_URL)%:%env(int:REDIS_PORT)%' # this defines the url to the redis server. "redis" up front is mandatory
- { retry_interval: 2, timeout: 5 } # defines number of connection retries and connection timeout (not item expiration!)
app.cache.adapter.sap_redis: # here we pass namespace and expiration timeout into the constructor of the redis adapter
parent: 'cache.adapter.redis'
tags:
- { name: 'cache.pool', namespace: 'sapData', default_lifetime: '%env(int:SAP_CACHE_TIMEOUT)%' }
app.cache.adapter.pers_redis: # here we pass a different namespace and expiration timeout into the constructor of the redis adapter
parent: 'cache.adapter.redis'
tags:
- { name: 'cache.pool', namespace: 'persData', default_lifetime: '%env(int:CACHE_TIMEOUT)%' }
You can also set those parameters within the usual cache-pool configuration.
framework:
cache:
default_memcached_provider: 'memcached://localhost'
# could also replace with
# default_redis_provider: 'redis://localhost' # or '%env(REDIS_DSN)%'
pools:
# creates a "custom_thing.cache" service
# autowireable via "CacheInterface $customThingCache"
# uses the "app" cache configuration
custom_thing.cache:
adapter: cache.app
# creates a "my_cache_pool" service
# autowireable via "CacheInterface $myCachePool"
my_cache_pool:
adapter: cache.adapter.filesystem
# uses the default_memcached_provider from above
acme.cache:
adapter: cache.adapter.memcached
# control adapter's configuration - customised provider adaptor & DSN
foobar.cache:
adapter: cache.adapter.memcached
provider: 'memcached://user:password#example.com'
# uses the "foobar.cache" pool as its backend but controls
# the lifetime and (like all pools) has a separate cache namespace
short_cache:
adapter: foobar.cache
default_lifetime: 60
The page (linked above) goes on to say how to tag a service for a specific namespace, but the various configured pools already have one set by default:
Each pool manages a set of independent cache keys: keys from different pools never collide, even if they share the same backend. This is achieved by prefixing keys with a namespace that’s generated by hashing the name of the pool, the name of the compiled container class and a configurable seed that defaults to the project directory.

Set JDBC properties on play-framework application.config

I'd like to set some JDBC properties on the application.config.
For example: useLegacyDatetimeCode=false&useUnicode=true&serverTimezone=UTC
And this is my application.config.
play {
db.prototype.hikaricp {
connectionTimeout = 30 seconds
maximumPoolSize = 5
}
}
db {
default {
driver="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://host:port"
username="user"
password="password"
}
}
However, my program need to access multiple databases so that I cannot combine the url, username, password and properties in the url property.
Is it possible to configure it?
I've tried this, but it does not work.
db {
default {
driver="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://host:port"
username="user"
password="password"
useLegacyDatetimeCode=false
}
}
Thanks.
So, in order to set the JDBC driver specific properties in play configuration you have to configure them through the connection pool implementation.
It will then initiate connections with the given properties to the connection driver.
For example with default connection pool implementation in play (HikariCP)
# SQLServer driver properties, timeout In seconds
db.default.hikaricp.dataSource.queryTimeout = 15
This will map any property to the driver props

Integrating oracle 11g with Grails and Hibernate

I have created a simple grails 3 application. I am trying to connect it to an Oracle database in the datasource configuration.
When I run
SELECT * FROM V$VERSION
in sql developer, the following data is returned back about my database.
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
my application.yml file looks like this:
dataSources:
dataSource:
pooled: true
dialect: org.hibernate.dialect.Oracle10gDialect
driverClassName: 'oracle.jdbc.OracleDriver'
username: 'superCool'
password: 'password'
url: 'jdbc:oracle:thin:#127.0.0.1:1521:coolio'
dbCreate: ''
my build.gradle file contains these lines for hibernate and oracle dependencies.
dependencies {
(...)
compile "org.grails.plugins:hibernate:4.3.10.5"
(...)
compile "org.hibernate:hibernate-ehcache"
compile("com.oracle:ojdbc7:12.1.0.2")
}
My service file looks as follows:
class DatabaseService {
DataSource dataSource
public void testMyDb(User user) {
try {
registerUser(new Sql(dataSource), user)
} catch (SQLException e) {
LOGGER.error("unable to register the user", e)
throw e
}
}
public void registerUser(Sql sql, User user) {
sql.call("{call isertUser(?)}", [user.name])
}
If I remove the
compile "org.grails.plugins:hibernate:4.3.10.5"
from the build.gradle, I can run my integration tests and the database is successfully reached. If I keep it there, I get the following error:
ERROR DatabaseService - unable to register the user
java.sql.SQLRecoverableException: Closed Connection
at oracle.jdbc.driver.PhysicalConnection.getAutoCommit(PhysicalConnection.java:2254) ~[ojdbc7-12.1.0.2.jar:12.1.0.2.0]
UPDATE 1:
I updated my build.gradle file to reference
compile("com.oracle:ojdbc6:11.2.0.2")
as opposed to
compile("com.oracle:ojdbc7:12.1.0.2")
and the generated error now refers to the setter:
ERROR DatabaseService - unable to register the user
java.sql.SQLRecoverableException: Closed Connection
at oracle.jdbc.driver.PhysicalConnection.setAutoCommit(PhysicalConnection.java:2254) ~[ojdbc7-12.1.0.2.jar:12.1.0.2.0]
UPDATE 2:
I caught the SQLException and got the sql error code from it. The code returned back: 08003. According to https://docs.oracle.com/cd/E15817_01/appdev.111/b31228/appd.htm ,
08003 - connection does not exist
So at this point, I set the pooled flag to false in the datasource, and everything worked just fine. So the problem here is narrowed down to that. The plugin is not reacting well to the pooled properties.
I have issued the following sql commands to figure out the size of my pool:
SELECT name, value FROM v$parameter WHERE name = 'sessions';
that returns back 1524.
I have also issued the sql command to see the current allocated amount:
SELECT COUNT(*) FROM v$session;
which returns back 58.
I suppose the question now is, what is causing the pooled property to go crazy.
The solution to this was to disable my pooling. I cannot tell if its a bug, r why it fails, but it does. Thankfully for me, I used jndi lookup for my dataSources, so replacing that made the spark.
dataSources:
dataSource:
pooled: false
dialect: org.hibernate.dialect.Oracle10gDialect
driverClassName: 'oracle.jdbc.OracleDriver'
username: 'superCool'
password: 'password'
url: 'jdbc:oracle:thin:#127.0.0.1:1521:coolio'
dbCreate: ''

Grails - Connection Closed message in Tomcat 7

I have a grails application that connects to an Oracle database over the firewall. I run into "Connection Closed" message.
I am not sure as to why it's happening. My production datasource is configured as follows:
production {
datasource {
dbCreate = "update"
url = ${datasource.url}
}
}
This isn't valid syntax: url = ${datasource.url}. It should be url = "${datasource.url}". Where is datasource.url coming from? If it's a string, you can just use url = datasource.url

Building a JMX client in a servlet installed on the Deployment Manager

I'm building a monitoring application as a servlet running on my websphere 7 ND deployment manager. The tool uses JMX to query the deployment manager for various data. Global Security is enabled on the dmgr.
I'm having problems getting this to work however. My first attempt was to use the websphere client code:
String sslProps = "file:" + base +"/properties/ssl.client.props";
System.setProperty("com.ibm.SSL.ConfigURL", sslProps);
String soapProps = "file:" + base +"/properties/soap.client.props";
System.setProperty("com.ibm.SOAP.ConfigURL", pp);
Properties connectProps = new Properties();
connectProps.setProperty(AdminClient.CONNECTOR_TYPE, AdminClient.CONNECTOR_TYPE_SOAP);
connectProps.setProperty(AdminClient.CONNECTOR_HOST, dmgrHost);
connectProps.setProperty(AdminClient.CONNECTOR_PORT, soapPort);
connectProps.setProperty(AdminClient.CONNECTOR_SECURITY_ENABLED, "true");
AdminClient adminClient = AdminClientFactory.createAdminClient(connectProps) ;
This results in the following exception:
Caused by: com.ibm.websphere.management.exception.ConnectorNotAvailableException: ADMC0016E: The system cannot create a SOAP connector to connect to host ssunlab10.apaceng.net at port 13903.
at com.ibm.ws.management.connector.soap.SOAPConnectorClient.getUrl(SOAPConnectorClient.java:1306)
at com.ibm.ws.management.connector.soap.SOAPConnectorClient.access$300(SOAPConnectorClient.java:128)
at com.ibm.ws.management.connector.soap.SOAPConnectorClient$4.run(SOAPConnectorClient.java:370)
at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:118)
at com.ibm.ws.management.connector.soap.SOAPConnectorClient.reconnect(SOAPConnectorClient.java:363)
... 22 more
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at java.net.Socket.<init>(Socket.java:366)
at java.net.Socket.<init>(Socket.java:209)
at com.ibm.ws.management.connector.soap.SOAPConnectorClient.getUrl(SOAPConnectorClient.java:1286)
... 26 more
So, I then tried to do it via RMI, but adding in the sas.client.properties to the environment, and setting the connectort type in the code to CONNECTOR_TYPE_RMI. Now though I got a NameNotFoundException out of CORBA:
Caused by: javax.naming.NameNotFoundException: Context: , name: JMXConnector: First component in name JMXConnector not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
To see if it was an IBM issue, I tried using the standard JMX connector as well with the same result (substitute AdminClient for JMXConnector in the above error)
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/JMXConnector");
Hashtable h = new Hashtable();
String providerUrl = "corbaloc:iiop:" + dmgrHost + ":" + rmiPort + "/WsnAdminNameService";
h.put(Context.PROVIDER_URL, providerUrl);
// Specify the user ID and password for the server if security is enabled on server.
String[] credentials = new String[] { "***", "***" };
h.put("jmx.remote.credentials", credentials);
// Establish the JMX connection.
JMXConnector jmxc = JMXConnectorFactory.connect(url, h);
// Get the MBean server connection instance.
mbsc = jmxc.getMBeanServerConnection();
At this point, in desperation I wrote a wsadmin sccript to run both the RMI and SOAP methods. To my amazement, this works fine. So my question is, why does the code not work in a servlet installed on the dmgr ?
regards,
Trevor
For the SOAP error, the ConnectException looks like the wrong SOAP host/port was used for the dmgr. I would double-check the server logs for the SOAP port. For the RMI error (NameNotFoundException), it looks like you're trying to use JMXConnectorFactory, which isn't supported by WAS.
If your application is installed on the dmgr, it's probably easiest to just use AdminServiceFactory.getAdminService to get an in-process reference to the AdminService rather than trying to open a new connection to the same process:
http://publib.boulder.ibm.com/infocenter/wasinfo/fep/topic/com.ibm.websphere.javadoc.doc/web/apidocs/com/ibm/websphere/management/AdminServiceFactory.html

Resources