How to get fixed object name for c3p0 mbeans object - java

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.

Related

log4J setSyslogHost(...) equilivant in log4j2

I am migrating a large codebase from log4j to log4j2. Log4j has a method to set the SyslogHost.
syslog.setSyslogHost(syslogDomainName);
I am looking for an equivalent in log4j2.
For completeness, the original log4J code looked like this:
SyslogAppender syslog = (SyslogAppender)Logger.getLogger("available-loggers").getAppender("syslog");
syslog.setSyslogHost(syslogDomainName);
The new code is looking to be a bit more complicated:
org.apache.logging.log4j.Logger logger
= org.apache.logging.log4j.LogManager.getLogger("available-loggers");
org.apache.logging.log4j.core.Logger coreLogger
= (org.apache.logging.log4j.core.Logger)logger;
org.apache.logging.log4j.core.LoggerContext context
= (org.apache.logging.log4j.core.LoggerContext)coreLogger.getContext();
org.apache.logging.log4j.core.config.Configuration configuration = (Configuration)context.getConfiguration();
Appender appender = configuration.getAppender("syslog");
SyslogAppender syslog = (SyslogAppender) appender;
...
plus the replacement for
syslog.setSyslogHost(syslogDomainName);
Edit to add - I am wondering if I can use the AppenderBuilder to create a syslog appender with the correct hostname.
syslog.newSyslogAppenderBuilder().withHost(syslogDomainName);
EDITED -
I am still having trouble making this work.
The log4J2.xml socket configuration below works for basic logging and is what I'm using:
<Socket name="syslog" port="514" host="${sys:log4j.syslog.host}" protocol="UDP" ReconnectionDelay="200">
<JsonLayout2/>
</Socket>
We have a log collector in AWS that can go away at any time, then scale back up with a new IP address. I need to figure out how to get it to switch to that to that new IP.
Log4J1 was pretty simple to do with the syslog.setSyslogHost during runtime. Any ideas on what I am missing in Log4J2?
The first question I would ask is "Why do you want to do this"? If it is because you need to determine the host name dynamically I would point you at Log4j's Lookup mechanism. If you are wanting to log events in RFC 3164 (BSD) format, the SyslogAppender is normally configured as
<Syslog name="bsd" host="targetHost" port="514" protocol="TCP"/>
If you want to set targetHost dynamically then do something like:
<Syslog name="bsd" host="${sys:syslogHost}" port="514" protocol="TCP"/>
which would get the hostname from a system property named "syslogHost". See Lookups for more lookup options or you can write your own custom Lookup.
But if, for some reason, you really need to programatically configure the Appender then there are multiple ways to do it which are described on the Log4j web site. Which you choose depends on whether you are programmatically creating the configuration or whether you want to modify and existing configuration.
To programmatically create a configuration Log4j recommends using a ConfigurationBuilder. This follows Log4j's normal mechanism of creating a configuration in two passes. In the first pass whatever the configuration dialect is (including the ConfigurationBuilder) is converted into a node tree. In the second pass the node tree is converted into the actual configuration. The second pass is generally common to all configurations built this way. So when you look at the ConfigurationBuilder API you won't be building specific classes. Instead you will be creating configuration components, which will later cause the corresponding classes to be created.
Modifying an Appender of an existing configuration cannot be done in a thread-safe manner so it is not allowed. Instead, you can create a new Appender with the same name and start it, remove the existing appender from the Configuration, add the new Appender, modify all the LoggerConfig objects to reference the new Appender instead of the old one, then stop the old Appender. You can find an example of this on Log4j's custom configuration page.
I should also note that Log4j's SocketAppender, on which the SyslogAppender is built, accepts a DNS name that returns multiple ip addresses. If the connection fails the SocketAppender will try to reconnect at any one of the ip addresses.

How do I set java:comp/DefaultDataSource in WildFly?

According to the JEE spec, there should be a default data source provided to applications using java:comp/DefaultDataSource. WildFly out of the box will provide that data source as per the spec.
What I can't seem to find is a way of changing the value to point somewhere else without changing the java:comp/DefaultDataSource mapping on the application itself.
Under "Container" -> "JPA Subsystem" there's a Default DataSource which I have tried setting, but the connection still goes to the
java:jboss/datasources/ExampleDS
#Resource(name = "somedatasource", lookup = "java:comp/DefaultDataSource")
private DataSource ds;
One thing to note, I am not using JPA for the application, I just wanted to get the default data source and use raw JDBC calls as I am working with a lot of LOB data and dynamic table names and it is more only possible on raw JDBC.
The way I test it is
System.out.println(ds.getConnection().getMetaData().getURL());
Which yields jdbc:h2:mem:test
Open your standalone.xml in your favourite editor and locate the line in the urn:jboss:domain:ee:2.0 subsystem that says:
<default-bindings
context-service="java:jboss/ee/concurrency/context/default"
datasource="java:jboss/datasources/ExampleDS"
jms-connection-factory="java:jboss/DefaultJMSConnectionFactory"
managed-executor-service="java:jboss/ee/concurrency/executor/default"
managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default"
managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
and set the datasource value to the physical datasource name that you would like to be mapped to java:comp/DefaultDataSource.

Programmatically accessing camel property from camel context

The project I am working at the moment uses camel as the routing framework.
When configuring camel context in spring we pass a property file that contains a bunch of global properties needed when configuring camel routes or for controlling run time behavior:
<camel:camelContext xmlns="http://camel.apache.org/schema/spring" id="my-id">
<camel:propertyPlaceholder location="my-system.properties" id="global-properties"/>
...
</camel:camelContext>
and say my-system.properties has an entry like below:
my-system.properties
# Global properties that control my-system configuration and run time
...
foo={{bar}}
...
When configuring the routes I can access foo property using the {{foo}} notation. It is also available to other beans using #PropertyInject annotation. However there is one use case in my design when a plain POJO not created by spring (an enum instead but this is not relevant) needs to access my foo property. Because this POJO it is passed the CamelContext as a method argument I find it natural to think I should be able to get the value of foo from there. However I spent a bit of time and could not figure out by myself how.
I know I can load the properties file again or even get the system property System.getProperty("bar") and everything will work but it looks like cheating to me.
There is an api on CamelContext to resolve property placeholders - its the resolvePropertyPlaceholders method:
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/CamelContext.html#resolvePropertyPlaceholders(java.lang.String)
If your POJO is not being managed by the SpringContext I don't see any way you can automatically inject the property. Although your approach may not seem the most fancy or elegant, it has the advantage of not giving you any overhead you could have by using another injection tool.

ActiveMQ: how to set DB lock transaction isolation type properly?

In my ActiveMQ configuration I would like to change the default DB lock transaction isolation level to TRANSACTION_REPEATABLE_READ.
API documentation writes:
public void setTransactionIsolation(int transactionIsolation)
set the Transaction isolation level to something other that
TRANSACTION_READ_UNCOMMITTED This allowable dirty isolation level may
not be achievable in clustered DB environments so a more restrictive
and expensive option may be needed like TRANSACTION_REPEATABLE_READ
see isolation level constants in Connection
In the XML configuration, the jdbcPersistenceAdapter's transactionIsolation attribute accepts only integer-type values, so I cannot use the Connection.TRANSACTION_REPEATABLE_READ constant directly, but only it's value (4) instead:
<persistenceAdapter>
<jdbcPersistenceAdapter dataDirectory="${activemq.data}" dataSource="#mysql-ds" transactionIsolation="4" lockKeepAlivePeriod="5000">
<locker>
<lease-database-locker lockAcquireSleepInterval="10000"/>
</locker>
</jdbcPersistenceAdapter>
</persistenceAdapter>
Is there a way, that I could specify the constant instead of hardcoding number "4"?
As ActiveMQ is Spring-based, I thought I could try to assign it somehow via using <util:constant>, but could not find how to do it...
Try that way:
<util:constant id="transactionType" static-field="java.sql.Connection.TRANSACTION_REPEATABLE_READ" />
EDIT:
The problem is not in spring but in activemq XML Schema:
<xs:attribute name="transactionIsolation" type="xs:integer">
So it wont accept any other value than hardcoded int - you can try put property placeholder here:
transactionIsolation="#{myproperty}"
but i'm not sure if this will work.
Work around to this problem is to somehow configure activemq by pure spring beans (bean id=...) without using dedicated amq tags.
EDIT2: here you have sample config with pure spring tags http://activemq.apache.org/jms-and-jdbc-operations-in-one-transaction.html

How do you pass a variable into the FileSystemResource?

predhme
You came up with a way to read environment variable into a Spring Bean then "was able to then pass that into the FileSystemResource".
Here:
Can I use an Environment variable based location for Spring FileSystemResource?
Could you please explain how you passed the variable to FileSystemResource?
Thanks!
Charlie
You want to use a PropertyPlaceholderConfigurer.
Once you have that set up, you should be able to pull any environment variable with the:
${variableName}
syntax anywhere in your configuration file.
I don't like the idea of having system properties for individual variables like these. Sooner you might turn into hundreds of system properties that might need to be set. Instead as others suggest, have the property file outside of the build and specify the location of the property file as a system property.
Having the properties that change with environment, in a properties file outside of the build (JAR / WAR..) helps a lot in making good builds.
This blog post might help.
Or something similar as below:
Using a property placeholder configurer
<bean id="myConfigPlaceholder"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="${my.sys.variable}/fooModule/foo.properties"
p:placeholderPrefix="#foo{"
p:placeholderSuffix="}" />
Injecting in beans
#Value("#foo{some.key.defined.in.fooPropertiesFile}")
String myFileSystemResourcePath;
(or)
Using util:properties
<util:properties id="fooProps"
location="file:///${my.sys.variable}/fooModule.properties/>
Injecting in beans
#Value("#fooProps[some.key.defined.in.fooPropertiesFile]")
String myFileSystemResourcePath;
Note: When defining property-placeholder-configurer bean, there are different syntactic variations that are supported. You might choose any. Also instead of injecting with #Value, you can reference the property in the xml file with ${variableName} as dlawrence suggested.
Setting the environment variable
for one project:
Setting the envVariable, in this example my.sys.variable can be just done with
project-->(right click)-->run as-->run as configurations-->vm arguments
and there: -Dmy.sys.variable=file:///D:/myBaseDir
globally as a preference:
If this envProp is to be shared with different projects in eclipse, then you can do
Windows->Preferences->Java->Installed JREs->(select the jre)->edit->default vm arguments->and set it with something like -Dmy.sys.variable=file:///D:/myBaseDir

Categories