lunedì 12 dicembre 2011

EJB - Stateful session bean and timeout

This article well explains how you can set the timeout for a stateful session bean in JBoss:
http://www.mastertheboss.com/jboss-application-server/47-ejb-session-beans-.html?start=1

HOW DO YOU CONTROL THE TIMEOUT PERIOD ?

Stateful session beans have configurable timeout values which can control the amount of time a bean can remain idle prior to passivation or removal. Notice the @org.jboss.annotation.ejb.cache.simple.CacheConfig annotation. The idleTimeoutSeconds parameter configures the amount of idle time before the bean is passivated and the removalTimeoutSeconds configures the amount of idle time before the bean is permanently removed. For example, in order to set the timeout to 300 seconds:
@CacheConfig (idleTimeoutSeconds=300)

If the timeout is reached and you use the bean, the exception thrown is:


javax.ejb.NoSuchEJBException: Could not find stateful bean: am203n-6zhbku-gw3ysx5p-1-gw3yw2kw-dg

domenica 11 dicembre 2011

JBoss and cron job

If your application needs to run a cron style job, Quartz Scheduler is best solution I found.

In JBoss (6.x) it is already in the environment and can be used within a Message driven bean.

My application generates a lot of "volatile" data that have to be removed from the database when it is old or it is already processed and re-aggregated.


@MessageDriven(activationConfig =
{@ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "0,30 * * ? * *")})
@ResourceAdapter("quartz-ra.rar")
public class CreanerJob implements Job {

    public void execute(JobExecutionContext arg0) {
          System.out.println("JOB");
    }

}

venerdì 25 novembre 2011

Exception thrown by Query.getSingleResult() on empty resultset

When I ran a query (javax.persistence.Query) to check the existence of a record I got:

22:06:12,026 ERROR [org.jboss.ejb3.tx2.impl.CMTTxInterceptor] javax.ejb.EJBTransactionRolledbackException: No entity found for query

As described in this thread getSigleResult() if there isn't any record to fetch throws a NoResultException.
Use instead getResultList() 

MySql and case sensitive in where clause

By default the content of a VARCHAR field in MySql is not case sensitive in string searches.
This official article gives some solutions if you need distinguish between "hello" and "Hello".

In my case I  have a table with a string field computed starting from the auto-incremental numeric id.
This alias (unique) is stored for performance reasons and uses a set of 62 symbols (A-Za-z0-9).

It is a base-62 representation of the real id so of course, the alias "xa" is different from "xA".

My first table definition was:


CREATE TABLE IF NOT EXISTS `boxes` (
  `idboxes` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `alias` varchar(45) NOT NULL,
  `language` varchar(45) DEFAULT NULL,
  `lastvisit` timestamp NULL DEFAULT NULL,
  `readonly` int(11) DEFAULT NULL,
  `password` varchar(60) DEFAULT '',
  PRIMARY KEY (`idboxes`),
  KEY `aliasIndex` (`alias`)
)


That with this query returned the following records:


select * from boxes where alias='xi'



'320', '2011-11-25 14:22:26', 'xI', 'text/x-java', NULL, '0', '123'
'317', '2011-11-16 17:19:30', 'xi', 'text/plain', NULL, '0', 'pwd'


Since alias must be an unique id this is a BIG problem!
The solution is to set the field collation to one case sensitive charset (or to a binary). You can identify them from the suffix "_cs" (or _bi).

In my case cp1251_general_cs is enough good because it contains all my 62 symbols set.
So the table can be changed in this way:



CREATE TABLE IF NOT EXISTS `boxes` (
  `idboxes` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `alias` varchar(45) CHARACTER SET cp1251 COLLATE cp1251_general_cs NOT NULL,
  `language` varchar(45) DEFAULT NULL,
  `lastvisit` timestamp NULL DEFAULT NULL,
  `readonly` int(11) DEFAULT NULL,
  `password` varchar(60) DEFAULT '',
  PRIMARY KEY (`idboxes`),
  KEY `aliasIndex` (`alias`)
)


The same change have to be applied to the password field!

martedì 8 novembre 2011

Creating a new MySQL DS

Create a file in the deploy directory (eg. mysql-ds.xml) with a content like this:


<datasources>
    <local-tx-datasource>
        <jndi-name>SourceBoxDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/sourcebox</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>root</user-name>
        <password></password>
    </local-tx-datasource>
</datasources>


If JBossAS is running, in the console you will get:

15:17:06,859 INFO  [org.jboss.resource.connectionmanager.ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=SourceBoxDS' to JNDI name 'java:SourceBoxDS'
It's clear from this log that now the db object is mapped in JNDI to the path "java:SourceBoxDS".
In order to use it in the entities definition you can set in the persistence.xml file this property:
 <jta-data-source>java:SourceBoxDS</jta-data-source>

Error in deployment

ERROR: Using the standard deployment precedure with JBossTools I got an error because of a locked file that can not be overwritten.

Error renaming C:\Users\Tiziano\Desktop\Progetti\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_6.x_Runtime_Server1320242844193\tempDeploy\tmp4708729525866439817.jar to C:\Users\Tiziano\Desktop\Progetti\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_6.x_Runtime_Server1320242844193\deploy\SourceBoxEAR.ear\lib\SourceBoxEntities.jar. 
This may be caused by your server's temporary deploy directory being on a different filesystem than the final destination.
You may adjust these settings in the server editor.


 SOLUTION:  Deploy as compressed archive changing the setup in the server configuration.