Configurable values to MDB annotations - java

I'm trying to use this method for receiving mail in our EJB3 app. In short, that means creating an MDB with the following annotations:
#MessageDriven(activationConfig = { #ActivationConfigProperty(propertyName = "mailServer", propertyValue = "imap.company.com"),
#ActivationConfigProperty(propertyName = "mailFolder", propertyValue = "INBOX"),
#ActivationConfigProperty(propertyName = "storeProtocol", propertyValue = "imap"),
#ActivationConfigProperty(propertyName = "debug", propertyValue = "false"),
#ActivationConfigProperty(propertyName = "userName", propertyValue = "username"),
#ActivationConfigProperty(propertyName = "password", propertyValue = "pass") })
#ResourceAdapter("mail-ra.rar")
#Name("mailMessageBean")
public class MailMessageBean implements MailListener {
public void onMessage(final Message msg) {
...snip...
}
}
I have this working, but the situation is less than ideal: The hostname, username and password are hardcoded. Short of using ant and build.properties to replace those values before compilation, I don't know how to externalize them.
It would be ideal to use an MBean, but I have no idea how to get the values from the MBean to the MDB configuration.
How should I do this?

You can externalise the annotations into the ejb-jar.xml that you deploy in the META-INF of your jar file as follows:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.0">
<enterprise-beans>
<message-driven>
<ejb-name>YourMDB</ejb-name>
<ejb-class>MailMessageBean</ejb-class>
<activation-config>
<activation-config-property>
<activation-config-property-name>username</activation-config-property-name>
<activation-config-property-value>${mdb.user.name}</activation-config-property-value>
</activation-config-property>
...
...
</activation-config>
</message-driven>
</enterprise-beans>
Then you can set the mdb.user.name value as a system property as part of the command line to your application server using -Dmdb.user.name=theUserName and it will magically get picked up by the mdb.
Hope that helps.

As of JBoss AS 5.1 at least, you can use AOP to configure the #ActivationConfigProperties. I discovered this by looking at the examples that jboss provides here. This is useful if you do not want your username and passwords available to the entire container in a systems property, or if you are like me and never, I repeat NEVER, want to deploy an artifact with a username/password in it. Any how, here is the jist...
Annotate the mdb like this...
...
#MessageDriven
#AspectDomain("TestMDBean")
public class TestMDBean implements MessageListener {
...
Then add a ${whatever}-aop.xml to the deploy dir with internals like below. I left the original comments in there in case Jaikiran does make the changes mentioned...
Note: the annotation must be on one
line only.
<?xml version="1.0" encoding="UTF-8"?>
<aop xmlns="urn:jboss:aop-beans:1.0">
<!-- TODO: Jaikiran - These interceptor declarations need not be here since they
are already declared through the ejb3-interceptors-aop.xml. Duplicating them leads to
deployment errors. However, if this custom-ejb3-interceptors-aop.xml needs to be
independent, then we must find a better way of declaring these. Right now, commenting these
out, can be looked at later. -->
<!--
<interceptor class="org.jboss.ejb3.AllowedOperationsInterceptor" scope="PER_VM"/>
<interceptor class="org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor" scope="PER_VM"/>
<interceptor factory="org.jboss.ejb3.security.RunAsSecurityInterceptorFactory" scope="PER_CLASS"/>
<interceptor class="org.jboss.ejb3.stateless.StatelessInstanceInterceptor" scope="PER_VM"/>
<interceptor factory="org.jboss.ejb3.interceptor.EJB3InterceptorsFactory" scope="PER_CLASS_JOINPOINT"/>
<interceptor factory="org.jboss.aspects.tx.TxInterceptorFactory" scope="PER_CLASS_JOINPOINT"/>
-->
<domain name="TestMDBean" extends="Message Driven Bean" inheritBindings="true">
<annotation expr="!class(#org.jboss.ejb3.annotation.DefaultActivationSpecs)">
#org.jboss.ejb3.annotation.DefaultActivationSpecs (value={#javax.ejb.ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"), #javax.ejb.ActivationConfigProperty(propertyName="destination", propertyValue="queue/MyQueue"), #javax.ejb.ActivationConfigProperty(propertyName="user", propertyValue="testusr"), #javax.ejb.ActivationConfigProperty(propertyName="password", propertyValue="testpwd")})
</annotation>
</domain>
</aop>

Related

EhCache 3: How to unwrap statistics bean?

<?xml version="1.0" encoding="UTF-8"?>
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.1.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.1.xsd">
<service>
<jsr107:defaults enable-management="false" enable-statistics="true"/>
</service>
<cache alias="mySlidingExpiryJCache">
<key-type>java.lang.Long</key-type>
<expiry>
<tti unit="seconds">2</tti>
</expiry>
<resources>
<heap unit="entries">200</heap>
</resources>
<jsr107:mbeans enable-statistics="true"/>
</cache>
</config>
I want to show statistics by extracting the MBean, however I don't know how, because on the net I can see only the bean injected programmatically (see also this SO question).
StatisticsService statisticsService = new DefaultStatisticsService();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.using(statisticsService)
.build();
cacheManager.init();
Any advice ?
You enabled JSR107/JCache statistics. Those are available via JMX. If you want to access those JMX beans programmatically, you can do something like this:
Cache cache = // a JSR107 cache
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("javax.cache:type=CacheStatistics," +
"CacheManager=" + cache.getCacheManager().getURI().toString() +
",Cache=" + mbeanSafe(cache.getName()));
long hits = mBeanServer.getAttribute(name, "CacheHits");
Be aware that the JCache Cache is created differently then you do it in your question. See the extensive documentation here: https://www.ehcache.org/documentation/3.0/107.html
JSR107/JCache is a standard API that many Java caches support. It also includes the exposure of statistics via JMX. The available metrics are defined at: https://github.com/jsr107/jsr107spec/blob/master/src/main/java/javax/cache/management/CacheStatisticsMXBean.java

junit test for stateless ejb + jpa

I would like to write a junit test for my stateless ejb + jpa demo code. I think it is actually not a junit test, it is an integration test.
I have a stateless ejb with an injected EntityManager and PostgreSQL database server is used. I use CDI (Spring is not used in my project) and EclipseLink with a persistent.xml file. My application will be executed on GlassFish server.
I would like to write a test which checks the full logic: calls a method on my example stateless ejb and persist data into a in-memory database. I want to start the in-memory database with my tests and stop it when my test class was executed.
ejb class:
#Stateless
public class PropertyServiceImpl implements PropertyService {
#PersistenceContext(name = "anything-jndi-em")
private EntityManager em;
public String getStringValue(final String key) {
Property property = em.createNamedQuery("Property.findByKey", Property.class)
.setParameter("key", key)
.getSingleResult();
return property.getValue();
}
}
enitity class:
#Entity
#Table(name = "APPLICATION_SETTING")
#NamedQueries({
#NamedQuery(name = "Property.findByKey", query = "select a from Property a where a.key = :key and a.status = 1")
})
public class Property
{
#Id
#SequenceGenerator(name = "APPLICATION_SETTING_SEQ", sequenceName = "APPLICATION_SETTING_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "APPLICATION_SETTING_SEQ")
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "KEY", length = 200, nullable = false)
private String key;
...
}
If I am correct I need to follow the next steps:
create a new persistent.xml file with the proper jdbc connection parameters which will connect to the in-memory dadabase and put it under the /test/Resources/META-INF folder
add some pom dependencies for in-memory database (ex.: hsqldb) and embedded ejb container
create a simple PropertyServiceImplTest.java class
configure somehow that the /test/Resources/META-INF/persistent.xml file will be user by my test class
initialize the embedded ejb container and start the in-memory database
execute my juni test method:
#Test
public void testGetStringValue() {
PropertyService service = new PropertyServiceImpl();
assertNotNull(service.getStringValue("abc"));
}
Could you please help my to write a proper test java class for this scenario?
I highly recommend Arquillian. I use it with gradle on Wildfly 8, 9 and 10. Once setup properly, which can be a bit arduous, it works wonders.
You need only annotate your JUnit test like so:
#RunWith(Arquillian.class)
public class MRSInjectionServiceTests extends ...
And then provide a deployment archive which I do via JBoss ShrinkWrap:
#Deployment
public static WebArchive createDeployment() {
return ShrinkWrap.create(ZipImporter.class, "MRSInjectionServiceTests.war").importFrom(new File(ROOT_WAR_DEPLOYMENT_LOCATION)).as(WebArchive.class);
}
Then you can run these integration tests from maven or gradle. Arquillian will run your App server container (Wildfly, GLassfish, etcetera) based upon your configuration and will run the JUnit tests as a system test with your entire system running.
It is very nice. Well worth the effort.
In your actual test case boot up the javax.ejb.embeddable.EJBContainer. After that use its javax.naming.Context to lookup your stateless bean. The you can use your bean like you are used to and assert its behavior. Keep in mind that an embeddable container impl only has to support a subset (ejb lite) of functionality compared to a full blown ejb container. Here you find a pretty neat example.
Code snippet:
JBContainer ejbContainer = EJBContainer.createEJBContainer();
Context ctx = ejbContainer.getContext();
PropertyService service = (PropertyService) ctx.lookup("java:global/classes/PropertyServiceImpl");
assertNotNull(service.getStringValue("abc"));
I want to share with you my solution. According to your help I had a look at the Arquillian documentation and finally I was able to create a proper integration test.
My test uses GlassFish embedded EE container with HSQL in-memory database.
test java class:
#RunWith(Arquillian.class)
public class PropertyServiceImplTest {
#EJB
private PropertyService propertyService;
#Deployment
public static JavaArchive createTestArchive() {
return ShrinkWrap.create(JavaArchive.class, "test.jar").
.addPackage(Property.class.getPackage())
.addPackage(PropertyService.class.getPackage())
//.addPackage(PropertyServiceImpl.class.getPackage())
addAsResource("META-INF/persistence.xml");
}
#Test
public void testGetStringValue() {
assertNotNull(propertyService);
Property property = new Property();
property.setKey("aaa");
property.setValue("5");
propertyService.setStringValue(property);
assertEquals(propertyService.getStringValue("aaa"), "5");
}
}
persistence.xml
Valid values for target-database: eclipselink doc
<persistence-unit name="example" transaction-type="JTA">
<jta-data-source>jdbc/my-ds</jta-data-source>
<class>a.b.domain.Property</class>
<properties>
<property name="eclipselink.target-database" value="HSQL"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="ALL"/>
</properties>
</persistence-unit>
arquillian.xml
How to eliminate the crazy "Potential problem found" warning message? DatatypeFactory properties has to be set.
WARNING: Potential problem found: The configured data type factory
'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database
'HSQL Database Engine' (e.g. some datatypes may not be supported properly). In rare cases you might see this
message because the list of supported database products is incomplete (list=[derby]). If so please request a
java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory,
ensure that you override getValidDbProducts() to specify the supported database products.
DBUnit specific settings: jboss documentation
DataType factories: dbunit documentation
<engine>
<property name="deploymentExportPath">target/arquillian</property>
</engine>
<container default="true" qualifier="glassfish">
<configuration>
<property name="resourcesXml">myproject/src/test/resources/glassfish-resources.xml</property>
</configuration>
</container>
<extension qualifier="persistence">
<property name="defaultDataSource">jdbc/my-ds</property>
</extension>
<extension qualifier="persistence-dbunit">
<property name="datatypeFactory">org.dbunit.ext.hsqldb.HsqldbDataTypeFactory</property>
</extension>
glassfish-resources.xml
<resources>
<jdbc-connection-pool name="jdbc/my-pool"
res-type="javax.sql.DataSource"
datasource-classname="org.hsqldb.jdbc.JDBCDataSource">
<property name="PortNumber" value="9001" />
<property name="serverName" value="localhost" />
<property name="URL" value="jdbc:hsqldb:mem:arquillian" />
<property name="user" value="sa" />
<property name="password" value="" />
</jdbc-connection-pool>
<jdbc-resource jndi-name="jdbc/my-ds" pool-name="jdbc/my-pool" />
</resources>
Project structure:
src/test/java/a.b.PropertyServiceImplTest.java
src/test/resources/META-INF/persistence.xml
src/test/resources/arquillian.xml
src/test/resources/glassfish-resources.xml
I am so disappointed after I spent 3-4 days with arquillian.
I read documentation about this testing framework and I have created a nice environment with it. There were created beautiful xml files with placeholders for prod and test environments and pom files are done. Everything works fine with my simple ejb and entity java classes.
Today I have been started working on my real java 8 application. After a while something had happened because my tests have failed. When I removed lambda expression from my code then my tests worked fine again.
So when I use lambda expression then the injected ejb is always null:
#EJB
private ConfigurationService configurationService;
The last release of GlassFish Managed 3.1 Container is 1.0.0.CR4, release date: 2013-04-29. It is quite old :(
Arquillian GlassFish module is totally useless :(
I had that problem too, but you can fix it using Payara's embedded server.
<dependency>
<groupId>fish.payara.extras</groupId>
<artifactId>payara-embedded-all</artifactId>
<version>4.1.1.162</version>
<scope>test</scope>
</dependency>

Is it possible to control set-jaxb-validation-event-handler programmatically?

In a CXF SOAP webservice, I'm using the following annotations to disable the xsd validation:
#EndpointProperties({
#EndpointProperty(key = "set-jaxb-validation-event-handler", value = "false")
})
I would like the validation to controlled at runtime (enable/disable it, based on the value of a setting retrieved from a database). My question is: is it possible to disable/enable this handler at runtime? Maybe by writing a custom event handler and not using this property at all?
Thanks.
Edit: an option would be not to disable the validation with set-jaxb-validation-handler, and rather subclass ValidationEventHandler. As explained here, I would then check the database setting in handleEvent and return according to its value.
But there are still a few downsides with this approach: first, this webservice is configured with annotations, and I can't seem to find a way to apply a ValidationEventHandler with annotations (same question as: How to set custom ValidationEventHandler on JAXB unmarshaller when using annotations).
Secondly, it means that the validation will be performed even if I don't need it; I would then lose any performance benefit.
It doesn't in fact exactly suit my needs, so I'm still open to any suggestion.
Yes, it is possible.
MyService service = new MyService();
MyServiceInterface port = service.getMyServicePort();
BindingProvider bindingProvider = (BindingProvider) port;
bindingProvider.getRequestContext().put(
"set-jaxb-validation-event-handler", Boolean.FALSE);
I finally found a working solution.
As I'm running CXF on JBoss EAP 6.0, I added the following configuration to the webservices subsytem in standalone.xml:
<subsystem xmlns="urn:jboss:domain:webservices:1.2">
<!-- ... -->
<endpoint-config name="myconfig">
<property name="set-jaxb-validation-event-handler" value="false"/>
</endpoint-config>
<!-- ...-->
</subsystem>
And the following annotation to the SEI implementation:
#org.jboss.ws.api.annotation.EndpointConfig(configName = "myconfig")
This is the related Maven dependency:
<dependency>
<groupId>org.jboss.ws</groupId>
<artifactId>jbossws-api</artifactId>
<version>1.0.1.Final</version>
<scope>provided</scope>
</dependency>
We still need a restart of the server if we want to change the property value, but it's a lesser evil.
For the people trying to configure that on the bus level, the following worked for me:
<cxf:bus id="soapClientCxfBus" bus="soapClientCxfBus" >
<cxf:properties>
<entry key="set-jaxb-validation-event-handler" value="false" />
</cxf:properties>
</cxf:bus>

Making maxSession property configurable for a specific MDB in JBoss EAP 5.1

How to make maxSession value for an MDB user-configurable?
There is an MDB that listens for a message from a specific queue. It is defined as an annotation.
#ActivationConfigProperty(propertyName = "maxSession", propertyValue = "5").
In order to change the value of the maxSession, the code has to be compiled everytime.
Is there a way to make it user configurable so that there is no build required and without restarting jboss?
Kindly help.
This is the way to externalize this setting from ear:
https://community.jboss.org/thread/178162
But restart is still required.
Update
Found a way to apply new maxSession with system property reference in ejb-jar.xml:
<activation-config-property>
<activation-config-property-name>maxSession</activation-config-property-name>
<activation-config-property-value>${my.mdb.maxSession:30}</activation-config-property-value>
</activation-config-property>
Full JBoss restart is not required, only ear redeploy is needed in this case.
It works for all JBoss versions until JBoss AS 7.
Note that maxSession must be in sync with max pool size:
https://community.jboss.org/message/549083#549083
Note as well, that both the number of sessions and the instance pool size can be specified in an AOP configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<aop xmlns="urn:jboss:aop-beans:1.0">
<domain name="IBMMQ Message Driven Bean" extends="Message Driven Bean" inheritBindings="true">
<annotation expr="class(*)">
#org.jboss.ejb3.annotation.Pool (value="StrictMaxPool", maxSize=10, timeout=10000)
</annotation>
<annotation expr="!class(#org.jboss.ejb3.annotation.DefaultActivationSpecs)">
#org.jboss.ejb3.annotation.DefaultActivationSpecs (value={#javax.ejb.ActivationConfigProperty(propertyName = "channel", propertyValue = "SSL.CLIENTS"), #javax.ejb.ActivationConfigProperty(propertyName = "queueManager", propertyValue = "SSLQM"), #javax.ejb.ActivationConfigProperty(propertyName = "hostName", propertyValue = "10.0.0.124"), #javax.ejb.ActivationConfigProperty(propertyName = "port", propertyValue = "1415"), #javax.ejb.ActivationConfigProperty(propertyName = "transportType", propertyValue = "CLIENT"), #javax.ejb.ActivationConfigProperty(propertyName = "sslCipherSuite", propertyValue = "SSL_RSA_WITH_3DES_EDE_CBC_SHA")})
</annotation>
</domain>
</aop>
You then add the annotation:
#AspectDomain("IBMMQ Message Driven Bean")
to your MDB. This is can be used to externalize both the number of seesions and the instance pool size.
According to this how many Message Driven Beans are created in Jboss? maxSession can't exceed the setting of StrictMaxPool. So when tweaking maxSession - this setting need to be changed as well!

Annotations args dynamic

Every Devlopers Nightmare is how well does his/her code fit into the final packaging....
problem with EJB3.x is usage of annotations with out being able to re compile the code with fresh set of args for the unit to pass thru integration test
ex:
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/Messagess") })
Question is How many J2ee Containers guarantee the queue jms box is always "queue/Messagess"
Well the naming can be "queue/xyzabc" .....
How can such arguments be configured in EJB3.x with out recompiling the code ...???
with regards
karthik
Use activation-config-property in XML.
<message-driven>
<ejb-name>YourMDBName</ejb-name>
<activation-config>
<activation-config-property>
<activation-config-property-name>destination</activation-config-property-name>
<activation-config-property-value>YourValue</activation-config-property-value>
</activation-config-property>
</activation-config>
</message-driven>
Just because you use EJB 3.x with annotations for ease-of-development does not mean that using XML to override annotation config data is "wrong".

Categories